ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Java代码审计实战:从靶场到信息泄露漏洞排查

Java代码审计实战:从靶场到信息泄露漏洞排查

前些日子为了准备Java方向的代码审计技能点,集中刷了一批市面上常见的圈内靶场,DVWN算是我整理信息泄露这一类问题时比较顺手的一个环境。不少朋友以为信息泄露就是“在响应包多看到点字段”或者“目录扫出来几个备份文件”,真上手审计才发现,这套东西分布在代码的每一层,可能是路由、过滤器、DTO、日志切面,甚至还藏在模板渲染的注释里。信息泄露不一定是高危,但它往往是其他漏洞的加速器——先拿到内部接口清单、真实路径、加密盐值,后面挖注入或者越权就轻松得多。

这篇博文不打算把靶场当黑盒去“打”,而是直接翻源码做白盒审计。我会用一个相对完整的流程,演示从部署靶场、信息收集到逐个定位泄露点的全过程。每个环节都附上判断依据和坑点,适合刚学完Java基础、想进安全审计这块但对代码还不太熟的朋友。已经有点经验的人也能拿来做一套自己的排查清单。

1. 靶场审计信息泄露,到底在审什么

1.1 靶场是什么定位,为什么首选它

DVWN延续了经典低中高三档漏洞环境的设计思路,但整体转型为Java全栈应用,技术栈接近我日常接触到的中小型后台系统:Spring Boot做接口层,持久层用MyBatis,前端有简单的模板页面和弹窗提交,数据库内置了用户、订单、文件记录等测试表。靶场里塞了常见的登录、个人中心、订单查询、文件上传下载、后台菜单等模块,差不多把大多数业务系统的常见点覆盖了一遍。

这中间的信息泄露并不是单独一个漏洞战点,而是散在每个功能点周围的“提示物”。有的在配置文件里直接暴露数据库口令,有的在登录接口响应里把用户哈希一起回传,有的把文件下载参数做得过于宽松,路径拼接后直接把源码关联文件拉走。靶场刻意把这些内容布置在看上去合理的业务位置,练的就是在审计时保持敏感度,别只顾着看主流程,忽略了返回体、静态资源还有异常分支。

1.2 白盒审计和黑盒渗透的信息泄露差异

黑盒状态下的信息泄露,一般依赖指纹识别、目录爆破、响应包观察,靠的是对路径命名的经验积累和对返回字段的直觉。白盒审计更进一步,你手里握着全部代码,问题就从“哪能看”变成了“哪些数据被有意无意地暴露了”。代码审计里的信息泄露隐蔽性更细,比如一个Controller把整个Entity直接回传,而Entity里有台账创建人、内部状态、设备序列号;比如一个切面在异常时打印完整参数,数据库连接串和SQL参数全落日志;再比如某个审计员自己写的单元测试数据里写了线上地址和密钥。这类问题不靠跑目录和看响应能立刻定位,必须顺着数据流逐层搜。

所以我建议把信息泄露作为一个横向线索来审,而不是单独跑一遍“找敏感文件”就完事。靶场练的就是这个习惯:先跑通功能,再从功能入口往底层翻,看哪些中间产物落到了审计视野之外的地方。

2. 审计开始前,先把这三样东西备好

2.1 环境准备与工具清单

我习惯准备一套相对固定的审计环境,避免换个项目还要重新折腾依赖。工具清单如下:

  • JDK与Maven:靶场多数基于标准Java工程,Maven能直接拉齐依赖,同时用mvn dependency:tree快速理清第三方库版本。
  • 数据库客户端:我用本地的开源数据库工具,主要用于核对数据表字段,判断哪些字段属于敏感数据。
  • 抓包工具或浏览器开发者工具:主要用于对比前端实际接收到的响应和代码里的返回值差异。
  • 代码搜索工具:IDE里的全局搜索、正则匹配、快速查找引用,比肉眼扫文件有效率得多。

提示:审计环境建议和前端的对外环境分离,不要把靶场跑在比较正式的公共环境里。这类漏洞程序的数据库通常带默认口令,部署到公网等于主动制造信息泄露。

2.2 先把项目跑起来,再开始翻代码

不少初学者习惯直接下源码然后逐个文件看,不动手启动,结果很多需要运行期才能暴露的问题完全看不出来。我的流程是先按README完成部署,注册两个测试账号,分别跑一遍普通用户和管理员能访问的菜单。跑的过程中重点做三件事:

  • 记下默认端口和根路径,留意是否存在特殊的上下文路径。
  • 观察控制台启动日志,有些框架版本、数据库连接配置会在启动阶段输出。
  • 用浏览器开发者工具逐个接口看响应,建立“正常响应长什么样”的基准。

这个过程中顺便把框架和版本指纹收下来。技术栈信息直接决定接下来要找哪些框架级泄露点,比如某些模板引擎默认报错页面会带内部堆栈,某些ORM框架在特定模式下会把SQL拼进异常信息。

3. 信息泄露的高发地带,先按图索骥

3.1 全局配置与依赖清单是第一站

打开项目先看pom.xml和application.yml/properties,这属于老规矩了,但永远有收获。靶场在配置文件里往往给出两类线索:一是数据库账号口令、连接地址、调试开关、日志级别;二是自定义的系统参数,比如文件存储路径、密钥前缀、内部接口白名单。

查看依赖时别只看名字,要看有没有低版本的传参框架、模板引擎和工具库。这类组件在特定接口里会顺手把异常栈、参数映射、内部类路径吐出来,等于给你做信息收集之便。举一个常见场景:某个JSON序列化库开启了一类错误详情的输出,当参数类型不匹配时,返回体里包含完整的目标类名称和方法签名,这对后续构造payload很有帮助。

3.2 面向业务对象的返回模型最容易被忽视

翻Controller之前,建议先把vo、dto、entity这些包结构过一遍。很多项目的原型设计是直接拿实体类当返回对象用的,审计时盯着接口的return类型看,就能发现实体类里的内部状态、创建人、加密盐、审计字段全落到了前端响应里。

靶场在这个点布置得很典型:个人资料接口返回的数据结构里有头像路径、手机号、身份证号这类业务字段,还捎带了数据库自增主键、账号创建时间、备注字段。如果整体代码没有脱敏和字段过滤,一次正常调用就把用户行记录的底细全暴露了。审计时凡是看到return entity或return list直接返回持久层对象的,都值得进一步核对该实体类的字段清单。

3.3 异常处理和日志切面是泄露重灾区

信息泄露里最有价值的一块其实是异常分支。正常流程开发人员会做字段校验、权限判断,但异常分支经常图省事直接把异常抛给前端框架,于是错误页、统一返回体里可能出现完整SQL、文件绝对路径、第三方服务地址和内存状态。

检查要点很明确:

  • 全局异常处理器:找到@ControllerAdvice或者对应拦截器,看异常的detail字段是否原样输出异常信息。
  • 日志切面:看过入参出参切面里打了哪些内容,很多人把请求参数整个打成JSON,其中可能包含密码、Token。
  • 错误页面配置:针对404、500的错误页是否包含堆栈驱动信息。

靶场比较狡猾的一点是,把日志级别设成DEBUG,于是某个文件下载功能把保存路径、文件大小、归属用户的完整信息全打印了出来。运行时看控制台,等于给审计报告白送了一条证据链。

4. 实际操作:按业务流程靶场信息泄露点逐个落锤

4.1 从登录功能开始抠敏感字段

登录接口是信息泄露审计绕不开的入口,重点是看它的响应结构和处理逻辑。靶场的登录流程是这样的:前端提交用户名密码,后端先按用户名查用户表,比对密码哈希,比对成功后将用户ID写入会话,往前端返回一个“登录成功”的提示和跳转地址。

代码表面上看没什么问题,但翻开用户Mapper对应的查询语句后,发现select *把整行记录都查出来了,Controller层拿到这个对象后直接作为响应体的一部分抛回前端。于是前端能从响应里读到数据库中密码哈希字段。这个哈希虽然没有明文密码,但结合靶场里密码策略比较弱的账号,完全够做离线暴力尝试了。

审计结论记录上,我会把这个问题标成“敏感字段超出最小化返回范围”,并附带修复建议:查询时显式列出返回列,或单独做一个只包含用户ID、昵称、头像的VO对象。千万别图省事直接复用do对象拼响应。

4.2 个人中心的IDOR型信息泄露

信息泄露和越权经常是双胞胎。靶场个人中心接口长这样:/user/profile/{id},传入用户ID就返回对应资料。登录后的正常操作应该只允许查看自己的ID,但代码里完全没有对当前会话身份和目标ID做一致性校验,唯一限制是要求登录态。

于是拿A账号登录,然后遍历ID直接看别人的资料,手机号、邮箱、地址全部暴露。这属于典型的水平越权导致的信息泄露,审计时看两条线:路由上有没有对{id}做鉴权注解,Controller方法开头有没有拿会话属性做比对。靶场故意把第一个实例做得很“裸”,就是为了让你建立这个思维:凡是处理用户可操控参数的接口,都要检查归属校验。

顺手再说一个坑:靶场这个接口返回的字段里还包括用户的密码重置令牌,好在代码里这个令牌在修改成功后会被清空,但历史数据里如果有未使用的重置链接,遍历接口时也会一并泄露。这类令牌一旦泄露,后续账号接管就是顺水推舟的事。

4.3 文件模块里的路径拼接与源码泄露

文件下载接口是源码泄露的重灾区,靶场在“下载附件”模块里做了一个典型的路径拼接漏洞。看实现的逻辑:

String path = fileRoot + File.separator + fileName; File f = new File(path);

文件名没做过滤,还在前端给了一个可以编辑的文本框,等于允许用户把fileName改成../../../../conf/database.properties这类相对路径,直接把内部配置文件拉下来。这个洞从黑盒看只是一个任意文件读取,但白盒审计时能进一步发现fileRoot本身是配置在属性文件里的绝对路径,攻击者下载application.yml之后还能推导出更多内部结构。

这类问题的修复思路不难:用文件ID作为存储名而不是文件名,将前端传入的原始文件名仅用于展示;下载的真实文件地址统一从数据库记录里取,不要和用户输入拼接。

4.4 后台未鉴权接口的配置信息泄露

靶场还塞了个“系统环境信息”的管理接口,属于后台菜单功能,却没做后台权限校验。普通账号登录后直接访问这个接口,能拿到运行环境、Java版本、操作系统架构、应用启动时间、内存使用情况等一整套运行期信息,甚至连数据库连接池状态都被纳入了返回结果里。

这类问题在审计里很典型:功能菜单设计时默认“没人知道路径”,就跳过鉴权。审计时不能只看登录后展示的菜单,要把Controller的路由映射完整拉一遍,看哪些方法没走统一的鉴权切面。靶场里这个接口没被菜单展示,但路由是硬编码在类注解上的,全局搜RequestMapping就能发现。

修复上我通常建议两步:菜单权限归菜单权限,接口鉴权归接口鉴权,任何路由都必须在入口层声明访问角色;运维信息接口直接限制为本机访问或由网关统一拦截,不公开到业务路由表里。

4.5 模板文件与注释泄漏毫不设防

代码审计过程中偶尔会扫到模板页面的源码注释和前端注解信息。靶场在前端页面的HTML注释里留了一段“仅供内部调试使用”的说明,底下跟着一条隐藏的接口地址。这类信息看上去只是个提示,但接口地址往往对应用一个后台查询功能,未鉴权状态下可以直接访问。

搜索注释的方法是全局搜debug、todo、测试、临时这些关键词,比肉眼翻文件夹快得多。我遇到过不止一次,代码里的TODO注释写“这里先写死,正式环境替换”,后头跟着一个硬编码的内部服务地址,对攻击者来说等于免费给了一张内网测绘地图。信息泄露的价值不在于单个字面量本身,而在于它能拼出多少内部结构。

5. 审计结果怎么写,以及怎么从工程角度止损

5.1 审计记录的标准化输出

信息泄露类问题因为大多不是直接getshell的高危漏洞,报告容易被业务方忽略。我的习惯是按“泄露数据的影响面”和“配合其他漏洞的利用难度”两个维度给严重程度打分,而不是只看官方漏洞定级。

每条审计记录建议包含:

  • 问题定位:文件路径、方法名、接口地址、触发参数。
  • 泄露内容:我具体拿到了哪些数据,附响应报文或日志截图。
  • 利用链路:这处泄露能串联哪些其他漏洞,比如先读配置文件再挖数据库弱口令。
  • 修复建议:尽量给出具体改动方案,不只是“注意脱敏”这种空话。

信息泄露报告如果只有现象没有链路,业务方很容易标低优先级;一旦写出“泄露的口令正好可以登录某后台”这类实证,推动修复就顺畅得多。

5.2 修复方案要落到框架层

信息泄露的修复不能一个个接口打补丁,工程上按层次收口更稳:

  • 返回模型层:统一对输出对象做字段白名单校验,禁止直接返回持久化实体。
  • 异常处理层:全局异常处理器只输出错误码和通用提示,把堆栈写入日志文件并不回传前端。
  • 凭证与路径:数据库口令、密钥、内部地址统一放入环境变量或密钥管理服务,不落配置仓库。
  • 权限入口:所有路由注册时强制走鉴权过滤器,后台管理接口额外加角色判断,不做“路径隐藏即安全”的假设。
  • 日志与调试:生产环境关闭DEBUG级别,审计关键操作时不记录敏感字段原文,必要的话用掩码函数替代。

靶场审计的终点不是我“利用成功”了,而是我能拿同一套标准和真实项目对照,确认哪些修复手段能稳定阻断这一系列问题。

6. 踩过的坑与信息泄露排查速查表

6.1 审计里容易误判的几个地方

响应字段和业务定义混淆。有些字段在开发眼里是必要信息,比如订单创建时间、物流单号,但在安全视角它们可能辅助推断业务量级、内部流程。审计时要区分“数据该不该返回”和“当前用户能不能看”,前者对照最小化原则,后者对照权限模型。

用了高版本依赖不等于没事。靶场里一些泄露其实不依赖框架漏洞,就是业务代码写得随意造成的。拿着依赖CVE清单排查时别把注意力全放在版本号上,重点还是看框架提供的默认错误页、序列化策略是否被主动改成了暴露模式。

只看Java源码不够,前端源码也值得扫。构建后的静态资源里如果没有做压缩混淆,接口地址、密钥常量、加密逻辑会直接暴露在JS文件里。信息泄露审计应该在前后端两份代码上都过一遍。

6.2 信息泄露排查速查表

排查位置重点观察点常见泄露内容修复方向
配置文件数据库口令、密钥、内部地址连接串、密码、白名单IP密钥外置,仓库脱敏
Controller返回值DTO/Entity直出密码哈希、用户内部字段独立的VO返回模型
异常处理堆栈、SQL、路径输出错误详情、类结构、文件路径全局异常包裹与脱敏
日志切面入参出参、异常日志明文口令、令牌、请求体日志脱敏,降级DEBUG
文件下载文件名校验、路径拼接源码、配置、数据库文件用存储ID映射下载
模板/注释硬编码接口、调试信息内部路由、测试接口发布前清理调试注释
未鉴权路由后台接口直接可达运行环境、配置、敏感数据统一鉴权过滤器

6.3 最后一个实际经验

我个人在实际操作中的体会是:信息泄露类漏洞的发现速度,很大程度取决于你在审计早期是否建立了完整的“数据资产地图”。别一上来就盯某个接口,先花半小时把配置、路由、过滤器、异常处理器、返回模型这五层过一遍,后面所有问题的定位都会快很多。靶场里的信息泄露点不算特别多,但胜在位置刁钻,认真走一遍下来,比闷头看十份安全文档都有用。

后期如果还想扩展,建议把同一套靶场的常见入口和真实系统上报过的泄露事件做一次对照,你会发现在真实场景中,信息泄露往往披着“业务需要”的外衣出现,审计的职责就是判断这层外衣底下有没有藏着不应该被带出应用边界的数据。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进