靶场实战03|搞懂数据库,才能玩转注入(附docker靶场部署步骤)
原创
安全值班室
安全值班室
安全值班室
2026年9月19日 09:00
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
你访问的每个网站,几乎都是三层结构:浏览器里的页面是前端,背后处理请求的是后端程序,存账号、订单、商品的是数据库。攻击者盯上的,正是这三层之间来回传递的参数。
这一期我们把地基打牢:HTML/JS是什么、MySQL怎么增删改查、联合查询为什么是后面注入拖库的钥匙。全程在本地Docker里动手,零风险。
01 / 环境搭建:5分钟搭起LAMP三层架构
本章靶场是标准的LAMP环境(Linux+Apache+PHP+MySQL),全部用官方镜像,一条条命令启动,完全隔离在本机:
# 创建容器网络docker network create lab-net# 启动MySQL5.7docker run -d --name lab-db --network lab-net \\-e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=shop \\-p 3307:3306 docker.1ms.run/library/mysql:5.7# 启动PHP7.4-Apache,挂载网站目录docker run -d --name lab-web --network lab-net \\-p 8080:80 -v $PWD/www:/var/www/html \\docker.1ms.run/library/php:7.4-apache# 安装数据库扩展并重启web容器docker exec lab-web docker-php-ext-install mysqli pdo_mysqldocker restart lab-web
靶场说明:为什么选LAMP?因为它是全球部署最广的Web架构,也是SQL注入、文件上传、反序列化等绝大多数Web漏洞的第一现场。把\"数据从浏览器到数据库的完整旅程\"看明白,后面学漏洞会非常顺。php:7.4-apache和mysql:5.7都是官方镜像,稳定、干净、行为可预期。
避坑指南(新手必看):
① MySQL连不上报\"Can't connect\":不是命令错了,是MySQL首次启动要初始化数据目录,约30-60秒。等1分钟,或执行 docker logs lab-db 看到\"ready for connections\"再连。
② 端口冲突报\"bind: address already in use\":8080/3307被占用了。换端口,比如 -p 8081:80,或先 docker ps 找到占用容器停掉。
③ PHP页面报\"Call to undefined function mysqli\_connect\":忘了装扩展。必须执行第4步 docker-php-ext-install 并重启容器,扩展才会生效。
④ 老教程里的 --link 参数已标记废弃,统一用 docker network create 建网,更规范也少踩坑。
02 / 模拟攻击:从数据库基础到注入前夜
先别急着打打杀杀。这一课的\"攻击\"是预习:在本地靶场里把数据库和联合查询玩熟,到第9章学SQL注入时直接就能上手。分5步走:
步骤1|初始化数据表——进入数据库容器,建一张商品表:
docker exec -it lab-db mysql -uroot -proot shop
CREATE TABLE goods ( id INT PRIMARY KEY, name VARCHAR(50), price DECIMAL(10,2));INSERT INTO goods VALUES (1,'路由器',199.00),(2,'摄像头',89.00),(3,'硬盘',459.00);SELECT * FROM goods;
说明:goods表模拟电商商品表,后面所有实验都围绕它。SELECT是查询,WHERE id=2就是\"查ID为2的商品\"。
步骤2|写一个有\"坏味道\"的查询页面——新建 www/goods.php:
<?php$conn = new mysqli('lab-db','root','root','shop');$id = $_GET['id'];$sql = \"SELECT name, price FROM goods WHERE id = $id\";$result = $conn->query($sql);while($row = $result->fetch_assoc()){ echo $row['name'].' '.$row['price'].'';}?>
注意第3、4行:用户输入被直接拼进SQL。这是教科书级的错误写法,但很多老系统里真实存在。浏览器打开 http://localhost:8080/goods.php?id=1,正常返回\"路由器 199.00\"。
步骤3|正常访问,记住基线——curl验证:
curl -s \"http://localhost:8080/goods.php?id=1\"# 输出:路由器 199.00
步骤4|加一个单引号,探一探——把id改成 1' :
# 传入单引号,触发SQL语法错误curl -s \"http://localhost:8080/goods.php?id=1'\"# 响应特征:页面返回数据库语法报错# 拼接后的SQL语句:# SELECT name, price FROM goods WHERE id = 1'# 多出一个单引号,SQL语法断裂# 注:报错返回的库名、账号等敏感信息已打码 [REDACTED]
为什么?因为SQL是拼出来的,多出来的单引号破坏了语句结构。这就是注入点的\"探针\":只要参数拼接SQL,单引号就会让它现形。注意:这一步只在本地靶场做,真实系统没有授权就是违法。
步骤5|用UNION预习\"拖库\"——在MySQL里直接执行:
-- UNION 联合查询,读取数据库用户与版本信息SELECT name, price FROM goods WHERE id = 1 UNION SELECT user(), version();# 返回结果多出一行:root@[REDACTED] | 5.7.xx
UNION把两条查询的结果上下拼接,硬性要求两边列数一致(这里都是2列)。user()返回当前数据库用户,version()返回版本号。如果页面把这两列原样输出,攻击者就能用同样的语法把数据库里的用户名、密码哈希一行行\"借\"出来——这就是注入拖库的原理雏形。
响应包特征总结:正常请求200+两列商品数据;加单引号变500/语法错误;UNION请求200且多出一行非商品数据。三步特征串起来,就是一条完整的注入探测链。
03 / 日志分析:数据库在日志里留下的脚印
攻击特点:在Apache访问日志里,注入探测长这样(脱敏):
192.168.1.10 - - [17/Aug/2026:14:03:22 +0800] \"GET /goods.php?id=1 HTTP/1.1\" 200 451192.168.1.10 - - [17/Aug/2026:14:03:25 +0800] \"GET /goods.php?id=1%27 HTTP/1.1\" 500 320192.168.1.10 - - [17/Aug/2026:14:03:28 +0800] \"GET /goods.php?id=1%20UNION%20SELECT%20user(),version() HTTP/1.1\" 200 128
逐行解读:
第1行:id=1,正常请求,200,返回45字节——这是基线。
第2行:id=1%27(%27是单引号的URL编码),返回500且字节数飙到320——异常参数引发服务器报错,第一条警报。
第3行:id=1%20UNION%20SELECT...(%20是空格),200但返回128字节——参数里出现SQL关键字,返回内容异常。
判断标准(真实攻击,不是误报/爬虫):
① 参数编码异常:%27、%20、%2C(引号、空格、逗号)密集出现在参数里,正常用户绝不会这么输入。
② SQL关键字命中:URL里出现 union、select、sleep、benchmark 等,直接指向注入尝试。
③ 状态码节奏异常:200→500→200,同一IP几秒内连续请求同一页面——这是\"探测-确认-利用\"的典型节奏。
④ 响应字节突变:同一页面正常45字节,攻击时128+字节,说明返回了额外数据。
注意区分:搜索引擎爬虫路径规范、无参数探测、频率稳定,不是攻击;而上述四条同时出现,基本可以断定是人工注入尝试。
04 / 如何防护:把代码变回数据
先讲原理:SQL注入能成功,根本原因不是数据库不安全,而是开发者在拼接SQL时把用户输入当成了代码。输入里的单引号和关键字被数据库当成SQL语句的一部分执行了。只要输入永远是\"数据\",注入就不存在。
基础级(必须做):参数化查询。用PDO预处理,SQL结构提前固定,输入只作为参数传递:
<?php$pdo = new PDO('mysql:host=lab-db;dbname=shop','root','root');$stmt = $pdo->prepare('SELECT name, price FROM goods WHERE id = ?');$stmt->execute([$_GET['id']]); // 用户输入只当做数据,不能篡改SQL结构$rows = $stmt->fetchAll();?>
推荐:白名单校验+最小权限。id只允许数字,用 (int) 强转;给Web应用单独建一个只有SELECT权限的数据库账号,即使被注入也拿不到表结构、改不了数据。
纵深防御:WAF拦截SQL特征请求、开启数据库审计日志、异常参数告警联动;代码上线前用静态扫描找出所有\"字符串拼接SQL\";敏感操作双人复核。分层设防,让攻击者每一层都要付出代价。
05 / 总结复盘
本章要点(新手必须记住):
① Web是三层架构:前端、后端、数据库,攻击发生在参数传递处。
② SQL注入的根源是字符串拼接,不是数据库本身。
③ UNION注入要求两边列数一致,这是拖库的关键语法。
④ 参数化查询是防注入的黄金标准,写第一行代码就要用。
⑤ 状态码节奏+参数编码异常,是日志里发现探测的第一道线索。
面试可能怎么问:
\"SQL注入的原理?\" 答:用户输入未过滤直接拼接进SQL,输入变成代码执行,破坏语句结构并窃取数据。
\"UNION注入的前提?\" 答:两边列数一致,且结果能回显到页面。
\"预处理为什么能防注入?\" 答:SQL语句结构在绑定参数前已由服务端编译确定,输入只作为数据传递,无法改变语句结构。
下一期进入\"安全测试方法论与工具环境\":Burp Suite代理、浏览器DevTools、完整测试流程。
关注我,下期不迷路
MORE
往期回顾
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论