{"id":13845494,"url":"https://github.com/USTC-Hackergame/hackergame-challenge-docker","last_synced_at":"2025-07-12T02:31:39.464Z","repository":{"id":46217722,"uuid":"354750431","full_name":"USTC-Hackergame/hackergame-challenge-docker","owner":"USTC-Hackergame","description":"nc 类题目的 Docker 容器资源限制、动态 flag、网页终端","archived":false,"fork":false,"pushed_at":"2024-03-19T11:42:49.000Z","size":58,"stargazers_count":69,"open_issues_count":4,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-06-06T20:57:58.815Z","etag":null,"topics":["ctf","ctf-docker","ctf-platform","pwn","pwn-deploy","pwn-xinetd"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/USTC-Hackergame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-04-05T07:10:36.000Z","updated_at":"2024-05-10T09:59:18.000Z","dependencies_parsed_at":"2023-01-28T08:45:19.285Z","dependency_job_id":"cff19f16-5e01-4674-96d4-f079b6fea0b8","html_url":"https://github.com/USTC-Hackergame/hackergame-challenge-docker","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USTC-Hackergame%2Fhackergame-challenge-docker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USTC-Hackergame%2Fhackergame-challenge-docker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USTC-Hackergame%2Fhackergame-challenge-docker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USTC-Hackergame%2Fhackergame-challenge-docker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/USTC-Hackergame","download_url":"https://codeload.github.com/USTC-Hackergame/hackergame-challenge-docker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213940215,"owners_count":15660315,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ctf","ctf-docker","ctf-platform","pwn","pwn-deploy","pwn-xinetd"],"created_at":"2024-08-04T17:03:26.092Z","updated_at":"2024-08-04T17:15:29.734Z","avatar_url":"https://github.com/USTC-Hackergame.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Hackergame nc 类题目的 Docker 容器资源限制、动态 flag、网页终端\n\n## 快速入门\n\n### 配置证书\n\n证书用于验证用户 Token。请确保这里的证书文件（cert.pem）与 [Hackergame 平台](https://github.com/ustclug/hackergame) 配置的证书相同，这样 Hackergame 平台为每个用户生成的 Token 才可以通过这里的用户验证。\n\n如果你仅仅想测试一下，可以使用 [dynamic_flag/cert.pem](dynamic_flag/cert.pem) 自带的证书，以及这个 Token：\n\n`1:MEUCIQCjK1QcPFro86w3bKPb5zUZZd96ocp3EZDFcwLtJxNNDAIgEPk3Orw0mE+zHLQA7e31kSFupNtG9uepz2H4EqxlKWY=`\n\n在生产环境中，请使用自己生成的证书，方法如下：\n\n生成私钥 `openssl ecparam -name secp256k1 -genkey -noout -out private.pem`\n\n生成证书 `openssl req -x509 -key private.pem -out cert.pem -days 365`\n\n然后将生成的 `cert.pem` 文件放在 [dynamic_flag/cert.pem](dynamic_flag/cert.pem)。\n\n### 配置题目\n\n如果你仅仅想测试一下示例题目，那么可以跳过此步骤。\n\n本项目的目录结构设计为可以被 [Hackergame 平台的题目导入命令](https://github.com/ustclug/hackergame/blob/master/frontend/management/commands/import_data.py) 直接导入。\n\n[dynamic_flag](dynamic_flag) 目录中包含了题目容器化、连接限制、动态 flag 相关的逻辑。\n\n[web_netcat](web_netcat) 目录中包含了网页终端的逻辑。\n\n如果仅仅是使用本项目，那么以上两个目录中的内容都不需要修改，它们也不会被 Hackergame 平台导入（因为没有 `README.md` 文件）。\n\n示例题目在 [example](example) 目录中，其中的 [example/docker-compose.yml](example/docker-compose.yml) 中引用了以上两个目录中的内容。你可以把 example 目录复制多份为不同的名字，它们在被导入到 Hackergame 平台后会显示为多道题目。\n\n题目是 Docker 化的，注意每次运行题目 Docker 时 **只启动一个题目的实例，通过标准输入输出交互，你的题目不需要监听端口，也不需要做任何资源限制。** 参见 [example/Dockerfile](example/Dockerfile) 和 [example/example.py](example/example.py)。\n\n你需要修改 [example/.env](example/.env) 文件，针对题目的情况进行配置，包括 nc 的端口（`port`）、网页终端的端口（`web_port`）、运行时间和资源限制、flag 文件位置、动态 flag 规则、题目的容器名称等。动态 flag 的生成方法可以由你自己决定，可以使用类似 `'flag{prefix_' + sha256('secret'+token)[:10] + '}'` 的方案，示例中使用了 Python 的 f-string。对于多个 flag 的情况，`flag_path` 中路径和 `flag_rule` 中 Python 表达式都用 `,` 分隔即可。容器名称（`challenge_docker_name`）是 docker-compose 自动命名的，请设置为目录名 + \"_challenge\"。对于每一个连接，如果 Token 合法并且连接频率没有超过限制，那么你的题目容器会以指定的资源限制启动，动态生成的 flag 会被挂载到指定的路径，选手的 TCP 连接将会被连接到容器的标准输入输出上。如果你的题目需要获得用户 Token，直接读取 `hackergame_token` 环境变量即可。\n\n[example/README.md](example/README.md) 是用于导入 Hackergame 平台的，里面配置的 flag 需要与 `.env` 中配置的 flag 相同，端口也需要进行相应修改。\n\n### 运行题目\n\n在 [example](example) 目录中运行 `docker-compose up --build` 即可，然后你可以通过 `nc 127.0.0.1 10000` 来连接，也可以使用 [http://127.0.0.1:10001/](http://127.0.0.1:10001/) 的网页终端。\n\n## 本项目的背景\n\n与很多 CTF 比赛类似，USTC Hackergame 需要运行选手与服务器交互的 nc 类题目。然而 CTF 比赛中常见的做法有以下问题：\n\n- 通过求解 PoW 来做题目的连接限制，对新手不友好，也在某种程度上影响比赛的体验\n\n- pwn 题缺少真正有效的资源限制。我调研了很多开源的 Docker 化方案，也咨询了很多比赛的出题人，结论是现有的方案都无法真正防止针对性的资源耗尽攻击（所谓“搅屎”）。很多 pwn 题的部署方案会限制选手能够使用的命令，这只是增加了资源耗尽攻击的难度而已，并没有从根本上解决问题。\n\n- 动态 flag、监听端口很多时候是题目逻辑的一部分，而我想做到这部分逻辑对出题人是透明的，这样也可以让题目更统一、更稳定。\n\n因为以上提到的原因，我在 Hackergame 2019 前开发了这套系统，并且在 Hackergame 2020 前进行了一些改进，但是这部分代码一直没有开源。\n\n如今，我把这份代码以 MIT 协议开源出来，欢迎大家测试、使用和改进。\n\n## 本项目的功能\n\n- 对用户 Token 进行验证，只有合法的 Token 才可以运行题目\n\n- 根据 Token 中的用户 ID 进行连接频率限制\n\n- 根据 Token 动态生成 flag，并自动挂载进题目 Docker\n\n- 限制题目的资源使用，包括限时、进程数限制、内存限制、不允许联网等\n\n- 保证题目的稳定性和安全性，用户无论在题目 docker 中做什么，都不会影响其他用户做题\n\n- 为题目提供一个网页终端，方便新手直接在网页上尝试做题，配合 Hackergame 平台可以实现 Token 的自动填充。\n\n## 本项目的限制\n\n本项目只适用于每个连接启动一个进程的题目，包括 pwn 题和其他的 nc 连接服务器类题目。\n\n如果你的题目是一个一直运行的应用，例如 flask app，那么请自己进行 Token 的验证和动态 flag 生成。\n\nToken 的验证方法见 [dynamic_flag/front.py](dynamic_flag/front.py) 中的 `validate` 函数。由于 Token 是非对称签名，所以证书和验证代码完全可以公开。\n\n如果不需要进行连接限制，那么不验证 Token 的合法性也无妨。\n\n自己实现对用户的连接限制时，注意请按用户 id 限制，不要按 Token 限制，因为签名系统不保证每个 id 只有唯一的合法签名。\n\n## 已知问题\n\n- 证书是否过期不会被检查\n\n- Windows 系统上可能无法正常使用，Linux 和 macOS 经测试没有问题\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUSTC-Hackergame%2Fhackergame-challenge-docker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FUSTC-Hackergame%2Fhackergame-challenge-docker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FUSTC-Hackergame%2Fhackergame-challenge-docker/lists"}