作者:天融信阿爾法實驗室
公眾號: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文件導入產品

導入之后如下圖所示

WooCommerce中的每個產品都有一個產品說明,商店經理可以在其中插入有限的HTML,即非常基本的HTML標簽和屬性,例如<a>與href屬性結合的標簽。
導入過程分為四步:上傳、列映射、導入以及done!
每一步對應的request分別如下
上傳:


列映射



導入


值得一提的是,導入步驟以及后續Done步驟的請求,是第三步列映射(mapping)請求完成后,通過使用admin-ajax.php 實現wordpress的ajax請求來完成的。后續步驟并不需要用戶操作。在列映射步驟中,點擊運行導入器按鈕后,用戶只需等待導入完成即可,程序將通過ajax向后臺自動發送該導入等請求。
漏洞分析
WooCommerce導入功能代碼邏輯分析
我們先來看下,WooCommerce導入功能是怎么運作的
跟入后臺代碼,看看程序是如何處理導入的四個步驟的
當每個步驟請求發起后,后臺都會使用dispatch來處理

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

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

如上圖,當$_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

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/#)的值,看看此時要執行什么方法,如下圖

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

可見上圖288行存在check_admin_referer方法
跟入check_admin_referer方法,如下圖

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

這個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目錄

直接在媒體里上傳就行了
但是這個csv,是需要管理員權限,才能導入到woocommerce的產品中
漏洞利用思路
通過上文我們對導入功能代碼的分析可以發現,該插件對csv文件的上傳(upload)步驟,做了csrf防護,但是隨后三個步驟,并沒有進行csrf防護。雖然我們沒法對上傳步驟發起csrf攻擊,但是我們可以繞過上傳步驟,直接攻擊后續步驟
WordPress對作者權限的用戶,開放上傳媒體文件的權限,如下圖

我們可以利用這個功能,替換有csrf保護的upload步驟
此時的思路是:
1、 使用有作者權限的用戶在媒體庫上傳一個惡意的csv文件
2、 構造csrf,誘騙管理員執行發起導入產品請求,將我們上傳的csv導入woocommerce的產品中
3、導入成功,產品中被插入xss
4、管理員訪問產品頁面,xss執行
接下來驗證我們的思路
上傳一個惡意的CSV文件
首先,我們構造了一個csv

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

最后,記錄上傳好的地址
wp-content/uploads/2019/10/products-6.csv
上傳部分完成
構造CSRF誘使管理員導入
我們先來看下正常情況下,導入csv的過程的請求

Head

Body

可以發現,在body中存在一個security參數
在后臺程序校驗上傳請求是否合法時,會對post body中該參數進行校驗,如下圖

問題又來了,雖然導入請求沒有csrf token的保護,但是如果我們想直接構造一個上圖的導入表單,通過來誘騙管理員訪問并提交如上請求來導入惡意csv,就需要知道這個security參數值。
這個security參數是如何生成的?我們是否可以偽造這個參數?或者,既然這是一個ajax請求,我們能否繞開這個security?
security參數值分析
這個參數是由上一個step(mapping列映射)的請求生成的

Head

Body

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

注意看上圖紅框處的import_nonce值,與我們上文中的security參數值是一樣的
Security算法分析
跟蹤后臺代碼,分析下這個import_nonce/Security值是如何計算出來的

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

可見最終計算Import_nonce值,需要使用action,token四個變量
變量$i由wp_nonce_tick方法生成,跟入wp_nonce_tick方法看一下

可見這個是用來計算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列映射這一步的請求的后臺代碼,仍然分析下圖這塊代碼

上文我們分析了這塊代碼的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被會被導入,此時查看產品列表,如下圖

這條惡意的產品信息已經存在于產品列表中
當打開產品頁面時,其中的腳本就會被執行

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

這里的&file=../wp-content/uploads/2019/10/products-6.csv為之前步驟中,上傳的惡意csv的路徑,需要根據實際情況構造
Payload中form的兩個input,map_from與map_to,是mapping列映射步驟后臺必須存在的參數,參見下圖代碼

需要注意的是,我們構造的js語句插入在csv中哪個字段,這里的map_from map_to就要寫對應的字段名稱,否則導入時會出錯
管理員訪問該payload,csrf漏洞將會被觸發。表單被提交后,首先完成mapping步驟,接著,程序通過ajax自動發送import以及done步驟的請求,完成后續步驟。稍加等待,我們惡意的產品數據將會被導入,當管理員訪問產品頁面時,插入的js腳本將會被執行
XSS to RCE
WordPress中允許博客管理員編輯管理控制臺中的主題和插件文件。通過濫用XSS漏洞,攻擊者可以在遠程服務器上執行任意PHP代碼。
例如我們可以通過編輯插件功能,在后臺寫下payload

編輯插件頁面如上圖
我們構造惡意csv如下圖

構造csrf表單如下圖

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

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