If you find your CSE in this “Creating, but not actually running” state, the best approach is to delete it entirely (if you’re sure the process you executed with it is no longer running), which can be accomplished with the following command:
az resource delete –ids “/subscriptions/[subscription]/resourceGroups/[resource group]/providers/Microsoft.HybridCompute/machines/[computer name]/extensions/[CSE Name]”
Attempting to delete a CSE when the underlying executable is still running (e.g., an https beacon running as NT_AUTHORITY\SYSTEM that can’t egress due to proxy controls) will not cause the process to exit, nor will it cause the CSE to delete itself. Instead, it can result in the CSE extension getting stuck in a Deleting state indefinitely, with the only full remediation I identified being to delete the Hybrid Identity parent object from Azure, uninstall the Arc client from the managed system and reinstall everything. It sounds scary, but once I figured this out, it was like a five-minute process to get everything up and running again.
One other thing to keep in mind regarding deleting CSEs: the deletion process removes the C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension folder from the disk of the client system, wiping any files you may have uploaded or modified in that structure. Furthermore, it does take three to five minutes to process the CSE delete command in Azure; this is normal.
One of the interesting things that a CSE can do in addition to executing commands is downloading files from the Internet. An array of files can be specified under the settings arg in the fileUris attrib, which allows for the download of files to the C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\[version]\Downloads\[iterator] folder. This folder structure persists until the CSE is deleted within Azure, at which point everything related to the CSE extension is deleted from disk. This means that you could create a script that would copy files out of this folder to elsewhere on disk, allowing for a mechanism for smuggling files that doesn’t rely on a traditional web download cradle. As these files persist once they are moved outside of the default directory, they could be copied and then run with a subsequent CSE from elsewhere on disk, breaking a static detection dependent on identifying executions from the previously noted CSE downloads folder.
When creating more advanced logic like this, which may or may not succeed, it is also helpful to be able to retrieve output that indicates if an execution was successful or not. While we’re not able to directly recover output from CSE executions, exit codes are returned, meaning that we can include conditional branching in our code that exits with a specific code based on the current state of the program (e.g., successful file copy). Putting these pieces together, let’s stage a super contrived demo that does the following:
Downloads two files via the fileUris parameter from a web server titled notVirus.exe and alsoNotVirus.txt. In this instance, I’ll use a local web server with a hostname of legitServer. As this will be handled via fileUris, we don’t need to explicitly code this into our PowerShell script.The PowerShell script should copy the downloaded files to C:\Windows\TempFinally, the script exits with an exit code of 10 on successful download + copy, and a code of 20 on a failure
A simple PowerShell script that accomplishes these things would look something like:
try
{
Copy-Item -Path “NotVirus.exe” -Destination “C:\Windows\Temp\NotVirus.exe” -Force –
ErrorAction Stop
Copy-Item -Path “AlsoNotVirus.txt” -Destination “C:\Windows\Temp\AlsoNotVirus.txt” –
Force -ErrorAction Stop
if ((Test-Path “C:\Windows\Temp\NotVirus.exe”) -and (Test-Path
“C:\Windows\Temp\AlsoNotVirus.txt”))
{
exit 10
}
else
{
exit 20
}
}
catch
{
exit 20
}