作者:深信服千里目實驗室
原文鏈接:https://mp.weixin.qq.com/s/9IWS0VX90CUJzhh8i0myAw
一、組件介紹
1.1 基本信息
ThinkCMF是一款基于PHP+MYSQL開發的中文內容管理框架。ThinkCMF提出靈活的應用機制,框架自身提供基礎的管理功能,而開發者可以根據自身的需求以應用的形式進行擴展。每個應用都能獨立的完成自己的任務,也可通過系統調用其他應用進行協同工作。在這種運行機制下,該系統的用戶無需關心開發SNS應用是如何工作的,但他們之間又可通過系統本身進行協調,大大的降低了開發成本和溝通成本。
普通的CMS(內容管理系統)一般不能完成所有的需求,而因為CMS在ThinkCMF內部只是一個應用的形式存在,所以使用ThinkCMF可以用CMS來管理內容,用電影網站系統來管理視頻,用電商系統來管理電商網站。這些程序不會影響,也可以模塊化的增加或減少應用。
ThinkCMF自身層次非常清晰,邏輯也相當的嚴謹,特別是系統自帶的protal應用非常適合PHP初學者使用。采用了國內優秀的開源php框架ThinkPHP使得ThinkCMF具備了優秀的性能以及良好的安全性。
1.2 版本介紹
ThinkCMF基于ThinkPHP框架進行了二次開發,經過逐年演化,逐漸成為了一款功能齊全的內容管理框架。ThinkCMF發展至今已有近8年歷史,其核心開發系列共有以下三個,即ThinkCMF V1.x系列,ThinkCMFX 2.x系列,ThinkPHP 5.x系列。ThinkCMF同時與ThinkPHP的版本有以下對應關系:ThinkCMF V1.x系列版本基于ThinkPHP 3.1.3版本進行開發的、ThinkCMFX 2.x系列版本是基于ThinkPHP 3.2.3而進行開發、ThinkCMF 5.x系列版本是基于ThinkPHP 5版本開發的。其中ThinkCMF 1.x、ThinkCMFX 2.x官方已經停止了維護,ThinkCMF 5.x屬于現階段核心版本。而ThinkCMFX 2.x系列基于其優良的性能,也在過去積累了很多的歷史客戶,使得ThinkCMF 5與ThinkCMFX 2在市場上并駕齊驅。版本細分如下圖所示:

1.3 使用量及使用分布
根據全網數據統計,使用ThinkCMF的網站多達2萬余個,其中大部分集中在國內,占使用量的75%以上。其中,浙江、北京、山東、廣東四省市使用量最高,由此可見,ThinkCMF在國內被廣泛應用。通過網絡空間搜索引擎的數據統計和柱狀圖表,如下圖所示。

二、高危漏洞介紹
通過對ThinkCMF漏洞的收集和整理,過濾出其中的高危漏洞,可以得出如下列表。
| 漏洞名稱 | 漏洞ID | 影響版本 | 漏洞披露日期 |
|---|---|---|---|
| ThinkCMF X2.2.3 任意文件刪除漏洞 | CVE-2018-16141 | ThinkCMFX <=2.2.3 | 2018 |
| ThinkCMF X2.2.3 SQL注入漏洞 | CVE-2018-19894 | ThinkCMFX <= 2.2.3 | 2018 |
| ThinkCMF X2.2.3 SQL注入漏洞 | CVE-2018-19895 | ThinkCMFX <= 2.2.3 | 2018 |
| ThinkCMF X2.2.3 SQL注入漏洞 | CVE-2018-19896 | ThinkCMFX <= 2.2.3 | 2018 |
| ThinkCMF X2.2.3 SQL注入漏洞 | CVE-2018-19897 | ThinkCMFX <= 2.2.3 | 2018 |
| ThinkCMF X2.2.3 SQL注入漏洞 | CVE-2018-19898 | ThinkCMFX <= 2.2.3 | 2018 |
| ThinkCMF X2.2.3 前臺文件上傳漏洞 | ThinkCMFX <=2.2.3 | 2018 | |
| ThinkCMF X2.x緩存Getshell(display函數) | ThinkCMFX <= 2.2.3 | 2018 | |
| ThinkCMF X2.2.3代碼注入漏洞(fetch函數) | ThinkCMFX <= 2.2.3 | 2018 | |
| ThinkCMF X2.2.3代碼注入漏洞(plugin類) | ThinkCMFX <= 2.2.3 | 2019 | |
| ThinkCMF 后臺任意代碼執行漏洞1 | CVE-2019-6713 | ThinkCMF <= 5.0.190111 | 2019 |
| ThinkCMF 后臺任意代碼執行漏洞2 | CVE-2019-7580 | ThinkCMF <= 5.0.190111 | 2019 |
從中可以看出,ThinkCMF近年出現的高風險漏洞主要分布在ThinkCMF X2.x系列中,且其中主要集中在SQL注入漏洞,看過筆者上一篇ThinkPHP分析文章的讀者都知道,ThinkPHP 3.x系列存在大量SQL注入風險函數,不出意外,這些風險函數最終都在二次開發的基礎上被使用,造成了SQL注入漏洞。幸好,在ThinkCMF開發的的過程中,開發人員做過一些SQL注入的風險控制,這就使得這些SQL注入漏洞被利用的難度會大大增加,提高了框架被攻陷的門檻。
ThinkCMF X2.x系列除了以上的SQL注入的風險之外,另外最大的風險存在于ThinkCMF框架中Controller中的兩個模板操作函數,fetch()以及display()函數,這兩個函數在處理模板文件的過程中,存在漏洞,會導致任意代碼注入,最終造成任意代碼執行,且不需要任何權限,所以該漏洞的風險很高。
我們再看ThinkCMF 5系列,這個系列的安全性基于ThinkPHP 5的安全性提高也隨之大大提高,近兩年比較出名的就是CVE-2019-6713、CVE-2019-7580兩個后臺任意代碼執行漏洞,這兩個漏洞源于在后臺處理router的時候,沒有經過嚴格驗證,導致攻擊者可以通過單引號逃逸,將惡意代碼注入到ThinkCMF數據庫中,最終代碼會產生在router.php文件中。
三、漏洞利用鏈
基于ThinkCMF高危漏洞,我們可以得出幾種可以利用的ThinkCMF框架漏洞利用鏈。
3.1 ThinkCMFX 2.x GetShell

ThinkCMF 2.x - GetShell
- ThinkCMF 低版本可以使用以上代碼注入漏洞,獲取服務器權限。
3.2 ThinkCMF 5.x GetShell

ThinkCMF 5.x - GetShell
- 首先明確ThinkCMF框架系列版本。
- 首先需要獲取到ThinkCMF的后臺登錄賬號密碼,執行ThinkCMF后臺代碼執行漏洞,即可getshell。
四、高可利用漏洞分析
從高危漏洞列表中,針對ThinkCMF高可利用漏洞進行深入分析。
4.1 ThinkCMF 2.x 代碼注入漏洞(fetch函數)
4.1.1 漏洞簡介
漏洞名稱:ThinkCMF 2.x 代碼注入漏洞(fetch函數)
漏洞編號:無
漏洞類型:代碼注入
CVSS評分:無
漏洞危害等級:高危
4.1.2 漏洞概述
ThinkCMF是一款基于ThinkPHP+MySQL開發的中文內容管理框架。攻擊者可利用此漏洞構造惡意的url,向服務器寫入任意內容的文件,從而實現遠程代碼執行。該漏洞只適用windows系統。
4.1.3 漏洞影響
1.6.0 <= ThinkCMFX <= 2.3.0
4.1.4 漏洞修復
1.將 HomebaseController.class.php和AdminbaseController.class.php 類中 display 和 fetch 函數的修飾符改為 protected
2.目前廠商已不維護2.x版本,請受影響的用戶使用升級到ThinkCMF 5系列或者采用以上臨時解決方案
4.1.5 漏洞分析
分析該漏洞,我們要詳細跟蹤一下content參數值的流向,我們從程序入口開始往后跟蹤:
Step1:首先通過ThinkPHP.php入口文件進入到Think.class.php文件中的start()函數;
在start()函數中,進入到App.class.php文件中的主函數run();

進入到文件中的exec()函數,exec函數的作用就是解析請求的路由,這一塊的處理模式即為ThinkPHP的處理模式;


通過路由解析,解析出了請求的module、action,分別為:view的fetch。然后通過invokeAction()函數中的反射,定位到具體類以及具體的操作函數。以下即為第一階段的路由解析階段的調用鏈。

Step2:在定位了操作函數之后,首先定位到了HomebaseController.php文件中的fetch()函數;

然后通過return parent::fetch返回到其父類的Controller.php文件中的fetch()函數;

根據之前的路由解析,我們知道即將調用View然后即進入到View.class.php文件中的fetch()函數,進行模板處理。

我們可以看到該函數中,再起始有一個ob_start();,然后對content進行處理后,通過$content = ob_get_clean();將content清空,所以我們在清空之后下斷點,然后我們即進入到view_parase模塊,通過跟蹤,我們解析出了模塊對應的是ParseTemplateBehavior.php文件;

進入到ParseTemplateBehavior::run()主函數中,我們將面臨著兩個分支,我們分別在兩個分支打上斷點,來驗證此處程序的走向。我們發現content的值是第一次發送的話,將會走else分支,如果不是第一次發送,將會走第一個分支,從判斷條件也可得知,如果緩存中存在content的緩存,即走if分支,否則就走else分支。

我們利用第一次發送的poc,進入到else分支中的fetch函數,我們發現進入到Template.class.php文件中的fetch函數,

我們可以看到fetch函數中調用了loadTemplate()函數,進入到該函數中,我們可以看到content最終被賦值到了 $tmplContent參數中;

然后$tmplContent (content)經過編譯后通過Storage::put函數保存,最終將文件生成到data/runtime/Cache/Portal文件夾中。最后,最后在Template.class.php文件中調用了Storage::load加載cache文件,最終導致代碼執行。

4.2 ThinkCMF 2.2.x 前臺任意文件上傳漏洞
4.2.1 漏洞簡介
漏洞名稱:ThinkCMF 2.2.x 前臺任意文件上傳漏洞
漏洞編號:無
漏洞類型:文件上傳
CVSS評分:無
漏洞危害等級:高危
4.2.2 漏洞概述
ThinkCMF是一套基于ThinkPHP的CMS(內容管理系統)。在 ThinkCMFX 2.2.3 最終版及以前版本中,存在一處任意文件上傳漏洞(需要普通用戶權限,默認可注冊)。遠程攻擊者可利用該漏洞上傳任意可執行文件。
4.2.3 漏洞影響
1.6.0 <= ThinkCMFX <= 2.2.3
4.2.4 漏洞修復
目前廠商已不維護2.x版本,請受影響的用戶使用升級到ThinkCMF 5系列。
4.2.5 漏洞分析
在/application/Asset/Controller/UeditorController.class.php中,存在一個上傳接口,但是在上傳前存在一個權限驗證,即登錄后才可上傳,前臺會員與后臺管理員權限均可。
然后進入到upload方法中,該方法支持上傳多種類型文件,我們可以選擇uploadfile接口繼續跟蹤,該接口調用了_ueditor_uplaod()函數;

進入到_ueditor_upload()函數中,我們發現這里是通過$allowed_exts=explode(',', $upload_setting[$filetype]);來進行后綴白名單設置的,明顯可以看出程序想用白名單數組,但是使用了filetype]獲得的是一個數組,包含upload_max_filesize和extensions兩個key,而explode的作用為把第二個參數通過字符串分割成數組,導致出錯,最終返回了一個Null;
故此處少了[‘extensions’],正確寫法應該是upload_setting);,此處最終會導致 $allowed_exts的值為Null,導致白名單失效。

然后就將調用Upload.php文件中的upload()函數,進行文件上傳操作

進入到upload()函數中,要進入一個check();

check()中將進行后綴檢查checkExt();

在checkExt方法中, 從剛才的分析可以知道$this->config[‘exts’]為null, empty(null)為true, 所以直接返回true了,不會再判斷后綴了。

在check之后, 通過getSaveName生成最終保存的文件名;

所以在$rule為$config中的savename屬性值 array(‘uniqid’,’’),文件的后綴來自,
$ext = empty($this->config['saveExt']) ? $file['ext'] : $this->saveExt;
在默認的上傳配置信息中’saveExt’ => ‘’,saveExt為空, 所以這里不會強制修改文件的后綴而是直接使用的上傳文件名的后綴。

生成好文件名之后, 就直接通過save方法進行上傳了。save方法中已經沒有了任何后綴校驗, 所以直接實現了任意文件上傳。

最終通過json數據將文件上傳的內容返回。

4.3 ThinkCMF 2.x 代碼注入漏洞(display函數)
4.3.1 漏洞簡介
漏洞名稱:ThinkCMFX 代碼注入漏洞(通過緩存GetShell)
漏洞編號:無
漏洞類型:代碼注入
CVSS評分:無
漏洞危害等級:高危
4.3.2 漏洞概述
ThinkCMF是一套基于ThinkPHP的CMS(內容管理系統)。由于ThinkCMF 2.x使用了ThinkPHP 3.x作為開發框架,默認情況下啟用了報錯日志并且開啟了模板緩存,導致可以使用加載一個不存在的模板來將生成一句話的PHP代碼寫入data/runtime/Logs/Portal目錄下的日志文件中,再次包含該日志文件即可在網站根目錄下生成任意PHP文件。
4.3.3 漏洞影響
1.6.0 <= ThinkCMFX <= 2.2.3
4.3.4 漏洞修復
1.將 HomebaseController.class.php和AdminbaseController.class.php 類中 display 和 fetch 函數的修飾符改為 protected
2.目前廠商已不維護2.x版本,請受影響的用戶使用升級到ThinkCMF 5系列或者采用以上臨時解決方案
4.3.5 漏洞分析
我們從程序入口開始往后跟蹤:
Step1:首先通過ThinkPHP.php入口文件進入到Think.class.php文件中的start()函數;

在start()函數中,進入到App.class.php文件中的主函數run();

進入到文件中的exec()函數,exec函數的作用就是解析請求的路由,這一塊的處理模式即為ThinkPHP的處理模式;


通過路由解析,解析出了請求的module、action,分別為:HomebaseController的display()。然后通過invokeAction()函數中的反射,定位到具體類以及具體的操作函數。以下即為第一階段的路由解析階段的調用鏈。

Step2:在定位了操作函數之后,首先定位到了HomebaseController.php文件中的display()函數;然后入到模板解析parseTemplate()函數;

在解析過程中,分別解析出了路徑path,module,以及模板文件名,$template.html;然后進行文件檢驗環節;

通過if(!file_exists_case(file);驗證文件是否存在,若文件不存在,則系統異常報錯,進入到E()中,拋出異常。




Step3:在將代碼注入到log文件中,然后再通過view.class.php在通過display()函數中的fetch()函數解析日志文件,最后執行日志文件中的惡意代碼。


4.4 ThinkCMF 5.x后臺 遠程代碼執行漏洞
4.4.1 漏洞簡介
漏洞名稱:ThinkCMF 5.x后臺 遠程代碼執行漏洞
漏洞編號:CVE-2019-6713
漏洞類型:代碼注入
CVSS評分:【CVSS v2.0:7.5】【CVSS v3.0:9.8】
漏洞危害等級:高危
4.4.2 漏洞概述
ThinkCMF是一套基于ThinkPHP的CMS(內容管理系統)。ThinkCMF 5.0.190111版本中的app/admincontroller/RouteController.php文件存在一個代碼注入。遠程攻擊者可利用該漏洞執行任意的PHP代碼。
4.4.3 漏洞影響
ThinkCMF < = 5.0.190111
4.4.4 漏洞修復
目前廠商已發布升級補丁以修復漏洞,補丁獲取鏈接:
https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvm13822
4.4.5 漏洞分析
0x0:首先我們可以控制數據庫的寫入:將payload插入數據庫
0x1:間接的控制了$allRoutes變量
0x2:逃逸單引號,我們可以往data/conf/route.php中寫入代碼并再寫入之后再次觸發執行
首先我們在ThinkCMF(ThinkPHP)的路由解析入口打上斷點,即在 $data = self::exec($dispatch, $config);處,然后往下走,

通過路由解析,解析出了請求的控制器、類、以及對應函數,分別為:RouteController.php的addPost函數。

在addpost()函數中,通過 $routeModel->allowField(true)->save($data);中的save函數存儲路由到數據庫中(INSERT INTOcmf_route(full_url,url,status) VALUES (‘portal/List/index’ , ‘list/:id’ , ‘1’))。

回到RouteController.php::index()函數中,該函數用于在請求/響應過程中遍歷所有的存儲路由。

在index()函數通過getRoutes()函數來進行的,進入到$routeModel->getRoutes(true);函數中,在該函數中,通過$allRoutes來存儲從數據庫中獲取到的所有路由內容。
最終在data/conf文件夾下生成route.php文件,可以看出是通過單引號逃逸在PHP文件中引入了在數據庫中注入的惡意PHP代碼。


4.5 ThinkCMF 5.x后臺 遠程代碼執行漏洞
4.5.1 漏洞簡介
漏洞名稱:ThinkCMF 5.x后臺 遠程代碼執行漏洞
漏洞編號:CVE-2019-7580
漏洞類型:代碼注入
CVSS評分:【CVSS v2.0:6.5】【CVSS v3.0:8.8】
漏洞危害等級:高危
4.5.2 漏洞概述
ThinkCMF是一套基于ThinkPHP的CMS(內容管理系統)。ThinkCMF 5.0.190111版本中存在安全漏洞。遠程攻擊者攻擊者可通過向portal/admin_category/addpost.html頁面發送'別名'參數利用該漏洞注入任意代碼。
4.5.3 漏洞影響
ThinkCMF < = 5.0.190111
4.5.4 漏洞修復
目前廠商已發布升級補丁以修復漏洞,補丁獲取鏈接:
https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvm13822
4.5.5 漏洞分析
0x0:首先我們可以控制數據庫的寫入:將payload插入數據庫
0x1:間接的控制了$allRoutes變量
0x2:逃逸單引號,我們可以往data/conf/route.php中寫入代碼并再寫入之后再次觸發執行
首先我們在ThinkCMF(ThinkPHP)的路由解析入口打上斷點,即在 $data = self::exec($dispatch, $config);處,然后往下走,

通過路由解析,解析出了請求的控制器、類、以及對應函數,分別為:AdminCategoryController.php的addPost函數。
在addPost函數中通過portalCategoryModel.php中的addCategory()函數添加路由分類:

繼續跟進到portalCategoryModel.php::addCategory()函數中看出,通過RouteModel.php::setRoute()函數將alias的值進行存儲。

在RouteModel.php::setRoute()函數中,首先確定該路由是否存在,若不存在,就直接將路由存儲到數據庫中。

數據庫中已經保存了新增的url的內容,如下:

回到portalCategoryModel.php::addCategory()函數中,在存儲完新路由后,然后就進入到$routeModel->getRoutes(true);函數中,在改函數中,通過$allRoutes來存儲所有的新增路由內容。

最終在data/conf文件夾下生成route.php文件,該文件中包含了數據庫中注入的惡意PHP代碼。


4.6 ThinkCMF 2.x 代碼注入漏洞(Api/Plugin)
4.6.1 漏洞簡介
漏洞名稱:ThinkCMF 2.x 代碼注入漏洞(Api/Plugin)
漏洞編號:無
漏洞類型:代碼注入
CVSS評分:無
漏洞危害等級:高危
4.6.2 漏洞概述
ThinkCMF是一套基于ThinkPHP的CMS(內容管理系統)。在 ThinkCMFX 2.2.3 最終版及以前版本中,存在一處模板注入漏洞。該漏洞源于程序未對模板文件名進行過濾,且接口權限控制不嚴。在模板名可控、文件內容可控的情況下,我們可以將 webshell 寫入緩存文件,然后框架會去包含緩存文件,這樣就成功執行了 webshell 。
4.6.3 漏洞影響
1.6.0 <= ThinkCMFX <= 2.2.3
4.6.4 漏洞修復
1.將 HomebaseController.class.php和AdminbaseController.class.php 類中 display 和 fetch 函數的修飾符改為 protected
2.目前廠商已不維護2.x版本,請受影響的用戶使用升級到ThinkCMF 5系列或者采用以上臨時解決方案
4.6.5 漏洞分析
分析該漏洞,我們要詳細跟蹤一下content參數值的流向,我們從程序入口開始往后跟蹤:
Step1:首先通過ThinkPHP.php入口文件進入到Think.class.php文件中的start()函數;

在start()函數中,進入到App.class.php文件中的主函數run();

進入到文件中的exec()函數,exec函數的作用就是解析請求的路由,這一塊的處理模式即為ThinkPHP的處理模式;


通過路由解析,解析出了請求的module、action,分別為:view的fetch。然后通過invokeAction()函數中的反射,定位到具體類以及具體的操作函數。以下即為第一階段的路由解析階段的調用鏈。

Step2:在定位了操作函數之后,首先定位到了HomebaseController.php文件中的fetch()函數;

然后通過return parent::fetch返回到其父類的Controller.php文件中的fetch()函數;

根據之前的路由解析,我們知道即將調用View然后即進入到View.class.php文件中的fetch()函數,進行模板處理。

我們可以看到該函數中,再起始有一個ob_start();,然后對content進行處理后,通過$content = ob_get_clean();將content清空,所以我們在清空之后下斷點,然后我們即進入到view_parase模塊,通過跟蹤,我們解析出了模塊對應的是ParseTemplateBehavior.php文件;

進入到ParseTemplateBehavior::run()主函數中,我們將面臨著兩個分支,我們分別在兩個分支打上斷點,來驗證此處程序的走向。我們發現content的值是第一次發送的話,將會走else分支,如果不是第一次發送,將會走第一個分支,從判斷條件也可得知,如果緩存中存在content的緩存,即走if分支,否則就走else分支。

我們利用第一次發送的poc,進入到else分支中的fetch函數,我們發現進入到Template.class.php文件中的fetch函數,

我們可以看到fetch函數中調用了loadTemplate()函數,進入到該函數中,我們可以看到content最終被賦值到了 $tmplContent參數中;

然后$tmplContent (content)經過編譯后通過Storage::put函數保存,最終將文件生成到data/runtime/Cache/Portal文件夾中。最后,最后在Template.class.php文件中調用了Storage::load加載cache文件,最終導致代碼執行。

五、漏洞利用
最后,通過深信服千里目實驗室漏洞利用工具Sniper進行最后的漏洞利用,具體操作如以下視頻所示:
5.1 ThinkCMF 2.x 代碼注入漏洞(fetch)
相關視頻,請轉到原文觀看,鏈接:https://mp.weixin.qq.com/s/9IWS0VX90CUJzhh8i0myAw
5.2 ThinkCMF 2.x 代碼注入漏洞(display)
相關視頻,請轉到原文觀看,鏈接:https://mp.weixin.qq.com/s/9IWS0VX90CUJzhh8i0myAw
5.3 ThinkCMF 2.x 前臺任意文件上傳漏洞
相關視頻,請轉到原文觀看,鏈接:https://mp.weixin.qq.com/s/9IWS0VX90CUJzhh8i0myAw
5.4 ThinkCMF 5.x 后臺遠程代碼執行漏洞
相關視頻,請轉到原文觀看,鏈接:https://mp.weixin.qq.com/s/9IWS0VX90CUJzhh8i0myAw
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1419/

暫無評論