Joomla3.4.6 RCE漏洞深度分析

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

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

0×00 背景

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

0×01 環境搭建

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

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

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

0×02 漏洞分析

Session會話機制

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

將序列化以後的數據存放在數據庫中所對應的處理函數爲由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會話逃逸

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 漏洞預防

一、版本更新

二、對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原創獎勵計劃,未經許可禁止轉載

相關文章
相關標籤/搜索