#CTF
# 引言
放暑假了,想着搭建一个 ctf 靶场训练下新生,但遇到的问题比我想象中的多得多。。。写个 blog 记录一下。
# 参考文章
-
ctfd 使用 ctfd-whale 动态靶机插件搭建靶场指南
-
手把手教你如何建立一个支持 ctf 动态独立靶机的靶场(ctfd+ctfd-whale)
-
CTFd-Whale 推荐部署实践
三篇文章所使用的方法基本上差不多,但是部署的 ctfd 版本和插件版本不尽相同,第一篇文章中使用的是 frankli0324 师傅修改后的 ctfd-whale,但是部署上之后测试发现,renew 功能无法使用,不知道是不是我部署错误的问题,而第二篇则是无法正确的映射题目的端口,所以最后还是选择了官方的部署教程。
经过更新后,frankli0324 师傅修改后的 ctfd-whale 已经可以正常使用。
# 部署
# 环境准备
-
安装 docker
-
安装 docker-compose
# 配置 swarm
docker swarm init | |
docker node update --label-add='name=linux-1' $(docker node ls -q) |
# 安装
- 下载 ctfd
git clone https://github.com/CTFd/CTFd --depth=1 | |
cd CTFd |
- 修改 docker-compose.yml
version '2' -> version '3' |
接着 docker-compose up -d
,对 CTFd 进行初始配置。
- 配置 frps,在 docker-compose-yml 中配置如下:
services: | |
... | |
frps: | |
image: glzjin/frp | |
restart: always | |
volumes: | |
- ./conf/frp:/conf | |
entrypoint: | |
- /usr/local/bin/frps | |
- -c | |
- /conf/frps.ini | |
ports: | |
- 10000-10100:10000-10100 # 映射 direct 类型题目的端口 | |
- 8001:8001 # 映射 http 类型题目的端口 | |
networks: | |
default: # 需要将 frps 暴露到公网以正常访问题目容器 | |
frp_connect: | |
ipv4_address: 172.1.0.3 | |
networks: | |
... | |
frp_connect: | |
driver: overlay | |
internal: true | |
ipam: | |
config: | |
- subnet: 172.1.0.0/16 |
- 创建目录 ./conf/frp,并创建
frps.ini
文件,填写:
[common] | |
# 下面两个端口注意不要与 direct 类型题目端口范围重合 | |
bind_port = 7987 # frpc 连接到 frps 的端口 | |
vhost_http_port = 8001 # frps 映射http类型题目的端口 | |
token = your_token | |
subdomain_host = node3.buuoj.cn # 访问http题目容器的主机名,需要配置泛解析域名 |
之后部署时需要把注释内容全部删除,否则会报错。
- 配置 frpc,同样修改 docker-compose.yml
services: | |
... | |
frpc: | |
image: glzjin/frp:latest | |
restart: always | |
volumes: | |
- ./conf/frp:/conf/ | |
entrypoint: | |
- /usr/local/bin/frpc | |
- -c | |
- /conf/frpc.ini | |
depends_on: | |
- frps #frps 需要先成功运行 | |
networks: | |
frp_containers: # 供 frpc 访问题目容器 | |
frp_connect: # 供 frpc 访问 frps, CTFd 访问 frpc | |
ipv4_address: 172.1.0.4 | |
networks: | |
... | |
frp_containers: | |
driver: overlay | |
internal: true # 如果允许题目容器访问外网,则可以去掉 | |
attachable: true | |
ipam: | |
config: | |
- subnet: 172.2.0.0/16 |
- 创建./conf/frp/frpc.ini,填写:
[common] | |
token = your_token | |
server_addr = 172.1.0.3 | |
server_port = 7987 # 对应 frps 的 bind_port | |
admin_addr = 172.1.0.4 # 请参考 “安全事项” | |
admin_port = 7400 |
- 检查 frp 配置是否正确
docker-compose up -d | |
docker-compose logs frpc |
查看日志是否正确,正确情况如下:
[service.go:224] login to server success, get run id [******], server udp port [******] | |
[service.go:109] admin server listen on ****** |
- 配置 CTFd
services: | |
ctfd: | |
... | |
volumes: | |
- /var/run/docker.sock:/var/run/docker.sock | |
depends_on: | |
- frpc #frpc需要先运行 | |
networks: | |
... | |
frp_connect: |
照着修改 docker-compose.yml 即可。
- 下载 CTFd-Whale
git clone https://github.com/frankli0324/CTFd-Whale CTFd/plugins/ctfd-whale --depth=1 | |
docker-compose build # 需要安装依赖 | |
docker-compose up -d |
- 配置 ctfd-whale
1. Auto Connect Network:ctfd_frp_containers
2. Http Domain Suffix:设置好的泛解析域名
3. Http Port:同 frps.ini 的 vhost_http_port
4. Direct IP Address:公网 ip
设置完成后理论上应该就成功了。
完整的 docker-compose.tml:
version: '3' | |
services: | |
ctfd: | |
build: . | |
user: root | |
restart: always | |
ports: | |
- "8000:8000" | |
environment: | |
- UPLOAD_FOLDER=/var/uploads | |
- DATABASE_URL=mysql+pymysql://ctfd:ctfd@db/ctfd | |
- REDIS_URL=redis://cache:6379 | |
- WORKERS=1 | |
- LOG_FOLDER=/var/log/CTFd | |
- ACCESS_LOG=- | |
- ERROR_LOG=- | |
- REVERSE_PROXY=true | |
volumes: | |
- .data/CTFd/logs:/var/log/CTFd | |
- .data/CTFd/uploads:/var/uploads | |
- .:/opt/CTFd:ro | |
- /var/run/docker.sock:/var/run/docker.sock | |
depends_on: | |
- db | |
- frpc | |
networks: | |
default: | |
internal: | |
frp_connect: | |
ipv4_address: 172.1.0.5 | |
nginx: | |
image: nginx:1.17 | |
restart: always | |
volumes: | |
- ./conf/nginx/http.conf:/etc/nginx/nginx.conf | |
ports: | |
- 80:80 | |
depends_on: | |
- ctfd | |
db: | |
image: mariadb:10.4.12 | |
restart: always | |
environment: | |
- MYSQL_ROOT_PASSWORD=ctfd | |
- MYSQL_USER=ctfd | |
- MYSQL_PASSWORD=ctfd | |
- MYSQL_DATABASE=ctfd | |
volumes: | |
- .data/mysql:/var/lib/mysql | |
networks: | |
internal: | |
# This command is required to set important mariadb defaults | |
command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --wait_timeout=28800, --log-warnings=0] | |
cache: | |
image: redis:4 | |
restart: always | |
volumes: | |
- .data/redis:/data | |
networks: | |
internal: | |
frps: | |
image: glzjin/frp | |
restart: always | |
volumes: | |
- ./conf/frp:/conf | |
entrypoint: | |
- /usr/local/bin/frps | |
- -c | |
- /conf/frps.ini | |
ports: | |
- 10000-10100:10000-10100 # 映射direct类型题目的端口 | |
- 8001:8001 # 映射http类型题目的端口 | |
networks: | |
default: # 需要将frps暴露到公网以正常访问题目容器 | |
frp_connect: | |
ipv4_address: 172.1.0.3 | |
frpc: | |
image: glzjin/frp:latest | |
restart: always | |
volumes: | |
- ./conf/frp:/conf/ | |
entrypoint: | |
- /usr/local/bin/frpc | |
- -c | |
- /conf/frpc.ini | |
depends_on: | |
- frps #frps需要先成功运行 | |
networks: | |
frp_containers: # 供frpc访问题目容器 | |
frp_connect: # 供frpc访问frps, CTFd访问frpc | |
ipv4_address: 172.1.0.4 | |
networks: | |
default: | |
internal: | |
internal: true | |
frp_connect: | |
driver: overlay | |
internal: true | |
ipam: | |
config: | |
- subnet: 172.1.0.0/16 | |
frp_containers: | |
driver: overlay | |
internal: true # 如果允许题目容器访问外网,则可以去掉 | |
attachable: true | |
ipam: | |
config: | |
- subnet: 172.2.0.0/16 |
# 遇到的问题
# 部署时提示找不到 python 和 python-dev
ERROR: unable to select packages: | |
required by: world[python] | |
python-dev (no such package): | |
required by: world[python-dev] |
修改 python 和 python-dev 为 python3 和 python3-dev
# 编译时提示 cannot execute 'cc1plus'
Dockerfile 中添加安装 g++
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ | |
apk update && \ | |
apk add \ | |
... | |
g++ \ | |
... |
# docker ps 正常但无法进入网站
docker logs 容器 id 显示
/usr/local/lib/python3.7/site-packages/tzlocal/unix.py:158: UserWarning: Can not find any timezone configuration, defaulting to UTC. | |
warnings.warn('Can not find any timezone configuration, defaulting to UTC.') | |
Starting CTFd | |
/usr/local/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: greenlet.greenlet size changed, may indicate binary incompatibility. Expected 144 from C header, got 152 from PyObject | |
return f(*args, **kwds) | |
/usr/local/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: greenlet.greenlet size changed, may indicate binary incompatibility. Expected 144 from C header, got 152 from PyObject | |
return f(*args, **kwds) | |
/usr/local/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: greenlet.greenlet size changed, may indicate binary incompatibility. Expected 144 from C header, got 152 from PyObject | |
return f(*args, **kwds) | |
[2020-10-11 12:31:30 +0000] [1] [INFO] Starting gunicorn 19.9.0 | |
[2020-10-11 12:31:30 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1) | |
[2020-10-11 12:31:30 +0000] [1] [INFO] Using worker: gevent | |
[2020-10-11 12:31:30 +0000] [21] [INFO] Booting worker with pid: 21 | |
[2020-10-11 12:31:31 +0000] [23] [INFO] Booting worker with pid: 23 | |
[2020-10-11 12:31:32 +0000] [25] [INFO] Booting worker with pid: 25 | |
[2020-10-11 12:31:34 +0000] [27] [INFO] Booting worker with pid: 27 | |
[2020-10-11 12:31:35 +0000] [29] [INFO] Booting worker with pid: 29 | |
[2020-10-11 12:31:36 +0000] [31] [INFO] Booting worker with pid: 31 | |
[2020-10-11 12:31:37 +0000] [33] [INFO] Booting worker with pid: 33 | |
[2020-10-11 12:31:39 +0000] [35] [INFO] Booting worker with pid: 35 | |
[2020-10-11 12:31:40 +0000] [37] [INFO] Booting worker with pid: 37(一直在加) |
删除 requirements.txt 中 gevent 的版本号。
# 无法更新 ctfd-whale 配置
这个问题很奇怪,我只遇到过一次,然后放了一晚上之后他就好了
所以,解决方法是,建议重启 docker