您好,登錄后才能下訂單哦!
這篇文章給大家介紹ThinkPHP漏洞分析以及用法,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
ThinkPHP是一個快速、兼容而且簡單的輕量級國產PHP開發框架,遵循Apache 2開源協議發布,使用面向對象的開發結構和MVC模式,融合了Struts的思想和TagLib(標簽庫)、RoR的ORM映射和ActiveRecord模式。
ThinkPHP可以支持windows/Unix/Linux等服務器環境,正式版需要PHP 5.0以上版本,支持MySql、PgSQL、Sqlite多種數據庫以及PDO擴展。
ThinkPHP發展至今,核心版本主要有以下幾個系列,ThinkPHP 2系列、ThinkPHP 3系列、ThinkPHP 5系列、ThinkPHP 6系列,各個系列之間在代碼實現及功能方面,有較大區別。其中ThinkPHP 2以及ThinkPHP 3系列已經停止維護,ThinkPHP 5系列現使用最多,而ThinkPHP 3系列也積累了較多的歷史用戶。版本細分如下圖所示:
通過對ThinkPHP漏洞的收集和整理,過濾出其中的高危漏洞,可以得出如下列表:
從上表數據來看,ThinkPHP 3系列版本的漏洞多是2016/2017年被爆出,而ThinkPHP 5系列版本的漏洞基本為2017/2018年被爆出,從2020年開始,ThinkPHP 6系列的漏洞也開始被挖掘。
從中可以看出,ThinkPHP近年出現的高風險漏洞主要存在于框架中的函數,這些漏洞均需要在二次開發的過程中使用了這些風險函數方可利用,所以這些漏洞更應該被稱為框架中的風險函數,且這些風險點大部分可導致SQL注入漏洞,所以,開發者在利用ThinkPHP進行Web開發的過程中,一定需要關注這些框架的歷史風險點,盡量規避這些函數或者版本,則可保證web應用的安全性。
根據ThinkPHP的歷史高危漏洞,梳理出分版本的攻擊風險點,開發人員可根據以下圖標,來規避ThinkPHP的風險版本,如下ThinkPHP暴露面腦圖。
基于暴露面腦圖,我們可以得出幾種可以直接利用的ThinkPHP框架漏洞利用鏈,不需要進行二次開發。
ThinkPHP低于3.0 - GetShell
ThinkPHP 低版本可以使用以上漏洞執行任意系統命令,獲取服務器權限。
ThinkPHP 5.0.x - GetShell
首先明確ThinkPHP框架系列版本。
根據ThinkPHP版本,如是0.x版本,即可使用ThinkPHP 5.x遠程代碼執行漏洞,無需登錄,即可執行任意命令,獲取服務器最高權限。
ThinkPHP 5.1.x - GetShell
首先明確ThinkPHP框架系列版本。
根據ThinkPHP版本,如是1.x版本,即可使用ThinkPHP 5.x遠程代碼執行漏洞1,無需登錄,即可執行任意命令,獲取服務器最高權限。
如需使用ThinkPHP 5.x遠程代碼執行漏洞2,則需要php文件中跳過報錯提示,即 文件中有語句:“error_reporting(0);”,故該漏洞在5.1.x系列版本利用需要滿足以上前提,利用較難。
從高危漏洞列表中,針對ThinkPHP不需二次開發即可利用的高危漏洞進行深入分析。
4.1.1、漏洞概要
漏洞名稱:ThinkPHP 2.x/3.0遠程代碼執行
參考編號:無
威脅等級:高危
影響范圍:ThinkPHP 2.x/3.0
漏洞類型:遠程代碼執行
利用難度:簡單
4.1.2、漏洞描述
ThinkPHP是為了簡化企業級應用開發和敏捷WEB應用開發而誕生的開源MVC框架。Dispatcher.class.php中res參數中使用了preg_replace的/e危險參數,使得preg_replace第二個參數就會被當做php代碼執行,導致存在一個代碼執行漏洞,攻擊者可以利用構造的惡意URL執行任意PHP代碼。
4.1.3、漏洞分析
漏洞存在在文件 /ThinkPHP/Lib/Think/Util/Dispatcher.class.php 中,ThinkPHP 2.x版本中使用preg_replace的/e模式匹配路由,我們都知道,preg_replace的/e模式,和php雙引號都能導致代碼執行的,即漏洞觸發點在102行的解析url路徑的preg_replace函數中。代碼如下:
該代碼塊首先檢測路由規則,如果沒有制定規則則按照默認規則進行URL調度,在preg_replace()函數中,正則表達式中使用了/e模式,將“替換字符串”作為PHP代碼求值,并用其結果來替換所搜索的字符串。
正則表達式可以簡化為“\w+/([\^\/])”,即搜索獲取“/”前后的兩個參數,$var[‘\1’]=”\2”;是對數組的操作,將之前搜索到的第一個值作為新數組的鍵,將第二個值作為新數組的值,我們發現可以構造搜索到的第二個值,即可執行任意PHP代碼,在PHP中,我們可以使用${}里面可以執行函數,然后我們在thinkphp的url中的偶數位置使用${}格式的php代碼,即可最終執行thinkphp任意代碼執行漏洞,如下所示:
index.php?s=a/b/c/${code} index.php?s=a/b/c/${code}/d/e/f index.php?s=a/b/c/d/e/${code}
由于ThinkPHP存在兩種路由規則,如下所示:
http://serverName/index.php/模塊/控制器/操作/[參數名/參數值...]
如果不支持PATHINFO的服務器可以使用兼容模式訪問如下:
http://serverName/index.php?s=/模塊/控制器/操作/[參數名/參數值...]
也可采用 index.php/a/b/c/${code}一下形式。
4.2.1、漏洞概要
漏洞名稱:ThinkPHP 5.0.x-5.1.x 遠程代碼執行漏洞
參考編號:無
威脅等級:嚴重
影響范圍:ThinkPHP v5.0.x < 5.0.23,ThinkPHP v5.1.x < 5.0.31
漏洞類型:遠程代碼執行
利用難度:容易
4.2.2、漏洞描述
2018年12月10日,ThinkPHPv5系列發布安全更新,修復了一處可導致遠程代碼執行的嚴重漏洞。此次漏洞由ThinkPHP v5框架代碼問題引起,其覆蓋面廣,且可直接遠程執行任何代碼和命令。電子商務行業、金融服務行業、互聯網游戲行業等網站使用該ThinkPHP框架比較多,需要格外關注。由于ThinkPHP v5框架對控制器名沒有進行足夠的安全檢測,導致在沒有開啟強制路由的情況下,黑客構造特定的請求,可直接進行遠程的代碼執行,進而獲得服務器權限。
4.2.3、漏洞分析
本次ThinkPHP 5.0的安全更新主要是在library/think/APP.php文件中增加了對控制器名的限制,而ThinkPHP 5.1的安全更新主要是在library/think/route/dispatch/Module.php文件中增加了對控制器名的限制。
從以上補丁更新可知,該漏洞的根源在于框架對控制器名沒有進行足夠的檢測,從而會在未開啟強制路由的情況下被引入惡意外部參數,造成遠程代碼執行漏洞。
由ThinkPHP的架構可知,控制器(controller)是通過url中的路由進行外部傳入的,即/index.php?s=/模塊/控制器/操作/[參數名/參數值…],控制器作為可控參數,經過library/think/APP.php文件進行處理,我們跟蹤路由處理的邏輯,來完整看一下該漏洞的整體調用鏈:
首先在run()主函數中,url傳入后需要經過路由檢查,如下代碼所示:
跟進 self::routeCheck 函數
在 620行中調用 $request->path() 函數,該函數位于thinkphp/library/think/Request.php文件中,在該函數中跟進到本文件的$this->pathinfo()函數,在該函數中,就進行url解析,獲取路由中的各個部分內容。
其中var_pathinfo參數即為系統默認參數,默認值為s,通過GET方法將獲取到的var_pathinfo的值,即s=/模塊/控制器/操作/[參數名/參數值…]的內容送到routeCheck()函數中$path參數進行路由檢查處理。
繼續回到routeCheck()函數:
在初始化路由檢查配置之后,就進行Route::check,由以上代碼看出,若路由尋不到對應操作,即返回$result=false,且開啟了強制路由$must的情況下,就會拋出異常,并最終進入Route::parseUrl函數,進行$path解析,以上就進入了我們的漏洞觸發點:
首先,在該函數中進行url解析,然后,進入到parseUrlPath函數,根據/進行路由地址切割,通過數組返回:
最終在parseUrl函數中,將返回的$path提取出路由,即module、controller、action,然后封裝到$route后返回:
回到thinkphp/library/think/App.php文件的run()函數:
在完成RouteCheck后,進入到exec()函數中去:
在該函數中,首先路由信息首先進入module()函數進行檢驗,該函數首先查看該路由中的模塊信息是否存在且是否存在于禁止的模塊類表中:
模塊存在的話,繼續往下跟蹤,分別將模塊中的controller、actionName經過處理后賦值到$instance、$action,最終$instance、$action被賦值給了$call參數。
最終$call參數進入了self::invokeMethod()進行處理:
在函數中,通過反射ReflectionMethod獲取controller(method[0])和action(method[1])對象下的方法,然后通過$args = self::bindParams($reflect, $vars);獲取到傳入參數。以上即為漏洞調用鏈。
我們根據Payload來進行最終攻擊鏈的總結:
siteserver/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
根據上面的分析,我們將路由解析為:
module:index
controller:think\app
action:invokefunction
通過上述的利用鏈,最終通過反射ReflectionMethod進入到Think/app文件中的invokefunction方法中:
通過構造參數,最終即可執行任意代碼。
4.3.1、漏洞概要
漏洞名稱:ThinkPHP 5.0.x-5.1.x遠程代碼執行漏洞
參考編號:無
威脅等級:嚴重
影響范圍:ThinkPHP v5.0.x < 5.0.23,ThinkPHP v5.1.x < 5.0.31
漏洞類型:遠程代碼執行漏洞
利用難度:容易
4.3.2、漏洞描述
2019年1月11日,某安全團隊公布了一篇ThinkPHP 5.0.遠程代碼執行漏洞文檔,公布了一個ThinkPHP 5.0.遠程代碼執行漏洞。文章中的該漏洞與2018年12月的ThinkPHP 5.0.*遠程代碼執行漏洞原理相似,攻擊者可利用該漏洞在一定條件下獲取目標服務器的最高權限。后經研究,在一定條件下,ThinkPHP 5.1.x版本也存在該漏洞,在滿足條件的情況下,攻擊者可利用該漏洞執行任意代碼。
4.3.3、漏洞分析
該漏洞的漏洞關鍵點存在于thinkphp/library/think/Request.php文件中:
從代碼中可知:
method()函數主要用于請求方法的判斷,var_method沒有通過,為可控參數,通過外部傳入,thinkphp支持配置“表單偽裝變量”,var_method在在外部的可控參數表現為_method:
由于var_method沒有做任何過濾,我們可以通過控制_method參數的值來動態調用Request類中的任意方法,通過控制$_POST的值來向調用的方法傳遞參數。由上可知,漏洞存在于method()函數中,我們就需要尋找該函數的調用鏈,來構造POC。
第一個構造鏈在__construct()構造方法中,該方法如下:
函數中對$option數組進行遍歷,當$option的鍵名為該類屬性時,則將該類同名的屬性賦值為$options中該鍵的對應值。因此可以構造請求如下,來實現對Request類屬性值的覆蓋,例如覆蓋filter屬性。filter屬性保存了用于全局過濾的函數。
再上一個漏洞分析過程中,我們跟蹤到了路由檢查self::routeCheck 函數,在過程中,會進入到thinkphp/library/think/Route.php文件中的check()函數,函數中調用了method()方法,并將函數執行結果轉換為小寫后保存在$method變量。在調用構造函數覆蓋變量時,可以直接覆蓋method,這樣上面的$method = strtolower($request->method()); 的$method最終的值就可以被控制了。
在該函數中,調用了method()函數,在該函數中,就將進行變量覆蓋:
通過調用構造函數__construct(),最終將請求參數保存到input參數。
在進行routecheck后,已完成了第一部分調用鏈,實現了變量覆蓋,接下來就是要實現變量覆蓋后的代碼執行,具體調用鏈如下:
返回到App.php文件中的run()函數,接著進入到exec()函數中,然后進入到module()函數中,最終進入到了invokeMethod()函數,
從invokeMethod()函數中進入到bindParams()函數,然后進入到param()函數:
然后最終調用到input()函數:
最終我們根據array_walk_recursive()函數,進入到了filterValue()函數:
最終,通過回調函數call_user_func執行了代碼,整個調用鏈如上所示。
關于ThinkPHP漏洞分析以及用法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。