The Token Games: The Ballad of Autopilot and Profiles

Last Updated on July 28, 2023 by rudyooms

This blog will be about me showing how the device tries to fetch its device token (x-device-token) and use it to fetch the Autopilot profile. I will also show you how you could get it yourself by using the same cached device token you could get from the registry!!

  1. Introduction
  2. How it works
  3. The Authentication flow
  4. Fetching the Profile ourselves < August Build
  5. Fetching the Profile ourselves > July Build

1. Introduction

When looking back at the blog I wrote about the Autopilot Marker, and how it could give you issues when fetching your Autopilot profile I decided to remove a specific part from the troubleshooting part because I was still in doubt if it could work. This troubleshooting part will show you how we could determine if the device is possible to fetch the Autopilot Profile.

So let’s dive into some background information first to know what happens before we are finally getting this wonderful Company branded Autopilot screen

Please Note: While writing this blog, I decided to remove some additional deep dives. I will dedicate a unique blog to each one of them. I will add the direct link to the blog, once they are released!

  • OfflineDeviceID
  • GetMSATicket
  • DeviceAddRequest

2. How it works

A small heads up! It’s best to just forget everything you probably know about how Autopilot before starting to read further.

When the device first boots and shows you the OOBE screen, it will establish an HTTPS connection in the background and starts communicating to the good old well-known service (1) login.live.com/ppsecure to perform some Device Authentication.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

The device will perform a DeviceAddRequest AKA AddCredentialRequest post to the https://login.live.com/ppsecure/deviceaddcredential.srf URL to start the Authentication and to fetch the device its Device Unique Identifier (DUID)

Afbeelding met tekst

Automatisch gegenereerde beschrijving

In this Passport SOAP post sent to login.live.com, you will notice some nice DeviceInfo. This DeviceInfo contains a lot of information about the device itself such as the EKPub/SmBiosSystemSerialNumber, OfflineDeviceID, etc. The stuff that makes the device unique!

It almost looks like the same information as from the HardwareHash……… ow wait it is…

Of course, besides this SOAP post with DeviceInfo in it, we will also notice the same DeviceAddRequest in the LiveID event log with the event 6115

In the SOAP-response the device got (2) when sending out the device info, we will also notice a unique HWDeviceID and the GlobalDeviceID in it (which seems different each time)

After we got ourselves the HWDeviceID, the device needs to (3) request a security token (RST) from the Security Token Service (STS): login.live.com/RST2.SRF.

To retrieve the security token, it needs to confirm its identity to the STS. I will assume for now, that it will also pass the HWDeviceID/DAToken we got before to confirm its identity to the STS

As shown below, a great overview from mohamad halabi of how a client requests a security token to get access to the “Service”

After login.live.com (STS) has verified the device its identity, the STS will send back the (4) x-device-token (MSA Ticket with the DDID in it).

My guess is that this security token/device token is somewhere stored in this Encrypted CipherData that we got in the response. (Need to spend some more time on it, I guess)

This security token is going to be used to (5) get the AutopilotDeviceBootstrapPolicies by sending out a get command to ztd.dds.microsoft.com/ztd/device/autopilotdevicebootstrappolicies with that same x-device-token as we noticed in the headers.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

As shown above, only the X-Device-Token is being sent to the Autopilot Service in its headers. The device DOES NOT send out the Hardware Hash directly but “only” the Security Token it got when authenticating to login.live.com/RST2!

Please Note: After the 2022-07 build, we will spot a small difference. In this get command to the same Autopilot service, it will also send out the Autopilot_Marker and the Hardware-Hash.

If the Autopilot Service recognizes the device it will check if it matches the Autopilot Device that was created when uploading the Hardware Hash in Microsoft’s back-end database. If it’s a match it will (6) return the famous Autopilot profile in JSON format as shown below if not you will end up with the error “Unable to get device ZtdId”

Afbeelding met tekst

Automatisch gegenereerde beschrijving

The Autopilot profile will be stored in the wmansvc folder and with it, it is able to (7) show us the Autopilot Company branding screen.

After entering the user its email address/password and approving the MFA the device will (8) start the AAD join and the Intune Enrollment. Let’s continue our story by looking at the corresponding flow below

3. The Authentication Flow

Even when I showed you a graphical overview about how ws-trust works, let’s convert all of the text and information from above into a simple flow to get it a bit more clear.

4. Fetching the Profile ourselves < August Build

Before continuing my store I noticed some funny behavior while playing around with the November update 2022-11

Afbeelding met tekst

Automatisch gegenereerde beschrijving

The funny behavior I am referring to is: After uploading the hash from the OOBE and clicking next, next, and letting the device reboot, it doesn’t get its Autopilot profile the first time.

To solve this stupid issue, you will need to reset/reboot the device and again click on next, next to watch the device reboot again. Before rebooting the device again to start over the language wizard etc I wanted to make sure the device was able to get it’s device-token and could authenticate with it out ztd.dds.microsoft.com

Of course, I first made sure the device its serial showed up on the Windows Autopilot Devices.

After I made sure the hash was uploaded successfully I didn’t reboot the device but I opened the registry as the current user (defaultuser1). Why I opened the registry? Because while writing this blog I stumbled upon some nice cached Security Tokens / MSA Tickets locations being mentioned in the WLIDSVC.dll

Let’s take a look at the IdentityCRL registry key and how it looks on the device.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

As shown above, HKCU:\SOFTWARE\Microsoft\IdentityCRL\Immersive\production\Token\ will show you some nice Security Tokens! Let’s fire up a PowerShell session and launch this script to find if I could spot some tokens with a ZTD reference in it (I borrowed this nice script from Dirk-Jan Mollema 😛 )

Add-Type -AssemblyName System.Security
$key_path = 'HKCU:\SOFTWARE\Microsoft\IdentityCRL\Immersive\production\Token\'
cd $key_path
$childs = (Get-ChildItem $key_path | where { $_.Property -eq "DeviceTicket" })
Foreach($child in $childs) {
$child."DeviceId" | write-host
$bytes = (Get-ItemProperty -Path $child.PSPath)."DeviceTicket" 
$b64 = [Convert]::ToBase64String($bytes[4..$bytes.length])
([Text.Encoding]::Unicode).GetString([Security.Cryptography.ProtectedData]::Unprotect($bytes[4..$bytes.length],$Null,
[Security.Cryptography.DataProtectionScope]::LocalMachine)) | write-host
 }
Afbeelding met tekst

Automatisch gegenereerde beschrijving

As shown above… It doesn’t mention the ZTD. Okay, so we got no ZTD information in the defaultuser1 its registry keys, let’s proceed and take a look at the same registry key but this time for the s-1-5-18 AKA NT Authority\SYSTEM user

Afbeelding met tekst

Automatisch gegenereerde beschrijving

By the looks of it, the s-1-5-18 system user also has some beautiful tokens we could use, I guess? As the keys are DPAPI protected, it looks like you can’t unprotect the SYSTEM token from another user session.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

As shown above, when trying to fetch the token from the SYSTEM account it will throw an error mentioning the fact that the “Key not valid for use in specific state”. Almost sounds like the error you could get when you want to export a certificate with its private key from the Certificate stare and the key is not marked as exportable. But who cares, we have Psexec. So Let’s elevate ourselves to SYSTEM by using psexec -I -s powershell.exe.

After elevating to SYSTEM privileges I entered the same PowerShell command I got from Dirk-jan to see what it could trigger. As shown below… yes we can spot something pretty useful! The MSA device ticket (X-device-token) for the ztd.dds.microsoft.com service AKA the Autopilot Service.

Afbeelding met tekst

Automatisch gegenereerde beschrijving

Let’s copy-paste that ticket and let’s invoke a web request to that same service and add the x-device-token to the headers

$headers = invoke-webrequest -uri "https://ztd.dds.microsoft.com/ztd/device/AutopilotDeviceBootstrapPolicies" -headers @{ "user-agent" = "Autopilot.10.1.1"; "X-Device-Token" = "TOKENYOUGOTFROMTHEREGISTRY"} -UseBasicParsing -verbose
Afbeelding met tekst

Automatisch gegenereerde beschrijving

As shown above… we got ourselves a nice response and when we request the “rawcontent” from the $headers variable, we will notice that it shows us the Autopilot information in JSON format. Looks familiar right? Yeah, it does! As it is your JSON Autopilot profile!

Afbeelding met tekst

Automatisch gegenereerde beschrijving

Please Note: The screenshot below is from another trace, so it shows a different AadDeviceId

When comparing the AadDeviceId, with the one in the Azure portal it is a match!!! Woohoo!! Isn’t that just wonderful?

Afbeelding met tekst, schermafbeelding, computer

Automatisch gegenereerde beschrijving

Even when the device wasn’t triggered to fetch the profile, we could still determine if the device should be capable to do so.

5. Fetching the Profile ourselves > July Build

In of my latest blogs I was mentioning the fact that a device could fail to download its Autopilot profile when the Autopilot_Marker was set. With this new “Autopilot requirement” I also need to show you how you could fetch the profile when your Autopilot Device was enrolled > July build. So my advice…please read this blog below first!

The bottom line: Microsoft added the Autopilot_Marker. If the Autopilot_Marker was set in the past (>July Build) and the device reaches out to the Autopilot Service, that Marker needs to match! If the device doesn’t send it or it isn’t a match you will end up with the famous 908: HardwareMismatchDetected

When looking at the PowerShell script I mentioned above and looking at the Fiddler trace, it now sends 4 properties in its headers

Luckily only 2 of them are necessary to fetch the Profile. As shown below, only the X-Autopilot-Marker and the X-Device-Token are required

So the only thing left is the AUTOPILOT_MARKER and to fetch it we can use the get-UEFIVariable I also showed in that blog

Once we got that second requirement, we can simply add it to our existing PowerShell script shown below

$headers = invoke-webrequest -uri "https://ztd.dds.microsoft.com/ztd/device/AutopilotDeviceBootstrapPolicies" -headers @{ "user-agent" = "Autopilot.10.1.1"; X-Autopilot-Marker: "MARKER"; "X-Device-Token" = "TOKENYOUGOTFROMTHEREGISTRY" -} -UseBasicParsing -verbose

Once we added the UEFI_Marker and fired off that PowerShell script we will notice that as shown above, the Autopilot service will deliver your Autopilot Profile

Conclusion

Knowing what happens behind the Autopilot curtains is always nice knowledge to have but knowing how you could determine if the device should be able to fetch its Autopilot profile is really important.

2 thoughts on “The Token Games: The Ballad of Autopilot and Profiles

  1. Cool! 🙂 My hope was to manually trigger autopilot branding on devices that pretend they are not supposed to enroll. One yesterday just skipped forward to normal Windows logon-screen.

  2. Hi, thanks for the detailed explanation of the tokens. I was following your guide today and first I managed to access S-1-5-18 SystemAccount tokens, but later that day it didn’t work. I am using an elevated powershell 7, and get the “Key not valid for use in specific state” error. Here is the complete code I use:

    “`
    Add-Type -AssemblyName System.Security
    New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS
    $key_path = “HKU:\S-1-5-18\SOFTWARE\Microsoft\IdentityCRL\Immersive\production\Token\”
    cd $key_path

    $childs = (Get-ChildItem (Get-Location).path | where { $_.Property -eq “DeviceTicket” })
    Foreach($child in $childs) {
    $child.”DeviceId” | write-host
    $bytes = (Get-ItemProperty -Path $child.PSPath).”DeviceTicket”
    $b64 = [Convert]::ToBase64String($bytes[4..$bytes.length])
    ([Text.Encoding]::Unicode).GetString([Security.Cryptography.ProtectedData]::Unprotect($bytes[4..$bytes.length],$Null,[Security.Cryptography.DataProtectionScope]::LocalMachine))
    }
    “`

Leave a Reply

Your email address will not be published. Required fields are marked *

54  +    =  59