PowerShell is a scripting language developed by Microsoft. It provides API access to almost everything in a Windows platform, less detectable by countermeasures, easy to learn, therefore it is incredibly powerful for penetration testing during post exploitation, or exploit development for payload execution. Take Metasploit’s windows/smb/psexec_psh.rb module for example: it mimics the psexec utility from SysInternals, the payload is compressed and executed from the command line, which allows it to be somewhat stealthy against antivirus. There’s only less than 30 lines of code in psexec_psh.rb (excluding the metadata that describes what the module is about), because most of the work is done by the Powershell mixin, nothing is easier than that.
The command line will automatically attempt to detect the architecture (x86 or x86_64) that it is being run in, as well as the payload architecture that it contains. If there is a mismatch it will spawn the correct PowerShell architecture to inject the payload into, so there is no need to worry about the architecture of the target system.
Requirements
To use the PowerShell mixin, make sure you meet these requirements:
- The target machine supports PowerShell. Vista or newer should support it.
- You must have permission to execute powershell.exe
- You must be able to supply system command arguments.
- You must set up a command execution type attack in order to execute powershell.exe
Usage
- To add PowerShell to your module, first you need to require it:
require 'msf/core/exploit/powershell'
- And then include the mixin within the scope of the
Metasploit3
class (or maybeMetasploit4
for some)
include Msf::Exploit::Powershell
- Use the
cmd_psh_payload
method to generate the PowerShell payload.
cmd_psh_payload(payload.encoded, payload_instance.arch.first)
The actual output of cmd_psh_payload
is a system command, which would look like the following format (as a one-liner):
%COMSPEC% /B /C start powershell.exe -Command $si = New-Object
System.Diagnostics.ProcessStartInfo;$si.FileName = 'powershell.exe';
$si.Arguments = ' -EncodedCommand [BASE64 PAYLOAD] ';
$si.UseShellExecute = $false;
$si.RedirectStandardOutput = $true;$si.WindowStyle = 'Hidden';
$si.CreateNoWindow = $True;
$p = [System.Diagnostics.Process]::Start($si);
A number of options can be used to adjust the final command depending on the circumstances of the exploit. By default the script is compressed but no encoding takes places of the wrapper. This produces a small command of around ~2000 characters (depending on the payload).
Of these encode_final_payload
is the most noteworthy as it will Base64 encode the full payload giving a very simple command with very few bad characters. However, the command length will increase as a result. Combining this with remove_comspec
means the payload would very simply be:
powershell.exe -nop -ep bypass -e AAAABBBBCCCCDDDD.....==
Check out the other advanced options in the API documentation below.
References
- https://docs.metasploit.com/api/Msf/Exploit/Powershell.html
- https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/exploit/powershell.rb
- https://github.com/rapid7/metasploit-framework/blob/master/data/exploits/powershell/powerdump.ps1