PRT_Utils.ps1
# Parses the Cloud AP Cache Data CacheData # C:\Windows\system32\config\systemprofile\AppData\local\microsoft\windows\CloudAPCache\AzureAD\<hash>\cache\cachedata # May 31st 2023 function Parse-CloudAPCacheData { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [byte[]]$Data ) Process { # Parse the header $p = 0; $version = [System.BitConverter]::ToInt32($Data,$p); $p += 4 if($version -ne 2) { Throw "Invalid version: $version. Was expecting 2." } $hash = $Data[($p)..($p-1 + 32)]; $p += 32 $p += 8 $dataLen = [System.BitConverter]::ToInt64($Data,$p); $p += 8 Write-Verbose "CacheData version: $version" Write-Verbose "CacheData SHA256: $(Convert-ByteArrayToHex -Bytes $hash)" Write-Verbose "CacheData length: $dataLen" $unk = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $keyId = [guid][byte[]]$Data[($p)..($p-1 + 16)]; $p += 16 Write-Verbose "CacheData key id: $keyId" # Number of nodes $nodes = [System.BitConverter]::ToInt32($Data,$p); $p += 4 # 00 00 02 00 $unk2 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 # Number of nodes (again) $nodes = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $cacheNodes = [array]::CreateInstance([pscustomobject],$nodes) Write-Verbose "$nodes nodes" for($n = 0 ; $n -lt $nodes; $n++) { $type = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose "Node $($n+1) type: $type" $cryptoBlobSize = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose " CryptoBlob length: $cryptoBlobSize" # 04 00 02 00 $unk3 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $encryptedBlobSize = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose " EncryptedBlob length: $encryptedBlobSize" # 08 00 02 00 $unk4 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $cacheNodes[$n] = [pscustomobject][ordered]@{ "Type" = $type "CryptoBlobSize" = $cryptoBlobSize "EncryptedBlobSize" = $encryptedBlobSize "CryptoBlob" = New-Object byte[] $cryptoBlobSize "EncryptedBlob" = New-Object byte[] $encryptedBlobSize } } foreach($cacheNode in $cacheNodes) { $cryptoBlobSize = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose "CryptoBlobSize: $cryptoBlobSize" $cacheNode.CryptoBlob = $Data[($p)..($p-1 + $cryptoBlobSize)]; $p += $cryptoBlobSize if($p % 4 -ne 0) { $p += (4 - ($p % 4)) } $encryptedBlobSize = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose "EncryptedBlobSize length: $encryptedBlobSize" $cacheNode.EncryptedBlob = $Data[($p)..($p-1 + $encryptedBlobSize)]; $p += $encryptedBlobSize if($p % 4 -ne 0) { $p += (4 - ($p % 4)) } } return $cacheNodes } } # Parses the decrypted data blob from CacheData # Jun 2nd 2023 function Parse-CloudAPEncryptedBlob { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [byte[]]$Data ) Process { # Parse the header $p = 0; $version = [System.BitConverter]::ToInt32($Data,$p); $p += 4 if($version -ne 0) { Throw "Invalid version: $version. Was expecting 0." } $unk01 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk02 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk03 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk04 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk05 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk06 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $unk07 = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $keyId = [guid][byte[]]$Data[($p)..($p-1 + 16)]; $p += 16 $id1 = $Data[($p)..($p-1 + 32)]; $p += 32 $id2 = $Data[($p)..($p-1 + 32)]; $p += 32 Write-Verbose "CacheData blob version: $version" Write-Verbose "CacheData key id: $keyId" Write-Verbose "CacheData blob ID1?: $(Convert-ByteArrayToHex -Bytes $id1)" Write-Verbose "CacheData blob ID2?: $(Convert-ByteArrayToHex -Bytes $id2)" # Return the payload return $Data[$p..$($Data.Length)] } } # Decrypts POP Key (Session Key) blob using DPAPI # May 31st 2023 function Unprotect-POPKeyBlob { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [byte[]]$Data ) Begin { # Load system.security assembly Add-Type -AssemblyName System.Security } Process { # Parse the header $p = 0; $version = [System.BitConverter]::ToInt32($Data,$p); $p += 4 $type = [System.BitConverter]::ToInt32($Data,$p); $p += 4 Write-Verbose "SessionKey version: $version" Write-Verbose "SessionKey type: $type" if($type -ne 1) { Throw "Only software key (type 1) can be exported." } # Get the key $key = $Data[$p..$($Data.Count)] # Decrypt using DPAPI return [Security.Cryptography.ProtectedData]::Unprotect($key,$null,'LocalMachine') } } |