Java 代码审计从入门到实战:完整流程与方法论
本文探讨了Java代码审计的重要性与方法,详细介绍了从源码获取到风险评估的整体流程,并重点分析了常见漏洞类型(如命令执行、SQL注入)及绕过校验逻辑的技术。通过实战思路总结,强调了提升代码审计能力对攻防演练及企业安全防护的关键作用。 2025-12-24 09:36:52 Author: www.freebuf.com(查看原文) 阅读量:1 收藏

freeBuf

主站

分类

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

特色

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

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

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

FreeBuf+小程序

FreeBuf+小程序

面向对象

  • 初学 Java 代码审计的安全从业者

  • 有 Web / 漏洞分析基础,希望系统化提升代码审计能力的人

  • 偏蓝队 / 攻防兼顾,关注真实漏洞成因与绕过思路的人

一、为什么要学习 Java 代码审计

在真实攻防和安全运营中,你会发现:

  • 扫描器 ≠ 真正的漏洞:自动化工具如 Fortify 或 SonarQube 能发现部分低危问题,但往往漏报业务逻辑漏洞或框架误用导致的高危问题。

  • 高危漏洞往往隐藏在:

    • 业务逻辑(如权限绕过、越权)

    • 框架使用不当(如 MyBatis SQL 注入、Spring 配置错误)

    • 二次开发代码(自定义工具类或历史遗留模块)

  • Java Web 项目源码体量大、框架复杂(如 Spring Boot + MyBatis),但漏洞模式高度可复用(例如参数传播到 Sink 的链路)

代码审计的核心价值在于:

  • 从“现象型漏洞”(如直接 exec 参数)升级为“机制型漏洞理解”(理解数据流污染和 Gadget 链)

  • 能做到:看代码 → 预判漏洞 → 构造利用 → 评估风险(结合业务影响评估 CVSS 分数)

掌握 Java 审计,能让你在 SRC、渗透测试或蓝队加固中占据优势,尤其在企业级系统中 Java 项目占比高。

二、Java 代码审计整体流程

一套可落地的 Java 审计流程如下(基于污点分析思想:Source → Process → Sink):

资产确认(收集目标系统信息、依赖版本)
  ↓
获取源码 / Jar / War(源码泄露、Burp 抓包下载、Git 泄露等)
  ↓
反编译 & 环境还原(IDEA 导入项目,Maven/Gradle 构建)
  ↓
框架识别(SSM / SpringBoot / Struts2 / Shiro 等,通过 pom.xml 或配置文件)
  ↓
入口点分析(Controller / Action / Servlet / Filter)
  ↓
参数传播链追踪(Source → Process → Sink,使用 IDE 搜索调用链)
  ↓
危险函数定位(Sink,如 exec、executeQuery、readObject)
  ↓
校验逻辑分析 & 绕过尝试(黑名单、正则等是否可绕)
  ↓
漏洞验证(数据包 / POC / Exp,利用 ysoserial 等工具)
  ↓
风险评估 & 修复建议(结合业务逻辑评估影响)

下面将围绕该流程逐步展开。审计时优先高危模块(如登录、上传、支付),不追求一次性读完所有代码。

三、反编译

3.1 常见形式

  • xxx.jar(第三方库或独立模块)

  • xxx.war(Web 项目打包,常包含所有 class)

  • 线上 class 文件(服务器目录遍历或备份泄露)

3.2 常用反编译工具

工具适用场景优点缺点使用示例
JD-GUI快速查看GUI 界面简单,直观对 JDK8+ Lambda 支持一般直接打开 jar/war
CFR命令行,现代 Java 特性支持好支持 Lambda、try-with-resources,可读性高无 GUIjava -jar cfr.jar target.jar --outputdir src
FernFlowerIDEA 集成,逻辑完整分析型反编译,结构还原好速度稍慢IDEA 内置,或命令行java -jar fernflower.jar target.jar out
Jadx混淆代码、Android 相关GUI + 命令行,支持搜索主要针对 Dex,但对 class 也行图形化很方便

Jadx很快就能编译出源码,也可以搜索很方便
image.png

3.3 反编译后

  • 看入口注解:

    • @Controller/@RestController

    • @RequestMapping/@GetMapping

    • Struts 的 Action 类(继承 ActionSupport)

    image.png

  • 看 Servlet 方法:

    • doPost/doGet

    • execute()(Struts)
      image.png

  • 是否有自定义工具类(util / common / helper / tools),这些往往是高危 Sink 聚集地

  • pom.xml / build.gradle:检查第三方依赖版本(FastJSON、Shiro 等历史漏洞)

反编译不是终点,而是入口。导入 IDEA 后,利用 Ctrl + Shift + F 全局搜索关键词(如 "exec"、"query")加速定位。

四、Java Web 基础审计(Servlet 层)

4.1 典型入口

protected void doPost(HttpServletRequest request, HttpServletResponse response)

老项目常见,现在多用注解

4.2 参数来源(Source)

String cmd = request.getParameter("cmd");

常见 Source(用户可控输入点):

  • getParameter()/getParameterValues()/getParameterMap()

  • getHeader()(如 User-Agent、Referer)

  • getCookies()

  • getInputStream()/getReader()(JSON Body)

  • Session / Cookie / PathVariable
    image.png
    审计时,从这些 Source 出发,正向追踪参数传播(IDE 的 "Find Usages")。

五、SSM 框架审计

5.1 Spring MVC 审计思路

特征:

@Controller
@RequestMapping("/user")
public class UserController {

    @PostMapping("/login")
    public String login(@RequestParam String username, String password) {
        ...
    }
}

审计重点:

  • 参数是否自动绑定(@RequestParam / @PathVariable / POJO 绑定)

  • 是否存在 未校验直接入库 / 拼接 / 执行(如直接拼 SQL 或命令)

  • 拦截器 / Filter 是否全局过滤(XSS、SQL 注入)

5.2 MyBatis SQL 注入审计

危险写法(${} 拼接,可注入):

<select id="getUser" resultType="User">
    SELECT * FROM user WHERE name = '${name}'
</select>

安全写法(#{} 预编译):

WHERE name = #{name}

利用数据包示例:

POST /user/get HTTP/1.1

name=admin' or '1'='1

审计技巧:搜索 Mapper.xml 中的 "${",或 Java 中的 concat / + 拼接 SQL。

六、Struts2 框架审计

6.1 框架识别

  • struts.xml 配置

  • ActionSupport 继承

  • OGNL 表达式(如 ${} 在 JSP)

6.2 经典危险点

public String execute() {
    Runtime.getRuntime().exec(cmd);
}

6.3 OGNL 注入思路

  • 参数自动封装到 Action 属性

  • ValueStack 上下文执行 OGNL

  • Method 调用(如动态方法调用开启时 ! 通配)

历史漏洞多(如 S2-045、S2-046),审计时检查是否升级到最新版。

七、Sink 函数体系化总结

常见高危 Sink(危险函数)分类:

7.1 命令执行

  • Runtime.getRuntime().exec(cmd)

  • new ProcessBuilder(cmd).start()

7.2 SQL 注入

  • Statement.execute(sql)/executeQuery(sql)

  • PreparedStatement但参数拼接

7.3 文件操作(任意读写 / 遍历)

  • new File(path)+ delete/read/write

  • new FileInputStream(path)/FileOutputStream

  • FileReader

7.4 反序列化

  • ObjectInputStream.readObject()

  • XMLDecoder.readObject()

  • YAML.load()等第三方

其他:SSRF(URL.openStream)、XSS(response.getWriter().print(unescaped))、XXE(SAXParser 无禁用外部实体)。

审计时:从 Source 逆向找 Sink,或全局搜索这些函数。

八、校验逻辑分析与绕过技巧

8.1 表面校验

if(!cmd.contains("rm") && !cmd.contains("cat"))

绕过:

  • ca${IFS}t(空格替换)

  • 编码(如 %20、Base64)

  • 分段执行(如 cd /tmp && rm)

8.2 黑名单问题

  • 只防一种(如只禁 "select",忽略大小写或 "union all select")

  • 忽略编码 / 注释(如 /**/)

  • 正则不严(如 ^ls$,但可 ls|cat)

蓝队视角:优先白名单 + 参数化。

九、真实审计思路总结

不追求一次看完所有代码(体量大时分模块)

  • 先分析:

    • 入口类(Controller 包)

    • 工具类(util 包,常有反射/反序列化)

    • 历史遗留模块(旧代码易遗漏校验)

  • 漏洞 = 业务 + 框架 + 开发习惯(如硬编码密钥、弱加密)

  • 结合静态工具(FindSecBugs、SpotBugs)辅助

十、结语

Java 代码审计不是“看代码找洞”,而是:

站在开发者的视角,理解系统;再站在攻击者的视角,破坏系统。

我们要做到:

  • 看到 Controller 就想到风险点(如越权)

  • 看到参数流就能预判 Sink(如传播到 exec)

坚持实战,结合黑白盒,快速提升!

免责声明

1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。

2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。

3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。

已在FreeBuf发表 0 篇文章

本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)


文章来源: https://www.freebuf.com/articles/web/463615.html
如有侵权请联系:admin#unsafe.sh