Earlier this year, I submitted a pull request to SharpSCCM’s repository. SharpSCCM is a tool that Chris Thompson developed with the purpose of demonstrating possible attacks against Microsoft Configuration Manager (ConfigMgr, formerly Microsoft Systems Center Configuration Manager [SCCM]) deployments.
The submitted PR was meant to extend SharpSCCM’s functionality by implementing the option of executing CMPivot queries through the Administration Service (AdminService) REST API. When operating within an SCCM/ConfigMgr site, and under the right context, this added capability can provide offensive operators with the ability to enumerate almost every aspect of a client’s software and hardware (starting with Configuration Manager 1810).
TL;DR — You Can Now Leverage CMPivot with SharpSCCM
SharpSCCM now lets you execute CMPivot queries against clients of a ConfigMgr site. You can see some practical use examples here.
I did not entirely come up with this idea myself. Instead, I was lucky enough to be part of a conversation where the potential of leveraging ConfigMgr’s CMPivot queries and AdminService for offensive tradecraft was discussed. Chris Thompson (@_Mayyhem), Duane Michael (@subat0mik), Andy Robbins (@_wald0), Stephen Hinck (@StephenHinck), all of whom are much more experienced and well-versed than me in the subject at hand and offensive security overall, really brought to light the potential of leveraging these services as an offensive operator. Beyond that, Chris and Duane really pushed and helped me towards the goal of making this happen. Thanks for all the support!
The objective of this blogpost is to show the ways we can leverage the AdminService API as a malicious actor and execute CMPivot queries on ConfigMgr clients, which can now be done with SharpSCCM. The post also aims at providing a brief look at the background and inner workings of this new functionality and with that, hopefully maximizing its effectiveness and safety during use.
When operating with the required permissions, a user can leverage the AdminService to deploy operations to any client devices within the ConfigMgr site. These operations can allow for enumeration of:
And so much more!
There are more than 130 entities (querying objects) available with CMPivot. These entities can be combined and filtered to create more targeted queries as well.
You can follow the link on the operations listed above to see practical use case examples for each.
The following permissions are needed for CMPivot:
· Run CMPivot permission on the Collection scope
· Read permission on Collections
· Read permission on the SMS Scripts object (n/a after version 2107)
· The default scope (n/a after version 2107)
A lot of this terminology may sound unfamiliar if you have not looked into the subject before. This first section is a very general and quick introduction to the main concepts we’ll be discussing in this article.
If you are completely new to Microsoft Configuration Manager (ConfigMgr), there are a multitude of resources from where you can learn online, and although not the main purpose of the article, a good gateway to the subject for me was Chris Thompson’s post “Coercing NTLM Authentication From SCCM”. It has a quick summary of most things you should know in order to start with it from an offensive security perspective.
CMPivot has been a part of the ConfigMgr framework since version 1806. It is presented as an in-console || standalone solution that allows for real-time collection of data from hosts that are clients within a ConfigMgr/SCCM site. The collection of this data is made based on several different entities or queries. These queries allow the user to pull data like Windows event logs, registry values, file contents, operating system (OS) information, hardware information, local group information, and more from any ConfigMgr client host.
Something very useful is also the option to apply different filters to such queries to make them more efficient and better target our desired data. For example, we can filter a query that enumerates the OS of a target in a way that will only show the ones running a 64-bit OS architecture. We can also point these queries against a certain scope. For example, we can run it against a specific resource or target an entire collection of hosts instead.
On the left-hand side of the CMPivot console, we can see just a small portion of the many different entities and queries within them that we can execute to obtain information from clients. These CMPivot queries use a subset of the KUSTO Query Language (KQL).
Administrator Service REST API
Way back with the release of a technical preview of Configuration Manager 1612, Microsoft introduced something called the CMRestProvider. This was a newly implemented open data endpoint that allowed accessing data that was available in the Configuration Manager WMI Provider (Systems Management Service Provider) via a REST API.
As in Microsoft’s fashion, the names changed at least once from then and gave way to what is now known as the AdminService REST API. As part of its regular functioning, ConfigMgr uses this API in the background to perform different queries. For example, ConfigMgr can be configured so an administrator can approve or deny application installation requests from clients by clicking a link in an email, eliminating the need to do this from the ConfigMgr console.
This REST API is available to any domain account that holds the right permissions; this means a user with the required privileges can make queries by sending GET and POST requests to this endpoint. These requests can be made via a web browser, PowerShell, or whatever tool that allows for sending these types of requests.
Several methods are available with the AdminService, but the ones we care about from the perspective of this blogpost are the ones that let us execute CMPivot queries. For this, we can use the AdminService.RunCMPivot method.
When sending our requests, the query must be sent as JSON within the body of the request, and we have the option of pointing it against a collection of resources (hosts, users) or against a single target. This is a little excerpt on how SharpSCCM makes these requests.
Enter Invoke admin-service Command
Now that we have covered a bit of the basics, we can dig a little deeper into the implementation of this capability with SharpSCCM. The new feature now adds the admin-service option to SharpSCCM’s invoke command and with this the possibility to execute any CMPivot queries that we specify with the “-q” flag. A basic example of a query that enumerates the processes running within a particular host/target:
Note: In the example, the target is identified by its resource-id. I will show how SharpSCCM can get us that information in a later section.
Depending on the data we are trying to gather, we can also have the option of applying some filters to our data to make the queries more efficient. In this case, we can do so by listing any process with the name msedge.exe
Results Collection Process
Before looking into some other options available with the admin-service command, let’s take a look at how the results of these queries are returned to us in the background.
After receiving an OperationId from a successful call to the AdminService.RunCMPivot method, we can use that information to call the AdminService.CMPivotResult method and obtain the results from our initial query. Figure 8 illustrates this and shows our enumeration of all processes running on a target the same way we did with SharpSCCM in the previous sections.
Something of note here is that two different method calls are made to complete the query.
If we were performing these actions from the CMPivot user interface, we would see the results of the query displayed in the console; however, since we are making our requests through the Admin Service, we must make a separate request for the results.
When doing this programmatically, keep in mind that there will need to be a delay between the initial query and the collection of results. This is to allow enough time for the PowerShell script that CMPivot uses to gather the queried data to complete its operations on the target.
Luckily, these delays are not too significant since data is sent from CMPivot to the client via SCCM’s fast channel and after the script completes on the client, the results are sent back via the quick state message system. However, we still need to take the wait into account.
Delay and Max Retries
To tackle this, SharpSCCM will periodically check for results after an operation has been triggered; the default is every five seconds for a maximum amount of five times. A user can also tweak these values with the “delay” and “max tries” flags respectively. For example, if we want the tool to check every 10 seconds for a maximum of three times, we could do the following:
Single Resource vs Collection
We can also take advantage of CMPivot’s ability to query either a single resource or a group of resources, known as a collection in SCCM lingo. If we are pointing our queries against a single target, we are going to need the resource-id associated with that host within the ConfigMgr/SCCM site. We can obtain this with SharpSCCM by using the resource-id option from the “get” command. We use the “-d” flag to indicate the hostname that we are trying to resolve. For example:
And if we want to point the query to a collection, we just need to know the name of it or choose a default collection (if available).
We can also have the data returned to us as JSON by using the “-j” flag to our commands.
Practical Use Cases
The following shows some practical examples with SharpSCCM.
We can attempt to enumerate active sessions on a client by leveraging CMPivot to collect records from the Windows Event Log of a target. Events with security Event ID 4624 — An account was successfully logged on — can give us a good idea of the current or recent sessions running on target. A query to get started would look like this:
Registry Keys and Values
Let’s say we want to enumerate a particular registry. For example, if we would like to check all the systems in the site that have PowerShell version 2 available, we would target the default “All Systems” (SMS00001) collection in the following query:
We can query for the local administrators of a certain target too:
Or we can query for a specific admin account on all clients:
Arbitrary File Contents
We can also read the contents of a sensitive file within a target. For example:
Or we can look for a particular file within all clients on the site. Note that it is important to factor in the size and bandwidth of the site before executing a broadly scoped query like this.
My hope is that this added functionality will help bring some attention to the vast power that comes from having full administrator or equivalent permissions within a ConfigMgr/SCCM site and how leveraging CMPivot can allow for very detailed data gathering and enumeration of client hosts.
Starting in Configuration Manager 1702, you have the option of enabling multi-factor authentication (MFA) authentication for SMS provider calls. This can help prevent any unauthorized administrative access request to it.
For some information on how to enable this, see https://learn.microsoft.com/en-us/troubleshoot/mem/configmgr/setup-migrate-backup-recovery/enable-mfa-for-sms-provider-calls
SharpSCCM’s wiki also includes a list of defensive recommendations for ConfigMgr/SCCM: https://github.com/Mayyhem/SharpSCCM/wiki#defensive-recommendations
Lateral Movement without Lateral Movement (Brought to you by ConfigMgr) was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.