最近遇到一个应急响应事件,服务器tmp目录被写入多个php临时文件,内容为php webshell文件,触发EDR告警;初时疑惑,但第一感觉不是真实攻击,因为写入的目录不对。
搜到这篇文章后豁然开朗,该文章来源于Zgao师傅的博客,分析到位,有理有据有节,给大家分享一下。
0x00 应急背景
记一次真实的应急场景,背景如下:
- 主机安全告警存在webshell。
- 木马文件名为php。同时/tmp目录下存在大量php临时文件。
- Nginx访问日志中存在大量扫描器流量,但木马文件生成时间未发现对应的异常请求。
- 该机器开通了waf,但扫描器的ip是被加白的(并非外网恶意扫描)。
主机安全告警隔离木马
0x01 初探迷踪-过程分析
上传的木马是一个最简单的webshell。
<?php
$cmd=$_GET['cmd'];
system($cmd);
?>
理论上这种没有编码的webshell直接就被waf拦截,根本不会上传成功。推测大概率是扫描器的上传的webshell。
由于是通过php临时文件写入的webshell(见上图隔离文件),同时/tmp目录下还存在大量php临时文件。
日志中存在大量扫描器特征,所以下面排查的方向就是找到是通过什么接口上传的webshell,并且只关注post的请求即可。
应急难点?
初步研判之后,梳理了排查方向。但是仍存在困难点。
- 日志量巨大,正常业务请求混杂扫描器流量。每分钟的日志量多到达上千条。
- 没有关键特征,Nginx日志不会记录post的body内容。
- 木马文件已隔离,但是文件的隔离时间不一定是文件真实写入时间。
排查php配置文件
php.ini中未指定upload_tmp_dir的路径,则php的临时文件会默认写入系统的临时目录/tmp下面。确定/tmp下的文件是由php生成的。
排查Nginx访问日志
由于木马文件已经被主机安全隔离,但是文件的隔离时间不一定是文件真实写入时间。所以通过木马隔离时间来排查对应Nginx的访问日志不一定准确。
正难则反,/tmp目录下还有其他大量php临时文件,这部分文件的写入时间是准确的。
最终排查多个php临时文件的生成时间对应的访问日志,并未发现没有异常的请求。
0x02 峰回路转-PHP机制
php临时文件是如何生成的?
既然正常排查没有结果,那换个思路。怎么才能让php生成这些临时文件?
我们对任意一个PHP文件发送一个上传的数据包时,不管这个PHP服务后端是否有处理$_FILES的逻辑,PHP都会将用户上传的数据先保存到一个临时文件中,这个文件一般位于系统临时目录,文件名是php开头,后面跟6个随机字符;在整个PHP文件执行完毕后,这些上传的临时文件就会被清理掉。
PHP的POST临时文件机制
- 该文件默认存储在 /tmp 目录中『可通过 php.ini 的 upload_tmp_dir 指定存储位置』
- 文件名为 php[6个随机字符],例:phpG4ef0q
- 若本次请求正常结束,临时文件会被自动删除
- 若非正常结束,比如崩溃,临时文件可能会被永久保留
所以能构造出异常的请求,比如让php崩溃最终不能删除临时文件,就能产生php临时文件。
0x03 拨云见日-本地复现
使用inotifywait命令监控/tmp目录下的文件变动,可通过yum安装。
yum -y install inotify-tools
inotifywait -m --timefmt "%Y-%m-%d %H:%M:%S" --format "[%T] : [%e] : %w%f" /tmp
在腾讯云主机开启主机安全实时监控,用于监控写入的webshell文件。
构造高并发请求
因为php对post请求的内容都会生成临时文件,所以可以手动构造高并发post请求让服务端生成大量php临时文件甚至出现错误。
这里模拟500个并发请求,post的内容为eval.php。
root@VM-8-15-ubuntu:/root# cat eval.php
<?php
$cmd=$_GET['cmd'];
system($cmd);
?>
root@VM-8-15-ubuntu:/root# for i in `seq 1 500`;do curl "http://target.com/" -F "[email protected]" -o /dev/null -s & done
在高并发的请求下成功写入webshell,同时收到一堆主机安全的告警短信。
查看告警事件详情,通过进程链分析可以发现由php-fpm写入文件。
最终比对模拟并发请求生成的webshell文件的进程链与应急排查主机的信息完全一致,证实了我一开始的猜想。
0x04 总结
php临时文件写入webshell这个trick虽然很早就有了,但也是第一次在应急实战中遇到。
并非所有的应急case都是被入侵导致的,比如这次高并发请求下将扫描器的post内容写入了php临时文件,却因为并发太高使php崩溃未能删除临时文件,导致被主机安全告警隔离。虽然可能只是小概率事件,但这个case还是很有趣的!
原文始发于微信公众号(篝火信安):应急响应 | php临时文件写入webshell排查
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论