作者:LoRexxar'@知道創宇404實驗室
時間:2019年2月22日

英文版本:http://www.bjnorthway.com/926/

2月20號,RIPS團隊在官網公開了一篇WordPress 5.0.0 Remote Code Execution,CVE編號CVE-2019-6977,文章中主要提到在author權限賬號下,可以通過修改Post Meta變量覆蓋、目錄穿越寫文件、模板包含3個漏洞構成一個RCE漏洞。

但在原文中,作者只大致描述了漏洞原理,其中大量的漏洞細節被省略,甚至部分的利用和后端服務器也有相對應的關系,所以在復現的過程中遇到了各種問題,我們花了大量的時間分析代碼,最終終于完全還原了該漏洞,其中部分關鍵利用點用了和原文有些許差異的利用方式(原文說的太含糊其辭,無法復現)。在下面的分析中,我會盡量按照復現過程中的思考方式及流程,以便讀者理解。

感謝在復現、分析過程中一起的小伙伴@Badcode,幫助我修改了很多錯誤的@Venenof7、@sysorem,給我提供了很多幫助:>

漏洞要求

在反復斟酌漏洞條件之后,我們最終把漏洞要求約束為

影響包括windows、linux、mac在內的服務端,后端圖片處理庫為gd/imagick都受到影響,只不過利用難度有所差異。

其中,原文提到只影響release 5.0.0版,但現在官網上可以下載的5.0.0已經修復該漏洞。實際在WordPress 5.1-alpha-44280更新后未更新的4.9.9~5.0.0的WordPress都受到該漏洞影響。

漏洞復現

下面的復現流程包含部分獨家利用以及部分與原文不符的利用方式,后面的詳情會解釋原因。

傳圖片

改信息

保留該數據包,并添加POST

&meta_input[_wp_attached_file]=2019/02/2-4.jpg#/../../../../themes/twentynineteen/32.jpg

裁剪

同理保留改數據包,并將POST改為下面的操作,其中nonce以及id不變

action=crop-image&_ajax_nonce=8c2f0c9e6b&id=74&cropDetails[x1]=10&cropDetails[y1]=10&cropDetails[width]=10&cropDetails[height]=10&cropDetails[dst_width]=100&cropDetails[dst_height]=100

觸發需要的裁剪

圖片已經過去了

包含,我們選擇上傳一個test.txt,然后再次修改信息,如前面

&meta_input[_wp_page_template]=cropped-32.jpg

點擊查看附件頁面,如果圖片被裁剪之后仍保留敏感代碼,則命令執行成功。

詳細分析

下面我們詳細分析一下整個利用過程,以及在各個部分踩的坑。我們可以簡單的把漏洞利用鏈分為4個大部分。

1、通過Post Meta變量覆蓋,修改媒體庫中圖片的_wp_attached_file變量。

這個漏洞是整個利用鏈的核心點,而WordPress的修復方式也主要是先修復了這個漏洞。WordPress很良心的在所有的release版本中都修復了這個問題(官網下載的5.0.0已經修復了),由于原文中曾提到整個利用鏈受到4.9.9和5.0.1的另一個安全補丁影響,所以只有5.0.0受影響。在分析還原WordPress的更新commit中,我們尋找到了這個漏洞的修復commit,并獲得了受該漏洞影響的最新版本為WordPress commit <= 43bdb0e193955145a5ab1137890bb798bce5f0d2 (WordPress 5.1-alpha-44280)

2、通過圖片的裁剪功能,將裁剪后的圖片寫到任意目錄下(目錄穿越漏洞)

在WordPress的設定中,圖片路徑可能會收到某個插件的影響而不存在,如果目標圖片不在想要的路徑下時,WordPress就會把文件路徑拼接為形似http://127.0.0.1/wp-content/uploads/2019/02/2.jpg 的url鏈接,然后從url訪問下載原圖

如果我們構造?或者#后面跟路徑,就能造成獲取圖片位置和寫入圖片位置的不一致。。

這部分最大問題在于,前端的裁剪功能并不是存在漏洞的函數,我們只能通過手動構造這個裁剪請求來完成。

action=crop-image&_ajax_nonce=8c2f0c9e6b&id=74&cropDetails[x1]=10&cropDetails[y1]=10&cropDetails[width]=10&cropDetails[height]=10&cropDetails[dst_width]=100&cropDetails[dst_height]=100

ps: 當后端圖片庫為Imagick時,Imagick的Readimage函數不能讀取遠程http協議的圖片,需要https.

3、通過Post Meta變量覆蓋,設置_wp_page_template變量。

這部分在原文中一筆帶過,也是整個分析復現過程中最大的問題,現在公開的所有所謂的WordPress RCE分析,都繞開了這部分。其中有兩個最重要的點:

  • 如何設置這個變量?
  • 如何觸發這個模板引用?

這個部分在下文中會詳細解釋。

4、如何讓圖片在被裁剪過之后,保留或者出現包含php敏感代碼。

這部分就涉及到了后端圖片庫的問題,WordPress用到的后端圖片處理庫有兩個,gd和imagick,其中默認優先使用imagick做處理。

  • imagick
    利用稍微比較簡單,imagick不會處理圖片中的exif部分。將敏感代碼加入到exif部分就可以不會改動。

  • gd
    gd的利用就比較麻煩了,gd不但會處理圖片的exif部分,還會刪除圖片中出現的php代碼。除非攻擊者通過fuzz獲得一張精心構造的圖片,可以在被裁剪處理之后剛好出現需要的php代碼(難度較高)。

最后通過鏈接上述4個流程,我們就可以完整的利用這個漏洞了,接下來我們詳細分析一下。

Post Meta變量覆蓋

當你對你上傳的圖片,編輯修改其信息時,你將會觸發action=edit_post

wp-admin/includes/post.php line 208

post data來自于POST

如果是修復過的,在line 275行有修復patch

$translated = _wp_get_allowed_postdata( $post_data );

https://github.com/WordPress/WordPress/commit/43bdb0e193955145a5ab1137890bb798bce5f0d2

這個patch直接禁止了傳入這個變量

function _wp_get_allowed_postdata( $post_data = null ) {
    if ( empty( $post_data ) ) {
        $post_data = $_POST;
    }
    // Pass through errors
    if ( is_wp_error( $post_data ) ) {
        return $post_data;
    }
    return array_diff_key( $post_data, array_flip( array( 'meta_input', 'file', 'guid' ) ) );
}

一路跟下去這個函數可以一直跟到wp-includes/post.php line 3770

update_post_meta會把所有字段遍歷更新

就會更新數據庫中的相應字段

配合變量覆蓋來目錄穿越寫文件

根據原文的描述,我們首先需要找到相應的裁剪函數

/wp-admin/includes/image.php line 25 

這里傳入的變量src就是從修改過的_wp_attached_file而來。

在代碼中,我們可以很輕易的驗證一個問題。在WordPress的設定中,圖片路徑可能會受到某個插件的影響而不存在,如果目標圖片不在想要的路徑下時,WordPress就會把文件路徑拼接為形似 http://127.0.0.1/wp-content/uploads/2019/02/2.jpg 的url鏈接,然后從url訪問下載原圖

這里的_load_image_to_edit_path就是用來完成這個操作的。

也正是因為這個原因,假設我們上傳的圖片名為2.jpg,則原本的_wp_attached_file2019/02/2.jpg

然后我們通過Post Meta變量覆蓋來修改_wp_attached_file2019/02/1.jpg?/../../../evil.jpg

這里的原圖片路徑就會拼接為{wordpress_path}/wp-content/uploads/2019/02/1.jpg?/../../../evil.jpg,很顯然這個文件并不存在,所以就會拼接鏈接為http://127.0.0.1/wp-content/uploads/2019/02/2.jpg?/../../../evil.jpg,后面的部分被當作GET請求,原圖片就會成功的獲取到。

緊接著進入save函數的新圖片路徑會拼接為{wordpress_path}/wp-content/uploads/2019/02/1.jpg?/../../../cropped-evil.jpg,我們就能成功寫入新文件了。

后面的save函數會調用你當前圖片庫的裁剪功能,生成圖片結果。(默認為imagick)

/wp-includes/class-wp-image-editor.php line 394

但這里看上去沒有任何限制,實際上不是的。在寫入的目標目錄下,存在一個假目錄,為1.jpg?

  • 而linux、mac支持這種假目錄,可以使用?號
  • 但windows在路徑中不能有?號,所以這里改用了#號
&meta_input[_wp_attached_file]=2019/02/2-1.jpg#/../../../evil.jpg

成功寫入文件

cropped-evil.jpg

控制模板參數來導致任意文件包含

進度進展到這就有點兒陷入僵局,因為原文中關于這部分只用了一句話帶過,在實際利用的過程中遇到了很多問題,甚至不同版本的WordPress會有不同的表現,其中誕生了多種利用方式,這里我主要講1種穩定利用的方式。

設置_wp_page_template

首先我們先正向分析,看看在什么情況下我們可以設置_wp_page_template

首先可以肯定的是,這個變量和_wp_attached_file一樣都屬于Post Meta的一部分,可以通過前面的操作來對這個變量賦值

但實際測試過程中,我們發現,我們并不能在任何方式下修改并設置這個值。

/wp-includes/post.php line 3828

  • 如果你設置了這個值,但這個文件不存在,則會被定義為default
  • 如果該值被設置,則沒辦法通過這種方式修改。

所以這里我們可能需要新傳一個媒體文件,然后通過變量覆蓋來設置這個值。

加載模板

當我們成功設置了該變量之后,我們發現,并不是所有的頁面都會加載模板,我們重新回到代碼中。

最終加載模板的地方在

wp-includes/template.php line 634

只要是在$template_names中需要被加載的文件名,會在當前主題的目錄下遍歷加載。

回溯跟入

wp-includes/template.php line 23

繼續回溯我們就能發現一些端倪,當你訪問頁面的時候,頁面會通過你訪問的頁面屬性,調用不同的模板加載函數。

wp-includes/template-loader.php line 48

在這么多的模板調用函數中只有兩個函數get_page_templateget_single_template這兩個在函數中調用了get_page_template_slug函數。

wp-includes/template.php line 486

get_page_template_slug函數從數據庫中獲取了_wp_page_template

/wp-includes/post-template.php line 1755

只要我們能讓模板加載時進入get_page_templateget_single_template,我們的模板就可以成功被包含。

由于代碼和前端的差異,我們也沒有完全找到觸發的條件是什么,這里選了一個最簡單的,即上傳一個txt文件在資源庫,然后編輯信息并預覽。

生成圖片馬

這部分就涉及到了后端圖片庫的問題,WordPress用到的后端圖片處理庫有兩個,gd和imagick,其中默認優先使用imagick做處理。

  • imagick

利用稍微比較簡單,imagick不會處理圖片中的exif部分。將敏感代碼加入到exif部分就可以不會改動。

  • gd

gd的利用就比較麻煩了,gd不但會處理圖片的exif部分,還會刪除圖片中出現的php代碼。除非攻擊者通過fuzz獲得一張精心構造的圖片,可以在被裁剪處理之后剛好出現需要的php代碼(難度較高)。

由于這不是漏洞最核心的部分,這里就不贅述了。

修復

1、由于該漏洞主要通過圖片馬來完成RCE,而后端圖片庫為gd時,gd會去除圖片信息中exif部分,并去除敏感的php代碼。但如果攻擊者精心設計一張被裁剪后剛好生成含有敏感代碼的圖片時,就可以造成RCE漏洞。如果后端圖片庫為imagick時,則將敏感代碼加入到圖片信息的exif部分,就可以造成RCE漏洞。

官網上可供下載的所有release版本中都修復了這個漏洞,更新至最新版或者手動將當前版本覆蓋安裝即可。

2、 通用防御方案
使用第三方防火墻進行防護(如創宇盾[https://www.yunaq.com/cyd/])。

3、技術業務咨詢
知道創宇技術業務咨詢熱線 :
400-060-9587(政府,國有企業)、028-68360638(互聯網企業)

總結

整個RCE的利用鏈由4部分組成,深入WordPress的底層Core邏輯,原本來說這4個部分無論哪個都很難造成什么危害,但卻巧妙地連接在一起,并且整個部分意外的都是默認配置,大大增加了影響面。在安全程度極高的WordPress中能完成這種的攻擊利用鏈相當難得,從任何角度都是一個非常nice的漏洞:>

最后再次感謝我的小伙伴們以及整個過程中給我提供了很大幫助的朋友們:>


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/822/