作者:天融信阿爾法實驗室
公眾號: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標簽的名單為

1

看起來是比較嚴格的,基本帶動作的標簽不可能出現,插不進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 函數 做了一些簡單的賦值過程:

2

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

3

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

4

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

5

僅僅判斷通過用戶身份Session身份判斷了,需不要添加過濾html的filter。管理員用戶在操作的時候,即默認是沒有插入對pre_comment_content的過濾html的鉤子,但是在判斷添加評論的時候又因為在想要的wpnonce驗證不通過的時候,又添加上了相應的filter,官方還是考慮到了相應的安全問題,但是為什么又要加一層身份判斷,添加不同的處理函數呢,直接插入wp_filter_kses不好嗎?

正是因為wp_filter_kseswp_filter_post_kses 不同上造成了后面的js執行 他們的不同在于過濾的嚴格度上,其實都一樣是白名單過濾。 但是跟pre_comment_content的鉤子函數組合起來,就發送了屬性逃逸。

看一下這個兩個函數的定義。

6

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

8

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

9

wp_rel_nofollow 鉤子在pre_comment_content中優先級為15,當插入 wp_filter_post_kses 鉤子時使用的默認值是10,在wp中執行鉤子時會有優先級判斷,剛好wp_filter_post_kses也在前,所以也不涉及到對后面溢出的屬性重新處理。

前面說了wp_filter_post_kseswp_filter_kses的不同在于使用的白名單不同。前者傳入的是post,后者傳入是current_filter(),這個值很好理解,這一系列鉤子都在pre_comment_content 標簽下。所以理所當然是pre_comment_content,選擇過程如下:

10

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

11

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

12

在第二部重要的鉤子 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的可能需要繞一下不能用引號和雙引號,可以這樣繞一下

13

playload如下:

14

0×03 總結

3.1 利用條件

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

15

進行了標簽為comment_text的過濾器,其中包含了wp_kses_post 鉤子 這也是為什么后臺不行。但是應該這個思路,文章顯示處也肯定用了這個標簽的過濾器,但是理論上是沒有使用的,因為使用以后溢出的屬性會被過濾掉。

在仔細跟一下,發現確實有存在使用這個標簽的情況,對comment_text過濾器的使用在check_comment()

16

是個判斷,看到這里你是否明白了這個使用的限定的條件?也就是說用戶評論自己的文章時是不需要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/

可手動修復:

17

0×05 參考連接

https://blog.ripstech.com/2019/wordpress-csrf-to-rce/


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