由00截断造成的文件读取(CVE-2023-47473分析)
字数 1493 2025-08-24 07:48:22
CVE-2023-47473分析:由00截断造成的文件读取漏洞教学文档
漏洞概述
CVE-2023-47473是一个由于Java JDK早期版本中未正确处理空字符(00截断)导致的文件读取漏洞。攻击者可以利用该漏洞绕过文件类型检查,读取服务器上的任意文件。
漏洞背景
该漏洞存在于一个Web应用程序中,具体涉及以下关键组件:
- 一个名为
getuploadimage.jsp的JSP文件 - JDK 1.7.0_40之前的版本
- 文件上传和读取功能
鉴权机制分析
过滤器配置
通过web.xml配置文件查看过滤器,所有路由都会经过SessionControl_UserLogin过滤器。
鉴权绕过机制
在SessionControl_UserLogin过滤器的doFilter方法中:
- 创建了一个迭代器检查请求URI
- 如果当前请求URI不在迭代器中,会从会话中获取用户认证信息进行校验
- 如果当前请求URI在迭代器中,则跳过校验
默认免校验URL列表:包含特定后缀的URL(如.jsp)可以绕过SessionControl_UserLogin过滤器的校验。
漏洞点定位
漏洞存在于getuploadimage.jsp文件中,该文件包含image.jsp可以绕过SessionControl_UserLogin过滤器的校验。
漏洞代码分析
关键代码段
String imageURL = request.getParameter("imageURL");
System.out.println(imageURL);
if (!ValidateUtil.isNull(imageURL)) {
try {
String fileName = StringUtil.getFileName(imageURL);
String fileType = StringUtil.getFileType(fileName, "unkown");
if ("gif".equals(fileType) || "png".equals(fileType) ||
"bmp".equals(fileType) || "jpg".equals(fileType) ||
"jpeg".equals(fileType)) {
// 通过校验
} else {
return; // 文件类型不符合则直接返回
}
response.setCharacterEncoding("UTF-8");
response.resetBuffer();
response.setContentType("image/jpeg");
File uploadedFile = new File(imageURL);
DataInputStream is = new DataInputStream(new FileInputStream(uploadedFile));
DataOutputStream os = new DataOutputStream(response.getOutputStream());
byte[] readBytes = new byte[128];
int buffflag = -1;
while ((buffflag = is.read(readBytes)) > -1) {
os.write(readBytes, 0, buffflag);
}
os.close();
is.close();
os = null;
response.flushBuffer();
out.clear();
out = pageContext.pushBody();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
}
}
文件处理流程
- 从请求参数获取
imageURL - 使用
StringUtil.getFileName()获取文件名 - 使用
StringUtil.getFileType()获取并校验文件类型 - 如果文件类型是图片(gif/png/bmp/jpg/jpeg),则读取文件内容并返回
关键工具方法
getFileName方法:
public static String getFileName(String fileName) {
int pos = fileName.lastIndexOf("\\");
return pos > 0 ? fileName.substring(pos + 1) : fileName;
}
getFileType方法:
public static String getFileType(String fileName, String defaultType) {
String fileType = "";
if (fileName != null && fileName.length() > 0) {
int i = fileName.lastIndexOf(46); // 46是'.'的ASCII码
if (i > -1 && i < fileName.length() - 1) {
fileType = fileName.substring(i + 1).toLowerCase();
}
}
if (!"pdf".equals(fileType) && !"doc".equals(fileType) &&
!"bmp".equals(fileType) && !"xls".equals(fileType) &&
!"exe".equals(fileType) && !"ppt".equals(fileType) &&
!"gif".equals(fileType) && !"html".equals(fileType) &&
!"xls".equals(fileType) && !"jpg".equals(fileType) &&
!"png".equals(fileType) && !"jpeg".equals(fileType) &&
!"xml".equals(fileType) && !"wav".equals(fileType) &&
!"wma".equals(fileType) && !"mp3".equals(fileType) &&
!"rar".equals(fileType) && !"txt".equals(fileType) &&
!"htm".equals(fileType) && !"zip".equals(fileType) &&
!"rm".equals(fileType) && !"swf".equals(fileType) &&
!"flv".equals(fileType) && !"docx".equals(fileType) &&
!"pptx".equals(fileType) && !"xlsx".equals(fileType)) {
fileType = defaultType;
}
return fileType;
}
漏洞原理
00截断问题
在JDK 1.7.0_40之前的版本中,Java没有对空字符(\u0000)进行有效检查,导致可以构造特殊的文件名绕过安全检查:
- 文件类型检查阶段:
getFileType方法检查最后一个点(.)后的扩展名 - 实际文件读取阶段:
File类在JDK 1.7.0_40之前会忽略空字符后的内容
利用方式:
构造如/etc/passwd%00.jpg这样的文件名:
- 文件类型检查时:获取
.jpg扩展名,通过校验 - 实际读取文件时:
%00被解析为空字符,实际读取/etc/passwd
JDK修复
JDK 1.7.0_40及之后版本增加了对空字符的检查:
final boolean isInvalid() {
if (status == null) {
status = (this.path.indexOf('\u0000') < 0) ?
PathStatus.CHECKED : PathStatus.INVALID;
}
return status == PathStatus.INVALID;
}
漏洞利用
攻击步骤
- 确认目标系统使用JDK 1.7.0_40之前的版本
- 构造恶意请求,在文件名后添加
%00和合法的图片扩展名GET /getuploadimage.jsp?imageURL=/path/to/sensitive/file%00.jpg - 服务器会返回目标文件内容
利用条件
- 目标系统使用JDK 1.7.0_40之前的版本
- 攻击者能够访问
getuploadimage.jsp或类似功能 - 服务器上存在可读的目标文件
修复建议
- 升级JDK:将JDK升级到1.7.0_40或更高版本
- 输入验证:
- 在文件操作前检查路径中是否包含空字符
- 使用白名单严格限制允许的文件扩展名
- 路径规范化:在处理文件路径前进行规范化处理
- 权限控制:限制应用程序的文件系统访问权限
防御代码示例
// 检查空字符
if (imageURL.indexOf('\u0000') >= 0) {
throw new IllegalArgumentException("Invalid file path");
}
// 规范化路径
String normalizedPath = new File(imageURL).getCanonicalPath();
// 检查路径是否在允许的目录下
if (!normalizedPath.startsWith(ALLOWED_DIRECTORY)) {
throw new SecurityException("Access denied");
}
总结
CVE-2023-47473是一个典型的文件读取漏洞,其核心问题在于:
- JDK早期版本对空字符处理不当
- 文件类型检查与实际文件操作之间存在不一致
- 缺乏严格的输入验证和路径处理
通过深入理解该漏洞,我们可以更好地防御类似的安全问题,特别是在文件操作相关的功能开发中。