从零构建PHP靶场:Docker实战BUUCTF Ezsql漏洞环境

在网络安全领域,理论知识的积累固然重要,但真正的技能提升往往来自于动手实践。本文将带你从零开始,使用Docker技术完整复现BUUCTF平台上的经典Ezsql漏洞环境,并在此基础上构建一个可自由扩展的PHP靶场系统。不同于简单的漏洞利用教程,我们将重点关注环境搭建、漏洞原理分析以及多维度防御方案的实施。

1. 环境准备与Docker基础配置

1.1 Docker环境初始化

首先确保你的系统已安装Docker和Docker Compose。对于Windows/macOS用户,建议安装Docker Desktop;Linux用户可通过包管理器直接安装:

# Ubuntu/Debian示例
sudo apt-get update
sudo apt-get install docker.io docker-compose
sudo systemctl enable --now docker

验证安装是否成功:

docker --version
docker-compose --version

1.2 项目目录结构规划

创建一个清晰的目录结构有助于后续维护:

ezsql-range/
├── docker-compose.yml
├── php/
│   ├── Dockerfile
│   └── src/
│       ├── index.php
│       └── dbConnect.php
├── mysql/
│   └── init.sql
└── README.md

2. 漏洞环境完整复现

2.1 编写Docker Compose配置

docker-compose.yml 文件定义整个服务架构:

version: '3.8'

services:
  web:
    build: ./php
    ports:
      - "8080:80"
    depends_on:
      - db
    volumes:
      - ./php/src:/var/www/html

  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: vulndb
      MYSQL_USER: ctfuser
      MYSQL_PASSWORD: ctfpass
    volumes:
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"

2.2 构建漏洞前端页面

php/src/index.php 中创建存在SQL注入的登录页面:

<?php
error_reporting(0);
include 'dbConnect.php';

if(isset($_GET['username']) && isset($_GET['password'])){
    $username = $_GET['username'];
    $password = $_GET['password'];
    
    $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
    $result = $mysqli->query($sql);
    
    if(!$result) die(mysqli_error($mysqli));
    
    if($result->num_rows > 0){
        echo "<h2>登录成功!</h2>";
    }else{
        echo "<h2>用户名或密码错误</h2>";
    }
}
?>

2.3 数据库初始化脚本

mysql/init.sql 创建测试数据:

CREATE DATABASE IF NOT EXISTS vulndb;
USE vulndb;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(50) NOT NULL
);

INSERT INTO users (username, password) VALUES 
('admin', 'secret123'),
('testuser', 'testpass');

3. 漏洞分析与利用实践

3.1 经典SQL注入攻击演示

启动环境后,访问 http://localhost:8080 ,尝试以下攻击向量:

  • 万能密码攻击:

    username: admin' OR '1'='1
    password: anything
    
  • 联合查询获取表结构:

    username: admin' UNION SELECT 1,table_name,column_name FROM information_schema.columns WHERE table_schema=database()#
    password: 
    

3.2 漏洞原理深度解析

该漏洞源于直接拼接用户输入到SQL语句中。攻击者可以通过精心构造的输入:

  1. 闭合原始查询中的引号
  2. 插入恶意SQL代码
  3. 注释掉剩余部分
-- 原始安全查询
SELECT * FROM users WHERE username='admin' AND password='secret123'

-- 被注入后的查询
SELECT * FROM users WHERE username='admin' OR '1'='1' AND password='anything'

4. 多维度防御方案实施

4.1 基础防御:参数化查询

修改 index.php 使用预处理语句:

$stmt = $mysqli->prepare("SELECT * FROM users WHERE username=? AND password=?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
$result = $stmt->get_result();

4.2 进阶防护:输入验证与过滤

添加输入验证层:

function validateInput($input){
    if(preg_match('/[\'"\\;]/', $input)){
        return false;
    }
    return htmlspecialchars($input, ENT_QUOTES);
}

$username = validateInput($_GET['username']);
$password = validateInput($_GET['password']);

4.3 安全增强:Web应用防火墙规则

在Docker环境中添加ModSecurity:

FROM php:7.4-apache

RUN apt-get update && \
    apt-get install -y libapache2-mod-security2 && \
    mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

COPY src/ /var/www/html/
COPY modsecurity_rules.conf /etc/modsecurity/rules.d/

5. 靶场扩展与教学应用

5.1 多漏洞类型集成

扩展靶场包含更多漏洞类型:

// 文件包含漏洞示例
if(isset($_GET['page'])){
    include($_GET['page']);
}

// XSS漏洞示例
echo "<div>欢迎, ".$_GET['name']."</div>";

5.2 自动化测试集成

添加简单的测试脚本 tests/injection_test.py

import requests

def test_sql_injection():
    url = "http://localhost:8080"
    payload = {"username": "admin' OR '1'='1", "password": "x"}
    response = requests.get(url, params=payload)
    assert "登录成功" in response.text
    
if __name__ == "__main__":
    test_sql_injection()

5.3 教学场景设计建议

设计渐进式实验路线:

  1. 基础注入:使用简单payload绕过登录
  2. 信息收集:获取数据库版本、表结构
  3. 数据提取:导出敏感数据
  4. 防御突破:尝试绕过基础防护
  5. 加固实践:实现有效防护方案