Java代码审计的技巧
字数 1540 2025-08-29 08:29:59
Java代码审计高级技巧详解
1. 反射安全绕过
危险代码示例
try {
Class<?> clazz = Class.forName("com.vuln.InternalService");
Method method = clazz.getDeclaredMethod("deleteAllData");
method.setAccessible(true); // 关键点:强制开启访问权限
method.invoke(null); // 执行敏感操作
} catch (Exception e) {
e.printStackTrace();
}
审计要点
- 搜索模式:全局搜索
setAccessible(true)调用点 - 敏感方法检查:分析反射操作的目标类是否包含
shutdown、delete等危险方法 - 输入追踪:检查反射的类名/方法名是否来自用户输入
- 调用栈分析:确定反射调用是否位于敏感操作路径上
2. 反序列化漏洞审计
典型Gadget链
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject(); // 反序列化入口
审计技巧
- 入口点识别:查找所有
readObject/readUnshared调用 - 依赖库分析:
java -jar gadget-inspector.jar --target lib/ - 危险类关注:
InvokerTransformerTemplatesImplChainedTransformerTransformedMap
3. 注解鉴权绕过
错误配置示例
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = false)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll(); // 致命错误
}
}
审计要点
- 注解一致性检查:验证
@PreAuthorize、@Secured等安全注解与实际配置是否匹配 - 空表达式检测:搜索没有实际限制的安全注解
- 全局权限检查:确认
WebSecurityConfigurerAdapter配置中无过度开放权限
4. Lambda表达式注入
RCE示例
Command cmd = (Command) LambdaMetafactory.metafactory(
null,
null,
null,
(MethodType)MethodType.methodType(void.class, String.class),
MethodHandles.lookup().findVirtual(Runtime.class, "exec",
MethodType.methodType(Process.class, String.class)),
(MethodType)MethodType.methodType(void.class, String.class)
).getTarget().bindTo(Runtime.getRuntime()).invokeWithArguments(userInput);
审计方法
- LambdaMetafactory定位:查找所有相关使用点
- 输入追踪:分析用户输入是否参与Lambda生成过程
- 字节码分析:使用ASM检查动态生成的字节码
5. 内部类数据暴露
漏洞示例
public class BankAccount {
private BigDecimal balance;
public class Auditor {
public void checkBalance() {
System.out.println(balance); // 暴露私有字段
}
}
}
审计技巧
- 内部类检查:分析内部类是否访问外部类私有成员
- 反射调用分析:检查
getDeclaredConstructor的参数类型 - 静态分析工具:使用FindBugs规则
EI_EXPOSE_REP、EI_EXPOSE_REP2
6. 类型混淆攻击
泛型漏洞
public class DataHolder<T> {
private T data;
public void setData(Object obj) {
this.data = (T) obj; // 未做类型检查
}
}
审计要点
- 强制转换检查:查找未进行类型检查的强制转换操作
- 字节码验证:通过ASM分析
checkcast指令 - 泛型容器审计:重点检查自定义泛型容器类
7. JNDI注入变种
JDK高版本绕过
String uri = "ldap://127.0.0.1:1389/deserialPayload";
Context ctx = new InitialContext();
Object obj = ctx.lookup(uri);
审计方法
- JNDI调用点:搜索所有
InitialContext.lookup()调用 - 输入源追踪:检查LDAP URL是否用户可控
- 监控工具:使用
jndimon进行运行时监控
8. 动态代理权限逃逸
绕过示例
AdminOperation proxy = (AdminOperation) Proxy.newProxyInstance(
loader,
new Class[]{AdminOperation.class},
(proxy1, method, args) -> {
// 直接调用方法,绕过检查
return method.invoke(new RealAdmin(), args);
});
proxy.deleteDatabase(); // 绕过SecurityManager
审计要点
- 代理实例检查:分析
Proxy.newProxyInstance使用场景 - 权限验证:检查
InvocationHandler是否跳过安全检查 - 调用路径:分析代理方法的实际执行路径
9. 注解处理器漏洞
RCE示例
@SupportedAnnotationTypes("*")
public class EvilProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
Runtime.getRuntime().exec("calc.exe");
return true;
}
}
审计方法
- 服务文件检查:检查
META-INF/services/javax.annotation.processing.Processor - 处理器分析:审查自定义注解处理器的行为
- 编译隔离:在隔离环境中执行编译过程
10. SPI机制滥用
漏洞示例
ServiceLoader<CipherService> loader = ServiceLoader.load(CipherService.class);
for (CipherService service : loader) {
String encrypted = service.encrypt(data); // 可能加载恶意实现
}
审计要点
- SPI加载点:查找
ServiceLoader.load()调用位置 - 实现类验证:检查SPI实现类的来源和签名
- 运行环境:使用沙箱环境运行关键服务
综合防御策略
深度防御示例
public void process(UserInput input) {
validateSyntax(input); // 语法层校验
validateBusiness(input); // 业务逻辑校验
sanitize(input); // 净化处理
execute(input); // 安全执行
}
工具链集成
# 依赖检查
mvn org.owasp:dependency-check-maven:check
# 静态分析
semgrep --config=p/java
# 字节码分析
spotbugs -textui -high -sortByClass target/*
动态监控
public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined,
protectionDomain, classfileBuffer) -> {
if (className.contains("Runtime")) {
// 插入监控代码
}
return classfileBuffer;
});
}
核心审计关注点
-
语言特性陷阱:
- 反射机制
- 泛型擦除
- 内部类访问
- 动态代理
-
框架机制滥用:
- Spring AOP
- Hibernate映射
- JNDI查找
-
运行时环境:
- 类加载机制
- SPI扩展点
- 注解处理器
-
防御突破技巧:
- 类型混淆
- 安全检查绕过
- 异常流控制
高级审计方法
- AST模式分析:使用CodeQL进行语义分析
- 字节码逆向:结合JD-GUI和ASM分析
- 运行时Hook:使用ByteBuddy/Java Agent进行动态监控
- 漏洞模式匹配:关联CVE数据库进行历史漏洞比对