基于Docker容器化构建模块化网络安全实战靶场指南

发布时间:2026/6/16 16:28:06
基于Docker容器化构建模块化网络安全实战靶场指南
1. 项目概述从“马卡巴卡”到实战靶场的蜕变最近在安全圈子里一个叫“makabaka的小推车靶场”的项目标题引起了我的注意。乍一看这个名字有点无厘头像是网络热梗和硬核技术的奇妙结合。“makabaka”这个发音很容易让人联想到最近流行的“马卡巴卡”谐音梗带着点轻松和戏谑的味道而“小推车”则是一种非常接地气的意象让人联想到搬运、装载和移动。当这两个元素和“靶场”这个信息安全领域的核心训练工具结合在一起时就构成了一个非常有趣的命题一个旨在降低安全技术学习门槛让知识像用小推车搬运一样轻松、可移动、可复现的实战训练环境。这个靶场本质上是一个集成了多种常见漏洞场景、攻击技术与防御演练的综合性网络安全实验平台。它不像一些大型企业级靶场那样庞大复杂而是更侧重于“小推车”的灵活与便携理念——易于部署、场景独立、目标明确。无论是刚入门的安全爱好者还是想巩固某方面技能的从业者都可以通过这个靶场在一个安全、可控的环境里进行“实战”从SQL注入、跨站脚本XSS到权限提升、内网渗透一步步推着你的“知识小推车”前进。接下来我将结合自己多年的渗透测试与安全研究经验为你深度拆解如何从零开始构建并玩转这样一个极具个人特色的实战靶场。2. 靶场核心设计思路与架构选型构建一个靶场首要问题不是急于安装软件或部署漏洞而是想清楚它的定位和服务对象。makabaka的小推车靶场这个标题已经暗示了它的风格轻量、模块化、富有趣味性且易于迭代。2.1 设计哲学为什么是“小推车”传统的靶场无论是DVWA、WebGoat还是自己搭建的复杂内网环境往往存在几个痛点环境依赖重搭建过程繁琐场景固化更新扩展麻烦一次部署难以在多台机器或不同时间段快速复现。而“小推车”的理念恰恰是针对这些痛点容器化与可移植性就像小推车可以装载不同的货物并轻松移动靶场的每个漏洞场景都应该是一个独立的、标准化的“集装箱”。Docker容器技术是实现这一理念的绝佳选择。每个漏洞应用例如一个存在SQL注入的博客系统打包成一个Docker镜像配合docker-compose编排可以实现一键启停、版本管理和环境隔离。模块化与积木化“小推车”上的货物可以随时更换。靶场不应是一个庞然大物而应由多个独立的、功能单一的漏洞模块组成。学习者可以根据自己的学习路径像搭积木一样选择今天练习“认证绕过”模块明天练习“文件上传”模块互不干扰。低门槛与引导性“小推车”意味着上手简单。靶场除了提供漏洞环境更应配备清晰的学习指引、难度分级和提示系统。对于makabaka这样的趣味性项目甚至可以设计一些剧情化的挑战说明让学习过程像游戏闯关一样降低初学者的畏难情绪。2.2 技术栈选型稳定、高效、易维护基于以上设计思路我选择了以下技术栈来搭建靶场的骨架核心引擎Docker Docker Compose。这是实现环境隔离和便携性的基石。所有靶机、漏洞应用、甚至网络拓扑如将Web服务器和数据库放在不同容器模拟真实环境都通过Docker容器来定义。漏洞应用来源经典集成直接使用成熟的漏洞平台镜像如vulhub/vulhub项目中的单个漏洞环境。它提供了海量的、复现最新漏洞的Docker Compose配置是极佳的“货物”来源。自主构建对于想深入理解漏洞原理的模块我会用PHP、Python或Node.js编写简单的、存在特定漏洞的Web应用并为其制作Dockerfile。这是体现“makabaka”个人特色的关键部分。编排与访问入口Nginx反向代理。当有多个靶场应用同时运行时我们不可能记住每个容器随机映射的端口。通过一个统一的Nginx配置基于子域名或路径的转发规则例如sqli.makabaka.local- 容器Axss.makabaka.local- 容器B可以让访问变得非常优雅和方便。辅助与监控数据库根据漏洞场景需要运行MySQL、PostgreSQL或Redis容器。监控可选运行一个Portainer容器来可视化管理和监控所有Docker容器对于管理靶场非常直观。注意所有操作均在本地或授权的虚拟化环境中进行。绝对禁止在公网或未授权环境中部署漏洞应用这不仅是法律红线也是安全从业者的基本伦理。2.3 目录结构规划清晰的目录结构是项目可维护性的保障。我的“小推车”靶场目录树大致如下makabaka-range/ ├── docker-compose.yml # 总编排文件定义网络、公共服务 ├── nginx/ │ ├── Dockerfile # 定制Nginx镜像如需 │ └── conf.d/ │ └── range.conf # Nginx反向代理配置 ├── scenarios/ # “小推车”上的各个“货物”模块 │ ├── 01-sqli-basic/ # 基础SQL注入场景 │ │ ├── docker-compose.yml # 该场景独立的编排文件 │ │ ├── src/ # 漏洞应用源代码 │ │ │ └── index.php │ │ ├── Dockerfile # 构建该应用的镜像 │ │ └── README.md # 挑战说明、攻略、知识点 │ ├── 02-xss-reflected/ # 反射型XSS场景 │ │ └── ... │ ├── 03-file-upload/ # 文件上传漏洞场景 │ │ └── ... │ └── 04-cve-2024-xxxx/ # 复现某个特定CVE漏洞 │ └── ... ├── data/ # 挂载卷持久化数据库数据等 └── scripts/ # 辅助脚本如初始化、备份、重置 └── init-range.sh这种结构允许每个scenario场景高度自治可以独立运行cd scenarios/01-sqli-basic docker-compose up也可以被主docker-compose.yml引用统一启动。3. 实战构建从零打造你的第一个漏洞模块理论说再多不如动手做一遍。让我们以构建一个基础数字型SQL注入靶场为例展示如何将想法落地。3.1 漏洞应用开发首先在scenarios/01-sqli-basic/src目录下创建一个极简但漏洞点清晰的PHP应用。文件index.php?php // 模拟一个简单的用户查询功能存在数字型SQL注入漏洞 error_reporting(0); header(Content-Type: text/html; charsetutf-8); $servername getenv(MYSQL_HOST) ?: db; // Docker Compose中的服务名 $username getenv(MYSQL_USER) ?: root; $password getenv(MYSQL_PASSWORD) ?: password; $dbname getenv(MYSQL_DATABASE) ?: vulndb; // 创建连接 $conn new mysqli($servername, $username, $password, $dbname); if ($conn-connect_error) { die(连接失败: . $conn-connect_error); } $id $_GET[id] ?? 1; // 漏洞点未对用户输入的id进行任何过滤 $sql SELECT * FROM users WHERE id $id; // 直接拼接致命漏洞 $result $conn-query($sql); echo h1用户查询系统/h1; echo p查询ID为 strong$id/strong 的用户信息。/p; if ($result $result-num_rows 0) { echo table border1trthID/thth用户名/thth邮箱/th/tr; while($row $result-fetch_assoc()) { echo trtd.$row[id]./tdtd.$row[username]./tdtd.$row[email]./td/tr; } echo /table; } else { echo 未找到该用户或查询出错。; if ($conn-error) { echo brsmall错误信息: . $conn-error . /small; // 故意显示错误方便初学者理解 } } $conn-close(); ?这个应用的核心漏洞在于第13行$id直接从$_GET获取并拼接进SQL语句攻击者可以通过构造id1 OR 11 --这样的参数来实施注入。3.2 Docker化封装为了让这个应用能像“货物”一样被“小推车”装载我们需要为其编写Dockerfile和docker-compose.yml。文件Dockerfile# 使用官方PHP镜像带Apache服务器 FROM php:8.1-apache # 安装MySQL扩展mysqli RUN docker-php-ext-install mysqli docker-php-ext-enable mysqli # 将我们的漏洞应用源代码复制到容器内的网站根目录 COPY src/ /var/www/html/ # 修改Apache配置允许.htaccess重写如果需要的话并调整文件权限 RUN a2enmod rewrite \ chown -R www-data:www-data /var/www/html \ chmod -R 755 /var/www/html EXPOSE 80文件docker-compose.yml(场景独立版)version: 3.8 services: web: build: . ports: - 8081:80 # 映射主机8081端口到容器80端口 environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: password MYSQL_DATABASE: vulndb depends_on: - db networks: - sqli-net db: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: vulndb volumes: - ./init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化数据库表和数据 - mysql-data:/var/lib/mysql networks: - sqli-net # 安全考虑仅限内部网络访问不暴露端口到主机 # ports: # - 3306:3306 networks: sqli-net: driver: bridge volumes: mysql-data:文件init.sql(数据库初始化脚本)CREATE DATABASE IF NOT EXISTS vulndb; USE vulndb; CREATE TABLE users ( id INT PRIMARY KEY, username VARCHAR(50), email VARCHAR(100) ); INSERT INTO users (id, username, email) VALUES (1, admin, adminmakabaka.local), (2, alice, aliceexample.com), (3, bob, bobexample.com);3.3 运行与测试进入scenarios/01-sqli-basic目录执行命令docker-compose up -d等待镜像构建和容器启动完成后在浏览器访问http://localhost:8081/?id1你应该能看到用户admin的信息。现在进行SQL注入测试探测漏洞访问http://localhost:8081/?id1 AND 11页面应正常显示id1的用户。确认注入访问http://localhost:8081/?id1 AND 12页面应显示“未找到该用户”。因为12为假整个查询条件不成立。联合查询尝试获取所有用户。首先需要判断列数http://localhost:8081/?id1 ORDER BY 3--(正常)http://localhost:8081/?id1 ORDER BY 4--(报错) 说明共3列。实施攻击使用联合查询注入http://localhost:8081/?id-1 UNION SELECT 1, database(), user()--页面会显示当前数据库名(vulndb)和数据库用户(root%)。至此一个最基础的SQL注入漏洞模块就构建并验证成功了。通过这个过程你不仅创建了一个靶标更深刻理解了漏洞产生的代码层面原因。4. 靶场统一管理与访问入口配置当“小推车”上的“货物”漏洞模块多起来后逐个访问不同的端口8081 8082...非常不友好。我们需要一个统一的“调度中心”这就是Nginx反向代理的作用。4.1 配置主编排文件在项目根目录 (makabaka-range/) 创建主docker-compose.yml用于启动核心基础设施。version: 3.8 services: nginx-proxy: image: nginx:alpine container_name: makabaka-nginx ports: - 80:80 - 443:443 # 如果需要HTTPS volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro # 挂载代理配置 - ./nginx/html:/usr/share/nginx/html:ro # 可选挂载一个漂亮的导航页 - ./nginx/logs:/var/log/nginx # 挂载日志 networks: - range-network restart: unless-stopped portainer: image: portainer/portainer-ce:latest container_name: makabaka-portainer restart: unless-stopped ports: - 9000:9000 volumes: - /var/run/docker.sock:/var/run/docker.sock - portainer_data:/data networks: - range-network # 建议仅本地访问或设置强密码 networks: range-network: driver: bridge name: makabaka-range-net # 给网络命名方便其他场景加入 volumes: portainer_data:4.2 配置Nginx反向代理规则在./nginx/conf.d目录下创建range.conf# 上游服务器定义指向各个漏洞场景的容器服务名 upstream sqli_basic { server scenarios-01-sqli-basic-web-1:80; # 注意服务名由docker-compose项目名和service名生成 } upstream xss_reflected { server scenarios-02-xss-reflected-web-1:80; } server { listen 80; server_name makabaka.local; # 本地测试域名需要在hosts文件添加 127.0.0.1 makabaka.local # 默认首页可以做一个导航页 location / { root /usr/share/nginx/html; index index.html; } # 根据路径转发到不同的靶场 location /sqli/ { proxy_pass http://sqli_basic/; # 注意结尾的斜杠会将/sqli/后面的路径传递过去 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-Proto $scheme; } location /xss/ { proxy_pass http://xss_reflected/; 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-Proto $scheme; } # 也可以使用子域名方式需配置泛域名解析或hosts多条记录 # server_name sqli.makabaka.local; # location / { # proxy_pass http://sqli_basic; # ...其他header设置 # } }4.3 修改场景编排文件以接入主网络为了让主Nginx能访问到各个场景的容器需要修改每个场景的docker-compose.yml让其加入主编排文件定义的网络并移除端口映射因为现在通过Nginx内部访问。以SQL注入场景为例修改后的scenarios/01-sqli-basic/docker-compose.ymlversion: 3.8 services: web: build: . # 移除 ports 映射不直接暴露给主机 # ports: # - 8081:80 environment: MYSQL_HOST: db MYSQL_USER: root MYSQL_PASSWORD: password MYSQL_DATABASE: vulndb depends_on: - db networks: - default # 场景内部网络 - makabaka-range-net # 加入主靶场网络 db: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: vulndb volumes: - ./init.sql:/docker-entrypoint-initdb.d/init.sql - mysql-data:/var/lib/mysql networks: - default # 数据库只需在场景内部网络无需暴露给主网络 networks: default: driver: bridge makabaka-range-net: external: true # 声明使用外部已存在的网络 name: makabaka-range-net volumes: mysql-data:4.4 启动与访问启动主基础设施在项目根目录执行docker-compose up -d启动Nginx和Portainer。启动特定场景进入某个场景目录如cd scenarios/01-sqli-basic执行docker-compose up -d。配置本地Hosts编辑你电脑的hosts文件Windows在C:\Windows\System32\drivers\etc\hosts Linux/Mac在/etc/hosts添加一行127.0.0.1 makabaka.local访问靶场导航页http://makabaka.localSQL注入靶场http://makabaka.local/sqli/?id1Portainer管理界面http://localhost:9000(首次访问需创建管理员账号)现在你的“makabaka的小推车靶场”就有了一个统一的访问入口结构清晰管理方便。5. 靶场内容规划与进阶场景设计一个优秀的靶场不仅要有技术骨架更要有精心设计的内容。我们可以按照OWASP Top 10、常见攻击手法等维度来规划“小推车”上的“货物”。5.1 基础Web漏洞模块这是靶场的核心适合所有初学者。模块编号漏洞类型难度核心知识点实现要点SC-01数字型/字符型SQL注入初级联合查询、报错注入、布尔/时间盲注、堆叠查询设计不同的过滤和错误回显方式。字符型重点练习闭合引号。SC-02反射型/存储型/DOM型XSS初级-中级脚本构造、事件处理器、编码绕过、CSP绕过分别实现三种类型。存储型需结合数据库。增加简单的过滤器如script过滤供绕过。SC-03文件上传漏洞初级-中级前端绕过、MIME类型检查、文件头检查、解析漏洞.htaccess, .user.ini设计多道关卡逐步增加防护措施让练习者层层突破。SC-04命令执行/代码执行中级系统命令拼接、危险函数eval, system、反序列化、模板注入PHP的eval()、Python的os.system()、Java的反序列化链构造。SC-05目录遍历/文件包含初级相对路径/绝对路径、NULL字节截断、PHP伪协议php://filter, zip://LFI到RCE的转化是重点练习方向。SC-06不安全的直接对象引用(IDOR)初级参数预测、权限校验缺失设计一个用户系统通过修改URL中的user_id参数访问他人数据。SC-07服务器端请求伪造(SSRF)中级协议利用file://, gopher://, dict://、内网探测、绕过技巧实现一个可以发起网络请求的功能并尝试读取本地文件或攻击内网Redis。5.2 权限提升与内网渗透模块这部分模拟真实攻防场景难度较高。模块编号场景主题难度核心目标环境设计SC-08Linux系统提权高级从Web Shell获取www-data权限提权至root靶机故意配置SUID文件、内核漏洞、Cron任务错误、sudoers配置错误等。SC-09Windows系统提权高级从普通用户权限提权至SYSTEM利用错误的服务配置、可写路径、令牌窃取、未打补丁的漏洞如PrintNightmare。SC-10简单内网渗透高级突破边界横向移动获取域控权限设计2-3台主机的简单内网一台DMZ区Web服务器入口点一台内部文件服务器一台域控制器。考察信息收集、漏洞利用、哈希传递、横向移动。5.3 漏洞复现与CTF挑战模块紧跟安全动态复现真实世界的漏洞。SC-11Log4j2 (CVE-2021-44228) 复现搭建一个使用脆弱Log4j2版本的Java Web应用练习JNDI注入和LDAP利用。SC-12Spring4Shell (CVE-2022-22965) 复现部署存在漏洞的Spring Boot应用利用数据绑定机制进行RCE。SC-13自定义CTF挑战设计一些需要综合运用多种技巧的谜题。例如一个登录框需要先通过SQL注入获取管理员密码的MD5然后破解MD5或利用二次注入最后结合XSS盗取Cookie完成登录。每个模块都应配备详细的README.md内容包括场景描述、学习目标、难度等级、启动方式、访问地址、解题思路可折叠隐藏以及深入的技术原理分析。6. 运维、安全与最佳实践一个长期运行的靶场需要考虑运维便利性和自身安全性。6.1 自动化脚本与运维编写Shell或Python脚本让靶场管理变得轻松。初始化脚本 (scripts/init-range.sh)一键安装Docker和Docker Compose拉取基础镜像配置本地hosts。#!/bin/bash echo [*] 初始化 makabaka的小推车靶场... # 检查并安装Docker # 检查并安装Docker Compose # 创建必要的目录 # 添加hosts记录询问用户确认 echo [] 初始化完成场景管理脚本 (scripts/scenario-ctl.sh)统一启动、停止、重置所有或指定场景。#!/bin/bash ACTION$1 SCENARIO$2 case $ACTION in start) if [ -z $SCENARIO ]; then echo [*] 启动所有场景... find ./scenarios -name docker-compose.yml -execdir docker-compose up -d \; else cd ./scenarios/$SCENARIO docker-compose up -d fi ;; stop) # ... 类似逻辑 ;; reset) # 重置数据库等状态 cd ./scenarios/$SCENARIO docker-compose down -v docker-compose up -d ;; *) echo 用法: $0 {start|stop|reset} [场景目录名] ;; esac备份与恢复脚本定期备份数据库卷和配置文件。6.2 靶场自身安全加固切记靶场是用于合法学习的。必须确保其不会意外暴露或成为攻击跳板。网络隔离所有靶场容器都应运行在独立的Docker网络中如我们创建的makabaka-range-net绝不将数据库、SSH等服务的端口映射到主机公网IP0.0.0.0。仅通过Nginx反向代理暴露必要的Web端口80/443且Nginx本身只绑定127.0.0.1或本地访问。最小化镜像使用Alpine等小型基础镜像构建漏洞应用减少攻击面。定期更新定期更新基础镜像如nginx:alpine,mysql:8.0以修复已知漏洞。访问控制可以在Nginx层面配置简单的HTTP Basic认证或者为Portainer设置强密码。更严格的情况下可以配置仅允许本地或特定IP段访问。资源限制在docker-compose.yml中为容器设置CPU和内存限制防止某个漏洞利用练习耗尽主机资源。services: web: # ... 其他配置 deploy: resources: limits: cpus: 0.5 memory: 512M日志审计收集Nginx和各个应用的访问日志、错误日志定期审查了解靶场被访问的情况。6.3 学习路径与引导设计为了让“小推车”更好推学习路径至关重要。我建议在靶场的导航页nginx/html/index.html做如下设计新手村按顺序排列SC-01到SC-07每个模块完成后再解锁下一个。进阶区集中放置SC-08到SC-10等权限提升和内网渗透场景。挑战营放置漏洞复现和综合CTF场景。知识库每个场景的README中除了攻略还应包含“扩展阅读”部分链接到OWASP备忘单、相关CVE详情、优秀技术文章等。在每个漏洞应用的界面上可以添加一个“提示”按钮分等级给出提示。例如提示1这个输入点似乎直接拼接到了数据库查询中。提示2试试在输入后加上一个单引号‘。提示3查看页面返回的错误信息它可能泄露了数据库结构。这种设计能有效平衡挑战性和学习效率避免初学者在第一步就卡住而放弃。构建和维护一个像“makabaka的小推车”这样的靶场本身就是一个极佳的学习过程。它迫使你去深入理解每一个漏洞的成因、利用方式和修复方案。当你能够流畅地向别人解释你靶场里的每一个挑战时你对这些安全知识的掌握就已经超越了大多数纸上谈兵者。这个靶场不仅是你的练习场更是你技术能力的立体名片。现在就动手打造属于你自己的那辆“小推车”吧从第一个简单的SQL注入模块开始一步步把它装满。