前言
在Java
里有一些渗透场景可以获得堆内存也即是heapdump
比如有的应用存在某个功能可以获取heapdump
、springboot
的/actuator/heapdump
也可以获取。但是网上比较多的分析文章讲的都比较浅导致挺多人不知道heapdump
里到底有什么东西,这篇文章讲一讲对heapdump
进行深入分析获取某些特定信息。
常规信息获取
先讲一下大多数人的分析方式。最早的时候大家都是使用MAT
、jhat
、jvisualvm
然后使用oql
语句去查询字符串里的敏感信息。我当时刚接触的时候对这个的分析文章比较少我记得最早讲的比较清楚的文章是下面这篇
https://zen-sec.github.io/fr/java-heapdump-extraction/
这个时期的oql
语句主要集中在查询配置信息,以及内存中可能存在的user|pass|email|oss|aksk|jwt|shiro-key
等信息后来有人写了自动化的分析工具主要是下面两款
https://github.com/wyzxxz/heapdump_tool
https://github.com/whwlsfb/JDumpSpider
距离工具发布到现在已经有好几年的时间了,然后我发现很多朋友好像已经不会使用oql
语句自定义查询信息了,都是使用这两款工具执行一下就结束然后这两款工具有的时候输出没什么敏感的东西就直接结束了不再进行深度利用,我将在下面写一下这两款工具没有覆盖的一些信息获取方式。
深度信息获取
假设我们利用上述两款工具没有获取到什么有用信息还可以使用下面的方式进行利用,这里仅列举出一些案例有其他感兴趣的东西可以自己构造语句查询。使用MAT
打开heapdump
,主要现在MAT
的主要版本需要使用jdk17+
才能使用,我jdk环境默认1.8可以使用命令行vm参数指定一个jdk17路径打开
MemoryAnalyzer.exe -vm "C:\Users\admin\.jdks\jbr-17.0.12\bin\javaw.exe"
从这里打开你下载的heapdump
然后点击下面图标进行oql
查询
查询依赖版本
我们首先可以查看这个应用有什么依赖以及他们具体是什么版本,直接从字符串中搜索DISTINCT
用于去重(也可通过类加载器查询)。
SELECT DISTINCT toString(s) FROM java.lang.String s WHERE (toString(s) LIKE "file.*\.jar!/")

比如这里发现fastjson
依赖在漏洞范围内即可尝试fastjson
漏洞。
查询session
这里以springboot
默认容器为例tomcat
默认的session
储存在org.apache.catalina.session.StandardSession
中所以可以写出如下oql语句
SELECT * FROM org.apache.catalina.session.StandardSession

我这里因为这个网站好像是被很多人扫描了导致尝试了大量无效session
总计有1w+,所以需要想办法排除掉一些无效session
这种无效session
的尝试大多数是扫描器直接访问一个路由然后返回包就会返回一个session
这种的话比较好筛选。我们可以注意点每个session
实例里都储存了以下信息
根据上面的分析我们可以加一个判断(s.lastAccessedTime - s.creationTime) > 6000
也就是最后访问时间需要大于创建时间6秒钟我们即认为是有效session
。但是这还不足以判断session
是否被设置了访问权限。一般登陆成功后都会使用setAttribute
往session
里设置属性加上一些其他判断我们可以写出如下oql
语句直接获取有效的sessionid
SELECT s.id.toString() FROM org.apache.catalina.session.StandardSession s WHERE ((s.isValid = true) and (s.attributes != null) and ((s.lastAccessedTime - s.creationTime) > 6000))

有的session
属性里甚至会直接存放账号密码
查询http数据包
上面我们查询到了session
但是有很多时候并不是使用默认的session
鉴权,所有可以获取http数据作为补充。我们知道springboot
默认使用tomcat
作为容器,经过代码分析已经查阅资料可知可以通过org.apache.coyote.http11.Http11InputBuffer
和org.apache.tomcat.util.net.SocketBufferHandler
分别获取我们heapdump
期间或之前尚未处理完的http
数据包。
获取请求包
SELECT h.byteBuffer.hb.toString() FROM org.apache.coyote.http11.Http11InputBuffer h

先全选然后右键COPY->Selection
即可复制所有数据
获取响应包,最开始以为会记录在Http11OutputBuffer
里面经过分析发现Http11OutputBuffer
里只记录返回包header
数据,完整数据记录需要使用下面的语句查询
SELECT rp.writeBuffer.hb.toString() FROM org.apache.tomcat.util.net.SocketBufferHandler rp

获取某些http
缓存数据段
SELECT DISTINCT bc.buff.toString() FROM org.apache.tomcat.util.buf.ByteChunk bc WHERE (bc.buff != null)
注意这里的数据不和请求包完全重叠,有可能记录一些更早的请求数据.比如这里直接获取了登陆的user、pass
从请求包那里查询是没获取到的
查询springboot路由信息
根据之前分析springboot
的经验可知路由信息储存在org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#mappingRegistry
中我们使用oql
语句查询它的实例
SELECT * FROM org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry
成功找到路由信息
注意到他最后都储存在java.util.LinkedHashMap$Entry
所以我们可以直接使用下面语句获取所有路由
SELECT key.toString() FROM java.util.LinkedHashMap$Entry entry WHERE (key.toString() LIKE "/.*")

也可通过MappingRegistration
获取路由对应的方法

可以注意到这里已经获取路由对应的方法了且包含参数个数以及参数类型,还差获取参数名研究了一下发现有的情况是可以获取到参数名的。需要之前触发过这个路由,且缓存信息没被删除。
select * from org.springframework.web.method.support.HandlerMethodArgumentResolverComposite

总结
本文介绍了Java heapdump
的深度分析方法。除了使用常规的自动化工具获取基础敏感信息外,还可以通过自定义OQL
语句进行更深入的信息挖掘。这些方法能够在常规工具无法发现敏感信息时,提供更深层次的数据挖掘能力,帮助渗透测试人员获取更多有价值的信息,如登录凭据、API接口、会话数据等。掌握这些技巧可以大大提升heapdump
文件的利用价值。