PHP 命令执行漏洞(Command Injection / RCE)——基础速览
好 —— 我把概念、成因、可视化示例(安全方向)、检测方法与防护要点都浓缩成一页速查,便于你快速上手理解与应用安全加固。⚠️(注意:我将避免提供可被用于攻击的具体利用 payload,只讲原理、易犯错误与如何修复/检测/防御。)
一、什么是“命令执行”漏洞?
命令执行(Command Injection / Remote Code Execution) 指的是攻击者能把任意输入注入到后端系统的命令执行上下文(例如 exec()、system()、反引号、shell_exec() 等),并被服务器当作操作系统命令执行,从而实现远程执行、读写文件、提权等严重后果。
两类常见情形:
- 命令注入(Command Injection):把输入拼到 shell 命令里导致注入执行。
- RCE(Remote Code Execution):更广泛,包含通过漏洞执行任意代码(例如通过不安全的
eval()、反序列化等)。
二、典型危险点(PHP 特有函数)
以下 PHP 函数如果直接把不可信输入拼进命令字符串,会非常危险:
exec(),system(),passthru(),shell_exec()- 反引号
`...` popen(),proc_open()eval()(并非系统命令,但可执行 PHP 代码)- 不安全的反序列化(
unserialize()) 也可导致 RCE
三、易出错的编码模式(示意,不提供攻击例子)
危险写法(示意)
// 危险:直接拼接用户输入到 shell 命令
$param = $_GET['file'];
$output = shell_exec("convert /tmp/input.png -resize 50x50 /tmp/{$param}");
风险点:用户能控制 $param,可注入特殊字符或额外命令。
更安全的写法(原则示意)
$param = $_GET['file'] ?? '';
// 1) 强白名单/格式校验(仅允许文件名字符且在指定目录内)
if (!preg_match('/^[a-z0-9_.-]+$/i', $param)) { die('invalid'); }
$path = '/var/www/uploads/' . $param;
// 2) 避免使用 shell,优先使用 PHP 原生函数(如图形处理用 GD 或 Imagick 扩展)
// 3) 如确需调用外部命令,使用 escapeshellarg 并尽量使用完全受控的命令参数
$cmd = 'convert ' . escapeshellarg('/tmp/input.png') . ' -resize 50x50 ' . escapeshellarg($path);
shell_exec($cmd);
说明:escapeshellarg() 有帮助,但不能替代白名单与避免 shell 的优先策略。
四、成因总结(为什么会发生)
- 把未过滤的外部输入直接拼接到 shell/命令中。
- 试图用字符串拼接动态构造命令、路径或参数,但未做允许列表校验。
- 错误使用
eval()或不安全的反序列化。 - 过度授予 Web 进程权限(以 root 或高权限账户运行)。
- 依赖外部二进制而非内建 API(更容易被注入)。
五、如何检测(安全测试导向)
- 静态代码审计:查找上述危险函数的使用点(
exec,system,`,eval,unserialize等),并跟踪其参数源。 - 动态测试(白盒 / 黑盒):在封闭测试环境中用安全测试工具(OWASP ZAP、Burp Suite)对输入点进行模糊/注入测试(只在授权和受控环境)。
- SAST 工具:SonarQube、RIPS、Semgrep 等可定位潜在命令注入。
- 日志与异常监控:监控异常 shell 执行、未知子进程、异常网络访问或外发连接。
六、防御与加固建议(最佳实践)
- 根本原则 — 尽量不要调用 shell
- 优先使用 PHP 原生库(例如图像处理使用 GD/Imagick、压缩用 ZipArchive、网络请求用 cURL 扩展而非 curl 命令)。
- 输入严格校验(白名单)
- 对文件名、参数、路径等用白名单验证(正则或枚举),拒绝任何不在允许集合中的值。
- 最小权限运行
- Web 服务以最小权限用户运行(不要用 root)。限制该用户对文件系统、网络和系统命令的访问。
- 避免字符串拼接命令
- 若必须调用外部命令,不要直接拼接未经验证的输入;使用
escapeshellarg()/escapeshellcmd()作防护(注意其局限),并对所有参数再做白名单校验。
- 若必须调用外部命令,不要直接拼接未经验证的输入;使用
- 禁用危险函数(防守性)
- 通过
php.ini的disable_functions禁用exec, system, passthru, shell_exec, popen, proc_open, pcntl_exec等(作为额外防线,但并非万能)。
- 通过
- 容器化 / 沙箱 / SELinux
- 使用容器或强化的访问控制(SELinux、AppArmor)限制进程能力与访问范围。
- 安全更新与依赖管理
- 定期更新 PHP、扩展与第三方库,修补已知漏洞。
- 审计与报警
- 对关键命令调用、异常进程、可疑外发连接做审计并触发告警。
- 代码审查与安全测试流程化
- 在 CI/CD 中加入 SAST、依赖扫描和动态测试环节。
七、示例检查清单(快速自查)
- 代码库中有没有使用
exec|system|shell_exec|`...`|eval|unserialize? - 这些调用点的参数是否来源于用户输入?是否做了白名单校验?
- Web 进程权限是否最小化?是否能访问敏感目录?
- 是否有 WAF / IDS / 日志告警监测到异常命令执行?
- 是否在受控环境中针对这些点做过模糊/注入测试?
八、安全测试与责任告知
若你需要在真实环境测试某个应用,请务必:
- 在授权且隔离的测试环境中进行(切勿在生产或未授权系统上进行任何攻击性测试)。
- 若发现厂商/第三方产品存在漏洞,请按负责任披露流程联系厂商或通过 CERT/安全通道上报。
发表回复