Java审计案例

wen java案例 2

本文目录导读:

Java审计案例

  1. 案例一:SSRF + 云服务元数据泄露(业务逻辑漏洞)
  2. 案例二:Spring Boot Actuator + JNDI注入(配置不当 + 反序列化)
  3. 案例三:MyBatis/MyBatis-Plus SQL注入(最经典但易忽视)
  4. 案例四:Java原生反序列化漏洞(RCE终极形态)
  5. 总结:Java审计的“黄金三角”

这是一份关于 Java审计(Java Security Audit/Code Review) 的实战案例分析合集。

在Java开发中,由于框架的成熟和第三方组件的丰富,安全问题往往隐藏在 业务逻辑缺陷框架配置不当序列化/反序列化漏洞 以及 复杂框架组合利用 中。

以下整理了四个具有代表性的Java审计案例,涵盖不同层级和攻击面。


SSRF + 云服务元数据泄露(业务逻辑漏洞)

场景: 一个“头像/图片抓取”功能,允许用户输入URL,服务端Java代码去读取该URL的图片并返回。

漏洞代码(伪代码):

// 对外暴露接口,接受imageUrl参数
@RequestMapping("/fetchImage")
public ResponseEntity fetchImage(@RequestParam String imageUrl) {
    // 无任何协议验证和IP白名单
    URL url = new URL(imageUrl);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    InputStream is = conn.getInputStream();
    // 读取并返回图片流...
}

审计发现:

  1. SSRF (Server Side Request Forgery): 攻击者输入 http://169.254.169.254/latest/meta-data/ (AWS云元数据地址)。
  2. Java行为: JDK内置的URL类直接发起GET请求到内网IP。
  3. 攻击效果: 服务器返回云服务器的临时凭证 (Access Key / Secret Key)。
  4. 利用链: http://10.0.0.1:8080/actuator/env (探测内网Spring Boot Actuator)。
  5. 更深层: 利用 file:///etc/passwd 协议读取本地文件。

修复方案:

  • 协议白名单: 强制只能使用 http://https://,禁止 file://ftp://
  • IP黑名单/白名单: 使用InetAddress解析URL中的域名,判断是否为内网IP(127.0.0.1, 10.x.x.x, 172.16.x.x, 192.168.x.x),是则拦截。
  • DNS Rebinding防御: 进行两次IP解析校验(第一次校验,第二次连接)。

Spring Boot Actuator + JNDI注入(配置不当 + 反序列化)

场景: 某Spring Boot应用开启了所有Actuator端点,且Spring版本较低(Log4j、Fastjson或Tomcat本地)。

审计发现:

  1. Actuator 未授权访问: /actuator/env 可查看环境变量,/actuator/beans 可查看Bean列表,/actuator/dump 可下载堆转储。
  2. 意外功能: POST /actuator/refresh(Config Client端)可动态修改配置。
  3. JNDI注入点: 代码中有类似 InitialContext.lookup(request.getParameter("url")) 或使用了存在漏洞的日志库(Log4j2 CVE-2021-44228)。

攻击链(综合利用):

  1. 访问 /actuator/env 获取数据库密码、Redis密码等。
  2. 如果存在远程配置中心(如Spring Cloud Config Server)且可写,攻击者修改配置属性(如 spring.datasource.url 指向恶意MySQL服务器)。
  3. 利用 POST /actuator/refresh 刷新配置。
  4. 应用重启或触发数据源连接时,恶意MySQL服务器返回包含恶意反序列化payload的数据包,触发RCE。

修复方案:

  • 生产环境禁用: 关闭所有Actuator端点或使用management.endpoints.web.exposure.exclude=*
  • 强认证: 引入Spring Security,为/actuator/**路径添加角色校验(如ADMIN角色)。
  • 升级依赖: 升级Log4j、Fastjson、Jackson等库,避免JNDI漏洞。

MyBatis/MyBatis-Plus SQL注入(最经典但易忽视)

场景: 项目使用MyBatis,查询接口使用了过多的 拼接。

漏洞代码(DAO层):

// Mapper接口
@Select("SELECT * FROM user WHERE ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

审计发现:

  1. 开发者为了方便动态传递排序字段或表名,使用了${column}
  2. 攻击者请求参数: /api/user?column=id&value=1 变更为 /api/user?column=id OR 1=1--&value=1
  3. 结果: SQL变更为 SELECT * FROM user WHERE id OR 1=1-- = ? ,注入了万能密码或绕过逻辑。

另一个变种(Order By注入):

// 使用MyBatis-Plus的Wrapper,但直接拼接用户输入
queryWrapper.orderByAsc(request.getSortField()); // 如果sortField是 user_id; DROP TABLE orders--

修复方案:

  • 严苛使用#{ }: 坚持传参必须使用(预编译占位符),只有当表名、字段名、ORDER BY子句等不能预编译时,才需白名单验证。
  • 白名单验证: 如果必须用,在Java代码层对参数进行枚举白名单校验。
    List<String> allowedColumns = Arrays.asList("id", "name", "create_time");
    if (!allowedColumns.contains(column)) { throw new IllegalArgumentException(); }

Java原生反序列化漏洞(RCE终极形态)

场景: 一个老的内部系统,接收用户POST的Base64字符串,直接进行反序列化,使用了Commons-Collections 3.2.1。

漏洞代码:

@RequestMapping("/deserialize")
public String deserializeData(@RequestBody String data) {
    byte[] bytes = Base64.getDecoder().decode(data);
    // 危险!使用了 ObjectInputStream
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bais);
    Object obj = ois.readObject(); // 在此触发RCE
    // ...
}

审计发现:

  1. 技术预判: 项目依赖了 commons-collections-3.2.1,该版本存在著名的 InvokerTransformer 链。
  2. 入口点: 任何读取 ObjectInputStream.readObject() 的地方都是高危入口,常见场景:
    • RMI接口调用(绑定对象)。
    • JMX连接。
    • Session持久化(Tomcat反序列化Session)。
    • Fastjson/Jackson自动反序列化。

攻击利用:

  • 攻击者使用 ysoserial 工具生成payload: java -jar ysoserial.jar CommonsCollections5 "calc.exe" > payload.bin
  • 将payload Base64编码后POST给接口。
  • 服务端反序列化时,执行命令(windows弹出计算器,Linux反弹shell)。

修复方案:

  • 替代序列化协议: 使用JSON(Jackson/Fastjson,注意配置SafeMode)替代Java原生序列化。
  • 黑白名单过滤: 重写ObjectInputStreamresolveClass方法,禁止反序列化危险类(如InvokerTransformerRuntime等)。
  • 升级库: 升级commons-collections到4.x(修复了Gadget链)或使用jackson-databind的SafeMode。

Java审计的“黄金三角”

在进行Java审计时,重点关注以下三个维度:

  1. 数据流入口(Input Source):

    • @RequestParam, @RequestBody, HttpServletRequest.getParameter()
    • ObjectInputStream.readObject(), JMS消息, RMI接口
    • 多部分文件上传 MultipartFile
  2. 危险函数/中间件(Sink Point):

    • Runtime.exec(), ProcessBuilder.start() (命令执行)
    • InitialContext.lookup() (JNDI注入)
    • URLClassLoader (动态类加载)
    • XMLReader.parse() , DocumentBuilder.parse() (XXE)
    • @Select ${} (SQL注入)
    • FileInputStream, FileOutputStream (任意文件读取/写入)
  3. 配置与依赖(Configuration & Dependency):

    • Spring Boot Actuator 是否暴露敏感端点。
    • log4j2fastjsonshirostruts2 等历史漏洞组件的版本。
    • Web.xml / Security Configuration 中路径权限配置是否遗漏(如全部放行)。

审计核心逻辑: 找到User Input ( 用户可控)如何流向Dangerous Functions ( 危险函数),中间经过了哪些Filter/Validation ( 过滤/校验),并判断该过滤是否可以被绕过。

抱歉,评论功能暂时关闭!