Autopilot: Escape the Administrator

Last Updated on March 29, 2024 by rudyooms

Did you ever run into an issue in which the user was still in the local administrator group after the device was enrolled with Windows Autopilot (at least that is what you thought happened) even when you configured the Autopilot profile and made sure the user account type was set to “standard

In this blog, I am going to explain at which point in time during Autopilot the user will become or NOT become a local admin. With this explanation, I am hoping things will be clearer after you have read this blog post!

I will divide this blog into multiple parts:

  1. Introduction
  2. Cloud Domain Join (Level 100)
  3. CloudAssignedOobeConfig (Level 200)
  4. getOobeSettingsOverrideAsync (Level 250)
  5. Dsreg (Level 300)
  6. The Flow
  7. Personal Devices
  8. Conclusion

1. Introduction

Every time I read these kinds of questions on Reddit, I immediately tell them the fact that the device didn’t receive the proper Autopilot profile and just enrolled and performed a regular Azure Ad Join/Entra Join instead.

With the use of Autopilot, we can natively make sure that the enrolling user is not going to be added to the local administrators‘ group. We can do so by configuring a simple Autopilot Profile setting to define the user account type. As shown below, the user account type is configured to Standard.

Nothing more, right? But I started questioning myself what this flow looked like and how I could explain it a bit better because just yelling at people and telling them the device didn’t receive the Autopilot profile isn’t going to work.

So let’s dive into how you could become an administrator (preferably not) during Windows Autopilot

Please Note: with a new option suddenly showing up in Entra under devices –> all devices –> device settings we can now also configure the same kind of setting for regular Entra enrollments. If you are wondering if that setting could interfere with the settings in the Autopilot Profile, please read this blog!

2. Cloud Domain Join

Let’s first start with explaining, when the user will become an Admin or not! When we need to explain at which point the user becomes or does not become a local admin on the device, we need to zoom in on the Azure Ad Join / Entra Join process.

If we kick off the Autopilot Enrollment, the device will eventually start enrolling the device into Entra if you enter the username and password. If you have read my blogs about Autopilot, there are some barriers it needs to cross first, so keep that in mind.

Afbeelding met tekst, schermopname, software, Webpagina

Automatisch gegenereerde beschrijving

If we enter our username and password, the Enrollment Status Page (ESP) will kick in (if configured) and the device will start joining your organization.

Afbeelding met tekst, schermopname, Lettertype, logo

Automatisch gegenereerde beschrijving

After generating the device and transport key, It will hand over the access token for the enrollment service and will start enrolling/registering the device. If everything works out the service will send back the MS-organization-Certificate

Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

Let’s start with how this Entra join request looks like when we configured the Autopilot user to be a standard user. To do so I am going to use the Fiddler tool. If we put Fiddler in place will notice a couple of things

Afbeelding met tekst, schermopname, algebra

Automatisch gegenereerde beschrijving

As shown above, In the device registration request that is sent over to enterpriseregistration.net together with the Access token, we will spot the MSA-DDID and the CertificateRequest.

In the device registration response we get, we will find some interesting information.

Afbeelding met tekst, elektronica, schermopname, scherm

Automatisch gegenereerde beschrijving

As shown above, in the device registration policy response we received, we will find the MS-Organization-Certificate and some additional information. This additional information contains the MemberShipChanges and the SIDs that will be added to the LocalSid S-1-5-32-544 AKA Local Administrator group.

Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

Those 2 SIDS(Global administrator role and the Device administrator role) are the default ones that will be added to the local administrator group.

If we don’t want everyone who has the global admin role to become an admin on all of our devices (duhhh), we need to make sure we change the device registration policy and configure the EnableGlobalAdmins to False. To do so we need to change this Global Adminstrator option in Entra and configure it to NO

The device registration request above is based on the fact that the enrolling user is a standard user but how does it look like when the enrolling user is NOT a standard user but a friendly local admin?

As shown above, the only real difference is that in the response we will notice an additional SID that has been added to the “AddSIDs”. This additional SID belongs to my user and this SID will be added to the local administrator group.

I need to add a small note here because when using Autopilot pre-provisioning this happens when the user logs in, NOT when we are pre-provisioning the device. (the device only joins Entra to enroll into MDM, from there on the Azure AD / Entra certificate is whacked, and with it the Entra enrollment)

So, when our device is getting a proper Entra Join with the enrolling user, that’s when the user will become a local administrator….. or not. But still, the question remains, how does this exactly happen?

3. CloudAssignedOobeConfig

When trying to find out what this process looked like, I started looking at the Windows Autopilot file: Windows.Management.Service.dll. In this DLL we have a function called: GetOobeSettingsOverride

Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

This nice function calls upon another function called GetConfig. I assume it tries to get a specific config.

The name spoils the fun a bit but let’s move on, shall we? Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

As shown above, this GetConfig function essentially attempts to retrieve the AutoPilot configuration named “CloudAssignedOobeConfig”

The CloudAssignedOobeConfig…. That is one we heard before, right? As in this blog, I was describing how a specific setting in the Autopilot profile allows or prevents the Pre-Provisioning

Only WhiteGlove in the Building – Call4Cloud | MMP-C | WinDC | Autopilot | Intune

At first, I was trying to find this Allow Pre-provisioning setting in the CloudAssignedOobeConfig but if you have read the blog above, that setting isn’t defined in the CloudAssignedOobeConfig. Maybe this time it’s different?

Let’s get back to the story to find out! The GetConfig is indeed trying to find the CloudAssignedOobeConfig. This config is stored on the disk in a file called AutopilotDDSZTDFile.Json in the c:\windows\servicestate\wmansvc folder

Besides being stored on the disk, it is also being cached in the registry. The CloudAssignedOobeConfig will be stored in the Microsoft\Provisioning\AutopilotPolicyCache registry node. To be precise in a PolicyJsonCache value

Afbeelding met tekst, schermopname, Lettertype, software

Automatisch gegenereerde beschrijving

If you ever are stuck with a lingering Autopilot Profile, just trash these registry keys above (Autopilot) and the corresponding JSON file on the disk. If we open this reg_sz value we will indeed spot the CloudAssignedOobeConfig in it with a value of 1310

If we change the setting in the Autopilot profile to define if the user is a standard user or a local admin, we will notice that just as shown below, the value will change with “2”

Afbeelding met tekst, schermopname, Lettertype, algebra

Automatisch gegenereerde beschrijving

This value 2, points us directly to the OobeUserNotLocalAdmin setting. I guess we can now be pretty sure that the CloudAssignedOobeConfig is responsible for making sure the user is or is NOT a local admin on the device.

This config will be checked when the device boots and the Windows Management Service is started. But still, the question remains… How does the CloudDomain Join process know how to start looking for this config? Do you know? Let’s find out!

4. getOobeSettingsOverrideAsync

Looking back, I should have started with the CloudDomainJoin.JS which is stored in the systemapps\Microsoft.Windows.CloudExperienceHost folder because that’s the file that holds the “code” to kick off the Cloud Domain in the first place.

Afbeelding met tekst, schermopname, Lettertype, nummer

Automatisch gegenereerde beschrijving

If we open that important JS file, we could spot a thing or 2. Let me describe how I think the Cloud Domain join that is taking place will determine if the user needs to be a standard user or not.

1.Initialization:

When the CloudDomain.JS code is executed, the getCommonFeatures function is called upon to compare client and server features.

Besides the wonderful MMPCRedirectFeature (which got my attention…) we also have an additional ClientFeature called: GetPolicy

Afbeelding met tekst, Lettertype, schermopname, lijn

Automatisch gegenereerde beschrijving

2.Fetching Policy Information:

The “CentralizedGetPolicy” will redirect me to the getPolicyString function. This function is called to retrieve the policy information.

Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

3. Fetching OOBE Settings (AutoPilot):

From there on the Getpolicystring will make a call to the getOobeSettingsOverrideAsync function. This function is used to retrieve AutoPilot OOBE settings.

I guess the circle is round, now, right?

getOobeSettingsOverride –> CloudDomain.js

The same function that got me on the correct path to the CloudAssignedOobeConfig is also mentioned in the Windows.Management.Service.dll

Afbeelding met tekst, schermopname, Lettertype, lijn

Automatisch gegenereerde beschrijving

To resume: The Cloud Domain Process checks which settings are defined in the Oobe Settings. This code is tied to the same one in the Windows Management Service.dll. With those settings in the pocket, it will determine if the user needs to be added to the local administrator group when the device is going to be Cloud Domain AKA Entra joined!

5. DSREG.Dll

You could say that the getOobeSettingsOverrideAsync function plays a key role in determining whether the user becomes a local administrator during device Entra join based on Autopilot settings but how does it go from there?

If we go back to part 2 (Cloud Domain Join) we would have noticed that during the Entra Join, based on the outcome of the OOBESettings the device would send out a device registration request to the service. The DLL responsible for registering a device in Entra Join is the famous DSREG.Dll! So, in this part, I am going to use the DSREG.Dll and combine it with the information you have learned from the previous parts.

Let’s assume we have configured the Autopilot profile and configured the user account type to be an Administrator

If we take a closer look at the device registration request this time with the dsreg.dll loaded in the back of our mind and the type set to administrator, we will notice that when the “ReturnClientSid” is added to the request

When taking a closer look at dsreg.dll and trying to find out which part of the dsreg.dll holds the ReturnClientSid, we will notice that this information is added in the Registration Request body.

If the User Account is set to Administrator in the Autopilot Profile, the “Flow will Supports Joiner as Admin” and would add the ReturnClientSid in the request (Which is also the default behavior with a regular AAD Join!)

If the user account is set to Standard in the Autopilot Profile, the flow will NOT support the joiner as admin and will NOT add the ReturnClientSid in the request.

Afbeelding met tekst, lijn, schermopname, Perceel
Automatisch gegenereerde beschrijving

If the request did NOT contain the ReturnClientSid attribute, we will notice that the device registration join response will mention that the User SID was not provided for the device Join.

Once the flow has determined if the user needs to be a local admin, it will also start Applying the MemberShip Changes.

In this ApplyMemberShipChanges, we noticed that it would add the array of SIDs that it received in the device registration response to the local administrator’s group

So if we switch back to Fiddler, this is what we would notice.

6. The Flow

As always all of my fancy words in a nice simple mspaint flow

7. Personal devices

Now we have learned the details about how a user becomes a standard user during Autopilot, we still need to defend ourselves when the device doesn’t receive the Autopilot profile.

When our device boots and somehow, the device doesn’t receive the Autopilot profile (issues with the Autopilot marker for example) The user could still enroll his device the old school way and with it become a local admin on his device. Believe me, you don’t want that to happen!

To make sure the user is a standard user, you also need to make sure that you are blocking the enrollment of personal devices!

Afbeelding met tekst, Lettertype, nummer, schermopname

Automatisch gegenereerde beschrijving

Overview of enrollment restrictions – Microsoft Intune | Microsoft Learn

If you are blocking personal devices to get MDM enrolled, the Intune enrollment will fail and with it the whole enrollment! So, if you didn’t configure this option, everyone could just enroll their device into Entra.

If you are using Autopilot, please make sure that this Enrollment restriction is in place and set to “block Personally owned MDM enrollment” If you are blocking personal devices, devices that didn’t receive the Autopilot profile because they aren’t recognized as an Autopilot profile will be blocked! If they are blocked you will not end up with a device with the enrolling user in the local administrator group!

Of course, this personal device restriction can be bypassed by configuring an offline Autopilot json file but then again, Autopilot isn’t a security feature.

Conclusion

The conclusion is straightforward: If the user on a newly enrolled Autopilot device is somehow a member of the local administrators group the device was NOT recognized as a Windows Autopilot device. If the device isn’t recognized as a Windows Autopilot device, it will just perform a regular device enrollment (if not blocked)

One thought on “Autopilot: Escape the Administrator

  1. hey Rudy,
    As always a terrific blog, was surprised to see this issue but it makes sense no enrollment profile so the user ends up as admin. However in our case, personal device enrollment is also blocked and still user ended up as local admin. Strange!

Leave a Reply

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

8  +  1  =