ThinkPHP多语言文件包含漏洞分析
2023-12-27 17:8:8 Author: 编码安全研究(查看原文) 阅读量:27 收藏

一、漏洞概述  

ThinkPHP是一个开源轻量级PHP框架,其6.0.13及以前版本存在一个文件包含漏洞。简要来讲,在多语言特性开启的条件下,远程攻击者可通过控制传入参数来实现任意PHP文件包含。默认条件下,该漏洞只能包含本地PHP文件;但在开启了register_argc_argv且安装了pcel/pear的环境下,攻击者可通过 get、header、cookie 等传入参数,实现目录穿越包含pearcmd 。最终,通过pearcmd实现写入webshell。该漏洞影响版本为:v6.0.1~v6.0.13、v5.0.x、v5.1.x。

二、漏洞分析  

本文的分析均使用6.0.12版本。该漏洞要成功被利用需要满足三个条件:
  • ThinkPHP开启了多语言特性

  • php.ini开启了register_argc_argv

  • 安装了pcel/pear

在app/middleware.php中开启多语言功能:
在Lang.php 193行处设置断点,发送如下报文:
GET /?lang=../../../../../public/index HTTP/1.1Host: localhost:80Cache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en;q=0.8Cookie: think_lang=zh-cnConnection: close
观察断点处的文件包含代码,file参数的值已经成功拼接了我们传入的../../../../../ public/index。
跟踪调用栈来查看漏洞的触发过程,由于系统开启了多语言功能,发送的请求将会进入/src/think/middleware/LoadLangPack.php的handle方法。
handle方法中调用detect方法,并将其返回的值赋值给$langset变量,然后判断langset是否为默认值,不是则带入到switchLangset方法。跟进detect方法,langSet初始为空,然后从get/header/cookie中判断是否存在对应的参数名,若有则赋值给langSet变量。get对应lang,header对应think-lang,cookie对应think_lang。
此处的93行有一个allow_lang_list,看似有对langSet的判断逻辑,但搜索allow_lang_list发现其默认为空。这意味着此处其实没有任何过滤,直接将获得的langSet值传递给range变量并返回到上层函数。
继续跟进switchlangset方法,其调用load。
Load方法里判断$name是否为文件,若是则调用parse方法,parse方法中最终漏洞触发点include $file。
显然,该漏洞只能实现php文件的包含。为了利用该漏洞,可以结合pearcmd的trick来实现RCE。
pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。但是,在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php。
Pear的pearcmd.php文件可以获取命令行参数并执行对应Commands,运行该文件可以看到它的功能。
查看pearcmd.php,argv从$_SERVER['argv']中获得。
PEAR_Command::setFrontendType('CLI');$all_commands = PEAR_Command::getCommands();
// remove this next part when we stop supporting that crap-ass PHP 4.2if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) { echo 'ERROR: either use the CLI php executable, ' . 'or set register_argc_argv=On in php.ini'; exit(1);}
$argv = Console_Getopt::readPHPArgv();// fix CGI sapi oddity - the -- in pear.bat/pear is not removedif (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') { unset($argv[1]); $argv = array_values($argv);}
当php.ini开启register_argc_argv=On,用户输入可以赋值给$_SERVER['argv']:
因此,攻击者可从web访问pearcmd的命令行功能,并传入命令行功能的参数。

三、漏洞复现  

发送如下报文即在根目录创建test.php文件,内容含传入的<?=phpinfo(); ?>。
访问test.php,可以看到已经成功执行phpinfo。
发送如下报文即下载远端phpinfo.php到根目录,虽提示phpinfo.php不是tgz file,但仍可被成功下载。
访问phpinfo.php。

四、漏洞修复  

漏洞修复在官方的commit:https://github.com/top-think/framework/commit/c4acb8b4001b98a0078eda25840d33e295a7f099。
核心是增加了校验,即如传入参数不符合正则表达式,最终被重置为默认的zh-cn。

参考链接:

[1] https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp
[2] https://y4tacker.github.io/2022/06/19/year/2022/6/%E5%85%B3%E4%BA%8Epearcmd%E5%88%A9%E7%94%A8%E6%80%BB%E7%BB%93/
[3] https://tttang.com/archive/1865/#toc__6
---END---
推荐↓↓↓

文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2NDY1MDc2Mg==&mid=2247504223&idx=2&sn=50a3ac7e30a202c68b13ce384bbb2d48&chksm=cffa5fb689ded5459093bf18f55ba34fa6d38e512373144e95f2c06e0a93e49b1f33f77cc306&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh