调用 pwn.college 提供的 API 入口
昨天做 pwn.college 环境自动加载 .bashrc 是为了走 ssh hacker@dojo.pwn.college hostname 的路子推导 module 和 challenge name,实现自动创建解题文件。也发现运行环境中有个 dojo CLI 提供 submit / restart 等功能,这下解题提交一条龙。
今天在阅读 dojo/workspace/core/dojo-cli.py at master · pwncollege/dojo 源码时注意到 pwn.college 有一个:
/pwncollege_api/v1/docker设置页面里又刚好提供了 Access Token 生成功能,就想着能不能直接用脚本查询来替代 ssh。
一开始按照 CTFd 的 API 文档测试:
curl -H "Authorization: Token $PWN_TOKEN" https://pwn.college/api/v1/users确实能返回结果。
但换成 /pwncollege_api/v1/ 下面的接口后,却始终像是没有登录。相同地址在浏览器里带着 Cookie Session 可以正常访问,用 Access Token 就会返回 302、403 或者登录页面。
原本以为 pwn.college 自己实现的接口只支持 Cookie,实际不是。
问题出在它使用的 CTFd 3.6.0 对 Access Token 的处理逻辑。只有下面两个条件同时满足时,CTFd 才会解析请求头里的 Token:
Authorization 存在
request.content_type == "application/json"所以即便只是一个完全没有请求体的 GET 请求,也必须主动附带:
Content-Type: application/json认证成功后,CTFd 会调用 login_user() 把 Token 对应的用户写入当前请求使用的 Session。后面的 /pwncollege_api/v1/ 接口仍然是通过 authed_only 检查 Session,因此它表面上看起来只认浏览器 Cookie,实际上 Access Token 也能走到同一套认证结果。pwn.college 当前构建也确实把 CTFd 3.6.0 和自己的 API Blueprint 放在同一个 Flask 应用中。
最终请求应该写成:
curl -sS \
-H "Authorization: Token $PWN_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
https://pwn.college/pwncollege_api/v1/users/me这里的认证类型是 Token,不能替换成常见的 Bearer。
pwn.college 在全局处理器中专门跳过了所有以 Bearer 开头的请求,后者被留给 Workspace CLI、SSH 和 Discord 等服务自己的临时凭据。普通的 CTFd Access Token 应该继续使用:
Authorization: Token ctfd_xxx之前使用 /api/v1/users 验证 Token 也有问题。这个接口本来就是公开的,没有 authed_only,即使请求中的 Token 完全没有被解析,也能得到用户列表。
更合适的验证接口是:
/api/v1/users/me
/pwncollege_api/v1/users/me这两个接口都明确要求登录。前者返回 CTFd 用户对象,后者返回 pwn.college 自己整理过的用户信息。
目前比较有用的查询入口主要是:
/pwncollege_api/v1/users/me
/pwncollege_api/v1/dojos
/pwncollege_api/v1/dojos/{dojo}/modules
/pwncollege_api/v1/dojos/{dojo}/solves
/pwncollege_api/v1/dojos/{dojo}/{module}/{challenge}/description
/pwncollege_api/v1/search?q={keyword}
/pwncollege_api/v1/docker
/pwncollege_api/v1/docker/next
/pwncollege_api/v1/workspace
/pwncollege_api/v1/score?username={username}
/pwncollege_api/v1/scoreboard/{dojo}/_/{duration}/{page}
/pwncollege_api/v1/scoreboard/{dojo}/{module}/{duration}/{page}
/pwncollege_api/v1/feed/events?limit=50&offset=0
/pwncollege_api/v1/feed/stream/dojos 可以取得当前用户可见的 dojo,随后用 /dojos/{dojo}/modules 获取模块和 challenge 层级。题目描述需要再调用带 /description 的接口,因为这里还会检查题目是否可见、是否被前置条件锁定。
/dojos/{dojo}/solves 不带 username 时查询当前用户,带上公开用户名后也可以查询其他未隐藏用户。它还支持 after 参数,用 ISO 8601 时间做增量查询。
/search 会同时搜索 dojo、module 和 challenge,不过关键词至少需要两个字符。
/docker 返回当前运行中的题目,/docker/next 返回当前题目的下一题。没有运行容器时返回 success: false,并不代表认证失败。
/workspace 在不携带 service 和 port 时可以拿来查询 Workspace 是否 active,以及当前 challenge。带上这些参数后可能会启动按需服务,就不能再把它当成纯查询接口了。
CTFd 原生接口里面目前比较值得用的则是:
/api/v1/users/me
/api/v1/users/me/solves
/api/v1/users/me/fails
/api/v1/users/me/awards
/api/v1/challenges
/api/v1/challenges/{id}
/api/v1/scoreboard
/api/v1/tokens不能直接把 CTFd 网站上的最新 ReDoc 当作 pwn.college 的准确接口表。pwn.college 部署的是 CTFd 3.6.0,而在线文档会继续随 CTFd 新版本更新,所以文档里出现、服务器上却返回 404 的路由不一定是权限问题,也可能只是当前部署版本根本没有实现。
最终最容易漏掉的其实只有这一行:
Content-Type: application/json没有它时,Access Token 根本没有进入认证流程;带上后,CTFd 原生 API 和 /pwncollege_api/v1/ 自定义 API 都可以使用同一枚 Token。