freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Java代码审计的技巧
Hrlies 2025-03-21 21:36:59 9768
所属地 陕西省

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)调用点

  • 检查反射操作的目标类是否包含敏感方法(如shutdowndelete等)

  • 结合调用栈分析(是否用户输入控制了反射的类/方法名)

2. 反序列化Gadget链构造

// 利用Apache Commons Collections链
ObjectInputStream ois = new ObjectInputStream(request.getInputStream());
Object obj = ois.readObject();  // 反序列化入口

// 攻击载荷构造(伪代码):
ChainedTransformer chain = new ChainedTransformer(transformers);
TransformedMap.decorate(map, null, chain);
...

审计技巧

  • 识别所有readObject/readUnshared调用点

  • 使用工具检测危险依赖链:

# 使用GadgetInspector检测
java -jar gadget-inspector.jar --target lib/
  • 特别关注InvokerTransformerTemplatesImpl等危险类

3. 注解绕过鉴权

// Spring Security错误配置案例
@PreAuthorize("hasRole('USER')")
public void viewProfile() { /* ... */ }

// 错误配置允许所有访问
@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表达式注入

// 动态生成Lambda导致RCE
public interface Command {
    void execute(String cmd) throws Exception;
}

public static void main(String[] args) {
    String userInput = "java.lang.Runtime.getRuntime().exec('calc');";

    // 动态生成恶意Lambda
    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);

    cmd.execute(""); // 触发命令执行
}

审计技巧

  • 查找LambdaMetafactory使用点

  • 跟踪用户输入是否参与Lambda生成

  • 结合动态代理分析(ASM字节码操作)

5. 内部类逃逸攻击

// 案例:通过内部类暴露私有字段
public class BankAccount {
    private BigDecimal balance; // 本应是私有字段

    public class Auditor {
        public void checkBalance() {
            System.out.println(balance); // 内部类直接访问外部类私有字段
        }
    }
}

// 攻击者通过反射获取内部类
Class<?> innerClazz = Class.forName("com.vuln.BankAccount$Auditor");
Object auditor = innerClazz.getDeclaredConstructor(BankAccount.class)
                          .newInstance(account);
Method method = auditor.getClass().getMethod("checkBalance");
method.invoke(auditor); // 泄露余额

审计技巧

  • 检查内部类是否暴露敏感数据

  • 分析getDeclaredConstructor的参数类型

  • 使用FindBugs规则:EI_EXPOSE_REPEI_EXPOSE_REP2

6. 类型混淆攻击

// 案例:利用泛型类型擦除
public class DataHolder<T> {
    private T data;

    public void setData(Object obj) {
        this.data = (T) obj; // 未做类型检查
    }
}

// 攻击者注入错误类型
DataHolder<String> holder = new DataHolder<>();
holder.setData(new File("/etc/passwd")); // 运行时不会报错
String data = holder.getData(); // ClassCastException延迟到此处

审计技巧

  • 查找未进行类型检查的强制转换

  • 使用checkcast字节码验证(通过ASM分析)

  • 重点关注自定义泛型容器类

7. JNDI注入的隐蔽变种

// 新版绕过技巧(JDK≥8u191后)
String uri = "ldap://127.0.0.1:1389/deserialPayload";
// 使用带Factory的Reference
Context ctx = new InitialContext();
Object obj = ctx.lookup(uri); 

// 利用javax.naming.spi.ObjectFactory绕过
public class EvilFactory implements ObjectFactory {
    public Object getObjectInstance(Object obj, Name name, 
                                   Context ctx, Hashtable<?,?> env) {
        Runtime.getRuntime().exec("calc.exe");
        return null;
    }
}

审计技巧

  • 搜索所有InitialContext.lookup()调用

  • 检查LDAP URL是否用户可控

  • 使用JNDI监控工具:jndimon

8. 动态代理权限逃逸

// 通过动态代理绕过权限检查
public interface AdminOperation {
    void deleteDatabase();
}

class RealAdmin implements AdminOperation {
    public void deleteDatabase() {
        SecurityManager sm = System.getSecurityManager();
        sm.checkPermission(new AdminPermission()); // 权限检查
        // 实际删除操作...
    }
}

// 攻击者构造代理绕过检查
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) {
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException e) { /*...*/ }
        return true;
    }
}

// META-INF/services/javax.annotation.processing.Processor 文件内容:
com.vuln.EvilProcessor

审计技巧

  • 检查项目中的META-INF/services文件

  • 分析自定义注解处理器的行为

  • 使用隔离环境编译代码

10. SPI机制滥用

// 利用ServiceLoader加载恶意实现
ServiceLoader<CipherService> loader = 
    ServiceLoader.load(CipherService.class);
for (CipherService service : loader) {
    // 攻击者可以在classpath中放置恶意实现
    String encrypted = service.encrypt(data); 
}

审计技巧

  • 检查ServiceLoader.load()的调用位置

  • 验证SPI实现类的来源

  • 使用沙箱环境运行关键服务

综合防御策略

  1. 深度防御

// 示例:多层校验
public void process(UserInput input) {
    validateSyntax(input);   // 语法层校验
    validateBusiness(input); // 业务逻辑校验
    sanitize(input);         // 净化处理
    execute(input);          // 安全执行
}
  1. 工具链集成

# 组合使用SAST/DAST工具
mvn org.owasp:dependency-check-maven:check   # 依赖检查
semgrep --config=p/java                     # 自定义规则扫描
spotbugs -textui -high -sortByClass target/* # 字节码分析
  1. 动态监控

// 使用Java Agent监控危险操作
public static void premain(String args, Instrumentation inst) {
    inst.addTransformer((loader, className, classBeingRedefined, 
                        protectionDomain, classfileBuffer) -> {
        if (className.contains("Runtime")) {
            // 插入监控代码
        }
        return classfileBuffer;
    });
}

总结

Java代码审计需要关注:

  • 语言特性陷阱:反射、泛型、内部类、动态代理

  • 框架机制滥用:Spring AOP、Hibernate映射、JNDI

  • 运行时环境:类加载机制、SPI扩展点、注解处理器

  • 防御突破技巧:类型混淆、安全检查绕过、异常流控制

实际审计中,建议结合以下方法:

  1. AST模式分析(使用CodeQL)

  2. 字节码逆向分析(使用JD-GUI+ASM)

  3. 运行时Hook(使用ByteBuddy/Java Agent)

  4. 历史漏洞模式匹配(CVE数据库关联分析)

# Java代码审计
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Hrlies 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Java白盒测试
Hrlies LV.5
微信公众号:从生活到技术上的安全
  • 13 文章数
  • 10 关注者
Java漏洞在白盒审计中的技巧——反序列化篇(Fastjson)
2025-03-30
Java漏洞在黑盒实战中的技巧——JNDI注入篇
2025-03-30
Java漏洞在黑盒实战中的技巧——反序列化篇
2025-03-27