低版本java.io.File类00截断分析
字数 1215 2025-08-25 22:58:55

Java.io.File类00截断漏洞分析与防御

漏洞概述

在低版本Java环境(特别是Java 1.6及以下版本)中,java.io.File类存在00截断漏洞(Null Byte Termination Vulnerability),攻击者可以利用此漏洞绕过文件后缀校验,实现任意文件下载或上传等安全风险。

漏洞原理

Java与C/C++字符串处理差异

  • Java字符串:不以\u0000(ASCII: 0x00)作为字符串结束标志,可以包含多个null字节
  • C/C++字符串:以0x00作为字符数组/串的结束标志(宽字符以0x0000结尾)

底层机制分析

当Java代码调用File类相关方法时:

  1. Java层传递包含null字节的路径字符串到native层
  2. Native层将Java字符串转换为C/C++宽字符字符串(WCHAR*)
  3. 转换过程中,由于C/C++字符串以null字节结尾,导致null字节后的内容被截断
  4. 最终操作的文件路径不包含null字节后的内容(如硬编码的后缀)

版本差异分析

Java 1.6及以下版本

  • 无null字节检查File类不检查路径中是否包含\u0000
  • 存在截断风险:文件操作时null字节后的内容被丢弃
  • 示例
    String bytes = "malicious\u0000.txt"; // 用户可控参数
    File file = new File("/fixed/path/" + bytes);
    // 实际操作的文件路径为"/fixed/path/malicious"
    

Java 1.8及以上版本

  • 新增安全检查File类增加了isInvalid()方法
    private boolean isInvalid() {
        if (status == null) {
            status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED : PathStatus.INVALID;
        }
        return status == PathStatus.INVALID;
    }
    
  • 严格校验:文件操作前调用isInvalid()检查null字节,存在则抛出异常
  • 安全增强FileInputStreamFileOutputStream等也间接调用此检查

攻击场景

任意文件下载

String taskID = request.getParameter("taskID"); // 用户可控
String path = "/fixed/dir/" + taskID + ".txt"; // 拼接硬编码后缀
File file = new File(path);
if(file.exists()) {
    // 下载文件
}

攻击方式

  • 提供taskID=../../etc/passwd\u0000
  • Java 1.6环境下实际访问/fixed/dir/../../etc/passwd
  • 硬编码的.txt被截断

文件上传绕过

MultipartFile file = request.getFile("file");
String filename = file.getOriginalFilename();
File dest = new File("/upload/" + filename);
file.transferTo(dest);

攻击方式

  • 修改上传文件名包含null字节(如shell.jsp\u0000.jpg
  • Java 1.6环境下实际保存为shell.jsp

防御措施

1. 升级Java版本

  • 使用Java 1.8及以上版本,利用内置的null字节检查

2. 手动校验null字节

if (filename.indexOf('\u0000') != -1) {
    throw new IllegalArgumentException("Filename contains null byte");
}

3. 路径标准化处理

File file = new File("/base/dir", userInput);
String canonicalPath = file.getCanonicalPath();
if (!canonicalPath.startsWith("/base/dir")) {
    throw new IllegalArgumentException("Invalid path");
}

4. 文件上传特殊处理

  • 使用CommonsMultipartFile时:
    • 自动取最后一个文件分隔符后的字符串作为文件名
    • 缓解跨路径上传风险
  • 使用Streams.checkFileName检查文件名(Apache Commons FileUpload)

5. 白名单校验文件后缀

String[] allowedExtensions = {".txt", ".pdf"};
boolean valid = false;
for (String ext : allowedExtensions) {
    if (filename.toLowerCase().endsWith(ext)) {
        valid = true;
        break;
    }
}
if (!valid) {
    throw new IllegalArgumentException("Invalid file type");
}

总结

Java.io.File类00截断漏洞主要影响低版本Java环境,通过利用Java与C/C++字符串处理机制的差异,攻击者可绕过文件后缀校验。防御措施应结合版本升级、输入校验、路径标准化等多种手段,特别是在处理用户提供的文件路径时需格外谨慎。

Java.io.File类00截断漏洞分析与防御 漏洞概述 在低版本Java环境(特别是Java 1.6及以下版本)中, java.io.File 类存在00截断漏洞(Null Byte Termination Vulnerability),攻击者可以利用此漏洞绕过文件后缀校验,实现任意文件下载或上传等安全风险。 漏洞原理 Java与C/C++字符串处理差异 Java字符串 :不以 \u0000 (ASCII: 0x00)作为字符串结束标志,可以包含多个null字节 C/C++字符串 :以0x00作为字符数组/串的结束标志(宽字符以0x0000结尾) 底层机制分析 当Java代码调用 File 类相关方法时: Java层传递包含null字节的路径字符串到native层 Native层将Java字符串转换为C/C++宽字符字符串(WCHAR* ) 转换过程中,由于C/C++字符串以null字节结尾,导致null字节后的内容被截断 最终操作的文件路径不包含null字节后的内容(如硬编码的后缀) 版本差异分析 Java 1.6及以下版本 无null字节检查 : File 类不检查路径中是否包含 \u0000 存在截断风险 :文件操作时null字节后的内容被丢弃 示例 : Java 1.8及以上版本 新增安全检查 : File 类增加了 isInvalid() 方法 严格校验 :文件操作前调用 isInvalid() 检查null字节,存在则抛出异常 安全增强 : FileInputStream 、 FileOutputStream 等也间接调用此检查 攻击场景 任意文件下载 攻击方式 : 提供 taskID=../../etc/passwd\u0000 Java 1.6环境下实际访问 /fixed/dir/../../etc/passwd 硬编码的 .txt 被截断 文件上传绕过 攻击方式 : 修改上传文件名包含null字节(如 shell.jsp\u0000.jpg ) Java 1.6环境下实际保存为 shell.jsp 防御措施 1. 升级Java版本 使用Java 1.8及以上版本,利用内置的null字节检查 2. 手动校验null字节 3. 路径标准化处理 4. 文件上传特殊处理 使用 CommonsMultipartFile 时: 自动取最后一个文件分隔符后的字符串作为文件名 缓解跨路径上传风险 使用 Streams.checkFileName 检查文件名(Apache Commons FileUpload) 5. 白名单校验文件后缀 总结 Java.io.File类00截断漏洞主要影响低版本Java环境,通过利用Java与C/C++字符串处理机制的差异,攻击者可绕过文件后缀校验。防御措施应结合版本升级、输入校验、路径标准化等多种手段,特别是在处理用户提供的文件路径时需格外谨慎。