## 一、漏洞概述
### 1. 漏洞简介
FreePBX之前被称为Asterisk Management Portal,是IP电话工具Asterisk的标准化实现,可提供Web配置界面和其他工   
FreePBX中的`functions.inc.php`文件存在对参数未经过滤直接拼接进`exec`,可导致远程命令执行  
### 2. 漏洞影响
攻击者可以在通过构造特定url,在目标系统上执行任意命令并取得返回结果
### 3. 漏洞触发条件
版本:`13.0.35`经过测试,其他版本未知   
权限:拥有管理员账号
## 二、漏洞原理分析
`functions.inc.php`中`get_headers_assoc()`:
```
function get_headers_assoc($url) {
    global $amp_conf;
    if ($amp_conf['MODULEADMINWGET']) {
        FreePBX::Curl()->setEnvVariables();
        //关键点
        exec("wget --spider --server-response -q ".$url." 2>&1", $wgetout, $exitstatus);
        $headers = array();
        if($exitstatus == 0 && !empty($wgetout)) {
            foreach($wgetout as $value) {
                $ar = explode(':', $value);
                $key = trim($ar[0]);
                if(isset($ar[1])) {
                    $value = trim($ar[1]);
                    $headers[strtolower($key)] = trim($value);
                }
```
`$url`传递给exec前未经任何过滤,导致远程命令执行,继续寻找调用该函数的文件   
`libraries/modulefunctions.class.php`中`1539`行:
```
function handledownload($module_location, $progress_callback = null) {
//...................................................
if (!is_array($progress_callback) && function_exists($progress_callback)) {
    $progress_callback('getinfo', array('module'=>$modulename));
} else if(is_array($progress_callback) && method_exists($progress_callback[0],$progress_callback[1])) {
    $progress_callback[0]->$progress_callback[1]('getinfo', array('module'=>$modulename));
}
$file = basename($module_location);
$filename = $amp_conf['AMPWEBROOT']."/admin/modules/_cache/".$file;
//关键点
$headers = get_headers_assoc($module_location);
if (empty($headers)) {
return array(sprintf(_('Failed download module tarball from %s, server may be down'),$module_location));
} 
}
```
调用get_headers_assoc()时传入的参数`$module_location`同样没有过滤  
`handledownload()`函数在文件`page.modules.php`被包含时调用,在管理员控制面板中访问`admin/config.php?display=modules`可以使得文件被包含.   
`page.modules.php`:
```
Line 174 : switch ($action) {
..............................
Line 643 : case 'upload':
..............................
$displayvars['processed'] = false;
if (isset($_REQUEST['upload']) && isset($_FILES['uploadmod']) && !empty($_FILES['uploadmod']['name'])) {
    $displayvars['res'] = $modulef->handleupload($_FILES['uploadmod']);
    $displayvars['processed'] = true;
} 
//关键点
elseif (isset($_REQUEST['download']) && !empty($_REQUEST['remotemod'])) {
    $displayvars['res'] = $modulef->handledownload($_REQUEST['remotemod']);
    $displayvars['processed'] = true;
} elseif(isset($_REQUEST['remotemod'])) {
    $displayvars['res'][] = 'Nothing to download or upload';
    $displayvars['processed'] = true;
}
```
传入`download`时,进入关键点处的判断,参数`$_REQUEST['remotemod']`也未进行任何过滤就传入`handledownload()`,最终这个参数将拼接进`exec()`执行   
调用流程:`page.modules.php:handledownload($_REQUEST['remotemod'])   --->   get_headers_assoc($module_location)   --->   get_headers_assoc($url)   --->   exec()`
                       
                       
        
          
暂无评论