Friday, December 4, 2015

WMI object correlation using ASSOCIATORS OF

tl;dr

While this post isn’t directly related to infosec, infosec pros who work with WMI should take note as there are some powerful queries that could be performed for both offense and defense. The point of this post is to shed some light on ASSOCIATORS OF and show how powerful connections can be made between related WMI objects.


Until recently, I found the ASSOCIATORS OF WMI query language statement to be very confusing. I understood it in theory – it links one “associated” WMI object with another. A lot of articles on the subject will use the following canonical example showing related objects to a Win32_LogicalDisk instance where its DeviceID is “C:”:

ASSOCIATORS OF {Win32_LogicalDisk.DeviceID="C:"}

This query returns an instance of a Win32_Directory, Win32_ComputerSystem, and Win32_DiskPartition. Okay. That’s great and all but where did you come up with the DeviceID property as a requirement and how can I know what classes might be associated with Win32_LogicalDisk? It’s those questions that I feel existing articles never commented on. That said, allow me to explain.

Let’s say I’m interested in finding WMI classes that might be related (i.e. associators of) to CIM_DataFile. For example, one attribute that I find lacking in CIM_DataFile is file ownership and ACL information. Let’s see if we can maybe obtain that information. First, I’ll get a CIM_DataFile instance of a file I’m interested in – C:\foo.txt

PS C:\> Get-WmiObject CIM_DataFile -Filter 'Name="C:\\foo.txt"' | Format-List *


PSComputerName        : TESTPC
Status                : OK
Name                  : c:\foo.txt
__GENUS               : 2
__CLASS               : CIM_DataFile
__SUPERCLASS          : CIM_LogicalFile
__DYNASTY             : CIM_ManagedSystemElement
__RELPATH             : CIM_DataFile.Name="c:\\foo.txt"
__PROPERTY_COUNT      : 33
__DERIVATION          : {CIM_LogicalFile, CIM_LogicalElement,
                        CIM_ManagedSystemElement}
__SERVER              : TESTPC
__NAMESPACE           : root\cimv2
__PATH                : \\TESTPC\root\cimv2:CIM_DataFile.Name="c:\\foo
                        .txt"
AccessMask            : 1179817
Archive               : True
Caption               : c:\foo.txt
Compressed            : False
CompressionMethod     :
CreationClassName     : CIM_LogicalFile
CreationDate          : 20151204080026.605819-480
CSCreationClassName   : Win32_ComputerSystem
CSName                : TESTPC
Description           : c:\foo.txt
Drive                 : c:
EightDotThreeFileName : c:\foo.txt
Encrypted             : False
EncryptionMethod      :
Extension             : txt
FileName              : foo
FileSize              : 13
FileType              : Text Document
FSCreationClassName   : Win32_FileSystem
FSName                : NTFS
Hidden                : False
InstallDate           : 20151204080026.605819-480
InUseCount            :
LastAccessed          : 20151204080026.749820-480
LastModified          : 20151204080026.751820-480
Manufacturer          :
Path                  : \
Readable              : True
System                : False
Version               :
Writeable             : True
Scope                 : System.Management.ManagementScope
Options               : System.Management.ObjectGetOptions
ClassPath             : \\TESTPC\root\cimv2:CIM_DataFile
Properties            : {AccessMask, Archive, Caption, Compressed...}
SystemProperties      : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers            : {dynamic, Locale, provider, UUID}
Site                  :
Container             :


You can quickly determine which property to use as a “key” in an ASSOCIATORS OF query by looking at the __RELPATH property which is showing the Name property as our key.

So now I want to know what classes are associated with my CIM_DataFile instance. The following query will return class definitions instead of the associated object instances:

PS C:\> Get-WmiObject -Query 'ASSOCIATORS OF {Cim_DataFile.Name="C:\\foo.txt"} WHERE ClassDefsOnly'


   NameSpace: ROOT\cimv2

Name                                Methods              Properties           
----                                -------              ----------           
Win32_Directory                     {TakeOwnerShip, C... {AccessMask, Archiv...
Win32_LogicalFileSecuritySetting    {GetSecurityDescr... {Caption, ControlFl...

So we now know that there are two classes associated with Cim_DataFile – Win32_Directory and Win32_LogicalFileSecuritySetting. If you look at the MSDN documentation for Win32_LogicalFileSecuritySetting, you’ll see that its GetSecurityDescriptor method will return the ACL for the file. Great!

I can now run the following query and get the associated Win32_Directory and Win32_LogicalFileSecuritySetting class instances:

ASSOCIATORS OF {Cim_DataFile.Name="C:\\foo.txt"}

But let’s say I’m only interested in returning instances of type Win32_LogicalFileSecuritySetting? The following query will get the job done:

ASSOCIATORS OF {Cim_DataFile.Name="C:\\foo.txt"} WHERE AssocClass=Win32_SecuritySettingOfLogicalFile

So you may now be wondering, “Where did Win32_SecuritySettingOfLogicalFile come from???”

In order to constrain an association query to a particular type of class instance, you must specify the association class that links the two classes together. You can get the association class by using the REFERENCES OF statement:

PS C:\> Get-WmiObject -Query 'REFERENCES OF {Cim_DataFile.Name="C:\\foo.txt"} WHERE ClassDefsOnly'


   NameSpace: ROOT\cimv2

Name                                Methods              Properties           
----                                -------              ----------           
CIM_DirectoryContainsFile           {}                   {GroupComponent, Pa...
Win32_SecuritySettingOfLogicalFile  {}                   {Element, Setting}   


So now you can see where the association class came from.

Finally, let’s tie everything together and retrieve the following info from foo.txt – file owner, full path, file size, and MAC times.

$CimDataFile = Get-WmiObject CIM_DataFile -Filter 'Name="C:\\foo.txt"'

$FileSecuritySetting = Get-WmiObject -Query "ASSOCIATORS OF {CIM_DataFile.Name=`"$($CimDataFile.Name.Replace('\','\\'))`"} WHERE AssocClass=Win32_SecuritySettingOfLogicalFile"

$FileACL = $FileSecuritySetting.GetSecurityDescriptor().Descriptor

$FileOwner = "{0}\{1}" -f $FileACL.Owner.Domain, $FileACL.Owner.Name

$Modified = [Management.ManagementDateTimeConverter]::ToDateTime($CimDataFile.LastModified)
$Accessed = [Management.ManagementDateTimeConverter]::ToDateTime($CimDataFile.LastAccessed)
$Created =  [Management.ManagementDateTimeConverter]::ToDateTime($CimDataFile.CreationDate)

$DocProperties = [Ordered] @{
    FileOwner = $FileOwner
    FullPath = $CimDataFile.Name
    FileSize = $CimDataFile.FileSize
    Modified = $Modified
    Accessed = $Accessed
    Created = $Created
}

New-Object PSObject -Property $DocProperties

FileOwner : BUILTIN\Administrators
FullPath  : c:\foo.txt
FileSize  : 13
Modified  : 12/4/2015 8:00:26 AM
Accessed  : 12/4/2015 8:00:26 AM
Created   : 12/4/2015 8:00:26 AM

So I hope that helps explain things a little bit better with regard to ASSOCIATORS OF. Personally, after figuring out what I did, I was still left wondering, “How could I enumerate all association classes and list out the classes they link?” After poking around with the WMI schema a bit, I came up with the following quick and dirty PSv3 script to do just that:

function Get-AssociatedClassRelationship {
    param (
        [String]
        $Namespace = 'root/cimv2'
    )

    Get-CimClass -Namespace $Namespace | ? { $_.CimClassQualifiers['Association'] -and (-not $_.CimClassQualifiers['Abstract']) } | % {
        $KeyQualifiers = @($_.CimClassProperties | ? { $_.Qualifiers['key'] })

        if ($KeyQualifiers.Count -eq 2) {
            $Properties = [Ordered] @{
                AssociationClassName = $_.CimClassName
                LinkedClassName1 = $KeyQualifiers[0].ReferenceClassName
                LinkedClassName2 = $KeyQualifiers[1].ReferenceClassName
            }

            New-Object PSObject -Property $Properties
        }
    }
}

So now, hopefully you’re armed with just enough information to begin forming association queries as well as discovering which associations exist!

Wednesday, December 2, 2015

Thoughts on Exploiting a Remote WMI Query Vulnerability

On December 1, 2015, a really interesting vulnerability was disclosed in the Dell Foundation Services software. If installed, a SOAP service will listen on port 7779 and grant an attacker the ability to execute unauthenticated WMI queries. I can’t say I’ve ever encountered such a vulnerability class so this posed an interesting thought exercise into how an attacker might effectively exploit such a vulnerability beyond just using the queries to conduct host recon. Specifically, this vulnerability only allows an attacker to query WMI object instances within the default namespace – ROOT/CIMv2. This means that you cannot invoke WMI methods or perform event registration - i.e. this is not a remote code execution vulnerability.

I released a PoC PowerShell exploit that allows you to easily view and parse WMI query output from a vulnerable host. The script could be used to test the exploit locally assuming you have a Dell computer to test on. The vulnerable software can be obtained from Dell. Specifically, the vulnerable function is contained within Dell.Tribbles.Agent.Plugins.SystemInfo.dll.

So what kinds of things could an attacker do that would give them the greatest bang for their buck? For starters, let’s say you wanted to list all available classes within the ROOT/CIMv2 namespace as a means of determining the attack surface?

PS C:\> Get-DellFoundationServicesWmiObject -IPAddress 127.0.0.1 -Query 'SELECT * FROM Meta_Class'

What you will find is that there is a sea of WMI classes. We’ll need to find the diamonds in the rough. Here is an extremely non-comprehensive list of what I came up with in conjunction with Sean Metcalf and Carlos Perez:

File listing for a specific directory. e.g. C:\ or search by extension
SELECT * FROM CIM_DataFile WHERE Drive="C:" AND Path="\\"
SELECT * FROM CIM_DataFile WHERE Extension="xlsx"

Process listing (including command-line invocation which could possibly include credentials)
SELECT * FROM Win32_Process

List all services
SELECT * FROM Win32_Service

Account/group enumeration
SELECT * FROM Win32_Account
SELECT * FROM Win32_UserAccount
SELECT * FROM Win32_Group
SELECT * FROM Win32_LoggedOnUser

List startup programs present in the
 registry and Start Menu
SELECT * FROM Win32_StartupCommand

OS/Hardware info
SELECT * FROM Win32_BIOS
SELECT * FROM Win32_ComputerSystem # Uptime, logged-in user, etc.
SELECT * FROM Win32_OperatingSystem

Hard disk enumeration
SELECT * FROM Win32_DiskDrive
SELECT * FROM Win32_DiskPartition
SELECT * FROM Win32_LogicalDisk
SELECT * FROM Win32_Volume
SELECT * FROM Win32_MountPoint

List system environment variables
SELECT * FROM Win32_Environment

List network devices and configurations
SELECT * FROM Win32_NetworkAdapter
SELECT * FROM Win32_NetworkAdapterConfiguration # Shows assigned IPs

List mapped shares
SELECT * FROM Win32_Share

Obviously, there are a ton of classes that I may be missing that you may find to be useful but these were the ones that stood out to me. Now, beyond performing simple recon actions, what other WMI queries might be impactful, enable leaks of extremely sensitive information, enable further exploitation, or cause system instability? Here are some queries I came up with:

Ping sweep. This could be used to conduct basic internal scanning.
SELECT * FROM Win32_PingStatus WHERE Address="10.10.0.1"

SELECT * FROM Win32_Product

List installed patches. i.e. Determine which patches are not installed.
SELECT * FROM Win32_QuickFixEngineering

Dump event logs. e.g. dump System log. This is the most sensitive info leak I can think of.
SELECT * FROM Win32_NtLogEvent WHERE Logfile="System"


If you can think of any additional classes that would go above and beyond host recon, please let me know on Twitter!