Joomla3.4.6 RCE漏洞深度分析
筆者《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()設定的\libraries\joomla\session\storage\database.php 中的write():
相應的取值函式read()也位於\libraries\joomla\session\storage\database.php中
接著從程式碼中可以看出,在存入資料庫之前,會將傳入資料中的chr(0) . ‘*’ .chr(0) 替換為\0\0\0, 原因是mysql資料庫無法處理NULL位元組,而protected 修飾符修飾的欄位在序列化之後是以\x00\x2a\x00開頭的。然後從資料庫中取出來的時候,再將字元進行替換還原,防止無法正常反序列化。
Session會話逃逸
session 在 Joomla 中的處理存在一些問題,它會把沒有通過驗證的使用者名稱和密碼儲存在hzlnp_session表中
當用戶在登陸過程中,會有一個 303 的跳轉,主要是用於write()資料庫寫入使用者會話然後read()相應取出會話進行對比,顯示結果
通過分析Session會話機制和Session逃逸我們還不明確Session形成的漏洞到底在哪!
首先需要了解一下PHP的序列化的機制,PHP在序列化資料的過程中,如果序列化的欄位是一個字串,那麼將會保留該字串的長度,然後將長度寫入到序列化之後的資料,反序列化的時候按照長度進行讀取。
知道PHP序列化過程之後,針對Joomla的內建序列化方法write和read函式,如果寫入資料庫的時候,是\0\0\0, 取出來的時候將會變成chr(0) . ‘*’ . chr(0),這樣的話,入庫的時候生成的序列化資料長度為6(\0\0\0), 取出來的時候將會成為3(N*N, N表示NULL),依據PHP反序列化原理,該資料在反序列化的時候,如果按照原先的長度進行讀取,就會導致溢位。
那麼由” \0\0\0”溢位會造成什麼問題呢?按照PHP反序列化的特點,PHP按照長度讀取指定欄位的值,讀取完成以分號結束,接著開始下一個,如果我們能夠控制兩個欄位的值,第一個用來溢位第一個欄位和第二個欄位的前一部分,第二個欄位的另一部分用來構造序列化利用的payload,最終序列化結果將會把第一個欄位開始部分到第二個欄位的前一部分當成第一個欄位的全部內容,第二個欄位內容成功逃逸出來並且被反序列化。
為了觸發我們的任意物件並實現RCE,我們需要將登入框處的兩個欄位username和password進行處理,第一個欄位將導致“溢位”,第二個欄位將包含漏洞利用的最後一部分。
漏洞利用大概思路
編寫本地測試程式碼
此處虛擬碼對Joomla內建的write()、read()函式進行模擬,username欄位通過9組”\0\0\0”進行賦值,其值序列化存入資料庫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,\0\0\0經read()函式處理之後會減半,所以要想覆蓋password欄位值,username欄位值就要取9組”\0\0\0”,同時password的欄位值長度至少需要是兩位(nn代表佔位符),因為實際上payload的長度會大於10。
測試結果 實現任意物件的注入
構造POP執行鏈,執行任意程式碼
首先參考PHITHON 師傅的一篇文章“Joomla遠端程式碼執行漏洞分析“收穫很多,依據PHITHON 師傅的思路,同樣,在我們可以控制反序列化物件以後,我們只需構造一個能夠一步步呼叫的執行鏈,即可進行一些危險的操作了。exp構造的執行鏈,分別利用了JDatabaseDriverMysqli和SimplePie類
我們可以在JDatabaseDriverMysqli類(\libraries\joomla\database\driver\mysqli.php)的解構函式裡找到一處敏感操作:
由於exp構造的物件反序列化後,將會成為一個JDatabaseDriverMysqli類物件,不管中間如何執行,最後都將會呼叫__destruct魔法函式,__destruct將會呼叫disconnect,disconnect裡有一處敏感函式:call_user_func_array。但很遺憾的是,這裡的call_user_func_array的第二個引數是我們無法控制的,但是,我們可以進行回撥利用:
call_user_func_array([$obj,"任意方法"],array( &$this))
進一步跟蹤到SimplePie類(\libraries\simplepie\simplepie.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原創獎勵計劃,未經許可禁止