Allureluoli 二月FEBRUARY

NESTCTF 2026 BenchLink:从配置泄露到堆任意写,停在 FSOP 触发点

这篇记的是 BenchLink / pendingreview2 没做完的部分:配置泄露和 CBC 授权绕过已经走通,工单 UAF、libc 泄漏与 tcache 任意写在本地复现成功,但没有形成远程读取 flag 的闭环。

先把结果放在前面

环节 记录中的结果
未授权读取配置 成功,拿到管理员口令并登录
BLT/1 信封位翻转 成功取得 field_service_authorized
工单释放后修改 确认 UAF,可写已释放缓冲区的前三字节
libc 泄漏、tcache 任意写 本地配套 libc 环境验证成功
FSOP 执行、远程 flag 未完成

不同实例出现过下线、Caddy 空 200、连接拒绝。这些只说明当时环境状态,不代表今天仍然如此,也不能算漏洞利用成功。

第一道门:配置备份没有认证

匿名请求 /cgi-bin/config-backup.bin 会原样返回 /app/device.cfg,其中包含 admin_user 和 admin_password。用配置中的账号执行 POST /api/login 后可进入管理员会话。

登录要求 application/x-www-form-urlencoded;用 JSON 发送相同字段并不会得到预期结果。这里拿到的管理员口令是后续入口,不能当成 flag。

第二道门:CBC 信封不校验完整性

GET /api/service/dispatch 返回 192 个十六进制字符,也就是 96 字节的 BLT/1 信封。布局为 16 字节 IV 和 AES-CBC 密文,明文包含 nonce、角色、站点标识及会话绑定字段。

关键问题是:信封没有 MAC,且被连带破坏的 nonce 块不参与有效检查。记录中的修改是对完整信封原始字节执行:

1
2
envelope = bytearray.fromhex(review_envelope)
envelope[27] ^= 1

再将修改后的十六进制字符串以原始正文提交给 POST /api/service/dispatch。角色字符从 0 变成 1,服务返回 field_service_authorized 与 control_authorized=true。偏移仅适用于这份题目布局。

早期笔记把随机 AES 密钥当成主要障碍,后来位翻转已经绕过这一步,因此不再把“恢复 AES 密钥”列为待办。

第三道门:工单 UAF 与三字节写

授权后可创建、取消和修改工单。取消时缓冲区被 free,但表项仍可用于 revision;revision 只能改前三字节,receipt 则能读取前八字节。

receipt 的 record_tag 有字节序陷阱:真实内存字节是 bytes.fromhex(tag)[::-1]。如果不先还原字节序,后面计算地址会全部错位。

配套 glibc 2.36 环境里,构造足够多的工单再释放,使合适大小的块进入 unsorted bin,可得到 libc 地址。记录中的本地校验偏移为:

1
libc_base = leak - 0x1d3cc0

这个值来自题目配套 libc,不是其他 glibc 2.36 构建都能套用的通用常量。

任意写如何在本地成立

safe-linking 使三字节写不能直接替换任意 64 位指针。后续利用先在堆内布置可控缓冲区和伪造链结点,再用低三字节覆盖把 tcache 链导入可控位置;从可控结点中读取完整的编码 next 指针,继续把分配导向目标。

本地的验证标准是:让目标地址指向一个仍存活工单的缓冲区,执行重新分配和写入,再从该工单 receipt 中读到写入内容。这证明了写原语;它尚不能证明远程已可执行任意命令。

最后为什么没有接上 FSOP

候选方案是构造 FILE / wide_data / vtable,借 _IO_wfile_jumps 一类路径触发执行。但当时的逆向记录显示,主循环没有正常返回路径,也没有可直接使用的 exit/abort 导入;发现的 fflush 作用于配置临时文件,而非 stderr 或全局流。

glibc 2.36 下也不能继续把 __free_hook = system 当成常规收尾办法。已经有写能力,仍然缺少“服务实际会走到哪里”的触发证据。

留给下一轮的工作

  1. 在同一二进制和配套 libc 上复现地址泄漏与写入,保存完整请求序列。
  2. 补齐 PIE 泄漏及全局状态定位,查清 accept 失败或主循环结束后是否真的进入 exit。
  3. 用本地断点确认 FILE 链确实被访问,再考虑远程验证。
  4. 最终以远程读取结果或平台判题为准,不用本地任意写替代通关结论。

资料来源

依据工作区 STATUS.md、nest_226/BENCHLINK.md、BenchLink 会话与原 WP 的后期记录整理。bench/NOTES.md 中“尚未绕过 dispatch”的内容属于早期状态。原记录引用的 exp2.py、h_*.py 等实验脚本未作为本文附件提供。

评论COMMENTS