SQL注入 报错注入+附加拓展知识,一篇文章带你轻松入门

4 篇文章 0 订阅
1 篇文章 0 订阅

第5关-------------------------------------------->

前端直接不会显示账号密码的打印;但是在接收前端的数据的那部分后端那里,会看前端传递过来的值是否正确,如果不正确,后端接收值那里就会当MySQL语句执行错误,直接打印MySQL的报错信息

怎样解决第二关:通过这一个打印错误信息的漏洞,再让updatexml()方法去真正执行MySQL语句,肯定会出现报错情况,出现了就会打印报错信息;

前面的第一关注入是在web页面会打印当前登录的账号,最后如果我们知道了表名和对应表的字段名的话,我们就可以通过group_concat(username),group_concat(password)这种将所有的username账号和password密码打印出来了;

但是要是前端web页面并不会显示你的账号密码,前端压根就不会答应你的账号密码怎么办?

拓展:

1、group_concat()和concat()的区别

---1、group_concat()函数是将同一个组内的所有指定的值拼接起来;

如:group_concat(id,':',name);

就是将整个表中的所有id和所有name都拼接起来

是一行一行拼接的,拼接的内容是将第一行的id值和‘:’和name值都拼接起来,

然后再将第二行的id值和‘:’和name值都拼接起来,

...最后整个表中的数据都拼接完成后再一次性打印在一行里面

---2、concat()

concat就是将每行记录的都分别拼接起来,分别打印在每一行

如:select concat(id,':',username) from users ;

---所以concat是拼接出来的有多个成员行数或者所成员个数不变,但是group_concat()是将所有的成员拼接成一个成员,所以成员变成了一个,适合有limit(0,1)的场合

注意:不管是group_concat()还是concat()都不能直接对  *   进行字符串连接,就是不能类似于这样写:select group_concat(*) from users /  select concat(*) from users ;

报错注入:

本篇后端php会打印你的MySQL报错信息,

答应代码:

这篇文章开头已经说了当你的web前端页面并不会打印你的账号密码,那怎么查询你的账号和密码的值呀?   

---说实话,基本上现在的web前端页面都不会打印你的账号密码的,你看看有哪个网站会打印这些重要信息

1、利用updatexml()的报错功能

原理:updatexml()方法实际上是去更新我们后端的xml文档,但是我们在xml文档路径的位置写一个MySQL的查询语句,然后我就会报错,但是他在报错的时候其实已经执行了这个MySQL的查询语句,因为就是执行了才知道这个是错误的;

注意执行的代码是mysql_quer()这个函数;

updatexml(old_value,xpath,new_value);

1、old_value   ---要更新的数据

2、xpath      ---这个xml文档的路径

3、new_value  ---更新后的数据

当有如下xml数据时:

那么我们想要将指定部分修改成新的数据,我们就应该:

这里的text()是获取student[1]下所有的数据;

----所以说从这里可以看出来我们在xpath位置必须准确的写上xpath路径,那么如果我们写上一个特殊字符,这系统显然就能看出来这个路径是不符合规定的,所以mysql_quer()在执行时就会发现updatexml的路径不对,所以就会报错但是mysql_quer()函数是会将其MySQL代码进行执行;

至于这个报错有没有被打印出来,那就要看这个后端有没有打印MySQL执行错误的相关代码了,反正第5关是打印了的;

2、直接在updatexml中在xpath部分执行MySQL代码;

---显然xpath部分是应该写xml路径的,这里我们写了写了一个不符合规定的路径就会报错,如在路径里写了特殊符号就显然会在mysql_quer()执行的时候报错,

但是报错的同时里面的MySQL代码还是会被执行;这个是updatexml的一个特性

你看,这里我就通过concat()方法将特殊字符‘~’插入到了xpath路径里面去,同时路径里面还包含了一个MySQL代码,mysql_quer()在执行的时候就会发现这个updatexml的路径部分有问题,自然而然的就会爆报错,同时还是会将其中MySQL代码进行执行;

最后因为后端的写了--将这个接收的参数值如果运行出问题的话,就会将其打印--的这种代码,所以最后就会将这个报错信息打印出来;

127.0.0.1/sqli-labs-master/Less-5/?id=1'andupdatexml(1,concat('!',(database())),1)--+

注意你要执行的那个嵌入在路径里面的MySQL代码必须要加括号,不然updatexml是真的无法识别你的MySQL代码;其实updatexml本意是不想识别出你的MySQL代码的,但是你加入了(),那她就没办法迫不得已识别出来了

---这样就把当前使用的数据库找到了;

---通过这种类似的方法最终像前面一样将你的数据库,列成员一个一个搞出来;

3、找到数据库,找数据表

127.0.0.1/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat('!',(selectgroup_concat(table_name)frominformation_schema.tableswheretable_schema=security)),1)--+

4、通过数据表查找列成员           ---条件:禁止了information_schema库

127.0.0.1/sqli-labs-master/Less-5/?id=1' and updatexml(1,concat('!',(select * from (select * from users a join users b using(id,username)) c)),1)--+

这里就是查找到了password这个成员;

5、通过列成员查找列成员的值,

这样如果我们直接输入:select * from users时,

会出现以下字样,这种显示的意思是应该只输出一个成员,这里显然 * 代表了id,username,password三个成员了;

因为updatexml的错误返回只能是一行字符串,所以我们需要使用到group_concat()或concat方法将他们合并;

--->

127.0.0.1/sqli-labs-master/Less-5/?id=1'andupdatexml(1,concat('!',(selectgroup_concat(concat(id,username,password))fromusers)),1)--+

---但是显然我们可以看出,这个账号密码并没有全部显示出来!

这是因为我们的updatexml()方法的报错返回最大只能返回32个字节;

所以我们接下来就需要对获取到的数据进行分段获取

分段获取有两种方法1、通过concat()和limit 0,1一起搭配使用

---http://127.0.0.1/sqli-labs-master/Less-5/?id=1%20and%20updatexml(1,concat(!,(select%20concat(id,username,password)%20from%20users%20limit 0,1)),1)--+

因为concats是将多个字段值合并成类似于一个字段值,但是行数不变;所以我们这里可以通过limit 一行一行的截取下来

2、通过substring(str,起始位置,终止位置)来对字符串进行截取;

---http://127.0.0.1/sqli-labs-master/Less-5/?id=1%20and%20updatexml(1,concat(!,(select%20substring(group_concat(concat(id,username,password)),32,64)%20from%20users)),1)--+

------------------》》extractvalue(1,xpath)这个函数和updatexml函数除开参数个数不一样,其余全部一样!!!

6、如果updatexml和extractvalue函数都被拦截禁用了,那么我们该怎么办;

--------------没办法,只能换函数!!

报错注入的7大函数:

  floor函数

1、7大函数中很多函数都被禁用了,且很多函数因为版本问题都是被淘汰或者还没有开发出来;

但是有一个报错注入函数在MySQL5.0到8.x依然还在继续用,这个函数就是---->floor函数

floor报错注入函数需要搭配rand()随机函数、group by分组count()统计一起搭配使用;

---->

127.0.0.1/sqli-labs-master/Less-5/?id=1' and  

select 1 from

(select count(*),concat(version(),floor(rand(0)*2))a from information_schema.tables group by a)x)--+

我们一步一步来解释

1、floor(rand(0)*2)   ---生成一个0到1的随机数,floor是向下取整,然后给这个列取别名为a

2、group by是将a进行分组,0为一组,1为一组

3、count(*)是计算所有组分别有多少个元素

好,问题就出现在这了,当我们的count(*)计算分组的元素个数时,会出现错误;

错误:我们的MySQL计算分组时,是这样的一个步骤

---1、我们的count(*)在计算分组的条数时,他会看到分组group by 是根据floor(rand(0)*2)的值来产生数据的;

所以我们的count(*)在取记录时首先是先去执行floor(rand(0)*2),执行结果是0;

好,count(*)发现0这个分组并没有被记录在案;好我们就需要把0插入到我的count(*)这个表中;

但又来了,我们的count(*)在插入时,还会执行一次group by的floor(rand(0)*2);

所以我们最终记录进入count(*)中的分组是1,且条数是1;

---floor(rand(0)*2)的前6条是011011,因为rand(0)会变得固定

---2、第二次取数据,实际上是第三次计算数据;

得出结果是1,然后count(*) 发现这个数据我们count(*)表是有的,所以我们就直接在有的基础上+1(取数据,和新插入数据才会对group by 的floor(rand(0)*2进行执行))

---3、第三次取数据,实际上是第四次计算数据;

我们计算出来的结果是0,然后count(*)又发现这个0是表中没有的,所以就需要进行插入,但是在进行插入的时候,又会对group by 的floor(rand(0)*2)进行计算一次;

这样原本要新插入的0就变成了要新插入的1,当这个1插入的时候,系统就会报错,这个1已经是存在了的 ,你这里再插入是属于重复插入;重复插入1;

就是这种就会出现报错;

所以最终我们随便去from一个表都可以,只要是有6个行数据即可;

只要能到达floor(rand(0)*2)=011011=6个数据即可

2、这里我们的重复插入1变成了重复插入 :版本号1,因为我们把版本号和1结合起来了;

所以最后就是因为出问题了,而且MySQL还是将其含有的MySQL代码执行了,

因为后端有php对MySQL执行出错误时的报错打印,这样版本号就会被连着错误一起打印出来了;

3、select 1 from ()

为什么要在最外层加入色了select 1 from ()?

因为不加入的话,select count(*),concat(version(),floor(rand(0)*2))a from information_schema.tables group by a ,这行代码代表的是有两个输出成员,不管最终有没有输出这两个列成员,但是这MySQL代码已经真真切切的表示了这里将会有两个列成员,所以系统会直接报错;

成员多了是在编译时就会被发现(编译时的错误)

报错注入是在运行时才会被发现,才会被报出有错误(运行时的错误)

但是打印MySQL错误的这行代码的时候

说明,floor错误信息的返回只能是一连串的字符串,不允许打印多行或多列的这种类似于表的东西;

所以我们不能直接打印,你说能直接使用concat(count(*),concat(version(),floor(rand(0)*2))a)吗,那你里面取的别名还有什么意义,你都包起来形成新的列了,所以不行;

所以你只能在最前加select 1 from ();

哎?这样也只是让列变少了,但是行数还是实打实的跟select count(*),concat(version(),floor(rand(0)*2))a from information_schema.tables group by a的行数一样呀,就是两行,0和1呀?

no,我们刚刚已经算过了,压根还没有真正新插入0这一行,单单就在插入1这里就出现了重复1的情况,所以select 1 from(...)实际上是只输出了一行,

所以最终是输出的一行一列,在满足MySQL错误打印的要求:只能打印一连串字符串,不能打印多行或多列的类似于表的东西;

---其余查询的用法就是和updatexml/extractvalue一样了

127.0.0.1/sqli-labs-master/Less-5/?id=1and(select1from(selectcount(*),concat((select*from(select*fromusersbjoinusers using(id))a),floor(rand(0)*2))afrominformation_schema.tablesgroupbya)b)--+

如查询字段id的值:group_concat(id)

---当我们查询字段username/password的值时:

值得注意的是:

1、我们前面已经说过,我们的update错误返回只能是一行的这种连续的字符串;

不能是多行或多列的显示;而对于floor来说,返回的错误信息,如果字符串太长,floor错误提示也会出问题,说你只能显示一行;

floor和count(*)组合的错误提示只能是一行的一连串的字符串,且这个字符串不能太长,比update的错误提示条件又多了一个字符串错误信息返回不能太长

2、我们的MySQL代码都需要用()包裹起来;

3、注意:这里的重复和自己组合起来的新表确实是有多行,但是你注意没有,MySQL的执行顺序是先把内层的执行了再执行外层的,这里肯定也是一样,先执行内层的,

而内层是select * from users b join users ;

注意这里也是不会直接进行展示的,这里是需要先进行把表连接起来,然后才进行展示;

最终:而在连接表的时候就会出现字段重复的现象!!最终达到破解字段名的目的;

---MySQL的执行顺序:从内到外,从右到左;

---updatexml/extractvalue 他们错误返回的是最多32个字节的字符串

---floor和count()返回的错误信息只能是字符串,且长度不能太长;

---order by是将字段值进行一个排序;

当一个数据表中有id,name,passwd时;那么order by 3就是将passwd字段的所有值进行一个排序

---------------------------------我们只讲思路,不讲详细过程;

                                          过程是背,思路是理解;

                                           想要走多远,10%背+90%理解

祝你年薪百万,成绩辉煌!!!

  • 20
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值