实战指南:利用CTFTraining题库与Docker-Compose在CTFd中一键部署Web靶场
1. 从零开始CTFd与Web靶场部署基础搞CTF的朋友都知道Web题目是最让人又爱又恨的类型。爱的是它能模拟真实漏洞场景恨的是部署起来总是一堆坑。去年我帮学校搭CTF比赛平台时光是部署Web题目就折腾了整整两天。后来发现了CTFTraining这个宝藏题库和Docker-Compose的组合部署效率直接提升10倍。先说下基本配置要求。你需要已经搭建好的CTFd平台建议1.3.0以上版本Linux服务器Ubuntu 18.04/20.04最稳定Docker环境版本19.03基础命令行操作能力为什么推荐这个方案实测下来有三个明显优势题库标准化CTFTraining收集了历年各大比赛的真题环境配置都已经调试好隔离性强每个题目独立容器互不干扰快速回滚题目出问题时一条命令就能重置我第一次用这个方案部署CISCN 2019的Web题从下载到上线只用了7分钟。相比之前手动配环境动不动就报错简直是降维打击。2. 环境准备Docker全家桶配置指南2.1 Docker引擎安装很多教程会推荐用curl -sSL https://get.docker.com | sh一键安装但我强烈建议用apt手动安装。一键脚本经常会把测试版包装上后面各种兼容性问题。这是我验证过最稳的安装方式# 卸载旧版本 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release # 添加官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo \ deb [archamd64 signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装Docker引擎 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io装完后一定要测试sudo docker run hello-world看到Hello from Docker!才算成功。如果卡在pull镜像记得配置国内镜像源sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [https://你的镜像地址.mirror.aliyuncs.com] } EOF sudo systemctl daemon-reload sudo systemctl restart docker2.2 Docker-Compose安装虽然现在Docker自带compose插件但CTFTraining的题目都是按老版本写的建议还是装独立的docker-composesudo curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose sudo chmod x /usr/local/bin/docker-compose验证版本docker-compose --version # 应该显示 1.29.2这里有个坑如果服务器在国内GitHub可能连不上。可以先用本地机器下载再scp传上去scp docker-compose-Linux-x86_64 useryour_server:/usr/local/bin/docker-compose3. 题库部署实战以CISCN2019真题为例3.1 题目获取与目录规划CTFTraining的题目都在GitHub上但直接clone整个仓库没必要。我习惯按比赛年份分类存放mkdir -p ~/CTF/{CISCN,CTFHub,RealWorld}/web cd ~/CTF/CISCN/web git clone https://github.com/CTFTraining/ciscn_2019_web_northern_china_day1_web1.git目录结构建议这样组织~/CTF/ ├── CISCN/ │ ├── web/ │ │ ├── ciscn_2019_web1/ │ │ │ ├── docker-compose.yml │ │ │ ├── www/ │ │ │ └── ... ├── CTFHub/ └── RealWorld/3.2 配置文件魔改技巧用vim打开docker-compose.yml后重点修改三个地方version: 2 services: web: build: . ports: - 0.0.0.0:12345:80 # 修改端口映射 environment: - FLAGflag{test_flag_123} # 设置自定义flag restart: always避坑指南端口建议选30000-40000范围避免冲突flag格式要符合CTFd校验规则默认要求flag{}包裹如果题目需要MySQL等组件要检查links配置我遇到过最奇葩的问题是题目需要特定PHP版本但dockerfile里没指定。这时候要自己改DockerfileFROM php:5.6-apache # 明确指定版本 RUN docker-php-ext-install mysql COPY www/ /var/www/html/3.3 容器启动与调试启动命令看似简单但有些隐藏参数很实用docker-compose up -d --build # 强制重新构建镜像 docker-compose logs -f web # 实时查看日志常见问题排查端口占用netstat -tulnp | grep 端口号容器启动失败docker inspect 容器ID | grep -A 10 State题目无法访问检查iptables规则sudo iptables -L -n有一次部署某SSRF题目时容器一直重启。后来发现是题目代码里有exit(0)导致服务退出。解决方法是在docker-compose.yml里加stdin_open: true tty: true4. CTFd集成题目上线全流程4.1 前端配置要点登录CTFd后台在Challenges页面点击New Challenge关键配置项Name题目名称建议包含年份和比赛名称CategoryWebValue动态分值建议初始500Description可以用HTML写解题提示最容易被忽略的是Connection Info字段格式必须是http://你的服务器IP:端口号4.2 Flag设置技巧在Flags标签页添加flag时有几个实用功能动态flag可以用{{}}模板变量正则匹配比如设置flag{.*}匹配任意flag区分大小写根据题目需求勾选实测发现一个坑如果flag里含特殊字符如$需要加转义符\。4.3 题目测试流程上线前一定要走完整测试流程用参赛者账号登录尝试解题检查flag提交是否正常测试多次错误提交后的提示验证容器在高并发下的稳定性我曾经遇到过选手提交flag后CTFd没反应最后发现是Nginx配置了body大小限制。解决方法是在CTFd的Nginx配置里加client_max_body_size 10M;5. 高阶技巧与故障处理5.1 批量部署方案当需要部署20题目时手动操作会累死。可以用这个脚本自动处理#!/bin/bash for dir in ~/CTF/*/web/*/; do cd $dir || exit docker-compose up -d port$(grep -oP ports:.*?\K\d docker-compose.yml) echo ${dir} 已启动端口 ${port} done更专业的做法是用Ansible这里给出playbook示例- hosts: ctf_servers tasks: - name: 部署Web题目 docker_compose: project_src: /home/ctf/{{ item }} state: present with_items: - CISCN/web/ciscn_2019_web1 - CTFHub/web/sql_injection5.2 资源监控与优化用这个命令监控容器资源占用docker stats --format table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}遇到性能瓶颈时可以限制CPUdocker-compose.yml里加cpus: 0.5限制内存mem_limit: 512m重启策略restart: unless-stopped5.3 常见报错解决方案问题1端口冲突ERROR: for web Cannot start service web: driver failed programming external connectivity on endpoint web (): Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use解决sudo ss -tulnp | grep 80 # 找出占用进程 sudo systemctl stop nginx # 停止冲突服务问题2权限拒绝Got permission denied while trying to connect to the Docker daemon socket解决sudo usermod -aG docker $USER newgrp docker问题3镜像拉取失败ERROR: pull access denied for web, repository does not exist or may require docker login解决检查docker-compose.yml里的image名称是否拼写错误6. 安全加固与维护6.1 容器隔离配置默认配置下容器有安全隐患建议在docker-compose.yml里添加security_opt: - no-new-privileges:true cap_drop: - ALL read_only: true tmpfs: - /tmp:rw,size10M6.2 日志收集方案用ELK收集题目日志的配置示例logging: driver: syslog options: syslog-address: tcp://你的ELK服务器:514 tag: {{.Name}}6.3 定期维护脚本这个脚本可以清理旧容器和悬空镜像#!/bin/bash # 停止所有运行中的题目 docker stop $(docker ps -aq --filter labelcom.docker.compose.projectctf) # 清理一周前的日志 find /var/lib/docker/containers -name *.log -mtime 7 -delete # 移除悬空镜像 docker image prune -f # 重启所有题目 docker start $(docker ps -aq --filter labelcom.docker.compose.projectctf)建议每天凌晨3点运行0 3 * * * /path/to/cleanup.sh /var/log/ctf_clean.log 217. 实战案例部署一个完整比赛去年给某高校搭建CTF比赛时我用这套方案部署了30道Web题。具体步骤选题规划简单题5道SQL注入、XSS等基础漏洞中等题15道SSRF、反序列化等难题10道内存破坏、沙箱逃逸等服务器配置8核16G云服务器 × 3台每台部署10道题用Nginx做负载均衡部署时间表环境准备1小时批量部署题目2小时压力测试1小时监控配置0.5小时比赛期间遇到最棘手的问题是某道题的容器不断重启。后来发现是选手的爆破请求触发了PHP-FPM的max_children限制。临时解决方案是docker exec -it 容器ID bash -c echo pm.max_children 100 /etc/php/7.4/fpm/php-fpm.conf service php7.4-fpm restart这个方案最大的优势是弹性扩展。当监测到某道题访问量激增时可以快速克隆到新服务器# 在新服务器上 rsync -avzP root原服务器:/home/CTF/CISCN/web/ciscn_2019_web1 . docker-compose up -d --scale web3 # 启动3个实例