Feb 3 2025 |
Further Adventures With CMPivot — Client Coercion
Further Adventures With CMPivot — Client Coercion
TL:DR
CMPivot queries can be used to coerce SMB authentication from SCCM client hosts
Introduction
CMPivot is a component part of the Configuration Manager framework. With the rise in popularity for ConfigMgr as a target in red team operations, this post looks to cover a way other than using CMPivot (CMP) data gathering capabilities for taking over a computer object in Active Directory environments. If interested in leveraging CMP for data enumeration, see the previous post “Lateral Movement without Lateral Movement”
Why
After learning about CMPivot’s potential for offensive operations, how much information it can pull from a client host (almost as if you’d be operating within the target itself) and more importantly for this post, how it achieves this, I always itched to go a little further than just using the queries for how they are meant to be used (i.e., data collection). This post will showcase a simple but effective way to use CMPivot to coerce authentication from an SCCM/ConfigMgr client host.
CMPivot for offensive operators
From the point of view of an offensive operator, CMPivot’s “intended” use flow of remote data querying does have the potential to reveal information that could indirectly aid in taking over an SCCM client host. For example, if we use the query that allows us to read file contents and happen to find an SSH key on a client host, we could then leverage those keys for lateral movement.
Now, even though the ability to enumerate almost any data from a host is a big plus for us as offensive operators, that is where the intended capabilities of CMPivot’s end: with data enumeration.
Rather than allowing any type of remote command execution, CMP was designed with the sole purpose of gathering information from client hosts.
Note: SCCM/ConfigMgr does have built in ways for a user to achieve execution on clients when working under the right context and privileges. These privileges are not always attainable and probably more closely tracked nowadays.
CMPivot Relay Background
The way CMPivot gathers data from clients is by taking any queries we make on the CMPivot GUI or via SharpSCCM (adminservice command) and sends those to the CCMExec client engine living on a client host. After this the client software runs a PowerShell script with our CMP query as one of the parameters. The CMPivot client PowerShell script on the target will then filter our queries most of the time for use with WMI methods to enumerate the specific information we asked for. The results of those queries will be collected and sent back to the ConfigMgr/SCCM site Management Point. Ultimately, that data will be presented to the querying user’s GUI.
In most cases, whatever input we provide as part of these CMPivot queries is correlated to a WMI class and method executed on the client host. For example, let’s look at the CMPivot client side script located at C:WindowsCCMScriptStore on client machines. When calling the “Users” CMPivot query from the GUI, the client side powershell script will leverage the Win32_LoggedOnuser WMI class as seen in the code block below.
elseif( $wmiquery -eq 'Users' )
{
$users = New-Object System.Collections.Generic.List[String]
foreach( $user in (get-WmiObject -class Win32_LoggedOnuser -ErrorAction Stop | Select Antecedent))
{
$parts = $user.Antecedent.Split("""")
# If this is not a built-in account
if(( $parts[1] -ne "Window Manager" ) -and (($parts[1] -ne $env:COMPUTERNAME) -or (($parts[3] -notlike "UMFD-*")) -and ($parts[3] -notlike "DWM-*")))
{
# add to list
$users.Add($parts[1] + "" + $parts[3])
}
}
# Create unique set of users
$users | sort-object -Unique | foreach-object { $results.Add(@{ UserName = $_ }) }
}
My assumption was that this was the modus operandi for all queries that we can make with CMPivot. Further inspecting the client-side PowerShell script shows this section referring to some “one-off” cases that are easier to deal with using straight PowerShell versus Windows Management Instrumentation (WMI) classes:
#Create the result set
$results = New-Object System.Collections.Generic.List[Object]
**#deal with one-offs that don't work well over WMI**
if( $wmiquery -eq 'SMBConfig' )
{
# Get Smb Config
$smbConfig = Get-SmbServerConfiguration -ErrorAction Stop| Select-object -Property $propertyFilter
.. SNIP SNIP ..
elseif ($wmiquery.StartsWith("FileContent(") )
Included in that section of the PowerShell script, we have the logic that deals with the “File” and “FileContent” CMPivot queries among others. Those two let us check if an arbitrary file exists on the target and to retrieve its contents depending on the type of data.
These two queries fall into what the CMPivot client script classifies as “one-off” calls. When calling either of those queries, our input is taken all the way to the command being executed , which can be seen here:
elseif ($wmiquery.StartsWith("FileContent(") )
{
$first = $wmiquery.IndexOf("'")+1
$last = $wmiquery.LastIndexOf("'")
$filepath = [System.Environment]::ExpandEnvironmentVariables( $wmiquery.Substring($first, $last-$first) )
#verify if the file exists
if( [System.IO.File]::Exists($filepath) )
{
$lines = (get-content -path $filepath -ErrorAction Stop)
# our code handles lines as list of object
# get-content return list of lines if multiple lines are present
# in case of single line a string is returned which is casted to list
if ($lines -is [string]) {
$lines = @($lines)
}
for ($index = 0; $index -lt $lines.Length; $index++)
{
$line = $lines[$index]
$hash = @{
Line = $index+1
Content = $line
}
$results.Add($hash)
}
}
}
Above, we can see that in the case of the “FileContent” query this is just ran as a simple PowerShell Get-Content cmdlet in the background.
Actual CMPivot Relay Demo
Where it gets more interesting is that the check for file existence [System.IO.File]::Exists($filepath) and the Get-Content cmdlet also allow for UNC paths and, as mentioned in my previous CMPivot blogpost, the actions taken to gather the data on client host are performed as NT AUTHORITY/SYSTEM. Something as simple as pointing our query to a UNC path under our control lets us coerce SMB authentication from any SCCM client host that we can run CMPivot queries against. Let’s look at a relay example.
For this example, I used PortBender to take over port 445/TCP on a previously compromised host where I had full control. If you are not familiar with PortBender, you can read about it here. There is also a great post by Nick Powers on taking over 445/TCP, which I highly recommend called Relay Your Heart Away: A Conscious Approach to 445 Takeover.
We start our relay server and point it to a certificate authority (CA) in order to take advantage of the incoming SMB authentication.
Next, we set up our required proxies:
…and our port forwards.
The relay server is set to point our victim to the domain’s CA and request for a certificate which can later be used to request a kerberos ticket for the machine account of our target.
We can use tools like SharpSCCM to execute a CMPivot query against the target SCCM client. The admin-service command is our ally in this case. For more CMPivot and SharpSCCM admin-service usage details, see the previous post Lateral Movement without Lateral Movement.
If we have access to the CMPivot GUI, we can use the standard FileContent query.
And we end up getting a hit on our relay server and the resulting base64 blob for our desired certificate.
Outro
Hopefully, this adds one more tool to the arsenal when it comes to getting control of a machine object without executing foreign tradecraft on a target and helps build tradecraft depth when operating within ConfigMgr/SCCM environments. If a low privilege account has been assigned the right security roles, that user could potentially escalate their privileges with this technique.
Requirements
These are some of the permissions and security roles that allow CMPivot querying:
Permissions:
- Run CMPivot permission on the Collection
- Read permission on Inventory Reports
- Read permissions on Devices and Collections.
Security Roles:
- Read-Only Analyst (Built-in role) — Can run CMPivot queries but cannot take action.
- Full Administrator — Has all permissions, including CMPivot.
- Custom Role (if creating a new one) — Needs specific permissions (see below).
When dealing with a custom security role, it needs at at least the following permissions:
Scope:
- The user must have access to the collections where CMPivot is being executed.
Connectivity:
For the scenario presented in the example:
- ConfigMgr clients should be able to talk to the Management Point
- Clients need to be able to reach the relay or proxy server
- A Certificate authority should be reachable
Abuse Vector:
- A vulnerable template must be available
Resources
- Changes to CMPivot – Configuration Manager
- Coercing NTLM Authentication from SCCM
- Relaying NTLM Authentication from SCCM Clients
- GitHub – subat0mik/Misconfiguration-Manager: Misconfiguration Manager is a central knowledge base for all known Microsoft Configuration Manager tradecraft and associated defensive and hardening guidance.
Further Adventures With CMPivot — Client Coercion was originally published in Posts By SpecterOps Team Members on Medium, where people are continuing the conversation by highlighting and responding to this story.