由来
我们实验室招新需要一个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- challengesnetworks: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/beszelcontainer_name: beszelrestart: unless-stoppedports:- 8090:8090volumes:- ./beszel_data:/beszel_data
这个相当于是webui,实际的监控软件是agent,但是登录到它的页面,它可以自己生成对应的docker-compose
下面是一个简单的例子
services:beszel-agent:image: henrygd/beszel-agentcontainer_name: beszel-agentrestart: unless-stoppednetwork_mode: hostvolumes:- /var/run/docker.sock:/var/run/docker.sock:ro- ./beszel_agent_data:/var/lib/beszel-agentenvironment:LISTEN: <port>KEY: '<key>'TOKEN: <token>HUB_URL: http://<IP>:8090
对于我这种在一个设备同时使用webui和agent的要修改一下
services:beszel-agent:image: henrygd/beszel-agentcontainer_name: beszel-agentrestart: unless-stoppednetwork_mode: hostvolumes:- /var/run/docker.sock:/var/run/docker.sock:ro- ./beszel_agent_data:/var/lib/beszel-agentenvironment:LISTEN: /beszel_socket/beszel.sockKEY: '<key>'TOKEN: <token>HUB_URL: http://<IP>:8090
LISTEN字段改成了sock,也就是使用Unix套接字路径作为主机/IP