1.进去以后我们先观察一下界面

2.这熟悉的界面。。。和我们之前做的两题可以说一模一样(实际上也是一个系列的题目。

那我先试试单独输入一个admin

3.这里显示的意思是要同时输入用户名和密码。

4.那我们试试在两个表单输入框里面输入1',1"看看这题存不存在sql注入

5.可以看到有报错回显,说明这题是存在sql注入的

这里解释一下为什么输入1'会有报错回显。

后端程序员在写登录验证代码时,通常会使用字符串拼接的方式来构建 SQL 语句。正常的 SQL 语句长这样:
SELECT * FROM users WHERE username = '你输入的用户名' AND password = '你输入的密码';

当你输入一个单引号(比如 admin')时,后端会原封不动地把它拼接到语句里,变成了:
SELECT * FROM users WHERE username = 'admin'' AND password = '...';

所以我们输入1'会导致后面多出来一个',让服务器解析不了,自然就会报错了。

6.那确认了有sql注入之后,我们试试万能密码能不能用

7.用不了。而且没报错。显示的是特殊的文案,说明我们进入了另一个分支,那我们可以猜测服务器对我们多输入的 or 1=1;里面的其中有些字符进行了过滤,导致返回的结果特殊。

8.那我们可以慢慢试试到底是那些字符被过滤。最常见的比方说。空格,等号,上次的or也是我们遇到过的过滤。具体测试我们就不演示了。我们直接说结果继续做下去,虽然我们这里跳过了,大家做的时候还是具体自己去试一下。那经过我们测试,发现 *、|、空格、等号会被过滤掉。

9.此路不通我们换一条路

先试试1'and#和1'union#看看有没有联合查询注入的可能

10.结果还是不行。到这里,就到我知识的上限了。这题要想做下去的话我只能去其他师傅的wp里面学习了。

11.在参考了其他师傅的wp以后,我知道了这题还有第三种的方法,也就是报错注入。这个东西属于新知识,我也不是很清楚,不知道的东西我们就问问AI

报错注入(Error-based Injection)攻击代码。它的核心目的,是利用数据库的报错机制,把原本看不见的数据库信息(比如当前数据库名)直接“炸”出来显示在网页的报错信息里。

updatexml()是报错注入的核心函数, 原本是 MySQL 用来更新 XML 文档的函数,它有三个参数:updatexml(目标文档, XPath路径, 新值)

报错原理:数据库规定,第二个参数(XPath路径)必须是合法的 XML 路径格式(通常以 / 开头)。如果我们故意传入一个非法的字符,数据库无法识别,就会抛出语法错误(XPATH syntax error),并且把这段非法的内容原样显示在报错信息里

12.在学习了报错注入的基本用法以后我们按照之前的四步走,爆库名,用库名查表,再用库名查字段名,看看有没有可疑的,一般在这一步都能看类似于flag一样的关键字。

13.那我们先查库名

1'or(updatexml(1,concat(0x7e,database(),0x7e),1))#

这里解释一下这段报错注入。1‘没啥好说的,就是用来闭合字段的,这个很熟悉了。

updatexml()前面解释过了。值得说的就是这里前面一个1代表目标文档,我们没信息,所以填个1占个位。后面那个1我们也不知道能填啥,所以也填个1。我们只知道我们需要得到数据库名。

这里

concat():这是一个拼接函数。它把 ~ + 数据库名 + ~ 串联在了一起。

0x7e:这是特殊符号波浪号 ~ 的十六进制表示。为什么要用它?因为 ~ 在 XML 路径中是非法字符,只要它一出现,就能完美触发报错。同时,它像一个醒目的“书签”,方便攻击者在长长的报错信息中快速定位到想要的数据。

特别注意的是URL和sql注入里面的#是不一样的。

使用hackbar的payload应该是

1'or(updatexml(1,concat(0x7e,database(),0x7e),1))%23

14.然后我们接着查表名

?username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))%23

这串payload有点长,看起来可能会有点懵,我们一起拆开来看

结构啥的就不说了,我们说一下concat()里面的东西,这里面的东西是精华。

首先。GROUP_CONCAT(table_name)是一个是一个聚合函数,它能将这些分散的表名(table_name全部拼接成一个长字符串,中间用逗号隔开。

然后。information_schema 是 MySQL 自带的一个“元数据数据库”,它像一个巨大的目录,记录了服务器上所有数据库、表、字段等基础信息。而 tables 是其中专门存储所有表名信息的表。

最后看WHERE后面,也就是筛选,

table_schema 代表数据库的名字。

DATABASE() 是一个内置函数,它会返回当前正在使用的数据库名称。

这句话的作用是进行过滤:只查找属于当前这个数据库的表,排除掉系统自带的其他数据库。

15.看懂了payload我们进网页输入看看

16.成功。那这个H4rDsq1就是表名了。

17.拿到了表名下一步不用我多说,我们开始查字段

username=1&password=1'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))%23

18.这里大部分和查表一样。有不同的地方我们这里说一下。

information_schema.columns:这是 MySQL 的系统表,里面记录了所有数据库、所有表的字段(列)信息。

WHERE table_name LIKE 'H4rDsq1':这里进行了精准定位,只查找表名为 H4rDsq1 的记录。

GROUP_CONCAT(column_name):和你上次遇到的逻辑一样,利用聚合函数把这张表里的所有字段名(比如 id,username,password)拼成一个长字符串,方便一次性提取。

19.输入进去看一下

20.得到字段名,id,username,password。那我们按常规逻辑判断,flag肯定藏在password里面。我们直接全爆出来。

这里我可以用到从其他大佬那边学来的substring函数,

SUBSTRING(字符串, 起始位置, 截取长度)

updatexml 报错注入的极限通常是 32 个字符

所以我们用substring函数可以完整的提取长数据

?username=admin&password=1'or(updatexml(1,concat(0x7e,(select(concat(id,',',username,',',substring(password,1,33)))from(H4rDsq1)),0x7e),1))%23

21,被过滤了。。。说明substring函数并不行了。这里没招了再看看其他师傅的wp。发现可以用left和right函数

 ?username=admin&password=1'or(updatexml(1,concat(0x7e,(select(left(password,33))from(H4rDsq1)),0x7e),1))%23

?username=admin&password=1'or(updatexml(1,concat(0x7e,(select(right(password,26))from(H4rDsq1)),0x7e),1))%23

21.拼接一下得到flag

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐