作者:天融信阿爾法實驗室
公眾號:https://mp.weixin.qq.com/s/jvVZlqdxNLhIB3N6IP4btw
概述
1.1 前言
2019年3月13號,RIPS又放了一個WordPress的CSRF,與此同時WordPress官方也提交相應的Commit,算是一個比較新的洞。問題出在文章的評論上,其實是有防CSRF相應的wpnonce,熟悉wp的人肯定不會陌生wpnonce,這是wp的防御機制,動作和postid構成的token,用來驗證reference,而且wordpress對標簽的過濾機制比較嚴格的。白名單機制,列如a標簽的名單為

看起來是比較嚴格的,基本帶動作的標簽不可能出現,插不進js。比較有趣是兩個對評論的filter組合起來造成了,a標簽中的屬性逃逸。RIPS文章也說的比較簡單,接下來看看具體的實現過程,其實存在利用條件的,RIPS也沒有指出來,總結時詳細說明。
1.2 背景介紹
1.2.1 漏洞描述
漏洞存在于5.1.1之前的WordPress版本中,可以使用默認設置進行利用。
根據其WordPress官方下載頁面,超過33%的互聯網網站正在使用WordPress。 文章評論是博客的核心功能并且默認情況下已啟用,該漏洞會影響數百萬個網站。
1.2.2 受影響版本
WordPress <= 5.1.1
1.3 測試環境
Kali 4.19.0 WordPress 5.1.1
0×02 漏洞實現過程
環境最新是5.1.1 昨天才官方剛commit的修復過程,算是比較新。既然是是CSRF,表單提交點在于每篇文章的評論處。wp-comments-post.php:25, wp_handle_comment_submission(wp_unslash( $_POST )),進入comment_handler 函數 做了一些簡單的賦值過程:

來看看上面對于用戶身份判斷的過程。評論需要用戶為登錄態。關鍵處:

其中判斷用戶能否不需要過濾html,到下面的判斷提交comment過程中的wpnonce驗證,若是沒有通過身份驗證會重新定義kses 處理過程的中的filter,具體看一下kses_init_filters

這里為什么會重新刪減filter,在前面初始化的過程中在init標簽的注冊了一個kses_init()

僅僅判斷通過用戶身份Session身份判斷了,需不要添加過濾html的filter。管理員用戶在操作的時候,即默認是沒有插入對pre_comment_content的過濾html的鉤子,但是在判斷添加評論的時候又因為在想要的wpnonce驗證不通過的時候,又添加上了相應的filter,官方還是考慮到了相應的安全問題,但是為什么又要加一層身份判斷,添加不同的處理函數呢,直接插入wp_filter_kses不好嗎?
正是因為wp_filter_kses 和wp_filter_post_kses 不同上造成了后面的js執行 他們的不同在于過濾的嚴格度上,其實都一樣是白名單過濾。 但是跟pre_comment_content的鉤子函數組合起來,就發送了屬性逃逸。
看一下這個兩個函數的定義。

傳入的第二參數不同,決定了后面允許使用的標簽和屬性的白名單不同。影響第二個鉤子函數。即使這里addslashes轉義了字符內容,緊接著下一個鉤子涉及到對屬性的處理,會恢復被轉義字符內容。

pre_comment_content 標簽的鉤子有默認的4個鉤子(我習慣叫鉤子函數),分別是 convert_invalid_entities ,wp_targeted_link_rel,wp_rel_nofollow,balance 根據優先級排序。第一個把€及以后的實體轉成相應的合法的unicode實體,第二個處理a標簽 中target屬性的,第三個是重點了兩個重要鉤子中的第二個,給a標簽添加rel屬性為nofollow,如果存在rel屬性則在其屬性值中添加nofollow,并去掉原來的rel屬性值,其過程會重新拼接a標簽。

wp_rel_nofollow 鉤子在pre_comment_content中優先級為15,當插入 wp_filter_post_kses 鉤子時使用的默認值是10,在wp中執行鉤子時會有優先級判斷,剛好wp_filter_post_kses也在前,所以也不涉及到對后面溢出的屬性重新處理。
前面說了wp_filter_post_kses 和 wp_filter_kses的不同在于使用的白名單不同。前者傳入的是post,后者傳入是current_filter(),這個值很好理解,這一系列鉤子都在pre_comment_content 標簽下。所以理所當然是pre_comment_content,選擇過程如下:

看當 post的情況下,默認是沒有注冊wp_kses_allowed_html標簽的,即每一步的apply_filters() 返回輸入的第一個值,post 的$allowedpostags包含的標簽及其屬性是比較多的,pre_comment_content 只能走到默認 $allowedtags.其中\$allowedtags 包含情況如下:

可以看到a標簽中的只允許 href 和title,而post 的$allowedpostags是允許包含rel屬性的

在第二部重要的鉤子 wp_rel_nofollow 中,其中存在rel屬性時才會去重新拼接,造成額外的屬性溢出。所以這就是差異之處,確實考慮到了XSS的執行,都是用的白名單,但經過重新拼接會出現額外的屬性。列如
<a title= ‘ maple? ” onmouseover=alert(1) id=” ‘ rel=”anything”>
通過拼接變成
<a title = ” maple”? onmouseover=alert(1) id=”" rel =”anything nofollow”>
在后面的過程中屬性里面的特殊字符會被轉義成實體。涉及到寫js的可能需要繞一下不能用引號和雙引號,可以這樣繞一下

playload如下:

0×03 總結
3.1 利用條件
其實這個洞再利用條件的有一定限定RIPS也沒有指出來,我在剛做時候,我添加了一個評論,我沒有去文章頁面看,我去的后臺管理界面評論管理處看,發現并沒有出現xss的情況,我很詫異不應該是一樣嗎?而后發現在輸出評論前

進行了標簽為comment_text的過濾器,其中包含了wp_kses_post 鉤子 這也是為什么后臺不行。但是應該這個思路,文章顯示處也肯定用了這個標簽的過濾器,但是理論上是沒有使用的,因為使用以后溢出的屬性會被過濾掉。
在仔細跟一下,發現確實有存在使用這個標簽的情況,對comment_text過濾器的使用在check_comment()中

是個判斷,看到這里你是否明白了這個使用的限定的條件?也就是說用戶評論自己的文章時是不需要check的,所以這里存在一定使用條件,在進行添加評論的時候必須是管理員發布的文章才行。
這個洞其實一眼真的很難看出來。白名單驗證,直接就放棄了。可不曾想存在一個弄巧的鉤子。官方修復在驗證wpnonce 不成立時給強制加了wp_filter_kses完全限定死了。當然了這個csrf依然存在。因為涉及到wp的特性pingback/trackback。總的來說還是非常細節的,在挖洞只能拼細節在這種流行的框架下。
0X04 修復建議
wp默認是開啟自動更新的,最新版本中已經得到修復,若關閉自動更新的環境,請及時檢查更新。 https://wordpress.org/news/2019/03/wordpress-5-1-1-security-and-maintenance-release/
可手動修復:

0×05 參考連接
https://blog.ripstech.com/2019/wordpress-csrf-to-rce/
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/858/
暫無評論