作者:天融信阿爾法實驗室
公眾號:https://mp.weixin.qq.com/s/j79MNsy-tnJQGfFg7ROxTw

漏洞簡介

WooCommerce是WordPress最受歡迎的電子商務插件,安裝量超過500萬。

WooCommerce處理產品導入方式的缺陷導致存儲型XSS漏洞的產生,可以通過跨站點請求偽造(CSRF)來利用該漏洞。由于wordpress后臺存在插件編輯等功能,通過xss漏洞,可以寫入php代碼

漏洞成因簡單來說,是因為WooCommerce存在csv文件導入功能,該功能可以將csv中內容導入到產品列表中

導入時共分四步(上傳、列映射、導入以及done),這四個步驟的請求是獨立的,可以單獨發送對應的請求,在后臺完成相應的功能。

WooCommerce只在第一步(上傳csv文件)的時候驗證了csrf token,而后續步驟并沒有進行csrf防護。由于一定權限的wordpress用戶可以直接在wordpress媒體庫中上傳csv文件,這將替代了有csrf防護的第一步,進而通過CSRF漏洞銜接后三步,導致了本次漏洞的產生。

在這篇文章中,我將會為大家分析WooCommerce插件后臺代碼,分析本次漏洞成因,并還原本次漏洞利用,介紹POC的構造以及一些wordpress機制。

WooCommerce導入功能介紹

WooCommerce可以通過csv文件導入產品

img

導入之后如下圖所示

img

WooCommerce中的每個產品都有一個產品說明,商店經理可以在其中插入有限的HTML,即非常基本的HTML標簽和屬性,例如<a>href屬性結合的標簽。

導入過程分為四步:上傳、列映射、導入以及done!

每一步對應的request分別如下

上傳:

img

img

列映射

imgimg

img

導入

img

img

值得一提的是,導入步驟以及后續Done步驟的請求,是第三步列映射(mapping)請求完成后,通過使用admin-ajax.php 實現wordpress的ajax請求來完成的。后續步驟并不需要用戶操作。在列映射步驟中,點擊運行導入器按鈕后,用戶只需等待導入完成即可,程序將通過ajax向后臺自動發送該導入等請求。

漏洞分析

WooCommerce導入功能代碼邏輯分析

我們先來看下,WooCommerce導入功能是怎么運作的

跟入后臺代碼,看看程序是如何處理導入的四個步驟的

當每個步驟請求發起后,后臺都會使用dispatch來處理

img

這里簡單解釋下,首先可見上圖中call_user_func執行$this->steps中的值,$this->steps值如下圖,是固定的

img

$this->steps對應了四步操作。

當每一步操作請求發送到后臺時,都會調用dispatch方法,從$this->step對應的‘upload’/’mapping’/’import’/’done’這些數組中尋找對應的方法執行,

img

如上圖,當$_POST['save_step']以及$this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#)非空的情況下,執行

1 call_user_func( this->step ]['handler'], $this );

否則,執行

1 call_user_func( this->step ]['view'], $this );

反觀四個上文四個步驟的請求,滿足$_POST['save_step']存在的,只有第一步upload

img

Upload請求發起時,執行

call_user_func( $this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#), $this );

我們在數組中查找$this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#)的值,看看此時要執行什么方法,如下圖

img

從上圖可見,此時的$this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#)的值是upload_form_handlerupload_form_handler方法將被執行

跟入upload_form_handler方法,如下圖

img

可見上圖288行存在check_admin_referer方法

跟入check_admin_referer方法,如下圖

img

如上圖,此時1101行需要檢驗$REQUEST[$query_arg]的值,該值即為請求中的_wpnonce

img

這個nonce值是生成在頁面中的,我們沒法獲取。可見,有了這個nonce的限制,在upload即上傳文件的這一步,我們沒法采用csrf攻擊

但是除此之外的其他步驟,并不會觸發這個方法,其他步驟執行的都是

call_user_func( $this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#), $this );

$this->steps[ $this->step ](http://blog.topsec.com.cn/wordpress-woocommerce-3-6-4-從csrf-到-rce/#)中的方法,并沒有檢查nonce

在WooCommerce插件的導入模塊中,只在upload這一步,加入了nonce,進行了csrf防御。也就是說,其他步驟并沒有對csrf進行防御

既然我們沒有辦法進行csrf攻擊,來上傳惡意csv,那是否還有其他辦法上傳呢?

其實,這個惡意的csv并不需要管理員來上傳,擁有作者權限的用戶,可以自行上傳csv文件到wordpress目錄

img

直接在媒體里上傳就行了

但是這個csv,是需要管理員權限,才能導入到woocommerce的產品中

漏洞利用思路

通過上文我們對導入功能代碼的分析可以發現,該插件對csv文件的上傳(upload)步驟,做了csrf防護,但是隨后三個步驟,并沒有進行csrf防護。雖然我們沒法對上傳步驟發起csrf攻擊,但是我們可以繞過上傳步驟,直接攻擊后續步驟

WordPress對作者權限的用戶,開放上傳媒體文件的權限,如下圖

img

我們可以利用這個功能,替換有csrf保護的upload步驟

此時的思路是:

1、 使用有作者權限的用戶在媒體庫上傳一個惡意的csv文件

2、 構造csrf,誘騙管理員執行發起導入產品請求,將我們上傳的csv導入woocommerce的產品中

3、導入成功,產品中被插入xss

4、管理員訪問產品頁面,xss執行

接下來驗證我們的思路

上傳一個惡意的CSV文件

首先,我們構造了一個csv

img

接著,我們用作者權限的用戶上傳媒體庫

img

最后,記錄上傳好的地址

wp-content/uploads/2019/10/products-6.csv

上傳部分完成

構造CSRF誘使管理員導入

我們先來看下正常情況下,導入csv的過程的請求

img

Head

img

Body

img

可以發現,在body中存在一個security參數

在后臺程序校驗上傳請求是否合法時,會對post body中該參數進行校驗,如下圖

img

問題又來了,雖然導入請求沒有csrf token的保護,但是如果我們想直接構造一個上圖的導入表單,通過來誘騙管理員訪問并提交如上請求來導入惡意csv,就需要知道這個security參數值。

這個security參數是如何生成的?我們是否可以偽造這個參數?或者,既然這是一個ajax請求,我們能否繞開這個security?

security參數值分析

這個參數是由上一個step(mapping列映射)的請求生成的

img

Head

img

Body

img

當這個請求執行后,在相應的body中,會包含我們所需要的security參數值

img

注意看上圖紅框處的import_nonce值,與我們上文中的security參數值是一樣的

Security算法分析

跟蹤后臺代碼,分析下這個import_nonce/Security值是如何計算出來的

img

Import_nonce的產生如上圖所示,是通過wp_create_nonce方法計算而來

跟入wp_create_nonce方法

img

可見最終計算Import_nonce值,需要使用action,token四個變量

變量$iwp_nonce_tick方法生成,跟入wp_nonce_tick方法看一下

img

可見這個是用來計算nonce失效時間的,上圖中的$nonce_life默認都是86400,也就是一天的總秒數,而上圖2053行最終計算表達式不難看出,只要是半天內($nonce_life/2)生成的, wp_nonce_tick方法返回的這個值都應該是一樣的。也就是說,Import_nonce值的生存期是半天(43200s)

接下來幾個參數就很簡單了,$action是固定的’wc-product-import’,uid,token這些都是管理員的值

我們是否需要關心security參數值?

但事實上,我們并不需要關心這個security參數值,甚至根本不用去構造import這一步的請求。

在Import這個步驟中,向后臺發送的是ajax請求,這個請求并不是用戶點擊發送表單完成的,而是mapping步驟完成后,連帶一同發起的。我們只需構造與發送mapping步驟的請求,程序將通過ajax自動完成后續import 以及Done步驟,因此,我們根本不需要關心Import步驟中的security值。

詳細分析如下:

仍然看mapping列映射這一步的請求的后臺代碼,仍然分析下圖這塊代碼

img

上文我們分析了這塊代碼的432行,也就是security值是如何計算出來的,但卻沒有介紹這塊代碼的實際作用

這里wp_localize_script()使用JavaScript變量的數據對注冊的腳本進行本地化操作,接著在442行處使用wp_enqueue_script將JS腳本添加到WordPress程序生成的頁面當中。如上圖,wc_product_import_params變量中的所有數據都由攻擊者控制,例如其中重要的file路徑。

mapping列映射這個請求完成后的生成頁面,將使用AJAX請求將攻擊者控制的$_POST變量和有效的隨機數一起發送到WordPress后端,完成導入步驟。

也就是說,我們只需構造mapping列映射這一步驟的表單,誘使管理員訪問,在mapping列映射完成后的返回頁面中,存在發起import步驟的js代碼,當頁面被瀏覽器加載時,使用AJAX請求將攻擊者控制的$_POST變量和有效的隨機數一起發送到WordPress后端,完成后續的導入步驟。

導入成功以及XSS觸發

將構造好的mapping步驟表單鏈接誘使管理員點擊,惡意csv被會被導入,此時查看產品列表,如下圖

img

這條惡意的產品信息已經存在于產品列表中

當打開產品頁面時,其中的腳本就會被執行

img

漏洞利用

根據上文我們分析,我們只需構造mapping列映射這一步驟的表單,誘使管理員訪問,即可完成mapping列映射以及導入步驟。

最終payload如下

img

這里的&file=../wp-content/uploads/2019/10/products-6.csv為之前步驟中,上傳的惡意csv的路徑,需要根據實際情況構造

Payload中form的兩個input,map_from與map_to,是mapping列映射步驟后臺必須存在的參數,參見下圖代碼

img

需要注意的是,我們構造的js語句插入在csv中哪個字段,這里的map_from map_to就要寫對應的字段名稱,否則導入時會出錯

管理員訪問該payload,csrf漏洞將會被觸發。表單被提交后,首先完成mapping步驟,接著,程序通過ajax自動發送import以及done步驟的請求,完成后續步驟。稍加等待,我們惡意的產品數據將會被導入,當管理員訪問產品頁面時,插入的js腳本將會被執行

XSS to RCE

WordPress中允許博客管理員編輯管理控制臺中的主題和插件文件。通過濫用XSS漏洞,攻擊者可以在遠程服務器上執行任意PHP代碼。

例如我們可以通過編輯插件功能,在后臺寫下payload

img

編輯插件頁面如上圖

我們構造惡意csv如下圖

img

構造csrf表單如下圖

img

當管路員訪問我們的csrf表單,惡意的csv將會被導入

當管理員訪問該產品頁面時,插入產品描述內容中的js腳本將會被執行,akismet.php中的內容將會被修改,從而達到的插入后門的作用,如下圖

img


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