目录

1. 简介

2. 影响范围

3. 环境搭建

3.1 安装Composer

4. 漏洞复现

4.1 列举目录

4.2 任意文件读取


1. 简介

ThinkAdmin 是基于 ThinkPHP后台开发框架,在ThinkAdmin v6版本存在路径遍历漏洞,该漏洞可以利用GET请求编码参数读取远程服务器上任意文件。

2. 影响范围

Thinkadmin ≤ 2020.08.03.01

v5(任意文件读取)

v6(列目录,任意文件读取)

3. 环境搭建

ThinkAdmin 源码仓库:https://github.com/zoujingli/ThinkAdmin

详细安装过程请查看官方手册,环境搭建过程均来自手册。

靶机   winserver 2008

ThinkAdmin版本小于 ≤ 2020.08.03.01

PHP >= 7.0.1

据手册说明6.0版本后,必须通过Composer方式安装和更新,所以无法通过Git安装。

3.1 安装Composer

如果还没有安装Composer,在 Linux 和 Mac OS X 中运行如下命令即可。

curl  -sS  https://getcomposer.org/installer  |  php

mv  composer.phar  /usr/local/bin/composer

如果是Windows环境,请先下载 Composer-Setup.exe 。至于想了解Composer是什么请自行百度,查阅相关手册。

然后双击安装包,一直默认就行了,根据官网的建议使用国内的镜像。

打开命令行窗口(windows用户)或者 Linux 控制台执行如下命令

composer  config  -g  repo.packagist  composer  https://mirrors.aliyun.com/composer/

如果是第一次安装,在命令行内,切换到指定的网站根目录下面执行命令:

composer  create-project  topthink/think thinkadmin

thinkadmin 是目录可以任意更改

如果是已经安装过了,执行以下命令更新

composer update topthink/framework

测试运行命令

进入命令行,执行命令 php think run

php think run -p 80 # 可以指定端口

在浏览器中输入地址访问测试。

到这儿整个靶机环境就算搭建完成

总结:使用Composer安装会有一个问题,关于Composer的详细情况请百度官方文档查看相关内容,但是要清除这个工具是一个PHP依赖管理工具,根据官方的安装文档执行命令后只需要执行一遍,如果需要重新执行安装需要彻底删除相关依赖库。个人建议直接下载源码安装,因为就算你安装了也需要自行导入数据库,本人开始以为是全自动的,浏览器有些不好用,使用抓包工具才发现是没有导入数据库和配置数据库配置文件。

4. 漏洞复现

互联网上应该找不到存在漏洞的版本了,所有的链接都是指向官方的代码仓库,下载的源码安装,本人未能成功利用本地环境复现成功。但是这怎么能难道足智多谋的本人呢?最终还没找到了一些还未及时修复的站。

使用 fofa 网络空间搜索引擎,搜索语法如下:

app="ThinkAdmin"

能获得很多结果,但是并不是所有的都存在相关漏洞的,具体的操作请自行发掘。

4.1 列举目录

查看版本url

https://xx.xx.xx.xx/admin/login.html?s=admin/api.Update/version

文件 app/admin/controller/api/Update.php存在3个function,都是不用登录认证就可以使用的,引用列表如下:

namespace app\admin\controller\api;use think\admin\Controller;
use think\admin\service\InstallService;
use think\admin\service\ModuleService;

version()可以获取到当前版本:2020.08.03.01,小于这个版本都有可能存在该漏洞。

在下面的代码里发现直接使用POST方法把rules和ignore参数传给 InstallService::instance()->getList() ,根据上面的use引用知道文件路径:

vendor/zoujingli/think-library/src/service/InstallService.php

/**
* 读取文件列表
*/
public function node()
{$this->success('获取文件列表成功!', InstallService::instance()->getList(json_decode($this->request->post('rules', '[]', ''), true),json_decode($this->request->post('ignore', '[]', ''), true)));
}

跟踪getList,会利用_scanList()去遍历$rules数组。

/*** 获取文件信息列表* @param array $rules 文件规则* @param array $ignore 忽略规则* @param array $data 扫描结果列表* @return array*/
public function getList(array $rules, array $ignore = [], array $data = []): array
{// 扫描规则文件foreach ($rules as $key => $rule) {$name = strtr(trim($rule, '\\/'), '\\', '/');$data = array_merge($data, $this->_scanList($this->root . $name));}// 清除忽略文件foreach ($data as $key => $item) foreach ($ignore as $ign) {if (stripos($item['name'], $ign) === 0) unset($data[$key]);}// 返回文件数据return ['rules' => $rules, 'ignore' => $ignore, 'list' => $data];
}

调用 scanDirectory()去递归遍历目录下的文件,最后在透过 _getInfo()去获取文件名与哈希,由下面的代码可知程序没有进行任何验证,攻击者可以在未授权的情况下读取服务器文件列表。

/*** 获取目录文件列表* @param string $path 待扫描目录* @param array $data 扫描结果* @return array*/
private function _scanList($path, $data = []): array
{foreach (NodeService::instance()->scanDirectory($path, [], null) as $file) {$data[] = $this->_getInfo(strtr($file, '\\', '/'));}return $data;
}
/*** 获取所有PHP文件列表* @param string $path 扫描目录* @param array $data 额外数据* @param string $ext 文件后缀* @return array*/
public function scanDirectory($path, $data = [], $ext = 'php')
{if (file_exists($path)) if (is_file($path)) $data[] = $path;elseif (is_dir($path)) foreach (scandir($path) as $item) if ($item[0] !== '.') {$realpath = rtrim($path, '\\/') . DIRECTORY_SEPARATOR . $item;if (is_readable($realpath)) if (is_dir($realpath)) {$data = $this->scanDirectory($realpath, $data, $ext);} elseif (is_file($realpath) && (is_null($ext) || pathinfo($realpath, 4) === $ext)) {$data[] = strtr($realpath, '\\', '/');}}return $data;
}
/*** 获取指定文件信息* @param string $path 文件路径* @return array*/
private function _getInfo($path): array
{return ['name' => str_replace($this->root, '', $path),'hash' => md5(preg_replace('/\s+/', '', file_get_contents($path))),];
}

利用以下payload读取网站根目录

http://xxxxx/ThinkAdmin/public/admin.html?s=admin/api.Update/node

利用POST方法控制$rules参数

4.2 任意文件读取

/*** 读取文件内容*/
public function get()
{$filename = decode(input('encode', '0'));if (!ModuleService::instance()->checkAllowDownload($filename)) {$this->error('下载的文件不在认证规则中!');}if (file_exists($realname = $this->app->getRootPath() . $filename)) {$this->success('读取文件内容成功!', ['content' => base64_encode(file_get_contents($realname)),]);} else {$this->error('读取文件内容失败!');}
}

首先从get读取 encode 参数并使用decode()解码:

/*** 解密 UTF8 字符串* @param string $content* @return string*/
function decode($content)
{$chars = '';foreach (str_split($content, 2) as $char) {$chars .= chr(intval(base_convert($char, 36, 10)));}return iconv('GBK//TRANSLIT', 'UTF-8', $chars);
}

解密utf8字符串,刚好上面有个加密utf8字符串的encode(),攻击时直接调用就可以了。

/*** 加密 UTF8 字符串* @param string $content* @return string*/
function encode($content)
{[$chars, $length] = ['', strlen($string = iconv('UTF-8', 'GBK//TRANSLIT', $content))];for ($i = 0; $i < $length; $i++) $chars .= str_pad(base_convert(ord($string[$i]), 10, 36), 2, 0, 0);return $chars;
}

跟进ModuleService::instance()->checkAllowDownload(),文件路径 vendor/zoujingli/think-library/src/service/ModuleService.php :

/*** 检查文件是否可下载* @param string $name 文件名称* @return boolean*/
public function checkAllowDownload($name): bool
{// 禁止下载数据库配置文件if (stripos($name, 'database.php') !== false) {return false;}// 检查允许下载的文件规则foreach ($this->getAllowDownloadRule() as $rule) {if (stripos($name, $rule) !== false) return true;}// 不在允许下载的文件规则return false;
}

代码是禁止下载数据库配置文件database.php,查看允许下载的文件规则 getAllowDownloadRule():

/*** 获取允许下载的规则* @return array*/
public function getAllowDownloadRule(): array
{$data = $this->app->cache->get('moduleAllowRule', []);if (is_array($data) && count($data) > 0) return $data;$data = ['config', 'public/static', 'public/router.php', 'public/index.php'];foreach (array_keys($this->getModules()) as $name) $data[] = "app/{$name}";$this->app->cache->set('moduleAllowRule', $data, 30);return $data;
}/**
*允许列表
*config
*public/static
*public/router.php
*public/index.php
*app/admin
*app/wechat
*/

参数$name被限制了必须要是允许文件列表和不能说是database.php文件才能够被读取,可以通过 'public/static/../../1.txt' 读取根目录的1.txt。在Linux环境下对于database.php的限制是没法绕过的,但是在windows下可以把 . 替换成 " ,传入

public/static/../../config/database"php

使用编码脚本进行编码的结果为:

尝试读取数据库配置文件(找了半天也没有找到windows的,也没法读取),于是尝试读取其他文件:

本文参考:

https://github.com/zoujingli/ThinkAdmin/issues/244

CVE-2020-25540:ThinkAdmin未授权列目录/任意文件读取漏洞复现相关推荐

  1. ThinkAdmin列目录/任意文件读取(CVE-2020-25540 )漏洞复现及环境搭建

    ThinkAdmin列目录/任意文件读取(CVE-2020-25540 )漏洞复现 漏洞介绍 ThinkAdmin 是基于 ThinkPHP后台开发框架,在ThinkAdmin v6版本存在路径遍历漏 ...

  2. Grafana 未授权任意文件读取漏洞复现

    1.fofa 批量搜索 app="Grafana" 漏洞URL: {{BaseURL}}/public/plugins/{{plugin-id}}/../../../../../. ...

  3. Grafana 中存在严重的未授权任意文件读取漏洞,已遭利用

     聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 Grafana Labs 发布紧急安全更新,修复了影响该公司主产品 Grafana 仪表盘中的严重漏洞 (CVE-2021-43798),CVS ...

  4. CVE-2021-43798 Grafana 未经授权的任意文件读取漏洞

    CVE-2021-43798 Grafana 未经授权的任意文件读取漏洞 目录 漏洞原理 漏洞信息 受影响版本 FOFA搜集相关资产 漏洞分析&漏洞复现 解决方案 漏洞原理 Grafana是一 ...

  5. ThinkAdmin任意文件读取漏洞(CVE-2020-25540)

    简述 ThinkAdmin是一套基于ThinkPHP框架的通用后台管理系统 漏洞描述 ThinkAdmin6版本存在路径遍历漏洞.该漏洞主要是因为api中存在危险函数,没有任何过滤.攻击者可利用该漏洞 ...

  6. python和django的目录遍历漏洞(任意文件读取)

    1. 什么是目录遍历漏洞 "目录遍历漏洞"的英文名称是Directory Traversal 或 Path Traversal.指攻击者通过在URL或参数中构造 ../ ..%2F ...

  7. [网鼎杯 2020 白虎组]PicDown(任意文件读取)

    打开界面发现有一个get传参然后,尝试任意文件读取漏洞,/etc/passwd看一下,提示下载了一个jpg图片然后 打不开只能用 010查看一下信息  看来是猜对了,然后 如果日记没删掉可以查看历史记 ...

  8. XenMobile目录遍历任意文件读取(CVE-2020-8209)

    XenMobile目录遍历任意文件读取(CVE-2020-8209) 利用此漏洞,可以读取Web服务器根目录之外的任意文件,包括配置文件和敏感的加密密钥.不需要授权. POC(路径遍历) /jsp/h ...

  9. 目录浏览(目录遍历)漏洞和任意文件读取/下载漏洞

    目录 目录浏览(目录遍历)漏洞 任意文件读取/下载漏洞 目录浏览(目录遍历)漏洞 目录浏览漏洞是由于网站存在配置缺陷,导致网站目录可以被任意浏览,这会导致网站很多隐私文件与目录泄露,比如数据库备份文件 ...

最新文章

  1. 不简单的 SimpleDateFormat
  2. graphviz linux教程,程序员绘图利器 — Graphviz
  3. POJ2406 KMP前缀周期
  4. python求最小值不能使用min和sotred_python基础——内置函数
  5. eclipse环境配置、快捷键及基本操作
  6. 机器学习线性回归案例讲解_09机器学习实战之简单线性回归
  7. 据说这是双11前互联网人的一天~
  8. vim xxd命令查看二进制文件内容
  9. 图像处理-RBG图像和灰度图像
  10. Spring : Importxxx系列注解
  11. scrapy 入门案例
  12. selenium 验证元素是否存在_使用selenium判断标签的元素值是否存在
  13. Java添加水印+图片水印+文字水印
  14. 冷热分离和直接使用大数据库_用读写分离与分表分库解决高访问量和大数据量...
  15. Git Bash 不能输入中文的简单解决办法
  16. linux必看书籍推荐
  17. 批量绘图 | EXCEL绘制基站扇区地图
  18. 动态规划之背包问题 01背包
  19. Linux内核的下载和解压
  20. 标准库intrins.h中的循环指令在多种流水灯方式上的应用

热门文章

  1. Java开发内存16g够用不_讨论!现在的你是否还能用16G手机,内存还够不够用?...
  2. Word 2016 公式编辑器中微分符号的竖线(2018.5.17)
  3. 亲戚(relative)
  4. 数字转中文大写= 1234= 一千二百三十四
  5. UltralSo制作u盘映像,出现“设备忙,请关闭其他应用程序”的处理方法。
  6. 解决烘焙光照贴图有黑斑
  7. 如何学习SDN及网络自动化
  8. 转:Flutter做出剑气效果
  9. SqlServer误删数据恢复
  10. linux系统fasta程序,Linux生信练习2--fastq/fasta