DiscuzX系列命令執行分析公開(三連彈)

wyzsk發表於2020-08-19
作者: tang3 · 2015/01/15 18:55

0x00 漏洞概要


昨天360補天發了這樣的一條微博:

enter image description here

然後打聽了一下細節,發現居然是我13年7月報給TSRC的漏洞,看今天大家玩的挺開心,與TSRC的人聊了兩句,說這個系列可以發幾個了,所以我也來湊個熱鬧,把原來的分析發出來給大家看一下(這裡做個廣告,TSRC提交Discuz的漏洞,獎品棒棒噠~~)。這個漏洞原來我是作為前臺命令執行發個TSRC的,雖然有限制,但是個人感覺還是不錯的。只發一個怕各位不過癮,就再來一發這個點比較直觀的後臺命令執行和繞過前臺命令執行的修復。原TSRC上的漏洞標題是《Discuz! X系列遠端命令執行漏洞(二)》、《Discuz! X系列遠端命令執行漏洞(三)》和《Discuz! X系列遠端命令執行漏洞(四)》。

下面是原漏洞報告的概要部分:

“騰訊旗下Discuz! X系列cms存在遠端命令執行漏洞,經測試在其2013年6月20日釋出的最新版本的Discuz! X3中仍存在此問題。目前這個漏洞尚未在網路中流傳,屬於0day漏洞。 這個漏洞存在於圖片裁剪功能中,需要管理員啟用ImageMagick上傳圖片功能方可觸發。此漏洞只需一個可訪問論壇內容的賬號,即可利用。”

0x01 原理分析


0. 一定條件下前臺命令執行


這個漏洞出現在\source\class\class_image.php檔案中的Thumb_IM()函式,問題程式碼如下:

#!php
function Thumb_IM() {
        switch($this->param['thumbtype']) {
            case 'fixnone':
            case 1:
                if($this->imginfo['width'] > $this->param['thumbwidth'] || $this->imginfo['height'] > $this->param['thumbheight']) {
                    $exec_str = $this->param['imageimpath'].'/convert -quality '.intval($this->param['thumbquality']).' -geometry '.$this->param['thumbwidth'].'x'.$this->param['thumbheight'].' '.$this->source.' '.$this->target;
                    $return = exec($exec_str);
                    if(!file_exists($this->target)) {
                        return -3;
                    }
                }
                break;
//省略部分程式碼

從第一行紅色程式碼中可以看出,程式透過一些變數的拼接形成一條系統命令,在第二行使用exec方法進行執行。若使用者可以控制這些變數中的任何一個,那麼就可能導致任意命令的執行。

1. 同點後臺命令執行


這個漏洞出現在\source\class\class_image.php檔案中的Thumb_IM()函式,問題程式碼如下:

#!php
function Thumb_IM() {
        switch($this->param['thumbtype']) {
            case 'fixnone':
            case 1:
                if($this->imginfo['width'] > $this->param['thumbwidth'] || $this->imginfo['height'] > $this->param['thumbheight']) {
                    $exec_str = $this->param['imageimpath'].'/convert -quality '.intval($this->param['thumbquality']).' -geometry '.$this->param['thumbwidth'].'x'.$this->param['thumbheight'].' '.$this->source.' '.$this->target;
                    $return = exec($exec_str);
                    if(!file_exists($this->target)) {
                        return -3;
                    }
                }
                break;
//省略部分程式碼

從第一行紅色程式碼中可以看出,程式透過一些變數的拼接形成一條系統命令,在第二行使用exec方法進行執行。若使用者可以控制這些變數中的任何一個,那麼就可能導致任意命令的執行。

[email protected]! X系列遠端命令執行漏洞分析(二)》報告中提到過這個問題,也已經提交給騰訊修復了,使用的利用點是param['thumbwidth']和param[' thumbheight']。而這次我使用到param['imageimpath']這個引數,這個引數對應的是後臺配置中的“ImageMagick程式安裝路徑”。

這個利用點應該是最後一個可控點了,因為param['thumbwidth']和param[' thumbheight']在提交給騰訊後新增了整形校驗轉換,無法傳遞字串。而source和target需要在前面進行檔案和檔案是否存在的驗證,無法自由發揮☹。

下面來看一下傳遞param['imageimpath']這個引數的程式碼,它的位置在\source\admincp\admincp_checktools.php檔案中:

#!php
$settingnew = $_GET['settingnew'];
    if(!empty($_GET['previewthumb'])) {
        $_G['setting']['imagelib'] = $settingnew['imagelib'];
        $_G['setting']['imageimpath'] = $settingnew['imageimpath'];
        $_G['setting']['thumbwidth'] = $settingnew['thumbwidth'];
        $_G['setting']['thumbheight'] = $settingnew['thumbheight'];
        $_G['setting']['thumbquality'] = $settingnew['thumbquality'];

        require_once libfile('class/image');
        @unlink(DISCUZ_ROOT.$_G['setting']['attachdir'].'./temp/watermark_temp1.jpg');
        @unlink(DISCUZ_ROOT.$_G['setting']['attachdir'].'./temp/watermark_temp2.jpg');
        $image = new image;
//省略部分程式碼

可以從紅色程式碼出看到imageimpath引數沒有進行任何過濾,便傳入到全域性變數中了。在後面的image類中使用它也是直接從全域性變數中提取,沒有做任何的過濾和校驗,下面是image類的建構函式程式碼:

#!php
function image() {
        global $_G;
        $this->param = array(
            'imagelib'      => $_G['setting']['imagelib'],
            'imageimpath'       => $_G['setting']['imageimpath'],
            'thumbquality'      => $_G['setting']['thumbquality'],
            'watermarkstatus'   => dunserialize($_G['setting']['watermarkstatus']),
            'watermarkminwidth' => dunserialize($_G['setting']['watermarkminwidth']),
            'watermarkminheight'    => dunserialize($_G['setting']['watermarkminheight']),
            'watermarktype'     => $_G['setting']['watermarktype'],
            'watermarktext'     => $_G['setting']['watermarktext'],
            'watermarktrans'    => dunserialize($_G['setting']['watermarktrans']),
            'watermarkquality'  => dunserialize($_G['setting']['watermarkquality']),
        );
}

2. 前臺命令執行修復繞過


[email protected]! X系列遠端命令執行漏洞分析(二)[email protected]! X系列遠端命令執行漏洞分析(三)》兩篇報告中,將視角盯死在了Thumb_IM這個方法上。在修復後,這個方法的命令執行失敗,導致利用後續操作停止。

但是如果讓這個方法正常完成它的工作,那麼他後面的操作中還是有很多修復中沒有考慮到的利用點。下面我們來看下其中的一個利用點,source/class/class_image.php中的Cropper_IM方法:

#!php
function Cropper_IM() {
        $exec_str = $this->param['imageimpath'].'/convert -quality 100 '.
            '-crop '.$this->param['srcwidth'].'x'.$this->param['srcheight'].'+'.$this->param['srcx'].'+'.$this->param['srcy'].' '.
            '-geometry '.$this->param['dstwidth'].'x'.$this->param['dstheight'].' '.$this->source.' '.$this->target;
        exec($exec_str);
        if(!file_exists($this->target)) {
            return -3;
        }
}

從上面程式碼可以看出,這個方法先拼接命令,然後透過exec函式執行。在拼接的過程中很多變數的內容是可控的,而且在到達這個方法之前沒有做足夠的校驗和過濾。從而導致攻擊者可以透過傳遞一些帶有命令操作的內容,來達到命令執行的目的。

0x02 利用思路


0. 一定條件下前臺命令執行


看到這個漏洞點後,我就開始嘗試透過關鍵字從原始碼中尋找呼叫Thumb_IM函式的地方。搜尋到使用此函式的檔案很多,但是由於這個函式的前兩個引數都是和上傳檔案的檔名相關,而且discuz對於上傳檔名做了隨機化命名和字尾白名單處理,所以導致前三個引數為不可控點。

所以這之後我將目標點瞄準到圖片寬度和高度這幾個點,從中篩選引數未被寫死的可控呼叫。這樣我找到了\source\module\misc\misc_imgcropper.php檔案,之後大量的時間花費在對於這個檔案呼叫的業務邏輯的查詢上。

1. 一定條件下前臺命令執行


2. 前臺命令執行修復繞過


漏洞的觸發點在source/module/misc/misc_imgcropper.php中,部分程式碼如下:

#!php
$cropfile = md5($_GET['cutimg']).'.jpg';
$ictype = $_GET['ictype'];

if($ictype == 'block') {
        require_once libfile('function/block');
        $block = C::t('common_block')->fetch($_GET['bid']);
        $cropfile = block_thumbpath($block, array('picflag' => intval($_GET['picflag']), 'pic' => $_GET['cutimg']));
        $cutwidth = $block['picwidth'];
        $cutheight = $block['picheight'];
    } else {
        $cutwidth = $_GET['cutwidth'];
        $cutheight = $_GET['cutheight'];
    }
    $top = intval($_GET['cuttop'] < 0 ? 0 : $_GET['cuttop']);
    $left = intval($_GET['cutleft'] < 0 ? 0 : $_GET['cutleft']);
    $picwidth = $cutwidth > $_GET['picwidth'] ? $cutwidth : $_GET['picwidth'];
    $picheight = $cutheight > $_GET['picheight'] ? $cutheight : $_GET['picheight'];

    require_once libfile('class/image');
    $image = new image();
    $prefix = $_GET['picflag'] == 2 ? $_G['setting']['ftp']['attachurl'] : $_G['setting']['attachurl'];
    if(!$image->Thumb($prefix.$_GET['cutimg'], $cropfile, $picwidth, $picheight)) {
        showmessage('imagepreview_errorcode_'.$image->errorcode, null, null, array('showdialog' => true, 'closetime' => true));
    }
    $image->Cropper($image->target, $cropfile, $cutwidth, $cutheight, $left, $top);
    showmessage('do_success', dreferer(), array('icurl' => $cropfile), array('showdialog' => true, 'closetime' => true));
}

可以看到在最後呼叫了$image物件的Cropper方法,而這個過程中$cutwidth和$cutheight都是使用者可控的變數,並且在執行到Cropper方法前沒有進行過任何校驗和過濾。

0x03 技術驗證


0. 一定條件下前臺命令執行


在管理員開啟ImageMagick上傳圖片功能的前提下,攻擊者只需要一個普通使用者許可權即可,後臺設定方法如下圖:

enter image description here

由於這個功能是對圖片進行處理的,所以,要在訪問時提供一個本站有效的圖片地址。而且最好是存放在data/attachment目錄下的,因為預設就是這個目錄,否則就要用“../”來修改路徑。

所以我的訪問路徑為:

http://localhost/Discuz_X3.0/upload/misc.php?mod=imgcropper&img=group/19/group_36_banner.jpg

然後使用chrome審查元素功能,修改picwidth的value為“||whoami&”,如下圖所示:

enter image description here

然後點選網頁右下角的裁剪按鈕就觸發了。為了能直觀顯示,我新增了一行程式碼將接受執行結果的$return變數,echo出來並exit來結束掉後面的語句,效果如下圖所示:

enter image description here

1. 同點後臺命令執行


在後臺全域性->上傳設定->ImageMagick 程式安裝路徑

enter image description here

由於這個功能是對圖片進行處理的,所以,要在訪問時提供一個本站有效的圖片地址。而且最好是存放在data/attachment目錄下的,因為預設就是這個目錄,否則就要用“../”來修改路徑。

所以我的訪問路徑為

http://192.168.188.142/DiscuzX3.1_1122/upload/misc.php?mod=imgcropper&img=forum/201312/05/094746ub04zw03jr4wi44m.jpg

然後直接點選左下角的裁剪,雖然會返回圖片訪問錯誤,但是命令卻正常執行了,如下圖所示:

enter image description here

2. ImageMagick


這個漏洞需要在後臺開啟ImageMagick功能,並確保ImageMagick功能正常執行。下圖是我在後臺中開啟的這個功能,並填寫ImageMagick安裝目錄。

enter image description here

如果這個功能開啟,我們甚至可以在沒有賬號的情況下,前臺完成命令執行的觸發。

首先訪問裁切圖片的這個功能,因為這個漏洞的觸發必須要有一張有效圖片,所以我們可以在論壇帖子中隨便找到一張圖片來引用。例如:我的發帖圖片是:

http://192.168.188.143/discuz20140604/data/attachment/forum/201406/13/155944d557e0dtcdpouoad.jpg

那麼我要訪問的裁切功能的URL為:

http://192.168.188.143/discuz20140604/misc.php?mod=imgcropper&img=forum/201406/13/155944d557e0dtcdpouoad.jpg

然後修改POST資料包中cutheight或者cutwidth中的內容為“%26%26mkdir tsrc||”提交,就可以在discuz根目錄下建立一個tsrc的目錄。

修改輸入包如下圖所示:

enter image description here

提交後效果如下圖所示:

enter image description here

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章