?

Jan 12 2019

【轉載】ThinkPHP 5.0 * 遠程代碼執行漏洞分析

首頁 » 代碼審計 » 【轉載】ThinkPHP 5.0 * 遠程代碼執行漏洞分析   

ThinkPHP 5.0 * 遠程代碼執行漏洞分析


本文主要以官網下載的5.0.23 完整版(thinkphp_5.0.23_with_extend.zip)為例分析。

Thinkphp處理請求的關鍵類為Request(thinkphp/library/think/Request.php)
該類可以實現對HTTP請求的一些設置。

其中成員函數method用來獲取當前請求類型,其定義如下

1.png

該函數主要在其他成員函數(例如isGet、isPost、isPut等)中被用來做請求類型判斷

2.png

因此在method()中,可以通過“表單偽裝變量”進行變量覆蓋實現對該類任意函數的調用,并且$_POST作為函數的參數傳入。


4.png



Request類的構造函數定義如下:

5.png


構造函數中,主要對option數組進行遍歷,當 option數組進行遍歷,當option數組進行遍歷,當option的鍵名為該類屬性時,則將該類同名的屬性賦值為$options中該鍵的對應值。

因此可以構造請求如下,來實現對Request類屬性值的覆蓋,例如覆蓋filter屬性。filter屬性保存了用于全局過濾的函數。
因此在thinkphp 5.0.10 中可以通過構造如下請求實現代碼執行:

6.png


在官網最新下載的5.0.23完整版中,在App類(thinkphp/library/think/App.php)中module方法增加了設置filter參數值的代碼,用于初始化filter。因此通過上述請求設置的filter參數值會被重新覆蓋為空導致無法利用。

7.png


在5.0.23的Request類中,存在param成員函數用于獲取當前請求的參數。其中也有調用method()函數,并且傳入參數值為true。param函數代碼實現如下:

8.png

當傳入的$method === true時 會執行如下代碼,

9.png

其中server()實現如下:

10.png


由此可見,參數$name為REQUEST_METHOD,最終會調用input函數。input函數實現如下。最終會執行到$filter = this?>getFilter( this->getFilter(this?>getFilter(filter,$default); 來解析過濾器。
11.png

此時filter為‘’, filter 為‘’,filter為‘’,default為null。
繼續跟進查看getFilter函數的實現:

122.png


由于filter=‘‘,因此可以執行到紅線處,并且最終 filter = ‘‘,因此可以執行到紅線處,并且最終filter=‘‘,因此可以執行到紅線處,并且最終filter會被賦值進this?>filter,和 this->filter ,和this?>filter,和default 即 null。因此經過“解析過濾器”的過程,filter最終可被添加來自請求中的filter。之后,代碼判斷了 filter最終可被添加來自請求中的filter。之后,代碼判斷了filter最終可被添加來自請求中的filter。之后,代碼判斷了data是否為數組,最終將每個值作為參數,通過filterValue()函數進行過濾。而data即為server()函數中傳入的 data即為server()函數中傳入的data即為server()函數中傳入的this->server ,因此也可通過在調用構造函數時,實現對$this->server值的覆蓋。

filterValue函數實現如下:

13.png


因此在debug模式下,發送如下請求可實現代碼執行:

14.png


例如touch /tmp/xxxx

15.png


繼續分析。可以看到“記錄路由和請求信息”之前,還實現了“未設置調度信息則進行URL路由檢測。”其中通過routeCheck函數來設置dispatch。最終再通過exec函數,將 dispatch。最終再通過exec函數,將dispatch。最終再通過exec函數,將request和config作為參數傳入后執行。其中 config 作為參數傳入后執行。其中config作為參數傳入后執行。其中config 是通過initCommon函數調用init函數來加載config配置文件來實現賦值。$request即為Request::instance()。

16.png

其中routeCheck函數實現如下:

17.png


首先會通過加載config文件導入“路由配置”。默認配置如下:

18.png

然后通過Route類的import方法加載路由。由于在入口文件index.php(public/index.php)中加載了start.php(thinkphp/start.php)

19.png

start.php又加載了base.php(thinkphp/base.php)

20.png

base.php中實現了注冊自動加載

21.png


register函數實現如下:

22.png

該函數完成了對VENDOR下class的加載。其中完成了驗證碼類路由的加載

23.png

因此上面import之后,Route類$rules值將形如下:

24.png


然后代碼會執行到“路由檢測”的部分即調用Route::check的地方,路由檢測主要用于根據路由的定義返回不同的URL調度。

Route類check函數實現如下:

25.png

可以看到該check函數中調用了Request類的method方法。并將函數執行結果轉換為小寫后保存在method變量。由于Request類中method函數在返回method時直接判斷了如果存在 method變量。由于Request類中method函數在返回method時直接判斷了如果存在method變量。由于Request類中method函數在返回method時直接判斷了如果存在this->method直接返回
26.png

因此我們在調用構造函數覆蓋變量時,可以直接覆蓋method,這樣上面的method=strtolower( method = strtolower(method=strtolower(request->method()); 的$method最終的值就可以被控制了。

回到check函數,在設置完method后,會根據 method 后,會根據method后,會根據method在self::rules中獲取對應 rules中獲取對應rules中獲取對應method的路由信息,并將結果賦值給$rules.
27.png

最終函數的return將依賴rules,因此 rules ,因此rules,因此method不同返回也不同。當method為get時, method 為get 時,method為get時,rules 將為如下:
28.png

由于$item = str_replace(’|’, ‘/’, $url); 而 url=strreplace( url = str_replace(url=strreplace(depr, ‘|’, url);而這個 url); 而這個url);而這個url最初為該函數的參數,在App類routeCheck方法中調用
29.png

而這個$path = $request->path();

Request類的path方法實現如下

30.png

當is_null($this->path)時,通過pathinfo()函數來獲取

31.png

其中var_pathino 默認值為s

32.png

因此綜上,我們可以通過URL中s參數來設置App類routeCheck函數中的path,即Router類check函數中的 path ,即Router類check函數中的path,即Router類check函數中的url ,最終即能控制 Router類check函數中的item從而控制check函數真正return哪種結果。從而最終影響App類run方法的 item 從而控制check函數真正return哪種結果。從而最終影響App類run方法的item從而控制check函數真正return哪種結果。從而最終影響App類run方法的dispath值即調度信息。

由于$dispatch 會作為參數在exec中調用。

33.png


其中exec的實現如下:

34.png

exec會根據dispatch[‘type’]來決定實際執行的代碼。前面分析可知,我們需要觸發Request類中param函數的調用來完成對filter的覆蓋。此處顯而易見的是,當 dispatch[‘type’]來決定實際執行的代碼。前面分析可知,我們需要觸發Request類中param函數的調用來完成對filter的覆蓋。此處顯而易見的是,當dispatch[‘type’]來決定實際執行的代碼。前面分析可知,我們需要觸發Request類中param函數的調用來完成對filter的覆蓋。此處顯而易見的是,當dispatch[‘type’]為controller 和method時有直接的調用。當然其他的類型,例如當dispatch[‘type’]為function,調用了invokeFunction,而invokeFunction調用了bindParams函數,bindParams函數里存在對param函數的調用。總之,我們需要控制請求url中s的值完成設置不同的 dispatch[‘type’]為function,調用了invokeFunction,而invokeFunction調用了bindParams函數,bindParams函數里存在對param函數的調用。總之,我們需要控制請求url中s的值完成設置不同的dispatch[‘type’]為function,調用了invokeFunction,而invokeFunction調用了bindParams函數,bindParams函數里存在對param函數的調用。總之,我們需要控制請求url中s的值完成設置不同的method,最終讓routeCheck返回我們需要的$dispath即可。

例如我們控制url為 /public/index.php?s=captcha,同時post body為_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls -al則check函數最終會進入


35.png


然后checkRoute函數,由于rule為字符串,

36.png


因此最終會進

37.png


然后會進入 parseRule

38.png

然后會進入

39.png

最后返回$result. 因此最終$dispatch值為:

40.png

因而在傳入exec函數后,觸發Request類的param方法,最終覆蓋Request類的server變量,接著通過Request類的input方法,實現任意代碼執行。

41.png

修復建議:

git更新最新框架代碼 https://github.com/top-think/framework


轉載:https://blog.csdn.net/qq_29647709/article/details/86307859


正文部分到此結束

文章標簽: thinkphp漏洞

版權聲明:若無特殊注明,本文皆為( mOon )原創,轉載請保留文章出處。

也許喜歡: «【轉載】Thinkphp5.1 ~ 5.2 全版本代碼執行 | thinkphp v5.x 遠程代碼執行漏洞poc(附腳本)»

你腫么看?

你還可以輸入 250/250 個字

? 微笑 大笑 拽 大哭 親親 流汗 噴血 奸笑 囧 不爽 暈 示愛 害羞 吃驚 驚嘆 愛你 嚇死了 呵呵

評論信息框

這篇文章還沒有收到評論,趕緊來搶沙發吧~

?
?
河北11选5开奖