CTFD支持动态靶机的搭建笔记 发表于 2023-08-30 | 更新于 2023-08-06
| 字数总计: 4k | 阅读时长: 17分钟 | 阅读量:
###ctfd搭建
基于docker搭建支持动态靶机的靶场 (yuque.com)
CTFD支持动态靶机的搭建笔记(docker:ctfd+ctf-whale) 本篇文章最后更新于2021.2.25 转载请注明来源:https://err0r.top/article/CTFD/
前言 ctfd可以说是如今最方便的ctf靶场搭建平台,支持各种插件与二次开发,赵师傅 早前写了一款插件ctf-whale非常方便,但本人在搭建的过程中遇到了不少问题,经过不断研究终于完成,特此记录,以防后期忘记,也供大家交流学习。 赵师傅开发的插件是为了适合 buu 的架构,本篇文章采用完整流程+填坑讲解的格式。
我修改了一份CTFd,已上传github:https://github.com/Err0rCM/CTFd_with_CTFd-whale ,启动后仍需按照教程后半部分配置,省去前半部分时间,如有问题请提issue或者从头自行配置。
强调! 由于当时国内git clone实在太慢,因为本人未配好代理,所以采用的方法是科学上网下载zip解压的方式,可自行百度git clong与Download zip的区别。本篇文章是用本地下载zip解压上传的方式完成在服务器上 搭建
如果阅读中操作出现问题请自行百度,翻到文末查看坑点讲解或者查看其它搭建文章
这里感谢赵师傅zhaoj,fjh1997等前辈写的文章指导,读者遇到问题或有不足或缺陷的地方请私信我添加改正
事前准备 注意 :本机为CentOS7 要求:
已安装基础环境,熟悉linux基本操作
已安装好 Docker 和 Docker-Compose,并且启用 Docker Swarm,完成换源等操作
会科学上网
有绝对的耐心
需求:
下载赵师傅改写的ctfd,赵师傅已经完成了镜像换源等操作
1 https://github.com/glzjin/CTFd.git ->赵师傅仓库
下载frp
1 2 3 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
也可以直接访问链接下载然后解压上传
下载ctf-whale
1 https://github.com/glzjin/CTFd-Whale
下载docker的frps
这里在赵师傅仓库里扒拉发现的
1 https://github.com/glzjin/Frp-Docker-For-CTFd-Whale
以上除ctfd解压后请确保字母小写,并只有一级文件夹
安装步骤 1.docker集群设置 输入命令
1 2 3 4 5 docker swarm init docker node ls docker node update --label-add name=linux-1 <节点 ID>
具体原理等可以查看其它ctfd搭建文章,文末会贴出,这里不做过多阐述
2.放入ctfd-whale 将解压的ctfd-whale改小写后放入/CTFd/CTFd/plugins
3.安装frps(这里有其他教程写的是不对的) 这里注意下,frp不是 装在服务器机子上的,简单来说,frps与frpc都是在docker里的。(大坑在这里) frpc是在ctfd里的,frps是在docker机里的
上传赵师傅的Frp-Docker-For-CTFd-Whale,进入目录后运行docker-compose up -d
即可,然后docker ps
可看到frps的容器运行中
这里看到frps有28000-28100,这是在Frp-Docker-For-CTFd-Whale里的docker-compose.yml ,可更改配置后compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 version: '2' services: frps: image: glzjin/frp:latest restart: always volumes: - ./frp:/conf/ entrypoint: - /usr/local/bin/frps - -c - /conf/frps.ini ports: - "28000-28100:28000-28100" - "6490:6490" networks: default: networks: default:
再看一下/frp/frps.ini
1 2 3 [common] bind_port = 6490 token = randomme
4.配置ctfd 直接上ctfd的docker-compose.yml 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 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: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 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
然后注意!注意!注意!
在docker-compose.yml同目录下建nginx文件夹,即与第一个#这里注意相应,然后建http.conf
文件写入以下内容
2021年2月25日更新 目前最新版本的CTFd已经有此配置了,不需要再另加了。
转载请注明来源:https://err0r.top/article/CTFD/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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.yml同目录下建frpc文件夹,即与第二个#这里注意相应,然后进入解压的/frp_0.29.0_linux_amd64文件夹,或直接上传,将
1 2 3 4 frpc frpc.ini frpc_full.ini LICENSE
放入frpc文件夹 接着配置frpc.ini,直接上配置
1 2 3 4 5 6 7 8 9 [common] token = randomme server_addr = 172.1.0.4 server_port = 6490 #此处必须与frpc.ini配置一致 pool_count = 200 tls_enable = true admin_addr = 172.1.0.3 #一定要加!!与后面相应 admin_port = 7400
此处非常重要,之前本人在这里踩了好多次坑。
5.配置Dockerfile 还是直接上配置,Dockerfile .注意,最新版本的CTFd已经更换了Dockerfile的写法,可以参考一下apt换源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 FROM python:3.7 -alpine RUN 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 RUN adduser -D -u 1001 -s /bin/bash ctfd WORKDIR /opt/CTFd RUN mkdir -p /opt/CTFd /var/log/CTFd /var/uploads COPY requirements.txt . RUN pip install -r requirements.txt -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/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://mirrors.tuna.tsinghua.edu.cn/pypi/web/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" ]
注意点:
第一处的镜像源可百度更换其它源,例如
1 2 sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories` 注意如果出现问题检查下最后有没有`&& \
python版本一般不需要换
RUN第三行我将python和python-dev删掉了,如果要加上则会报错python requires by world
之类的,请加上python2
或python3
,python2-dev
或python3-dev
.即可解决。删掉后没有发现对服务有什么影响
所有-i "url"
都是指定源,如果下载失败则可更换源再试
第二处注意即我更换了源,因为之前看其他教程下载失败了
6.准备完毕 运行docker-compose build
静待完成
然后运行docker-compose up -d
如图所示,有WARNING即为在集群网络类,是正常情况 运行docker ps
查看容器情况
访问 http://ip:8000 即可访问ctfd
配置CTFD 进入后随便设置,然后进Admin Panel进行设置
属性
配置
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
单位为秒
最后附上我的配置图片
设置docker网络 这个时候运行docker ps
发现frpc在无限重启,因为我们还没有配置网络 运行docker network ls
显示ctfd_frp-containers
运行docker network inspect ctfd_frp
这个是docker-compose里compose后创建的网络,我们将frps加入此网络,例如我的frp容器id为12345,则运行docker network connect ctfd_frp 12345<即frp容器id>
。再运行docker network inspect ctfd_frp
,如下
这里可以看到ip与我们之前设置的相应。
此时运行docker restart ctfd_frpc_1 frp_frps_1
然后docker ps
最终如下
成功完成。
最后设置道题目选择(我做了汉化)
docker ps
里可以看到容器成功启动,地址正常访问
坑点注意
如果frpc重复出现retrying,请返回检查docker-compose.yml。找到frpc设置,检查ip设置是否正确。再检查ctfd的Admin Panel里ctfd-whale设置是否正确。
如果出现安装某个文件失败问题,请更换源,很多都是源里没有指定文件造成的。可以自行访问一下网站,查看一下要下载的文件名,再进行配置。
似乎docker和系统的版本会有影响,本机为CentOS7.4 64位,腾讯云,docker配置如下
python的问题,上面提到的,可以删除,是因为没有指定版本的原因,也可以指定版本再下载
ctfd运行docker-compose up -d
后有可能提示docker-entrypoint.sh没有权限,手动加个权限即可。在CTFd文件夹下运行chmod a+x docker-entrypoint.sh
(docker-compose.yml里其实写了加权限,但是最后并没有加上去?)
如果docker容器无法启动或者frp端口无法映射可以进容器检查
确保docker api填写正确,如docker-compose.yml中写的unix:///var/run/docker.sock 你也可以使用端口形式的api如官方示例 :可以用IP:端口指定API
docker容器无法启动问题 进入容器检查:
1 2 3 4 5 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端口无法映射问题 进入容器检查:
1 2 3 4 5 6 7 8 //其实检查可以顺便检查一下上面的,因为都在ctfd容器内 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还是出现如下问题
1 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
1 2 3 4 5 6 7 8 9 [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")
应该就可以了<Response [200]>
遇事不决请重启
如果发现frp端口冲突,请检查本地frpc或者frps服务,frp是在docker上不是在本地 的!
1 2 systemctl stop frpc systemctl stop frps
活用查看log
1 2 docker logs <ctfd容器id> docker logs <frp容器id>
如果修改了任意配置,请跟着修改系列配置 ,很多就是因为漏改造成的
11.docker ps显示正常但是无法访问
可以使用 docker logs ctfd_ctfd_1
查看输出,如果发现输出类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /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
版本号即可,结果类似下面这样
1 2 3 4 5 6 7 8 /requirements.txt ... redis==3.3.11 datafreeze==0.1.0 gevent python-dotenv==0.10.3 flask-restplus==0.13.0 ...
然后 docker-compose down
再启动 docker-compose up -d --build
不出意外应该就能解决问题
(更新)12.出现如下问题可参考此issue 提出的问题,在ctfd的docker-compose.yml添加/var/run/docker.sock:/var/run/docker.sock
如下
2021.2.25 更新 最新的CTFd改了部分代码,由于兼容性问题,需要重新编辑一些东西,例如Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 FROM python:3.7 -slim-busterWORKDIR /opt/CTFd RUN mkdir -p /opt/CTFd /var/log/CTFd /var/uploads RUN echo 'deb http://mirrors.aliyun.com/debian/ buster main non-free contrib \ deb http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib \ deb http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib \ deb-src http://mirrors.aliyun.com/debian/ buster main non-free contrib \ deb-src http://mirrors.aliyun.com/debian/ buster-updates main non-free contrib \ deb-src http://mirrors.aliyun.com/debian/ buster-backports main non-free contrib \ deb http://mirrors.aliyun.com/debian-security/ buster/updates main non-free contrib \ deb-src http://mirrors.aliyun.com/debian-security/ buster/updates main non-free contrib' > /etc/apt/sources.list && \ apt-get update \ && apt-get install -y --no-install-recommends \ build-essential \ default-mysql-client \ python3-dev \ libffi-dev \ libssl-dev \ git \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* COPY requirements.txt /opt/CTFd/ RUN pip install -r requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --no-cache-dir COPY . /opt/CTFd RUN for d in CTFd/plugins/*; do \ if [ -f "$d /requirements.txt" ]; then \ pip install -r $d /requirements.txt -i http://mirrors.aliyun.com/pypi/simple/ --no-cache-dir; \ fi ; \ done ; RUN adduser \ --disabled-login \ -u 1001 \ --gecos "" \ --shell /bin/bash \ ctfd RUN chmod +x /opt/CTFd/docker-entrypoint.sh \ && chown -R 1001:1001 /opt/CTFd /var/log/CTFd /var/uploads USER 1001 EXPOSE 8000 ENTRYPOINT ["/opt/CTFd/docker-entrypoint.sh" ]
其他pip源
1 2 3 4 5 清华:https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://pypi.hustunique.com/ 山东理工大学:http://pypi.sdutlinux.org/ 豆瓣:http://pypi.douban.com/simple/
![image-20210225163821673](https://err0r.top/article/CTFD/image-20210225163821673.png
参考文章 CTFd-Whale 推荐部署实践 (赵师傅官方)
手把手教你如何建立一个支持ctf动态独立靶机的靶场(ctfd+ctfd-whale)
ctfd使用ctfd-whale动态靶机插件搭建靶场指南