ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE

这篇具有很好参考价值的文章主要介绍了ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本次我们继续以漏洞挖掘者的视角,来分析thinkphp的RCE

敏感函数发现

在调用入口函数:/ThinkPHP_full_v5.0.22/public/index.php 时
发现了框架底层调用了\thinkphp\library\think\App.php的app类中的incokeMethod方法

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 注意传递的参数,ReflectionMethod接受的参数。如果是数组的形式, 那么参数1是这个类的object,参数2是object的方法。如此就可以调用到index类的index方法
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 下面是整个调用链

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

那么现在思考incokeMethod方法接受的参数是否为为一个可控变量呢,如果可控是不是就意味着我们可以执行任意类中的任意funtion了。这里我们还不能直接调用system,exec这些函数,因为它们不属于任何类,它是一个全局函数。尝试找一下类中的敏感函数

敏感函数调用

恰好的是,就在app类中存在一个敏感的函数invokeFunction

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

下面给出一个ReflectionFunction的反射示例

function sum($a, $b) {
    return $a + $b;
}

class Example {
    public static function bindParams($reflect, $vars) {
        $args = [];
        foreach ($reflect->getParameters() as $param) {
            $name = $param->getName();
            if (isset($vars[$name])) {
                $args[] = $vars[$name];
            } else {
                $args[] = $param->getDefaultValue();
            }
        }
        return $args;
    }
    
    public static function executeFunction($function, $vars) {
        $reflect = new \ReflectionFunction($function);
        $args = self::bindParams($reflect, $vars);
        
        // 记录执行信息
        self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info');
        
        return $reflect->invokeArgs($args);
    }
}

$vars = array(
    'a' => 5,
    'b' => 10,
);

$result = Example::executeFunction('sum', $vars);
echo $result; // 输出 15

在这个示例中ReflectionFunction函数没有牵扯到类,sum是一个全局函数。如此我们现在可以尝试反射条用system函数了,

下面是经过我测试的反射调用exec,它可以弹出计算机

<?php
$reflection = new ReflectionFunction('exec');
echo $reflection->getName() . "\n";  // 输出函数名 
$params = $reflection->getParameters();
foreach ($params as $param) {
    echo "-----"."参数:" . $param->getName() . "\n";
}

$args = [calc];
$result = $reflection->invokeArgs($args);
//echo "结果:" . $result . "\n";
?>

按照这个思路,我就在invokeFunction中让参数$function='exec' 让参数$vars = [calc],就可以执行命令了,不过在此之前看看它的bindParams逻辑

敏感函数绕过

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 跟进getParameters 继续看调用逻辑
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 看到这里原有的设定就遇到了问题,因为这个参数绑定会遍历函数的参数名,像我们之前想调用的exec函数,其函数原型为

exec(string $command, array &$output = null, int &$return_var = null): string|false

 $reflect->getParameters() as $param 一定会依次得到command  - output -  return_var
如还想调用exec,那参数vars 必须写上如下形式

$reflection = new ReflectionFunction('exec');
$vars = [calc,null,null];
$result = $reflection->invokeArgs($vars);

以上本地测试还行,php正确接解析了null 然而在web中我们传递的参数大多为字符串,除非后端单独处理,否则我们想传递一个null类型的参数,几乎是不可能的,只能换其他的调用函数了,要执行系统命令,还要避开参数null这样的类型。system函数就不行有null类型

有没有我们需要的这严的函数呢 !还真有一个,它就是call_user_func_array函数

它的原型为

call_user_func_array(callable $callback, array $param_arr): mixed

 再次本地测试

<?php

$reflection = new ReflectionFunction('call_user_func_array');
$vars = [exec,[calc]];
var_dump($vars);
$result = $reflection->invokeArgs($vars);

?>

如此我用参数绑定的机制把exec 绑定在参数callback 把[calc]绑定在param_arr,通过$reflection->invokeArgs我们成功调用了calc (反射类似调用了call_user_func_array('exe',[calc])),null的问题得到完美解决。

回顾一下rce成立的条件
invokeMethod调用invokeFunction 
invokeFunction调用call_user_func_array
call_user_func_array调用exec

代码大致长这样样子

invokeMethod([对象,方法],参数1)
--------这里的对象对象要app类对象方法是invokeFunction 
-------参数1为一个数组[call_user_func_array,参数2]
这样就可调用call_user_func_array,我们将参数设置为[exec,[calc]] 就可以执行任意命令了。

接下来把重点放到参数可控上,如果我们使参数可控那么RCE漏洞就成立了 

参数可控分析

首先看调用了invokeMethod的地方

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

该段代码位于app类的module方法中,

看一看call是怎么来的

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

$call是一个数组符合我们的预期,我们要把这个instance换成app对象,action换成invokeFunction。

继续向上分析 instance怎么得来的

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 继续分析controller怎么得到的

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 这个result参数参数得来的,那就让result为一个数组  让其$result[1]=app类路径。

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 如此参数$call的instance就解决了,接下来看action

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 全局搜索action_suffix发现这个值为空,不影响action,继续分析actionName

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

actionName的是result数组索引2获取的,那好在传递module函数参数时,让result为一个数组  让其$result[2]=invokeFunction

如此$call的问题全部解决,看看剩下的$vars

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

这里放上找vars是空的啊,不要着急。既然vars向上找没有找到,那么在想向下仔细找找,是不是在调用的过程中被赋值。

向下走到invokeMethod方法中
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

bindParams对vars进行了处理 跟进去看看

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

全局搜索url_param_type,发现它为0 ,也就说我们会走到param方法,执行完毕后更新vars值

之后返回给变量$args。

进入param中

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

request对象中的param成员,存储的是我们get参数的内容param可以写成我们构造的[call_user_func_array,参数2],它之后被返回了
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

在input方法中他会过滤一些值

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

之后返回data这个数组

 ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 好!现在根据我们的猜想get传参function=call_user_func_array&vars[0]=exec&vars[1][]=calc
就可以上让request对象的param成员存储[call_user_func_array,参数2] 参数2是[exec,[calc]]

由此在调用invokeFunction之前$args就准备好了。 $vars的问题解决了

现在目光继续放在module 这个函数,根据之前分析的让result为一个数组  让其$result[1]=app类路径。让其$result[2]=invokeFunction

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

继续向上分析,exec会根据dispatch的type不同而调用module函数

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

传参是dispatch的module重点关注它

一样的思路,在app类的run方法中最后会执行exec方法

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

执行exec方法之前,它会初始dispatch 这个对象

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 我们跟进routecheck方法,重点关注成员module

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

result为我们准备返回值,request->path将url中?s= 之后的内容取了出来

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

这里注解提示了我们路由访问的规则,可以参考下,

这里depr="/"后面的controller_auto_search 是false

进入parseurl分析,在parseurl 最后的返回中出现了module成员 这正是我们想要的

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

重点分析route是怎么出来的

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

其实这里我们就可以根据手册说明

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

尝试把controller修改为我们的app类地址,action设置为 invokeFunction,module可以设置成index,如果没有达到预期可以在调试

那么app的类地址是什么呢, 如下写成think\app即可

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

下面就是调试版

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

跟如parseurlpath方法 
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

 这里的返回值是准备好的以“/”切分的数组,之后分别赋给module controller action

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

如此参数的确可控,RCE漏洞所有条件成立。poc打出,成弹出计算机。
ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE,PHP代码审计,开发语言,web安全,php,安全

本次漏洞研究结束

赋值poc

127.0.0.1/ThinkPHP_full_v5.0.22/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=exec&vars[1][]=calc文章来源地址https://www.toymoban.com/news/detail-818849.html

到了这里,关于ThinkPHP5.0.0~5.0.23路由控制不严谨导致的RCE的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • thinkphp6和thinkphp5有什么区别

    Thinkphp6.0完全开发手册 采用PHP7强类型(严格模式) tp5 环境要求PHP = 5.4.0 ThinkPHP6.0的环境要求 PHP = 7.2.5 6.0版本开始,必须通过Composer方式安装和更新,所以你无法通过Git下载安装。 支持更多的PSR规范 V6.0.10版本开始 支持 psr7 response 多应用支持 tp5默认使用多应用模式部署 tp6 安

    2024年02月06日
    浏览(10)
  • thinkPhp5返回某些指定字段

    thinkPhp5返回某些指定字段

    或者指定要的字段的数组  查询符合条件的多条数据  

    2024年02月09日
    浏览(16)
  • ThinkPHP5远程命令执行漏洞

    ThinkPHP5远程命令执行漏洞

    ThinkPHP是一个快速、兼容而且简单的轻量级国产 PHP开发框架 ,诞生于2006年初,原名FCS,2007年元旦正式更名为ThinkPHP,遵循Apache2开源协议发布,使用面向对象的开发结构和 MVC模式 ,从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式。 由于th

    2024年02月11日
    浏览(10)
  • thinkphp5拦截验证token

    写一个BaseController 类 基本思路: 1、继承一个公共基类,将验证相关代码放在基类 2、根据 孩子类下的notNeedToken 来决定是否进行验证 3、验证失败后,直接响应回来 这里需要封装一个主要代码: 如果直接return 返回,是不会终止执行的,而是会继续执行到指定的控制器,所以

    2024年02月15日
    浏览(13)
  • Thinkphp5.x全漏洞复现分析

    Thinkphp5.x全漏洞复现分析

    我们可以把namespace理解为一个单独的空间,事实上它也就是一个空间而已,子命名空间那就是空间里再划分几个小空间,举个例子: 当有多个子命名空间有相同名称类时,不指定使用哪个命名空间的情况下取最后定义的命名空间中的类,比如上面的 dog 取的时 dogC 中的类,在

    2024年04月22日
    浏览(13)
  • ThinkPHP5系列远程代码执行漏洞复现(详细)

    ThinkPHP5系列远程代码执行漏洞复现(详细)

    ThinkPHP是一款运用极广的PHP开发框架。其版本5中,由于框架对控制器名没有进行足够的检测,会导致在没有开启强制路由的情况下可执行任意方法,从而导致远程命令执行漏洞。 漏洞危害 启动环境 切换到/thinkphp/5.0.23-rce# 目录下 将version改为2,保存并退出 接着执行 此时环境

    2024年02月12日
    浏览(14)
  • ThinkPHP5.0.21远程命令执行漏洞

    ThinkPHP5.0.21远程命令执行漏洞

    漏洞出现的背景 : ThinkPHP是⼀款运⽤极⼴的PHP开发框架。 其5.0.23以前的版本中,获取method的⽅法中没有正确处理⽅法名, 导致攻击者可以调⽤Request类任意⽅法并构造利⽤链,从⽽导致远程代码执⾏漏洞。 由于ThinkPHP5框架对控制器名没有进⾏⾜够的安全检测,导致在没有开

    2024年02月04日
    浏览(12)
  • 知识笔记(九十)———ThinkPHP5中时间查询的方法

    使用 where 方法 where 方法支持时间比较,例如: 第三个参数可以传入任何有效的时间表达式,会自动识别你的时间字段类型,支持的时间类型包括 timestamps 、 datetime 、 date 和 int 。 使用 whereTime 方法 whereTime 方法提供了日期和时间字段的快捷查询,示例如下: 还提供了更方便

    2024年01月21日
    浏览(12)
  • thinkphp5.0.24反序列化漏洞分析

    thinkphp5.0.24反序列化漏洞分析

    thinkphp5框架: thinkphp5的入口文件在 publicindex.php ,访问 反序列化起点 写一个反序列化入口点 全局搜索 __destruct() 函数 thinkphp_5.0.24thinkphplibrarythinkprocesspipesWindows.php 中的 __destruct() 函数,调用了removeFiles() 跟进removeFiles(),第163行的file_exists可以触发 __toString 方法 全局搜索

    2023年04月08日
    浏览(18)
  • 【备忘】thinkphp5.1之websocket长连接框架使用流程简述

    前言 本文纯属经验备注,有许多地方未进行测试,请勿照搬,仅供参考。 之前专门花了几天时间测试了websocket,当时只记得踩了许多坑,但是没有对测试流程进行记录,导致长时间未使用从而无从下手。 今天就简单记录一下使用流程。 环境介绍 php7.4+ linux nginx thinkphp5.1 wo

    2024年01月23日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包