• 设为首页
  • 点击收藏
  • 手机APP
    手机扫一扫下载
    华域联盟APP
  • 关注官方公众号
    微信扫一扫关注
    华域联盟公众号

天融信关于ThinkPHP5.1框架分离RCE漏洞的深化剖析

[复制链接]
sterben 发表于 2019-4-27 18:45:19 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
. U3 F- W* R% J
0x00 前言
在前几个月,Thinkphp连续迸发了多个严重漏洞。由于框架应用的普遍性,漏洞影响十分大。为了之后更好地防御和应对此框架漏洞,阿尔法实验室对Thinkphp框架中止了细致地剖析,并在此分享给大家共同窗习。
本篇文章将从框架的流程讲起,让大家对Thinkphp有个大约的认识,接着讲述一些关于漏洞的相关学问,辅佐大家在剖析漏洞时能更好天文解漏洞原理,最后分离一个比较好的RCE漏洞(超链接)用一种反推的方式去中止剖析,让大家将漏洞和框架学问相融合。表现一个从学习框架到熟习漏洞原理的过程。

! s2 u( j. I2 @9 s+ N$ \; s0x01 框架引见
ThinkPHP是一个免费开源的,快速、简单的面向对象的轻量级PHP开发框架,是为了矫捷WEB应用开发和简化企业应用开发而降生的。ThinkPHP从降生以来不时秉承简约适用的设计准绳,在坚持出色的性能和至简的代码的同时,也注重易用性。

) D3 [7 f1 l) e) B0x02 环境搭建2.1 Thinkphp环境搭建
装置环境:Mac Os MAMP集成软件
PHP版本:5.6.10
Thinkphp版本:5.1.20
thinkphp装置包获取(Composer方式):
首先需求装置composer。
下载后,检查Composer能否能正常工作,只需求经过 php 来执行 PHAR:
若返回信息如上图,则证明胜利。
然后将composer.phar 移动到bin目录下并改名为composer
mv composer.phar /usr/local/bin/composer
Composer装置好之后,翻开命令行,切换到你的web根目录下面并执行下面的命令:
composer create-project topthink/think=5.1.20 tp5.1.20 –prefer-dist
若需求其他版本,可经过修正版本号下载。
考证能否能够正常运转,在阅读器中输入地址:
http://localhost/tp5.1.20/public/
假如呈现上图所示,那么祝贺你装置胜利。
2.2 IDE环境搭建及xdebug配置
PHP IDE工具有很多,我引荐PhpStorm,由于它支持一切PHP言语功用, 提供最优秀的代码补全、重构、实时错误预防、快速导航功用。
Xdebug
Xdebug是一个开放源代码的PHP程序调试器,能够用来跟踪,调试和剖析PHP程序的运转状况。在调试剖析代码时,xdebug十分好用。
下面我们说一下xdebug怎样配置(MAMP+PHPstrom)
1.下载装置xdebug扩展(MAMP自带 )。
2.翻开php.ini文件,添加xdebug相关配置
[xdebug]
xdebug.remote_enable = 1
xdebug.remote_handler = dbgp
xdebug.remote_host = 127.0.0.1
xdebug.remote_port = 9000 #端口号能够修正,避免抵触
xdebug.idekey = PHPSTROM
然后重启效劳器。
2.3.客户端phpstorm配置
2.3.1点击左上角phpstorm,选择preferences
2.3.2 Languages & Frameworks -> PHP,选择PHP版本号,选择PHP执行文件。
在选择PHP执行文件的时分,会显现 “Debugger:Xdebug”,假如没有的话,点击open翻开配置文件。
将注释去掉即可。
2.3.3配置php下的Debug
Port和配置文件中的xdebug.remote_port要分歧。
2.3.4配置Debug下的DBGp proxy
填写的内容和上面php.ini内的相对应。
2.3.5配置servers
点击+号添加
2.3.6配置debug方式
在Server下拉框中,选择我们在第4步设置的Server效劳称号,Browser选择你要运用的阅读器。一切配置到此终了。
2.4.xdebug运用
开启xdeubg监听
下一个断点,然后访问URL,胜利在断点处停下。

1 m8 L9 J( B0 r( o9 f% a0x03 框架流程浅析
我们先看入口文件index.php,入口文件十分简约,只需三行代码。
能够看到这里首先定义了一下命名空间,然后加载一些基础文件后,就开端执行应用。
第二行引入base.php基础文件,加载了Loader类,然后注册了一些机制–如自动加载功用、错误异常的机制、日志接口、注册类库别名。
这些机制中比较重要的一个是自动加载功用,系统会调用 Loader::register()办法注册自动加载,在这一步完成后,一切契合规范的类库(包括Composer依赖加载的第三方类库)都将自动加载。下面我细致引见下这个自动加载功用。
首先需求注册自动加载功用,注册主要由以下几部分组成:
1. 注册系统的自动加载办法 \think\Loader::autoload
2. 注册系统命名空间定义
3. 加载类库映射文件(假如存在)
4. 假如存在Composer装置,则注册Composer自动加载
5. 注册extend扩展目录
其中2.3.4.5是为自动加载时查找文件途径的时分做准备,提早将一些规则(类库映射、PSR-4、PSR-0)配置好。
然后再说下自动加载流程,看看程序是如何中止自动加载的?
spl_autoload_register()是个自动加载函数,当我们实例化一个未定义的类时就会触发此函数,然后再触发指定的办法,函数第一个参数就代表要触发的办法。
能够看到这里指定了think\Loader::autoload()这个办法。
首先会判别要实例化的$class类能否在之前注册的类库别名$classAlias中,假如在就返回,不在就进入findFile()办法查找文件,
这里将用多种方式中止查找,以类库映射、PSR-4自动加载检测、PSR-0自动加载检测的次第去查找(这些规则方式都是之前注册自动加载时配置好的),最后会返回类文件的途径,然后include包含,进而胜利加载并定义该类。
这就是自动加载办法,按需自动加载类,不需求逐一手动加载。在面向对象中这种办法经常运用,能够避免书写过多的援用文件,同时也使整个系统愈加灵活。
在加载完这些基础功用之后,程序就会开端执行应用,它首先会经过调用Container类里的静态办法get()去实例化app类,接着去调用app类中的run()办法。
在run()办法中,包含了应用执行的整个流程。
1.$this->initialize(),首先会初始化一些应用。例如:加载配置文件、设置途径环境变量和注册应用命名空间等等。
2. this->hook->listen(‘app_init’); 监听app_init应用初始化标签位。Thinkphp中有很多标签位置,也能够把这些标签位置称为钩子,在每个钩子处我们能够配置行为定义,浅显点讲,就是你能够往钩子里添加自己的业务逻辑,当程序执行到某些钩子位置时将自动触发你的业务逻辑。
3. 模块\入口绑定
中止一些绑定操作,这个需求配置才会执行。默许状况下,这两个判别条件均为false。
4. $this->hook->listen(‘app_dispatch’);监听app_dispatch应用调度标签位。和2中的标签位同理,一切标签位作用都是一样的,都是定义一些行为,只不过位置不同,定义的一些行为的作用也有所区别。
5. $dispatch = $this->routeCheck()->init(); 开端路由检测,检测的同时会对路由中止解析,应用array_shift函数逐一获取当前央求的相关信息(模块、控制器、操作等)。
6. $this->request->dispatch($dispatch);记载当前的调度信息,保管到request对象中。
7.记载路由和央求信息
假如配置开启了debug方式,会把当前的路由和央求信息记载到日志中。
8. $this->hook->listen(‘app_begin’); 监听app_begin(应用开端标签位)。
9.依据获取的调度信息执行路由调度
期间会调用Dispatch类中的exec()办法对获取到的调度信息中止路由调度并最终获取到输出数据$response。
然后将$response返回,最后调用Response类中send()办法,发送数据到客户端,将数据输出到阅读器页面上。
在应用的数据响应输出之后,系统会中止日志保管写入操作,并最终终了程序运转。

0 G" z/ \4 ^% S% K$ M9 {3 M0x04 漏洞准备学问
这部分主要解说与漏洞相关的学问点,有助于大家更好天文解漏洞构成缘由。
4.1命名空间特性
ThinkPHP5.1遵照PSR-4自动加载规范,只需求给类库正肯定义所在的命名空间,并且命名空间的途径与类库文件的目录分歧,那么就能够完成类的自动加载。
例如,\think\cache\driver\File类的定义为:
; G2 b) E( X, ~- w' u# ?
namespace think\cache\driver;class File{}
假如我们实例化该类的话,应该是:
$class = new \think\cache\driver\File();
系统会自动加载该类对应途径的类文件,其所在的途径是 thinkphp/library/think/cache/driver/File.php
可是为什么途径是在thinkphp/library/think下呢?这就要触及要另一个概念—根命名空间。
4.1.1 根命名空间
根命名空间是一个关键的概念,以上面的\think\cache\driver\File类为例,think就是一个根命名空间,其对应的初始命名空间目录就是系统的类库目录(thinkphp/library/think),我们能够简单的了解一个根命名空间对应了一个类库包。
系统内置的几个根命名空间(类库包)如下:
称号
描画
类库目录
think
系统中心类库
thinkphp/library/think
traits
系统Trait类库
thinkphp/library/traits
app
应用类库
Application
4.2 URL访问
在没有定义路由的状况下典型的URL访问规则(PATHINFO方式)是:
http://serverName/index.php(或者其它应用入口文件)/模块/控制器/操作/[参数名/参数值…]
假如不支持PATHINFO的效劳器能够运用兼容方式访问如下
http://serverName/index.php(或者其它应用入口文件)?s=/模块/控制器/操作/[参数名/参数值…]
什么是pathinfo方式?
我们都知道普通正常的访问应该是
http://serverName/index.php?m=module&c=controller&a=action&var1=vaule1&var2=vaule2
而pathinfo方式是这样的
http://serverName/index.php/module/controller/action/var1/vaule1/var2/value2
php中有一个全局变量$_SERVER[‘PATH_INFO’],我们能够经过它来获取index.php后面的内容。
什么是$_SERVER[‘PATH_INFO’]?
官方是这样定义它的:包含由客户端提供的、跟在真实脚本称号之后并且在查询语句(query string)之前的途径信息。
什么意义呢?简单来讲就是取得访问的文件和查询?之间的内容。
强调一点,在经过$_SERVER[‘PATH_INFO’]获取值时,系统会把’\’自动转换为’/’(这个特性我在Mac Os(MAMP)、Windows(phpstudy)、Linux(php+apache)环境及php5.x、7.x中中止了测试,都会自动转换,所以系统及版本之间应该不会有所差别)。
下面再分别引见下入口文件、模块、控制器、操作、参数名/参数值。
1.入口文件
文件地址:public\index.php
作用:担任处置央求
2.模块(以前台为例)
模块地址:application\index
作用:网站前台的相关部分
3.控制器
控制器目录:application\index\controller
作用:书写业务逻辑
4. 操作(办法)
在控制器中定义的办法
5. 参数名/参数值
办法中的参数及参数值
例如我们要访问index模块下的Test.php控制器文件中的hello()办法。
那么能够输入<http://serverName/index.php/index(模块)/Test(控制器)/hello(办法)/name(参数名)/world(参数值)
这样就访问到指定文件了。
另外再讲一下Thinkphp的几种传参方式及差别。
PATHINFO: index.php/index/Test/hello/name/world 只能以这种方式传参。
兼容方式:index.php?s=index/Test/hello/name/world
index.php?s=index/Test/hello&name=world
当我们有两个变量$a、$b时,在兼容方式下还能够将两者分离传参:
index.php?s=index/Test/hello/a/1&b=2
这时,我们知道了URL访问规则,当然也要了解下程序是怎样对URL解析处置,最后将结果输出到页面上的。
4.3 URL路由解析动态调试剖析
URL路由解析及页面输收工作能够分为5部分。
1. 路由定义:完成路由规则的定义和参数设置
2. 路由检测:检查当前的URL央求能否有匹配的路由
3. 路由解析:解析当前路由实践对应的操作。
4. 路由调度:执行路由解析的结果调度。
5. 响应输出及应用终了:将路由调度的结果数据输出至页面并终了程序运转。
我们经过动态调试来剖析,这样能分明明了的看到程序处置的整个流程,由于在Thinkphp中,配置不同其运转流程也会不同,所以我们采用默许配置来中止剖析,并且由于在程序运转过程中会呈现很多与之无关的流程,我也会将其略过。
4.3.1 路由定义
经过配置route目录下的文件对路由中止定义,这里我们采取默许的路由定义,就是不做任何路由映射。
4.3.2 路由检测
这部分内容主要是对当前的URL央求中止路由匹配。在路由匹配前先会获取URL中的pathinfo,然后再中止匹配,但假如没有定义路由,则会把当前pathinfo当作默许路由。
首先我们设置好IDE环境,并在路由检测功用处下断点。
然后我们央求上面提到的Test.php文件。
http://127.0.0.1/tp5.1.20/public/index.php/index/test/hello/name/world
我这里是以pathinfo方式央求的,但是其实以不同的方式在央求时,程序处置过程是有稍稍不同的,主要是在获取参数时不同。在后面的剖析中,我会中止阐明。
F7跟进routeCheck()办法
route_check_cache路由缓存默许是不开启的。
然后我们进入path()办法
继续跟进pathinfo()办法
这里会依据不同的央求方式获取当前URL的pathinfo信息,由于我们的央求方式是pathinfo,所以会调用$this->server(‘PATH_INFO’)去获取,获取之后会运用ltrim()函数对$pathinfo中止处置去掉左侧的’/’符号。Ps:假如以兼容方式央求,则会用$_GET办法获取。
然后返回赋值给$path并将该值带入check()办法对URL路由中止检测
这里主要是对我们定义的路由规则中止匹配,但是我们是以默许配置来运转程序的,没有定义路由规则,所以跳过中间关于路由检测匹配的过程,直接来看默许路由解析过程,运用默许路由对其中止解析。
4.3.3 路由解析
接下来将会对路由地址中止了解析分割、考证、格式处置及赋值进而获取到相应的模块、控制器、操作名。
new UrlDispatch() 对UrlDispatch(实践上是think\route\dispatch\Url这个类)实例化,由于Url没有结构函数,所以会直接跳到它的父类Dispatch的结构函数,把一些信息传送(包括路由)给Url类对象,这么做的目的是为了后面在调用Url类中办法时便当调用其值。
赋值完成后回到routeCheck()办法,将实例化后的Url对象赋给$dispatch并return返回。
返回后会调用Url类中的init()办法,将$dispatch对象中的得到$this->dispatch(路由)传入parseUrl()办法中,开端解析URL路由地址。
跟进parseUrl()办法
这里首先会进入parseUrlPath()办法,将路由中止解析分割。
运用”/”中止分割,拿到 [模块/控制器/操作/参数/参数值]。
紧接着运用array_shift()函数挨个从$path数组中取值对模块、控制器、操作、参数/参数值中止赋值。
接着将参数/参数值保管在了Request类中的Route变量中,并中止路由封装将赋值后的$module、$controller、$action存到route数组中,然后将$route返回赋值给$result变量。
new Module($this->request, $this->rule, $result),实例化Module类。
在Module类中也没有结构办法,会直接调用Dispatch父类的结构办法。
然后将传入的值都赋值给Module类对象自身$this。此时,封装好的路由$result赋值给了$this->dispatch,这么做的目的同样是为了后面在调用Module类中办法时便当调用其值。
实例化赋值后会调用Module类中的init()办法,对封装后的路由(模块、控制器、操作)中止考证及格式处置。
$result = $this->dispatch,首先将封装好的路由$this->dispatch数组赋给$result,接着会从$result数组中获取到了模块$module的值并对模块中止大小写转换和html标签处置,接下来会对模块值中止检测能否合规,若不合规,则会直接HttpException报错并终了程序运转。检测合格之后,会再从$result中获取控制器、操作名并处置,同时会将处置后值再次赋值给$this(Module类对象)去交流之前的值。
Ps:从$result中获取值时,程序采用了三元运算符中止判别,假如相关值为空会一概采用默许的值index。这就是为什么我们输入http://127.0.0.1/tp5.1.20/public/index.php在不指定模块、控制器、操作值时会跳到程序默许的index模块的index控制器的index操作中去。
此时调度信息(模块、控制器、操作)都曾经保管至Module类对象中,在之后的路由调度工作中会从中直接取出来用。
然后返回Module类对象$this,回到最开端的App类,赋值给$dispatch。
至此,路由解析工作终了,到此我们取得了模块、控制器、操作,这些值将用于接下来的路由调度。
接下来在路由调度前,需求另外阐明一些东西:路由解析完成后,假如debug配置为True,则会对路由和央求信息中止记载,这里有个很重要的点param()办法, 该办法的作用是获取变量参数。
在这里,在肯定了央求方式(GET)后,会将央求的参数中止兼并,分别从$_GET、$_POST(这里为空)和Request类的route变量中中止获取。然后存入Request类的param变量中,接着会对其中止过滤,但是由于没有指定过滤器,所以这里并不会中止过滤操作。
Ps:这里解释下为什么要分别从$_GET中和Request类的route变量中中止获取兼并。上面我们说过传参有三种办法。
1. index/Test/hello/name/world
2. index/Test/hello&name=world
3. index/Test/hello/a/1&b=2
当我们假如选择1中止央求时,在之前的路由检测和解析时,会将参数/参数值存入Request类中的route变量中。
而当我们假如选择2中止央求时,程序会将&前面的值剔除,留下&后面的参数/参数值,保管到$_GET中。
并且由于Thinkphp很灵活,我们还能够将这两种方式分离应用,如第3个。
这就是上面所说的在央求方式不同时,程序在处置传参时也会不同。
Ps:在debug未开启时,参数并不会取得,只是保管在route变量或$_GET[]中,不过没关系,由于在后面路由调度时还会调用一次param()办法。
继续调试,开端路由调度工作。
4.3.4 路由调度
这一部分将会对路由解析得到的结果(模块、控制器、操作)中止调度,得到数据结果。
这里首先创建了一个闭包函数,并作为参数传入了add办法()中。
将闭包函数注册为中间件,然后存入了$this->queue[‘route’]数组中。
然后会返回到App类, $response = $this->middleware->dispatch($this->request);执行middleware类中的dispatch()办法,开端调度中间件。
运用call_user_func()回调resolve()办法,
运用array_shift()函数将中间件(闭包函数)赋值给了$middleware,最后赋值给了$call变量。
当程序运转至call_user_func_array()函数继续回调,这个$call参数是刚刚那个闭包函数,所以这时就会调用之前App类中的闭包函数。
中间件的作用官方引见说主要是用于拦截或过滤应用的HTTP央求,并中止必要的业务处置。所以能够推测这里是为了调用闭包函数中的run()办法,中止路由调度业务。
然后在闭包函数内调用了Dispatch类中的run()办法,开端执行路由调度。
跟进exec()办法
能够看到,这里对我们要访问的控制器Test中止了实例化,我们来看下它的实例化过程。
将控制器类名$name和控制层$layer传入了parseModuleAndClass()办法,对模块和类名中止解析,获取类的命名空间途径。
在这里假如$name类中以反斜线\开端时就会直接将其作为类的命名空间途径。此时$name是test,明显不满足,所以会进入到else中,从request封装中获取模块的值$module,然后程序将模块$module、控制器类名$name、控制层$layer再传入parseClass()办法。
对$name中止了一些处置后赋值给$class,然后将$this->namespace、$module、$layer、$path、$class拼接在一同构成命名空间后返回。
到这我们就得到了控制器Test的命名空间途径,依据Thinkphp命名空间的特性,获取到命名空间途径就能够对其Test类中止加载。
F7继续调试,返回到了刚刚的controller()办法,开端加载Test类。
加载前,会先运用class_exists()函数检查Test类是承认义过,这时程序会调用自动加载功用去查找该类并加载。
加载后调用__get()办法内的make()办法去实例化Test类。
这里运用反射调用的办法对Test类中止了实例化。先用ReflectionClass创建了Test反射类,然后 return $reflect->newInstanceArgs($args); 返回了Test类的实例化对象。期间顺便判别了类中是承认义了__make办法、获取了却构函数中的绑定参数。
然后将实例化对象赋值赋给$object变量,接着返回又赋给$instance变量。
继续往下看
这里又创建了一个闭包函数作为中间件,过程和上面一样,最后应用call_user_func_array()回调函数去调用了闭包函数。
在这个闭包函数内,主要做了4步。
1.运用了is_callable()函数对操作办法和实例对象作了考证,考证操作办法能否能用中止调用。
2.new ReflectionMethod()创建了Test的反射类$reflect。
3.紧接着由于url_param_type默许为0,所以会调用param()办法去央求变量,但是前面debug开启时曾经获取到了并保管进了Request类对象中的param变量,所以此时只是从中将值取出来赋予$var变量。
4.调用invokeReflectMethod()办法,并将Test实例化对象$instance、反射类$reflect、央求参数$vars传入。
这里调用了bindParams()办法对$var参数数组中止处置,获取了Test反射类的绑定参数,获取到后将$args传入invokeArgs()办法,中止反射执行。
然后程序就胜利运转到了我们访问的文件(Test)。
运转之后返回数据结果,到这里路由调度的任务也就终了了,剩下的任务就是响应输出了,将得到数据结果输出到阅读器页面上。
4.3.5 响应输出及应用终了
这一小节会对之前得到的数据结果中止响应输出并在输出之后中止扫尾工作终了应用程序运转。在响应输出之前首先会构建好响应对象,将相关输出的内容存进Response对象,然后调用Response::send()办法将最终的应用返回的数据输出到页面。
继续调试,来到autoResponse()办法,这个办法程序会来回调用两次,第一次主要是为了创建响应对象,第二次是中止考证。我们先来看第一次,
此时$data不是Response类的实例化对象,跳到了elseif分支中,调用Response类中的create()办法去获取响应输出的相关数据,构建Response对象。
执行new static($data, $code, $header, $options);实例化自身Response类,调用__construct()结构办法。
能够看到这里将输出内容、页面的输出类型、响应状态码等数据都传送给了Response类对象,然后返回,回到刚才autoResponse()办法中
到此确认了细致的输出数据,其中包含了输出的内容、类型、状态码等。
上面主要做的就是构建响应对象,将要输出的数据全部封装到Response对象中,用于接下来的响应输出。
继续调试,会返回到之前Dispatch类中的run()办法中去,并将$response实例对象赋给$data。
紧接着会中止autoResponse()办法的第二次调用,同时将$data传入,中止考证。
这回$data是Response类的实例化对象,所以将$data赋给了$response后返回。
然后就开端调用Response类中send()办法,向阅读器页面保送数据。
这里依次向阅读器发送了状态码、header头信息以及得到的内容结果。
输出终了后,跳到了appShutdown()办法,保管日志并终了了整个程序运转。
4.4 流程总结
上面经过动态调试一步一步地对URL解析的过程中止了剖析,往常我们来简单总结下其过程:
首先发起央求->开端路由检测->获取pathinfo信息->路由匹配->开端路由解析->取得模块、控制器、操作办法调度信息->开端路由调度->解析模块和类名->组建命名空间>查找并加载类->实例化控制器并调用操作办法->构建响应对象->响应输出->日志保管->程序运转终了
# b4 |5 h, a# U
0x05 漏洞剖析及POC构建
置信大家在看了上述内容后,对Thinkphp这个框架应该有所了解了。接下来,我们分离最近一个思绪比较好的RCE漏洞再来看下。为了更好天文解漏洞,我经过以POC结构为导引的方式对漏洞中止了剖析,同时以下内容也表现了我在剖析漏洞时的想法及思绪。
在/thinkphp/library/think/Container.php 中340行:
在Container类中有个call_user_func_array()回调函数,经常做代码审计的小同伴都知道,这个函数十分风险,只需能控制$function和$args,就能构成代码执行漏洞
如何应用此函数?
经过上面的URL路由剖析,我们知道Thinkphp可由外界直接控制模块名、类名和其中的办法名以及参数/参数值,那么我们是不是能够将程序运转的方向引导至这里来。
如何引导呢?
要调用类肯定需求先将类实例化,类的实例化首先需求获取到模块、类名,然后解析模块和类名去组成命名空间,再依据命名空间的特性去自动加载类,然后才会实例化类和调用类中的办法。
我们先对比之前正常的URL试着构建下POC。
http://127.0.0.1/tp5.1.20/public/index.php/index/test/hello/name/world
http://127.0.0.1/tp5.1.20/public/index.php/模块?/Container/invokefunction
构建过程中,会发现几个问题。
1.模块应该指定什么,由于Container类并不在模块内。
2.模块和类没有联络,那么组建的命名空间,程序如何才干加载到类。
先别着急,我们先从最开端的相关值获取来看看(获取到模块、类名),此过程对应上面第四大节中的4.3.3路由解析中。
app_multi_module为true,所以肯定进入if流程,获取了$module、$bind、$available的值。在红色框处假如不为true,则会直接报错终了运转,所以此处需求$module和$available都为True。而$available的值一开端就被定义为False,只需在后续的3个if条件中才会变为true。
来看下这3个if条件,在默许配置下,由于没有路由绑定,所以$bind为null。而empty_module默许模块也没有定义。所以第三个也不满足,那么只能寄予于第二个了。
在第二个中,1是判别$module能否在遏止访问模块的列表中,2是判别能否存在这个模块。
所以,这就请求我们在结构POC时,需求保证模块名必需真实存在并且不能在禁用列表中。在默许配置中,我们能够指定index默许模块,但是在实践过程中,index模块并不一定存在,所以就需求大家去猜测或暴力破解了,不过普通模块名普通都很容易猜解。
获取到模块、类名后,就是对其中止解析组成命名空间了。此过程对应上面第四大节中的4.3.4路由调度中。
这里首先对$name(类名)中止判别,当$name以反斜线\开端时会直接将其作为类的命名空间途径。看到这里然后回想一下之前的剖析,我们会发现这种命名空间途径获取的方式和之前获取的方式不一样(之前是进入了parseClass办法对模块、类名等中止拼接),而且这种获取是不需求和模块有联络的,所以我们想是不是能够直接将类名以命名空间的方式传入,然后再以命名空间的特性去自动加载类?同时这样也脱离了模块这个条件的约束。
那我们往常再试着结构下POC:
http://127.0.0.1/tp5.1.20/public/index.php/index/think\Container/invokefunction
剩下就是指定$function参数和$var参数值了,依据传参特性,我们来结构下。
http://127.0.0.1/tp5.1.20/public/index.php/index/think\Container/invokefunction/function/call_user_func_array/vars[0]/phpinfo/vars[1][]/1
结构出来应该是这样的,但是由于在pathinfo方式下,$_SERVER[‘PATH_INFO’]会自动将URL中的“\”交流为“/”,招致破坏掉命名空间格式,所以我们采用兼容方式。
默许配置中,var_pathinfo默许为s,所以我们能够用$_GET[‘s’]来传送路由信息。
http://127.0.0.1/tp5.1.20/public/index.php?s=index/think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
另外由于App类继承于Container类,所以POC也能够写成:
http://127.0.0.1/tp5.1.20/public/index.php?s=index/think\App/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
漏洞应用扩展化
1.以反斜线\开端时直接将其作为类的命名空间途径。
2.thinkphp命名空间自动加载类的特性。
由于这两点,就会构成我们能够调用thinkphp框架中的恣意类。所以在框架中,假如其他类办法中也有相似于invokefunction()办法中这样的风险函数,我们就能够随意应用。
例如:Request类中的input办法中就有一样的风险函数。
跟入filterValue()办法
POC:
http://127.0.0.1/tp5.1.20/public/index.php?s=index/\think\Request/input&filter=phpinfo&data=1
+ U; z. E7 ]' ^  i) E; l5 D
0x05 结语
写这篇文章的其中一个目的是想让大家知道,经过框架剖析,我们不只能够在剖析漏洞时变得愈加容易,同时也能够对漏洞原理有一个更深的了解。所以,当我们在剖析一个漏洞时,假如很费劲或者总有点小中央想不通的时分,不如从它的框架着手,一步一步来,或许在你学习完后就会豁然开朗,亦或者在过程中你就会明白为什么。
天融信阿尔法实验室成立于2011年,不时以来,阿尔法实验室秉承“攻防一体”的理念,集聚众多专业技术研讨人员,从事攻防技术研讨,在安全范畴前瞻性技术研讨方向上不时前行。作为天融信的安全产品和效劳支撑团队,阿尔法实验室精深的专业技术水平、丰厚的排异阅历,为天融信产品的研发和升级、承担国度严重安全项目和客户效劳提供强有力的技术支撑。

点评

海!外直播 t.cn/RxBC0cw 禁闻视频 t.cn/RJJZmvl 这台湾的蔡英文把执政党赶下台在赵国是推翻国度政权罪的行为,看来全国媒体都要对台湾大选和蔡英文要好好批判一番...呵呵   发表于 2019-4-28 05:36
You look down on me today, tomorrow I can't let you have been

精彩评论1

关注0

粉丝6

帖子3328

发布主题
阅读排行 更多
广告位

扫描微信二维码

关注华域联盟公众号

随时了解更新最新资讯

admin@cnhackhy.com

在线客服(服务时间 9:00~18:00)

在线QQ客服

Powered by cnhackhy! © 2015-2019