Joomla3.4.6 RCE漏洞深度分析

  • 2019 年 10 月 26 日
  • 筆記

筆者《Qftm》原文發佈:https://www.freebuf.com/vuls/216512.html

*嚴正聲明:本文僅限於技術討論與分享,嚴禁用於非法途徑

0×00 背景

10月9號國內幾家安全媒體公布了Joomla RCE的漏洞預警,並且網上已公布漏洞利用EXP,影響版本包括Joomla 3.0.0 – 3.4.6。

0×01 環境搭建

Joomla是一套全球知名的內容管理系統。Joomla是使用PHP語言加上MySQL數據庫所開發的軟件系統,目前最新版本是3.9.11 。可以在Linux、Windows、MacOSX等各種不同的平台上執行。

Joomla環境搭建下載:https://github.com/joomla/joomla-cms/releases/tag/3.4.6

PS:搭建環境要求php 5.3.10以上

0×02 漏洞分析

Session會話機制

PHP本身對Session的存儲默認放在文件中,當有會話產生使用到Session時候,將會在網站服務端設置好的路徑寫入相應的Session文件,文件的內容為默認序列化處理器序列化後的數據。然而在Joomla中則改變了PHP的默認處理規則,相反將序列化之後的數據存放在數據庫的” hzlnp_session”表中存儲:

將序列化之後的數據存放在數據庫中所對應的處理函數為由session_set_save_handler()設置的librariesjoomlasessionstoragedatabase.php 中的write():

相應的取值函數read()也位於librariesjoomlasessionstoragedatabase.php中

接着從代碼中可以看出,在存入數據庫之前,會將傳入數據中的chr(0) . ‘*’ .chr(0) 替換為, 原因是mysql數據庫無法處理NULL位元組,而protected 修飾符修飾的字段在序列化之後是以x00x2ax00開頭的。然後從數據庫中取出來的時候,再將字符進行替換還原,防止無法正常反序列化。

Session會話逃逸

session 在 Joomla 中的處理存在一些問題,它會把沒有通過驗證的用戶名和密碼存儲在hzlnp_session表中

當用戶在登陸過程中,會有一個 303 的跳轉,主要是用於write()數據庫寫入用戶會話然後read()相應取出會話進行對比,顯示結果

通過分析Session會話機制和Session逃逸我們還不明確Session形成的漏洞到底在哪!

首先需要了解一下PHP的序列化的機制,PHP在序列化數據的過程中,如果序列化的字段是一個字符串,那麼將會保留該字符串的長度,然後將長度寫入到序列化之後的數據,反序列化的時候按照長度進行讀取。

知道PHP序列化過程之後,針對Joomla的內置序列化方法write和read函數,如果寫入數據庫的時候,是, 取出來的時候將會變成chr(0) . ‘*’ . chr(0),這樣的話,入庫的時候生成的序列化數據長度為6(), 取出來的時候將會成為3(N*N, N表示NULL),依據PHP反序列化原理,該數據在反序列化的時候,如果按照原先的長度進行讀取,就會導致溢出。

那麼由” ”溢出會造成什麼問題呢?按照PHP反序列化的特點,PHP按照長度讀取指定字段的值,讀取完成以分號結束,接着開始下一個,如果我們能夠控制兩個字段的值,第一個用來溢出第一個字段和第二個字段的前一部分,第二個字段的另一部分用來構造序列化利用的payload,最終序列化結果將會把第一個字段開始部分到第二個字段的前一部分當成第一個字段的全部內容,第二個字段內容成功逃逸出來並且被反序列化。

為了觸發我們的任意對象並實現RCE,我們需要將登錄框處的兩個字段username和password進行處理,第一個字段將導致“溢出”,第二個字段將包含漏洞利用的最後一部分。

漏洞利用大概思路

編寫本地測試代碼

此處偽代碼對Joomla內置的write()、read()函數進行模擬,username字段通過9組””進行賦值,其值序列化存入數據庫db.txt長度為54,反序列化取出長度變為27,加上後面第二個字段password的27個字符構成實際的username值:

O:4:”User”:2:{s:8:”username”;s:57:”xx。。。xxx”;s:8:”password”;s:nn:”payload”;}

由於”;s:8:”password”;s:nn:”長度為23,經read()函數處理之後會減半,所以要想覆蓋password字段值,username字段值就要取9組””,同時password的字段值長度至少需要是兩位(nn代表佔位符),因為實際上payload的長度會大於10。

測試結果 實現任意對象的注入

構造POP執行鏈,執行任意代碼

首先參考PHITHON 師傅的一篇文章“Joomla遠程代碼執行漏洞分析“收穫很多,依據PHITHON 師傅的思路,同樣,在我們可以控制反序列化對象以後,我們只需構造一個能夠一步步調用的執行鏈,即可進行一些危險的操作了。exp構造的執行鏈,分別利用了JDatabaseDriverMysqli和SimplePie類

我們可以在JDatabaseDriverMysqli類(librariesjoomladatabasedrivermysqli.php)的析構函數里找到一處敏感操作:

由於exp構造的對象反序列化後,將會成為一個JDatabaseDriverMysqli類對象,不管中間如何執行,最後都將會調用__destruct魔法函數,__destruct將會調用disconnect,disconnect里有一處敏感函數:call_user_func_array。但很遺憾的是,這裡的call_user_func_array的第二個參數是我們無法控制的,但是,我們可以進行回調利用:

call_user_func_array([$obj,”任意方法”],array( &$this))

進一步跟蹤到SimplePie類(librariessimplepiesimplepie.php),通過將SimplePie對象和它本身的init()函數可以組成一個回調函數[new SimplePie(), ‘init’],傳入call_user_func_array

分析init()函數

通過分析代碼發現此處的call_user_func 參數可控,只要滿足條件$this->cache=true && $parsed_feed_url[‘scheme’] !== Null,將其中第二個call_user_func的第一個參數cache_name_function賦值為assert,第二個參數賦值為我們需要執行的代碼,這樣就可以構成一個可利用的“回調後門“,達到任意代碼執行效果。

PS:對於網上爆的利用回調後門在網站根目錄下的configuration.php中寫入一句話木馬getshell這種方式,在真實環境中大多都不能利用成功(權限問題),效果並不是太好。

0×03 漏洞預防

1、版本更新

2、對session信息進行編碼存儲

0×04 參考鏈接

https://blog.hacktivesecurity.com/index.php?controller=post&action=view&id_post=41

https://www.leavesongs.com/PENETRATION/joomla-unserialize-code-execute-vulnerability.html

*本文原創作者:Qftmer,本文屬於FreeBuf原創獎勵計劃,未經許可禁止轉載