【CTFd搭建&虚拟机版本下载】CTFd动态靶机搭建(详细总结&虚拟机版本提供下载)By:Lxxx
交流群:
文章首发于:https://www.xiinnn.com/article/33b63ea2.html
搭建动态靶机的CTFd中间需要踩得坑挺多,因此我这里创建了一个群聊用于交流。
加群方式:
群号:950951985

成品展示:



环境:
- 主机:Ubuntu 20.10
- 本篇文章使用的机器的IP:192.168.2.151
- Docker版本:20.10.2
- Docker-compose版本:1.25.0
搭建步骤:
系统环境配置:
安装vim:
apt-get install vim

因为是官方源,所以会比较慢,后面会进行换源。
切换镜像源:
这里以Ubuntu20.10为例:ubuntu | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
vim /etc/apt/sources.list
将原有的内容删除,往source.list里面加入以下内容,加完之后保存退出。
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy main restricted universe multiversedeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-updates main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-updates main restricted universe multiversedeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-backports main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-backports main restricted universe multiversedeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-security main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-security main restricted universe multiverse# 预发布软件源,不建议启用# deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-proposed main restricted universe multiverse# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ groovy-proposed main restricted universe multiverse
注意:一定要更新一下镜像源!!(不然后面没法安装包)
apt-get update
安装docker:
apt-get install docker.io

输入y后回车
安装docker-compose:
apt-get install docker-compose

同样按y后回车
安装git:
apt-get install git

一般来说,安装过docker之后,git也已经安装好了,不过我们还是再确认一下。
docker镜像加速:
进入阿里云镜像服务官网:容器镜像服务 (aliyun.com)
根据下方教程配置自己的Docker静态加速器。

镜像地址每个人都不一样,根据每个人的情况设置。
sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-'EOF'{"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]}EOFsudo systemctl daemon-reloadsudo systemctl restart docker
下载CTFd:
这一个CTFd是赵师傅改写的,链接在下方。之所以要使用赵师傅改写的CTFd,是因为官方CTFd可能会与动态靶机插件ctf-whale冲突。
git clone https://github.com/glzjin/CTFd.git

如果clone的过程中卡住了,可以尝试Ctrl+C将命令掐断,然后重新执行,实在不行的话,可以挂代理。

下载frpc:
下载frpc:
wget https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz
同样的,如果clone的过程中卡住了,可以尝试Ctrl+C将命令掐断,然后重新执行,实在不行的话,可以挂代理。
将下载下来的frpc解压:
tar -zxvf frp_0.29.0_linux_amd64.tar.gz
下载ctfd-whale:
地址:https://github.com/glzjin/CTFd-Whale
git clone https://github.com/glzjin/CTFd-Whale.git

注意:这个时候要将CTFd-Whale文件夹重命名为小写。
mv CTFd-Whale/ ctfd-whale

下载docker版本的frps:
地址:https://github.com/glzjin/Frp-Docker-For-CTFd-Whale
git clone https://github.com/glzjin/Frp-Docker-For-CTFd-Whale
注意:将Frp-Docker-For-CTFd-Whale也重命名为小写
mv Frp-Docker-For-CTFd-Whale/ frp-docker-for-ctfd-whale

CTFd环境配置:
接下来就开始配置CTFd的一些文件了!
Docker集群设置:
先初始化:
docker swarm init

将刚刚初始化的这个集群加入到节点当中,命令执行后,返回的就是节点ID了,暂时不用管这个节点ID。
docker node update --label-add='name=linux-1' $(docker node ls -q)

将ctfd-whale放入CTFd的插件目录中:
如下图所示:

mv ctfd-whale/ CTFd/CTFd/plugins/


启动docker版本的frps及frps配置:
进入该目录:
cd frp-docker-for-ctfd-whale/
启动该docker:
docker-compose up -d

耐心等待镜像构建。

完成以后,可以使用docker ps查看是否正在运行。
这个时候我们查看一下frps的配置。
frps/frps.ini文件如下:
[common]bind_port = 6490token = randomme
这里的token可以改也可以不改,一般也就不改了。
将frpc传入CTFd中:
这一步骤实际上就是:将frpc,frpc.ini,frpc_full.ini,LICENSE这四个文件放在CTFd/frpc文件夹中。
进入CTFd目录中,新建一个frpc文件夹
cd CTFd/mkdir frpc

进入frpc的目录(frp_0.29.0_linux_amd64)
cd ../frp_0.29.0_linux_amd64
将上述四个文件移动到frpc文件夹中
mv frpc.ini ../CTFd/frpc/mv frpc_full.ini ../CTFd/frpc/mv frpc ../CTFd/frpc/mv LICENSE ../CTFd/frpc/

修改frpc.ini文件:
进入frpc目录中,修改frpc.ini文件
[common]token = randommeserver_addr = 172.1.0.4server_port = 6490pool_count = 200tls_enable = trueadmin_addr = 172.1.0.3admin_port = 7400
配置Dockerfile:
进入ctfd目录,将下方内容复制到Dockerfile中
FROM python:3.7-alpineRUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \apk update && \apk add linux-headers libffi-dev gcc make musl-dev py-pip mysql-client git openssl-dev #这里注意1RUN adduser -D -u 1001 -s /bin/bash ctfdWORKDIR /opt/CTFdRUN mkdir -p /opt/CTFd /var/log/CTFd /var/uploadsCOPY requirements.txt .RUN apk add gccRUN apk add musl-devRUN apk add libxslt-devRUN apk add g++RUN apk add makeRUN apk add libffi-devRUN apk add openssl-devRUN apk add libtoolRUN pip install -r requirements.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/ #这里注意2COPY . /opt/CTFdRUN for d in CTFd/plugins/*; do \if [ -f "$d/requirements.txt" ]; then \pip install -r $d/requirements.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/ ; \fi; \done; #同样注意2RUN chmod +x /opt/CTFd/docker-entrypoint.shRUN chown -R 1001:1001 /opt/CTFdRUN chown -R 1001:1001 /var/log/CTFd /var/uploadsUSER 1001EXPOSE 8000ENTRYPOINT ["/opt/CTFd/docker-entrypoint.sh"]
配置docker-compose.yml文件:
version: '2.2'services:ctfd-nginx:image: nginx:1.17volumes:- ./nginx/http.conf:/etc/nginx/nginx.conf #这里注意user: rootrestart: alwaysports:#- "85:80" #我将这里注释掉了,这里通过nginx转发感觉速度访问速度会变慢,可能因为我的配置问题,多次尝试之后直接开8000端口访问不会对服务造成影响- "443:443"networks:default:internal:depends_on:- ctfdcpus: '1.00' #可改mem_limit: 150M #可改ctfd:build: .user: rootrestart: alwaysports:- "8000:8000" #这里原本没开端口,直接打开访问网站速度会加快environment:- UPLOAD_FOLDER=/var/uploads- DATABASE_URL=mysql+pymysql://root:ctfd@db/ctfd- REDIS_URL=redis://cache:6379- WORKERS=1- LOG_FOLDER=/var/log/CTFd- ACCESS_LOG=-- ERROR_LOG=-- REVERSE_PROXY=truevolumes:- .data/CTFd/logs:/var/log/CTFd- .data/CTFd/uploads:/var/uploads- .:/opt/CTFd:ro- /var/run/docker.sock:/var/run/docker.sock #这里是添加的depends_on:- dbnetworks:default:internal:frp:ipv4_address: 172.1.0.2cpus: '1.00' #可改mem_limit: 450M #可改db:image: mariadb:10.4restart: alwaysenvironment:- MYSQL_ROOT_PASSWORD=ctfd- MYSQL_USER=ctfd- MYSQL_PASSWORD=ctfdvolumes:- .data/mysql:/var/lib/mysqlnetworks:internal:# This command is required to set important mariadb defaultscommand: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --wait_timeout=28800, --log-warnings=0]cpus: '1.00' #可改mem_limit: 750M #可改cache:image: redis:4restart: alwaysvolumes:- .data/redis:/datanetworks:internal:cpus: '1.00' #可改mem_limit: 450M #可改frpc:image: glzjin/frp:latest #赵师傅tqlrestart: alwaysvolumes:- ./frpc:/conf/ #这里注意entrypoint:- /usr/local/bin/frpc- -c- /conf/frpc.ininetworks:frp:ipv4_address: 172.1.0.3 #记住此处frp-containers:cpus: '1.00' #可改mem_limit: 250M #可改networks:default:internal:internal: truefrp:driver: bridgeipam:config:- subnet: 172.1.0.0/16frp-containers:driver: overlayinternal: trueipam:config:- subnet: 172.2.0.0/16
配置requirements.txt
这里主要是修改gevent的版本号,原本是1.4.0的,我这边修改成了20.9.0
Flask==1.1.1Werkzeug==0.16.0Flask-SQLAlchemy==2.4.1Flask-Caching==1.4.0Flask-Migrate==2.5.2Flask-Script==2.0.6SQLAlchemy==1.3.11SQLAlchemy-Utils==0.36.0passlib==1.7.2bcrypt==3.1.7six==1.13.0itsdangerous==1.1.0requests>=2.20.0PyMySQL==0.9.3gunicorn==19.9.0normality==2.0.0dataset==1.1.2mistune==0.8.4netaddr==0.7.19redis==3.3.11datafreeze==0.1.0python-dotenv==0.10.3flask-restplus==0.13.0pathlib2==2.3.5flask-marshmallow==0.10.1marshmallow-sqlalchemy==0.17.0boto3==1.10.39marshmallow==2.20.2gevent==20.9.0tzlocal==2.1jinja2<3.1.0
配置nginx:
在docker-compose.yml的目录下,新建一个nginx文件夹
mkdir nginx
进入nginx文件夹
cd nginx
创建一个文件http.conf,输入以下内容:
worker_processes 4;events {worker_connections 1024;}http {# Configuration containing list of application serversupstream app_servers {server ctfd:8000;}server {listen 80;client_max_body_size 4G;# Handle Server Sent Events for Notificationslocation /events {proxy_pass http://app_servers;proxy_set_header Connection '';proxy_http_version 1.1;chunked_transfer_encoding off;proxy_buffering off;proxy_cache off;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Host $server_name;}# Proxy connections to the application serverslocation / {proxy_pass http://app_servers;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Host $server_name;}}}
保存后退出。
开始构建:
进入docker-compose.yml所在的文件目录下
docker-compose up -d

耐心等待。。。
完成后应该是这个样子

配置网络:
我们先看一下现在的容器状态:
docker ps -a

可以看到ctfd_frpc_1这个容器的状态是退出状态。
我们再看一下现在docker的网络:
docker network ls

一会我们需要将ctfd_frpc_1,frp-docker-for-ctfd-whale_frps_1,ctfd_ctfd_1这三个容器加入到ctfd_frp网络中
并且这三个容器的IP如下:
- ctfd_ctfd_1:172.1.0.2
- ctfd_frpc_1:172.1.0.3
- frp-docker-for-ctfd-whale_frps_1:172.1.0.4
查看一下ctfd_frp网络
docker network inspect ctfd_frp

这个时候只有ctfd_ctfd_1这个容器是在ctfd_frp网络里的。
注意要指定IP:
docker network connect --ip 172.1.0.3 ctfd_frp ctfd_frpc_1
docker network connect --ip 172.1.0.4 ctfd_frp frp-docker-for-ctfd-whale_frps_1
然后重启一下这两个容器:
docker restart ctfd_frpc_1 frp-docker-for-ctfd-whale_frps_1

重启完成之后再查看一下ctfd_frp网络
docker network inspect ctfd_frp

可以看到,这个时候,ctfd_frpc_1,frp-docker-for-ctfd-whale_frps_1,ctfd_ctfd_1这三个容器已经加入到ctfd_frp网络中
查看ctfd_frpc_1容器日志:
docker logs ctfd_frpc_1

这样就算已经配置好了。
接下来就是ctfd-whale配置。
ctfd-whale配置:
在浏览器中访问IP:8000
我这台机器就是http://192.168.2.151:8000

这一块就是ctfd的前置配置,按照自己的需求配置一下就好了
网站初步配置完成之后,开始配置ctfd-whale插件。
设置方面,就按照赵总的配置就好了,我这边参考error师傅的。
| 属性 | 配置 |
|---|---|
| Docker API URL | unix://var/run/docker.sock |
| Frp API IP | frpc的ip配置 |
| Frp API Port | frpc的端口配置 |
| Frp Http Domain Suffix | Docker API URL to connect(可填None) |
| Frp Http Port | 80 |
| Frp Direct IP Address | 你的公网ip,本机即为127.0.0.1 |
| Frp Direct Minimum Port | 与之前frps最小端口呼应 |
| Frp Direct Minimum Port | 与之前frps最大端口呼应 |
| Max Container Count | 不超过最大-最小 |
| Max Renewal Times | 最大实例延时次数 |
| Frp config template | 填入frps的配置,只需填[common] |
| Docker Auto Connect Containers | ctfd_frpc_1 |
| Docker Dns Setting | 可填机器内DNS,没有可填个外网DNS |
| Docker Swarm Nodes | linux-1 与前面swarm集群呼应 |
| Docker Multi-Container Network Subnet | 内网题大子网ip配置/CIDR |
| Docker Multi-Container Network Subnet New Prefix | 每个内网题实例的CIDR |
| Docker Container Timeout | 单位为秒 |
其中Frp config template配置内容如下:
[common]token = randommeserver_addr = 172.1.0.4server_port = 6490pool_count = 200tls_enable = trueadmin_addr = 172.1.0.3admin_port = 7400
其他的按照下面这张图片配置就好
注意:
Frp Direct IP Address这个一定要修改成自己的IP,如果是云服务器就输入公网IP,如果是虚拟机那就输入虚拟机的IP。

添加一道题目:
添加的题目如下:

其中Docker image里就输入题目的tag就好了
测试开启题目:


可以看到,已经正确分配IP了
第一次获取题目要等一会,因为要拉题目镜像,等一会后就可以访问题目了。

在Docker里也可以看到相应的题目容器。

问题报错以及踩坑:
frpc日志报错:
报错:
如果日志像下方这样,那么就是网络没有配置好

解决方案:
仔细配置网络,网络配置的要求如下:
- 将ctfd_frpc_1,frp-docker-for-ctfd-whale_frps_1,ctfd_ctfd_1这三个容器加入到ctfd_frp网络中
- 这三个容器对应的IP如下:
- ctfd_ctfd_1:172.1.0.2
- ctfd_frpc_1:172.1.0.3
- frp-docker-for-ctfd-whale_frps_1:172.1.0.4
活用docker的日志功能:
docker logs <容器ID或名称>
活用docker的网络配置功能:
查看网络
docker network ls
给容器分配指定IP
docker network connect --ip 172.1.0.4 <网络名称> <容器ID或名称>
Dockerfile的gevent报错:
报错:


解决方案:
其他Dockerfile在构建的时候可能会出现gevent构建不成功的问题,有以下几种解决办法:
- 将镜像源替换为清华源
- 替换gevent版本
- 将Dockerfile文件中添加以下内容
(这篇文章的搭建方法,已经把坑都踩了,所以前面的教程是没有问题的)
Dockerfile的world模块报错:
报错:

解决方案:
将Dockerfile中的python和python-dev删掉,或者修改成python2或python3,python2-dev或python3-dev都可以。
构建的时候,ctfd镜像无法启动:
报错:

解决方案:
将docker-entrypoint.sh第一行修改为:
#!/bin/bash

修改后,重新build即可
ctfd_ctfd_1容器一直在重启:
现象:
ctfd_ctfd_1日志报错如下
TypeError: Only timezones from the pytz library are supported

解决方法:
出现时区问题,因此在requirements.txt中添加如下:
tzlocal==2.1
MySQL容器反复重启:
现象:
2021-11-01 11:20:22 0 [ERROR] InnoDB: Unsupported redo log format. The redo log was created with MariaDB 10.6.4.2021-11-01 11:20:22 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error2021-11-01 11:20:23 0 [Note] InnoDB: Starting shutdown...2021-11-01 11:20:23 0 [ERROR] Plugin 'InnoDB' init function returned error.2021-11-01 11:20:23 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.2021-11-01 11:20:23 0 [ERROR] Unknown/unsupported storage engine: InnoDB2021-11-01 11:20:23 0 [ERROR] Aborting

解决方法:
因为当前目录下的.data文件中的MySQL日志与容器版本不匹配
解决方法是将.data文件删除,重新构建镜像
2021年11月1日更新docker-compose.yml:
注意:只有当前面的方法不能搭建的时候再使用该docker-compose.yml
因为目前还没有测试过其他机器,不确保是否通用
version: '2.2'services:ctfd-nginx:image: nginx:1.17volumes:- ./nginx/http.conf:/etc/nginx/nginx.conf #这里注意user: rootrestart: alwaysports:#- "85:80" #我将这里注释掉了,这里通过nginx转发感觉速度访问速度会变慢,可能因为我的配置问题,多次尝试之后直接开8000端口访问不会对服务造成影响- "443:443"networks:default:internal:ipv4_address: 172.24.0.2depends_on:- ctfdcpus: '1.00' #可改mem_limit: 150M #可改ctfd:build: .user: rootrestart: alwaysports:- "8000:8000" #这里原本没开端口,直接打开访问网站速度会加快environment:- UPLOAD_FOLDER=/var/uploads- DATABASE_URL=mysql+pymysql://root:ctfd@db/ctfd- REDIS_URL=redis://cache:6379- WORKERS=1- LOG_FOLDER=/var/log/CTFd- ACCESS_LOG=-- ERROR_LOG=-- REVERSE_PROXY=truevolumes:- .data/CTFd/logs:/var/log/CTFd- .data/CTFd/uploads:/var/uploads- .:/opt/CTFd:ro- /var/run/docker.sock:/var/run/docker.sock #这里是添加的depends_on:- dbnetworks:default:internal:ipv4_address: 172.24.0.5frp:ipv4_address: 172.1.0.2cpus: '1.00' #可改mem_limit: 450M #可改db:image: mariadb:10.4restart: alwaysenvironment:- MYSQL_ROOT_PASSWORD=ctfd- MYSQL_USER=ctfd- MYSQL_PASSWORD=ctfdvolumes:- .data/mysql:/var/lib/mysqlnetworks:internal:ipv4_address: 172.24.0.4# This command is required to set important mariadb defaultscommand: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --wait_timeout=28800, --log-warnings=0]cpus: '1.00' #可改mem_limit: 750M #可改cache:image: redis:4restart: alwaysvolumes:- .data/redis:/datanetworks:internal:ipv4_address: 172.24.0.3cpus: '1.00' #可改mem_limit: 450M #可改frpc:image: glzjin/frp:latest #赵师傅tqlrestart: alwaysvolumes:- ./frpc:/conf/ #这里注意entrypoint:- /usr/local/bin/frpc- -c- /conf/frpc.ininetworks:frp:ipv4_address: 172.1.0.3 #记住此处frp-containers:cpus: '1.00' #可改mem_limit: 250M #可改networks:default:internal:driver: bridgeinternal: trueipam:config:- subnet: 172.24.0.0/16gateway: 172.24.0.1frp:driver: bridgeipam:config:- subnet: 172.1.0.0/16frp-containers:driver: overlayinternal: trueipam:config:- subnet: 172.2.0.0/16
虚拟机版本:
下载地址:
【CTFd 2.3虚拟机版本】链接:https://pan.baidu.com/s/11FLyPOKHzpLNBUfuxwJmag
提取码:flag
【CTFd 3.4.0 虚拟机版本】链接: https://pan.baidu.com/s/1AQGQV18GMBJWIs7AP88WDQ
提取码: kbqj
链接如果挂了,可以到我的个人博客联系我:https://www.xiinnn.com
虚拟机相关信息:
- 虚拟机用户:
- 用户名:ctf
- 密码:root
- 用户名:root
- 密码:root
- CTFd后台管理员:
- 用户名:admin
- 密码:password
使用方法:
导入虚拟机后启动
选中ctf用户,输入密码root后登陆
打开终端,切换为root用户,密码为root
su root
配置自己的网络(这里看自己的情况)
进入CTFd文件夹
cd CTFd
启动docker
docker-compose up -d

进入frp-docker-for-ctfd-whale文件夹:
cd ../frp-docker-for-ctfd-whale/
启动docker
docker-compose up -d

查看自己的IP:
ifconfig

一般是ens33或者eth0网卡
访问ip:8000即可

参考资料:
- CTFd/CTFd: CTFs as you need them (github.com)
- CTFD支持动态靶机的搭建笔记(docker:ctfd+ctf-whale)2020.10.17 - 灰信网(软件开发博客聚合) (freesion.com)
- glzjin/CTFd-Whale: A plugin for CTFd which allow your users to deploy a standalone instance for challenges. (github.com)
- CTFD支持动态靶机的搭建笔记(docker:ctfd+ctf-whale) | Err0r
- 手把手教你如何建立一个支持ctf动态独立靶机的靶场(ctfd+ctfd-whale)_fjh1997的博客-CSDN博客
- ctfd使用ctfd-whale动态靶机插件搭建靶场指南 | VaalaCat
