搭建一个CTF比赛平台的经过
由来
我们实验室招新需要一个ctf做题环境,但是我们平时使用的NSSCTF的比赛功能在升级 ,所以我们准备自己搭建一个比赛环境
原本我们是准备使用CTFd这个平台来搭建的,但是我看了下,它默认不支持动态容器,需要加插件,并且外观也不怎么样,
所以我最终选择了GZ::CTF作为比赛环境,CTFd作为归档刷题环境,只给Dockerfile和相关文件,不提供动态容器 自己去配docker做题罢
平台配置
GZ::CTF的官方文档写得很清楚,主要是对appsettings.json和compose.yml进行配置
但是在我进行docker compose up -d时,docker报错了(现在复现不了了,应该是修复了)
大概意思就是没法把数据库挂载到本地,找不到文件夹,我的解决方案是修改一下compose.yml,让他不使用原本数据库的路径
environment:
...
- "PGDATA=/var/lib/postgresql/custom-data"
volumes:
- "./data/db:/var/lib/postgresql/custom-data"
为了防止ip泄露,让别人压力测试我的靶场,我使用了cloudflare代理和验证码,并且把题目设置成了要使用平台代理
我这里使用的是WebSocketReflectorX
平台代理
配置如下:
appsettings.json:
"ContainerProvider": {
"Type": "Docker",
"PortMappingType": "PlatformProxy",
"EnableTrafficCapture": false,
"PublicEntry": "<IP>",
"DockerConfig": {
"SwarmMode": false,
"Uri": "unix:///var/run/docker.sock",
"ChallengeNetwork": "challenges"
}
compose.yml:
services:
gzctf:
...
networks:
- default
- challenges
networks:
challenges:
external: true
其中challenges网络是使用docker network创建的
官方文档写的是
docker network create challenges -d bridge --subnet 192.168.133.0/24
但是我的这个ip被我的另一个网络使用了,所以我换了个ip
cloudflare验证码
配置如下:
"CaptchaConfig": {
"Provider": "CloudflareTurnstile",
"SiteKey": "<SiteKey>",
"SecretKey": "<SecretKey>"
},
在cloudflare的管理页面选择添加Turnstile 小组件,然后按照步骤走,就可以拿到Key了,填进去就行
电子邮箱验证
为了防止有人忘记密码,然后找我重置,浪费彼此时间,或者重新注册账号,消耗我2H2G少得可怜的服务器资源,我配置了电子邮箱验证
配置如下:
"EmailConfig": {
"SenderAddress": "eee@yeah.net",
"SenderName": "eee@yeah.net",
"UserName": "eee@yeah.net",
"Password": "eee",
"Smtp": {
"Host": "smtp.yeah.net",
"Port": 465
}
},
平台部分大概就这些了,下面是题目配置
题目配置
我使用了一个ctf题目模板
因为我们这好像没人会写Dockerfile,并且我也只是能看懂和简单修改
之后有空我应该会去学它,到时候再写个blog记录一下
有了这个东西,题目就很好写了,至少对于我出的pwn题而言,我只要改个名字放进去就行了,web应该也差不多
用法很简单,按照它的readme走,然后就直接
docker build .
或者
docker-compose up -d
监控配置
前面说了,我的服务器是2H2G,经不起折腾,为了防止有人开n个容器卡我服务器,我配置了一个监控
这里我使用的是beszel
和Grafana相比,它比较轻量化,适合我的服务器
配置很简单,直接写个compose
services:
beszel:
image: henrygd/beszel
container_name: beszel
restart: unless-stopped
ports:
- 8090:8090
volumes:
- ./beszel_data:/beszel_data
这个相当于是webui,实际的监控软件是agent,但是登录到它的页面,它可以自己生成对应的docker-compose
下面是一个简单的例子
services:
beszel-agent:
image: henrygd/beszel-agent
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./beszel_agent_data:/var/lib/beszel-agent
environment:
LISTEN: <port>
KEY: '<key>'
TOKEN: <token>
HUB_URL: http://<IP>:8090
对于我这种在一个设备同时使用webui和agent的要修改一下
services:
beszel-agent:
image: henrygd/beszel-agent
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./beszel_agent_data:/var/lib/beszel-agent
environment:
LISTEN: /beszel_socket/beszel.sock
KEY: '<key>'
TOKEN: <token>
HUB_URL: http://<IP>:8090
LISTEN字段改成了sock,也就是使用Unix套接字路径作为主机/IP

浙公网安备 33010602011771号