"我的心田本空无一物,你来之后万物生长,你走之后,一片荒芜" --《隐入尘烟》
感谢这位兄弟:
https://www.yuque.com/docs/share/364ef08c-9405-45fe-b269-e9236de57242?#pBjVN,
自己这样写主要是整理出来好查询,在加上自己遇到的问题和解决方案,以及汉化,题目发放的疑惑,值得写一下。
主机:服务器版本的CentOs7
链接:http:
Docker版本:20.10.2
Docker-compose版本:1.25.0
IP地址:公网地址或虚拟机地址
yum update
centos 7 换阿里源方法:
先下载 wget :一定要确保有wget
yum install wget
阿里源:
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all
yum makecache
yum update
注:一定要运行yum update 确保软件的更新和下载
运行:
yum install openssh-server
下载vim 编辑工具:
yum install vim
配置/etc/sshd/sshd_config 不然xshell等工具不能连接,改过之后如图所示:
用xshell连接就能复制命令,方便下面的操作:
运行:
yum install -y git nginx mariadb mariadb-server Mysql-python python-pip gcc python-devel yum- utils device-mapper-persistent-data lvm2 epel-release
安装docker之前换源
命令:
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
选择合适的版本并安装
安装17.12.1.ce版本,可能很慢,耐心等待。
运行:
yum -y install docker-ce-17.12.1.ce
运行:
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
查看是否安装成功并启动
运行:
docker --version
# 下载docker compose
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# 添加可执行权限
chmod +x /usr/local/bin/docker-compose
# 将文件copy到 /usr/bin/目录下
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# 查看版本
docker-compose --version
运行:
git clone https://github.com/glzjin/CTFd.git
下载frp
运行:
wget https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz
下载完成后解压备用:
tar -zxvf frp_0.29.0_linux_amd64.tar.gz
运行:
git clone https://github.com/glzjin/CTFd-Whale.git
将下载的CTFd-Whale文件夹重命名为小写:
mv CTFd-Whale/ 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
下载之后截图:
注:如果不能下载,或者下载缓慢的话,可以挂代理,也可以下载下来在传到服务器上
运行:
docker swarm init
如果出现这种情况Cannot connect to the Docker daemon at unix:
运行:
systemctl start 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/
进入目录并配置frps.ini文件
运行:
cd frp-docker-for-ctfd-whale/frp
vim frps.ini
改成图片所示:一般token不用更改,端口根据自己喜好更改,一般采用默认
注意:是 frp-docker-for-ctfd-whale目录
运行:
cd ..
docker-compose up -d
耐心等待
构建完成以后查看是否正在运行
docker ps
首先进入CTFd目录中,新建frpc文件夹
运行:
(1)cd CTFd/ (2) mkdir frpc
进入frpc的目录(frp_0.29.0_linux_amd64)将里面的frpc,frpc.ini,frpc_full.ini,LICENSE这四个文件放在CTFd/frpc文件夹中
cd ../frp_0.29.0_linux_amd64
mv frpc.ini ../CTFd/frpc/
mv frpc_full.ini ../CTFd/frpc/
mv frpc ../CTFd/frpc/
mv LICENSE ../CTFd/frpc/
进入刚刚新建的CTFd/fprc目录,配置frpc.ini文件,直接复制粘贴
[common]
token = randomme
server_addr = 172.1.0.4
server_port = 6490
pool_count = 200
tls_enable = true
admin_addr = 172.1.0.3
admin_port = 7400
注意:这里的token要和frp-docker-for-ctfd-whale/frp/frps.ini的token一样,前面没改,这里就是randomme
进入CTFd目录,将下方内容复制到Dockerfile中,直接复制粘贴
FROM python:3.6-alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories &&\
apk update && \
apk add python3 python3-dev linux-headers libffi-dev gcc make musl-dev py-pip mysql-client git openssl-dev g++
RUN adduser -D -u 1001 -s /bin/bash ctfd
WORKDIR /opt/CTFd
RUN mkdir -p /opt/CTFd /var/log/CTFd /var/uploads
RUN pip3 config set global.index-url https://pypi.doubanio.com/simple
RUN pip3 config set install.trusted-host pypi.doubanio.com
COPY requirements.txt .
RUN pip install -r requirements.txt -i https://pypi.doubanio.com/simple
COPY . /opt/CTFd
RUN for d in CTFd/plugins/*; do \
if [ -f "$d/requirements.txt" ]; then \
pip install -r $d/requirements.txt -i https://pypi.doubanio.com/simple; \
fi; \
done;
RUN chmod +x /opt/CTFd/docker-entrypoint.sh
RUN chown -R 1001:1001 /opt/CTFd
RUN chown -R 1001:1001 /var/log/CTFd /var/uploads
USER 1001
EXPOSE 8000
ENTRYPOINT ["/opt/CTFd/docker-entrypoint.sh"]
在CTFd目录配置docker-compose.yml文件,直接复制粘贴
version: '2.2'
services:
ctfd-nginx:
image: nginx:1.17
volumes:
- ./nginx/http.conf:/etc/nginx/nginx.conf
user: root
restart: always
ports:
- "443:443"
networks:
default:
internal:
depends_on:
- ctfd
cpus: '1.00'
mem_limit: 150M
ctfd:
build: .
user: root
restart: always
ports:
- "8000:8000"
environment:
- UPLOAD_FOLDER=/var/uploads
- DATABASE_URL=mysql+pymysql://root:[email protected]/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
networks:
default:
internal:
frp:
ipv4_address: 172.1.0.2
cpus: '1.00'
mem_limit: 450M
db:
image: mariadb:10.4
restart: always
environment:
- MYSQL_ROOT_PASSWORD=ctfd
- MYSQL_USER=ctfd
- MYSQL_PASSWORD=ctfd
volumes:
- .data/mysql:/var/lib/mysql
networks:
internal:
command: [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:4
restart: always
volumes:
- .data/redis:/data
networks:
internal:
cpus: '1.00'
mem_limit: 450M
frpc:
image: glzjin/frp:latest
restart: always
volumes:
- ./frpc:/conf/
entrypoint:
- /usr/local/bin/frpc
- -c
- /conf/frpc.ini
networks:
frp:
ipv4_address: 172.1.0.3
frp-containers:
cpus: '1.00'
mem_limit: 250M
networks:
default:
internal:
internal: true
frp:
driver: bridge
ipam:
config:
- subnet: 172.1.0.0/16
frp-containers:
driver: overlay
internal: true
ipam:
config:
- subnet: 172.2.0.0/16
配置requirements.txt 这里主要是修改gevent版本号,gevent原本是1.4.0的,这边经过多次尝试,不指定版本号才能拉取,直接复制粘贴
Flask==1.1.1
Werkzeug==0.16.0
Flask-SQLAlchemy==2.4.1
Flask-Caching==1.4.0
Flask-Migrate==2.5.2
Flask-Script==2.0.6
SQLAlchemy==1.3.11
SQLAlchemy-Utils==0.36.0
passlib==1.7.2
bcrypt==3.1.7
six==1.13.0
itsdangerous==1.1.0
requests>=2.20.0
PyMySQL==0.9.3
gunicorn==19.9.0
normality==2.0.0
dataset==1.1.2
mistune==0.8.4
netaddr==0.7.19
redis==3.3.11
datafreeze==0.1.0
python-dotenv==0.10.3
flask-restplus==0.13.0
pathlib2==2.3.5
flask-marshmallow==0.10.1
marshmallow-sqlalchemy==0.17.0
boto3==1.10.39
marshmallow==2.20.2
gevent
tzlocal==2.1
配置nginx,在CTFd的目录下,新建一个nginx文件夹并进入
mkdir nginx
cd nginx
在上面创建的nginx目录下, 创建一个文件http.conf,输入以下内容,直接复制粘贴
worker_processes 4;
events {
worker_connections 1024;
}
http {
# Configuration containing list of application servers
upstream app_servers {
server ctfd:8000;
}
server {
listen 80;
client_max_body_size 4G;
# Handle Server Sent Events for Notifications
location /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 servers
location / {
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 up -d
拉取完镜像之后
拉取完成后配置docker网络,先看一下现在的容器状态
docker ps -a
看到ctfd_frpc_1这个容器的状态是退出状态。
查看docker的网络
docker network ls
并且这三个容器的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将其他两个容器加入ctfd_frp网络里
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
再次查看一下ctfd_frp网络
重启一下这两个容器
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容器如果没有一直重启就算配好了
直接访问http://你的ip:8000
至此,靶场已经搭建好了
注:这个主要是配置题目分发时端口开启情况,因为你做一道题肯定是访问网站的一个端口
CTF配置
管理员配置
样式配置
配置比赛开始时间
直接finish 后
进入管理员模板配置进行ctfd-whale配置
设置方面,现给出下面的参数配置详情
属性 | 配置 |
---|---|
Docker API URL | unix://var/run/docker.sock |
Frp API IP | frpc的ip配置 172.1.0.3 |
Frp API Port | frpc的端口配置 7400 |
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,没有可填个外网DNS114.114.114.114 |
Docker Swarm Nodes | linux-1 与前面swarm集群呼应 |
Docker Multi-Container Network Subnet | 内网题大子网ip配置/CIDR |
Docker Multi-Container Network Subnet New Prefix | 每个内网题实例的CIDR |
Docker Container Timeout | 单位为秒 |
Docker Auto Connect Network | ctfd_frp-containers |
其中Frp config template配置内容如下,一会直接复制粘贴就行
[common]
token = randomme
server_addr = 172.1.0.4
server_port = 6490
pool_count = 200
tls_enable = true
admin_addr = 172.1.0.3
admin_port = 7400
我的配置
网上按照教程一顿操作,弄一个,网站瘫痪一次。最后发现汉化版本不一样,本次CTFd 的版本是2.3.1 因此,直接去github搜一下,果然找到了一个,只是一个半汉化。先凑合着用呗,其实你也可以自己汉化,就是把里面的样式自己改一下,比如在标题那里英文改成中文。
https://github.com/cxaqhq/ctfd-2.3.1
汉化包:ctfd-2.3.1-master.zip
下载下来之后,直接把
这两个替换为
这两个
注:因为是swam模式本次仅仅测试了dynamic_ docker来添加题目 ,其他形式,请自测
因为拉取镜像需要时间,请耐性等待,多刷新浏览器
其实也没有啥,比如ctftraining/qwb_2019_supersqli 就是拉取了ctftraining的一道题目。我在CTFd源码里面没有找到,去github找了一下,发现了这个。
https://github.com/CTFTraining/CTFTraining
然后我尝试拉取其他的题目,比如 qwb_2019_upload 按照格式ctftraining/qwb_2019_upload进行拉取,果然成功了。大约6-8分钟拉取完一个题目,请耐心等待。
至于其他方式拉取题目我也测试了下,因为是swam模式,只有docker-dynamic这种方式比较简单。
standard 模式拉取ctftraining的试题也是可行的
比如我在~目录下创建一个CTFTraining目录,git 一道题目
mkdir CTFTraining
cd CTFTraining/
git clone https://github.com/CTFTraining/0ctf_2016_unserialize.git
cd cd 0ctf_2016_unserialize/
然后修改docker-compose.yml
修改之后,启动
这个时候你访问靶机地址:http://你的ip:8302 就能访问
同样在CTFd中加入这道题目
[是兄弟就来打我](http://192.168.52.164:8302/)
按照你自己的需求进行更改
flag 就是docker-compose.yml里面的flag
但是这种方式不太好,你打完这道题之后提交flag ,这道题目依然开着,只能手动关闭
https://github.com/ctfs/write-ups-2016
https://github.com/ctfs/write-ups-2015
https://github.com/ctfs/write-ups-2014
fbctf竞赛平台Demo
https://github.com/facebook/fbctf
ctf Resources
https://github.com/ctfs/resources
https://github.com/ctfwiki/ctf_game_history
https://github.com/SecWiki/ctf-hub
https://github.com/le31ei/ctf_challenges
注释:本人遇到的问题还算比较少,因此报错以及解决办法多是搬运他人写的。
解决方案:
仔细配置网络,网络配置的要求如下:
将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 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网络之后,重启完成之后再查看一下ctfd_frp网络,运行
docker network inspect ctfd_frp
如果还是不行,灵活使用docker 的logs功能,查看是什么问题报错
docker logs <容器ID或名称>
如果是以下报错,可以通过修改版本号解决
解决方案:
其他Dockerfile在构建的时候可能会出现gevent构建不成功的问题,有以下几种解决办法:
将镜像源替换为清华源
替换gevent版本
不指定gevent版本号
在CTFd目录下,修改requirements.txt的gevent
然后 docker-compose down 再启动 docker-compose up -d 不出意外应该就能解决问题
解决方案:
将Dockerfile中的python和python-dev删掉,或者修改成python2或python3,python2-dev或python3-dev都可以
解决方案:
将docker-entrypoint.sh第一行修改为
#!/bin/bash
修改后重新docker-compose up -d即可
ctfd_ctfd_1日志报错如下
解决方法:
出现时区问题,因此在requirements.txt中添加如下:
tzlocal==2.1
解决方案:
仔细配置网络,网络配置的要求如下:
将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 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
如果还是不行,灵活使用docker 的logs功能,查看是什么问题报错
docker logs <容器ID或名称>
如果是以下报错
则重新配置frpc,编辑/CTFd/frpc/frpc.ini
[common]
token = randomme
server_addr = 172.1.0.4
server_port = 6490
pool_count = 200
tls_enable = true
admin_addr = 172.1.0.3 #这里千万千万别忘加,之前要被搞气死
admin_port = 7400
然后运行
docker restart ctfd_frpc_1
解决方法:
因为当前目录下的.data文件中的MySQL日志与容器版本不匹配
解决方法是将.data文件删除,重新构建镜像
7.docker容器无法启动或者frp端口无法映射
如果docker容器无法启动或者frp端口无法映射可以进容器检查,确保docker api填写正确,如docker-compose.yml中写的unix:///var/run/docker.sock你也可以使用端口形式的api如官方示例:可以用IP:端口指定API
docker容器无法启动问题
进入容器检查:
docker exec -it <ctfd容器id> sh
/opt/CTFd# python
>>>import docker
>>>client=docker.DockerClient(base_url="unix:///var/run/docker.sock")
>>>client.images.list()
如果api正确会列出所有镜像
frp端口无法映射
其实检查可以顺便检查一下上面的,因为都在ctfd容器内 docker exec -it <ctfd容器id> sh
docker exec -it <ctfd容器id> sh
/opt/CTFd# python
>>>import requests
>>>requests.get("http://172.1.0.3:7400/api/reload")//即frp api的地址
返回
<Response [200]> #表示成功
如果frpc还是出现如下问题
requests.exceptions.ConnectionError: HTTPConnectionPool(host='172.1.0.3', port=7400): Max retries exceeded with url: /api/reload (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f8df919f850>: Failed to establish a new connection: [Errno 111] Connection refused'))
则重新配置frpc,编辑/CTFd/frpc/frpc.ini
[common]
token = randomme
server_addr = 172.1.0.4
server_port = 6490
pool_count = 200
tls_enable = true
admin_addr = 172.1.0.3 #这里千万千万别忘加,之前要被搞气死
admin_port = 7400
然后运行docker restart ctfd_frpc_1(这里再看frpc.ini会发现内容更新了,admin配置没了,不用担心)
再进容器检查requests.get("http://172.1.0.3:7400/api/reload")应该就可以了