一、前言
注:此漏洞利用和環境較為復雜,實際價值可能并不是很高,但對于XSS與權限管理也有一定參考價值。
上個月我們公布了WordPress 5.0中一個遠程代碼執行(RCE)漏洞(需通過身份認證)。本文公布了WordPress 5.1中存在的另一個嚴重的漏洞利用鏈,使未經身份認證的攻擊者能夠在5.1.1版之前的WordPress中獲得遠程代碼執行權限。
二、漏洞影響
如果WordPress站點啟用了評論(comment)功能,那么攻擊者可以誘騙目標網站管理員訪問攻擊者設置的一個站點,最終接管目標站點。一旦受害管理員訪問惡意網站,攻擊者就會在后臺通過跨站請求偽造(CSRF)攻擊目標WordPress站點,不會因此目標受害者警覺。CSRF攻擊中濫用了WordPress中的多個邏輯缺陷及數據過濾錯誤,并且結合這些缺陷實現RCE,最終完全接管目標站點。
5.1.1版之前默認配置的WordPress受這些漏洞影響。
根據WordPress下載頁面的統計數據,互聯網上超過33%的站點正在使用WordPress。考慮到博客評論是博客網站的核心功能,默認情況下處于啟用狀態,因此該漏洞會影響數百萬站點。
三、技術分析
攻擊過程參考此處視頻。
當用戶發表新評論時,WordPress并沒有檢查是否存在CSRF。如果執行檢查操作,那某些WordPress功能(如trackbacks
以及pingbacks
)將無法正常工作。這意味著攻擊者可以通過CSRF攻擊,以WordPress博客管理員用戶的身份創建評論。
這可能成為一個安全問題,因為WordPress網站管理員可以在評論中使用任意HTML標簽,甚至還可以使用<script>
標簽。理論上攻擊者可以簡單地濫用CSRF漏洞來創建包含惡意JavaScript代碼的評論。
WordPress會在評論表單中為管理員生成一個額外的nonce值,通過這種方法嘗試解決這個問題。當管理員提交評論并提供有效的nonce值時,WordPress將直接創建評論,沒有執行任何過濾此操作。如果nonce值無效,那么評論仍可以創建,但會被過濾處理。
我們可以通過如下代碼片段了解WordPress的處理過程。
源文件:/wp-includes/comment.php
(簡化版):
?
if ( current_user_can( 'unfiltered_html' ) ) {
if (! wp_verify_nonce( $_POST['_wp_unfiltered_html_comment'], 'unfiltered-html-comment' )) {
$_POST['comment'] = wp_filter_post_kses($_POST['comment']); // line 3242
}
} else {
$_POST['comment'] = wp_filter_kses($_POST['comment']);
}
?
事實上,從2009年起,WordPress就沒有在評論表單中部署CSRF防護機制。
然而,我們發現針對管理員的過濾過程中存在一處邏輯缺陷。如上代碼片段中,WordPress始終使用wp_filter_kses()
來過濾評論,除非創建該評論的是具備unfiltered_html
功能的管理員。如果滿足該條件,并且沒有提供有效的nonce值,那么WordPress就會使用wp_filter_post_kses()
來過濾評論(上述代碼第3242行)。
wp_filter_post_kses()
與wp_filter_kses()
在嚴格程度上有所區別。這兩個函數都會處理未經過濾的評論,只在字符串中保留特定的HTML標簽及屬性。通常情況下,使用wp_filter_kses()
過濾的評論只會留下非常基本的HTML標簽及屬性,比如<a>
標簽以及href
屬性。
這樣攻擊者就可以創建一些評論,其中包含比正常評論更多的HTML標簽及屬性。然而,雖然wp_filter_post_kses()
更為寬松,但仍會刪除可能導致跨站腳本漏洞的HTML標簽及屬性。
由于我們能注入其他HTML標簽及屬性,最終還是可以在WordPress中實現存儲型XSS。這是因為WordPress會以某種錯誤的方式解析并處理正常評論中通常不會設置的某些屬性,導致出現任意屬性注入問題。
當WordPress執行完評論的過濾過程后,就會修改評論字符串中的<a>
標簽,以適配SEO(搜索引擎優化)應用場景。
WordPress會將<a>
標志的屬性字符串(如href="#" title="some link" rel="nofollow"
)解析成一個關聯數組(如下代碼片段),其中key為屬性名,而value為屬性值。
源文件:wp-includes/formatting.php
function wp_rel_nofollow_callback( $matches ) {
$text = $matches[1];
$atts = shortcode_parse_atts($matches[1]);
?
隨后WordPress會檢查其中是否設置了rel
屬性。只有通過wp_filter_post_kses()
過濾評論時才會設置該屬性。如果設置了該屬性,則WordPress會處理rel
屬性,然后再次與<a>
標簽拼接起來。
源文件:wp-includes/formatting.php
if (!empty($atts['rel'])) {
// the processing of the 'rel' attribute happens here
?
$text = '';
foreach ($atts as $name => $value) { // line 3017
$text .= $name . '="' . $value . '" '; // line 3018
}
}
return '<a ' . $text . ' rel="' . $rel . '">'; // line 3021
}
上述代碼第3017及3018行處存在缺陷,其中屬性值在沒有被轉義處理的情況下就再次拼接在一起。
攻擊者可以創建包含精心構造的<a>
標簽的評論,并將title
屬性設置為title='XSS " onmouseover=alert(1) id="'
。這個屬性是合法的HTML數據,因此可以通過數據過濾檢查。然而,只有當title
標簽使用單引號時這種方法才有效。
當屬性再次拼接時,title
屬性會被封裝到雙引號中(第3018行)。這意味著攻擊者可以注入雙引號,閉合title
屬性,因此可以注入其他HTML屬性。
比如:<a title='XSS " onmouseover=evilCode() id=" '>
在處理之后會變成<a title="XSS " onmouseover=evilCode() id=" ">
。
由于此時評論已經被過濾處理過,因此攻擊者注入的onmouseover
事件處理函數會存儲在數據庫中,不會被刪除。將這種過濾缺陷與CSRF漏洞結合起來,攻擊者就可以將存儲型XSS payload注入目標網站中。
創建惡意評論后,為了實現遠程代碼執行(RCE),下一步攻擊者需要讓管理員執行已注入的JavaScript。WordPress評論會在目標博客的前端顯示,而WordPress本身并沒有使用X-Frame-Options
來保護前端頁面。這意味著攻擊者可以以隱藏iframe
的方式在網站上顯示評論。由于注入的屬性是一個onmouseover
事件處理函數,因此攻擊者可以讓iframe
跟隨受害者鼠標,立刻觸發XSS payload。
這樣一來,攻擊者就可以在目標網站上使用觸發CSRF漏洞的管理員會話來執行任意JavaScript代碼。有所的JavaScript都在后臺執行,不會引起管理員的注意。
現在攻擊者已經可能使用管理員會話來執行任意JavaScript代碼,那么也很容易就能實現RCE。默認情況下,WordPress允許博客管理員在管理面板中直接編輯站點主題和插件的.php
文件。攻擊者只需要簡單插入一個PHP后門,就可以在遠程服務器上獲得任意PHP代碼執行權限。
四、補丁情況
默認情況下,WordPress會自動安裝安全更新,因此我們應該已經更新至最新的5.1.1版。如果用戶或所屬托管商由于某些原因禁用了自動更新功能,那么在安裝補丁前,可以考慮禁用評論功能。更為重要的一點是,請管理員確保訪問其他網站之前,已經注銷當前的管理員會話。
五、時間線
六、總結
本文從CSRF漏洞開始介紹了一個完整的漏洞利用鏈。攻擊者只需要誘導目標網站管理員訪問某個惡意網站,然后就可以通過這條利用鏈來接管使用默認配置的WordPress站點。目標管理員并不會發現攻擊者的網站有任何異常,除了訪問攻擊者設置的網站之外,整條攻擊鏈中沒有其他交互過程。
感謝WordPress安全團隊,這些小伙伴們非常友善,并且合作解決問題時也非常專業。