基于docker搭建支持动态靶机的靶场
每做一道题,就会自动生成一个虚拟题目环境,每一个环境刚刚生成的时候都是崭新的。
我的环境
- 主机:腾讯云的轻量服务器CentOS7.6-Docker20
- Docker版本:20.10.17
- Docker-compose版本:20.10.17
- IP地址:公网地址
然后就完全按照这个链接上的做🧎🧎🧎:
成果:

系统环境搭建配置
更新yum源,和安装系统环境所需服务:
yum update
yum install -y git nginx mariadb mariadb-server Mysql-python python-pip gcc python-devel yum-utils device-mapper-persistent-data lvm2 epel-release
因为我的vps自带了docker,就不安装了。
靶场环境
cd ~
git clone https://github.com/glzjin/CTFd.git
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
mv CTFd-Whale/ ctfd-whale
git clone https://github.com/glzjin/Frp-Docker-For-CTFd-Whale
mv Frp-Docker-For-CTFd-Whale/ frp-docker-for-ctfd-whale
docker swarm init
docker node update --label-add='name=linux-1' $(docker node ls -q)
mv ctfd-whale/ CTFd/CTFd/plugins/
cd frp-docker-for-ctfd-whale
docker-compose up -d
cd ~/CTFd
mkdir 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/
cd ~/CTFd/frpc
vim frpc.ini
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
cd ~/CTFd
vim Dockerfile
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"]
vim docker-compose.yml
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: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
vim requirements.txt
requirements.txt的内容如下:
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==1.4.0
tzlocal==2.1
mkdir nginx
cd nginx
vim http.conf
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;
}
}
}
cd ~/CTFd
docker-compose up -d
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 ps
查看容器,应该有6个容器,且查看状态STATUS是否是UP。是UP就OK。
在浏览器访问:http://ip:8000 即可打开。
Docker
我尝试了自己写web题目,这就要用到docker的知识。docker里有2个很重要的概念:容器和镜像。容器和镜像类似于对象和类。每道题目实际上是实例化或销毁一个docker镜像。
在 https://www.yuque.com/docs/share/364ef08c-9405-45fe-b269-e9236de57242?#OE1rs 里发放web题目时有一个Docker Images填写的是ctftraining/qwb_2019_supersqil。docker images就是镜像,我们填写的镜像名字是ctftraining/qwb_2019_supersqil,但是我们本地没有这个镜像啊,怎么还是创建成功了呢?是因为:
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。
我们可以从Docker Hub网站上查找镜像:Docker Hub Container Image Library | App Containerization
那如何自己出题目,自己创建镜像捏。我查阅了菜鸟教程上docker的知识,懂了大概。
可以利用本地有的镜像,实例化成容器后,使用docker exec -it id /bin/sh命令进入容器,进行web环境的搭建。搭建好后exit退出容器。再使用docker commit id image从已经创建的容器中更新镜像,并且提交这个镜像。最后在发放web题目时docker images填写我们生成的image名字就行了。
一些常用命令:
容器:
| 命令 | 功能 |
|---|---|
| docker ps -a | 列出所有docker进程,可以查看id、状态…… |
| docker stop id | 关闭指定id的docker进程 |
| docker start id | 开启指定id的docker进程 |
| docker rm -f id | 删除指定id的docker容器 |
| docker exec -it id /bin/sh | 进入指定id的docker容器 |
| docker commit id image | 从已经创建的容器中更新镜像,并且提交这个镜像 |
镜像:
| 命令 | 功能 |
|---|---|
| docker images | 查看所有镜像 |
| docker run -it name /bin/sh | 实例化镜像 |
| docker rmi name | 删除镜像 |