freeBuf
主站

分类

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

特色

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

点我创作

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

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

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

FreeBuf+小程序

FreeBuf+小程序

99+

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

干货 | HW中盛行的Java内存马,如何全面检测?
网宿安全演武实验室 2024-10-21 23:10:30 180330
所属地 福建省

1. 背景

1.1. Java内存马是什么?

内存马是一种仅在内存中运行、没有文件落地的恶意程序,因此具有较强的隐蔽性,能够避开常规的基于文件系统的检测。Java内存马是针对Java语言的内存马,它利用Java语言的动态特性,如类加载机制、动态代理和反射技术等,在Java应用的内存中注入恶意代码,从而实现远程控制。

1.2. Java类加载机制

Java虚拟机(JVM)的类加载机制在程序运行时根据需要动态地加载类,而不是在启动时一次性加载所有类。而类可以在运行时从不同的来源,如本地文件系统、远程网络或者其他自定义位置加载。攻击者可以利用这一特性,在运行时加载恶意类,从而向内存中引入不受信任的代码。

1.3. 内存马检测的必要性

近年来,内存马因其持久性、隐蔽性、兼容性强等特性,已被攻击者广泛应用于各种复杂的攻击场景。内存马通过驻留在内存中,规避文件系统的监控,使得传统的杀毒软件和入侵检测系统难以发现其踪迹。因此,需要研究专门的内存马检测技术,以便及时发现并消除内存马带来的安全威胁,从而保障系统的安全性。

2. 检测

Java程序的内存检测一般以Class字节码为维度进行,简单分为两个步骤:

  1. 读取内存中的Class信息
  2. 对Class信息进行分析检测

检测大纲:

1729521415_67166707dfa0fdee792d3.jpg!small

2.1. Class信息获取

2.1.1. 获取方式

2.1.1.1. Serviceability Agent (SA)

SA是JDK提供的一个强大的调试工具集,适用于语言层和虚拟机层,支持调试运行着的Java进程、core文件和虚拟机crash之后的dump文件。SA运行在单独的进程中,和目标Java进程是隔离的,在使用SA工具时,不会在目标Java进程中执行任何代码,但是,在SA读取数据的过程中,目标Java进程会被挂起。

通过sa-jdi.jar中sun.jvm.hotspot.tools.jcore.ClassDump类的方法接收进程id,能够把对应进程已加载的类全部读取出来。

代码示例:

1729521745_671668516c738e62267ce.jpg!small

2.1.1.2. Java Agent

Java Agent 是一种基于 Java Instrumentation API 的机制,可用于在 Java 应用程序运行时动态地修改其字节码。Java Agent 提供了两个主要方法:

  • premain:在 Java 进程启动前加载。这个方法可以在实际类加载之前插入自定义的字节码操作逻辑。
  • agentmain:在 Java 进程启动后加载。这个方法可以在进程运行时对已加载的类进行操作,如读取、修改类字节码等操作。

通过VirtualMachine.attach(pid)方法,可以将当前进程附加到目标 JVM 实例,实现动态代码注入。

PS:冰蝎工具的防检测功能会删除/tmp/.java_pid文件,导致无法使用attach进行注入,可用SA方式替代。

1729522049_67166981a16180bf914e2.jpg!small

正常进行attach以后,可使用agentmain方法注入到另一个进程中来实现内存信息获取。代码示例:

1729522166_671669f603669afce78d9.jpg!small

2.1.2. 获取内容

获取Java类的详细信息,主要关注以下几个字段:

  • 类名(className):获取内存中加载的类的完整名称,有助于识别和追踪潜在的恶意类。
  • 类加载器(classLoader):获取负责加载该类的类加载器,以了解其加载来源,并识别异常或不寻常的加载行为。
  • 包名(packageName):获取类所属的包,以帮助判断类的组织结构和潜在的风险区域。
  • 父类(parentClass):获取该类的父类,分析其继承关系,以发现可能隐藏的恶意代码。
  • 类路径(classPath):获取类在文件系统中的位置,用于验证类的合法来源和检查潜在的篡改迹象。
  • 接口(interfaces):获取该类实现的所有接口,了解其功能和行为契约,检测异常接口实现或恶意接口。
  • 注解(annotations):获取类上的注解,识别可能影响类行为的元数据。
  • 类字节码(classBytes):获取类的字节码内容,深入分析其实际实现,识别可能的恶意代码或不符合预期的行为。

2.2. Class信息检测

对获取到的Class信息进行检测,可以分为两个方面:

  1. 首先对Class进行筛选,识别风险类。
  2. 根据需求对全部类或者风险类的Class字节码内容进行检测。

2.2.1. Class风险类检测

2.2.1.1. Web风险类检测

首先,根据不同内存马的分类来分析潜在的Web风险类

  • 组件型内存马:仅需要针对内存中对应的Servlet、filter、Listener等组件进行分析即可。
  • JSP内存马:仅针对内存中实现HttpServlet的类进行分析即可。
  • agent型内存马:由于agent机制几乎可以改写内存中的任何类,可以hook的位置非常多,具体特征需跟着技术发展不断迭代更新。hook点一般都在Web调用的关键链路上。

虽然有各种各样的内存马,但他们通常都作用在Web调用的关键链路上,通过Web请求触发内存马,通过请求参数执行逻辑。

1) Web调用链分析:

哪些调用链是Web调用的关键链路?

以springboot 的Web项目为例,处理Web请求的调用堆栈大概如下:

1、tomcat建立HTTP连接并添加读写事件的监听:

1729522309_67166a857651a981f880e.jpg!small

2、tomcat 收到请求数据包并放到线程池中处理数据包:

1729522412_67166aecd51f76635e9b2.jpg!small

3、tomcat实际处理请求数据包:

1729522533_67166b65d8353809ea167.jpg!small

实际应用场景中,hook点大概率会发生在tomcat实际处理请求数据包转http请求request之后。

从堆栈信息可以看出来,调用链路会经过tomcat的Valve组件,servlet的FilterChain及Filter组件,Servlet组件,以及springmvc的相关处理,进而执行到Controller的helloworld方法。

那是不是只要关注上述调用链路就可以了?

当然不是,每个方法里都会有其他代码逻辑,实际Web调用过程中会涉及的调用类远比上述调用链更多。

故光靠分析调用链,无法圈定需要内存分析的所有类,只能找出比较高危的类做重点分析。

2) Web容器注册分析

为什么要做Web容器注册分析?

Web框架在进行Web调用处理时,一般分成两步:

  1. 程序启动时注册组件,即Web程序启动时定义好当收到请求时该交给哪个组件如何进行处理。
  2. 实际发生Web调用时,Web容器根据调用信息,找到对应的组件进行处理。

所以,我们可以通过读取Web容器的注册组件对应类进行内存分析,目标性更强,更精准。

此处介绍两种最常见的Web容器:tomcat和springmvc。

a) tomcat容器:

在使用tomcat作为Web容器时,可通过其核心对象StandardContext中获得filter、servlet、listener的注册信息。

获取的过程如下:

  • StandardContext --> filterConfigs,filterDefs --> filter
  • StandardContext --> servletMappings,children --> servlet
  • StandardContext --> applicationListeners,listeners --> listener

Valve也是tomcat中非常重要的组件,但valve是tomcat中内置的组件,正常情况下并不会进行自定义,只需要通过判断类实现Valve接口过滤即可。

而filter、servlet、listener是servlet规范中提供给开发者自定义的开放性组件,则更具有进一步通过容器注册分析的意义。

b) springmvc容器:

springmvc作为最常见的Web框架,其注册信息同样具备针对性分析的价值。

需要获取的注册信息:

springmvc中主要获取的是HandlerMethod对象和HandlerInterceptor对象信息。

  • 容器中注册的HandlerMethod对象表示请求的实际处理方法,表示springmvc中的controller对象和对应处理方法。
  • 容器中的HandlerInterceptor是开放的拦截器,springmvc提供了在请求处理前后进行自定义处理的机制。

如何获取注册信息:

先获取spring的容器组件ApplicationContext,再从中获取springmvc的核心组件DispatcherServlet,进而获取注册信息。获取过程如下:

  • ApplicationContext --> DispatcherServlet --> List<HandlerMapping> handlerMappings --> AbstractHandlerMethodMapping.getHandlerMethods()
  • ApplicationContext --> DispatcherServlet --> List<HandlerMapping> handlerMappings --> AbstractHandlerMapping.adaptedInterceptors

在实际按照上述方式获取springmvc的注册信息时,可能会用到反射获取信息,且可能会不知道从哪获取最源头的ApplicationContext对象,进而无从下手。

最源头的ApplicationContext对象,一般需要从类的静态变量中获取。可通过内存分析ApplicationContext对象的引用关系,找到获取的链路。

获取方式举例如下:

1729522687_67166bff1e1501a89e52a.jpg!small

2.2.1.2. Class基础信息检测

1) classPath为空

通过分析classPath为空的类,排除已知的正常情况,剩下的类大概率为风险类

1、getProtectionDomain().getCodeSource()为空

这意味着该类没有关联的代码源信息。可能的原因包括:

  • 该类是 JVM 自带的类(例如,java.* 中的类),因为这些类是由 JVM 自身加载的,它们没有显式的代码源。
  • 该类是通过字节码操作动态生成的,或者是以非标准的方式加载的(如通过某些代理类或字节码工具动态生成)。
  • 该类是在 Java 运行时生成的,例如使用 Proxy、ClassLoader.defineClass() 等方法生成的类。

2、getClassLoader().getResource(className.replace(".", "/") + ".class")为空

这意味着类加载器无法找到与指定类对应的资源路径。可能的原因包括:

  • 类是由一个特定的类加载器加载的,但该类加载器不使用标准的路径查找机制(如 URLClassLoader 或自定义的 ClassLoader)。
  • 该类是通过内存中直接加载的方式(如字节码生成工具)加载的,而不是从文件系统或网络资源中获取的,因此找不到相应的类文件资源。
  • 类加载器因为安全限制或者其他原因,无法访问该类的实际存储位置。

2) 关键字特征匹配

可以通过检测包名、类名、父类名、类加载器等类基础信息中是否包含诸如 shell、exploit 等可疑关键字,识别可能由内存马生成工具创建的恶意类。

  • 冰蝎的包名以net.rebeyond.开头或带有Behinder关键字
  • 哥斯拉的包名以core.shell.开头或带有Godzilla关键字
  • msf的包名以com.metasploit.开头
  • 蚁剑带有AntSword关键字
  • ...

2.2.2. Class字节码检测

通过检测Class基础信息方式识别内存马的方式仅对Class的一些表象特征进行分析,其优势在于消耗低,但容易被绕过。而内存马注入的恶意代码肯定是以Class字节码存在在内存之中,通过检查Class字节码内容是一种更直接的方式。

2.2.2.1. 内存与磁盘字节码比对

读取已加载的字节码信息,和磁盘中的字节码信息进行比对。如果不一致,则为可疑类。

如果直接对Class的字节流进行比对,可能经常会误报,可以使用ASM工具将Class内容解析成属性和方法,再对每个属性和方法进行比对。

代码示例:

1729522836_67166c94279ea796d4ddf.jpg!small

1729522970_67166d1ad0163a6870fba.jpg!small

2.2.2.2. 敏感代码调用检测

使用ASM工具解析Class字节码的方法,与敏感代码特征进行比对

高敏感的代码调用:

1、命令执行:

  • java.lang.Runtime#exec
  • java.lang.ProcessBuilder#start
  • java.lang.UNIXProcess#forkAndExec
  • ...

2、JNI加载动态库:

  • java.lang.System#load
  • java.lang.Runtime#load
  • ...

3、类加载:

  • java.lang.ClassLoader#defineClass
  • java.lang.reflect.Proxy#defineClass0
  • sun.misc.Unsafe#defineAnonymousClass
  • java.lang.invoke.MethodHandles.Lookup#defineHiddenClass
  • ...

其他敏感代码调用:

  • 获取系统信息
  • 字节码生成类库
  • 文件操作
  • 编码加密
  • ...

2.2.2.3. 反射调用检测

由于Java语言开放和动态的特性,可通过反射等方式动态地调用上述的敏感代码,进而绕过正常的检测规则。

反射调用方式:

  • java.lang.reflect.Method#invoke
  • sun.reflect.NativeMethodAccessorImpl#invoke
  • jdk.internal.reflect.NativeMethodAccessorImpl#invoke0
  • java.lang.invoke.LambdaMetafactory#metafactory
  • java.lang.invoke.MethodHandle#invoke
  • java.lang.invoke.MethodHandle#invokeExact
  • java.lang.invoke.MethodHandle#invokeWithArguments
  • ...

如何有效检测反射调用:

有师傅提出用模拟栈帧的方式进行检测,但是模拟栈帧的方式开销大,同时只能将检测范围圈定在单个方法内,而反射调用的入参可能在其他方法中定义,甚至在Web请求参数中定义,故有一定的局限性。

由于反射的运行时确定的特性,可以通过运行时检测,修改字节码,在反射代码前插桩,判断反射的参数是否命中敏感代码调用,进而告警。

2.2.2.4. Webshell引擎检测

将Class字节码反编译为Java文件后,交由成熟的Webshell检测引擎进行扫描。将反编译后的Class文件视作普通源代码进行检测,其核心依然是识别潜在的Webshell。通过这种方法,充分利用现有的检测技术,识别出隐藏在内存或代码中的恶意行为,进一步提升检测的准确性与效率。

3. 总结

本文系统性地列举了Java内存马的检测方法,涵盖了从类的基本信息获取到字节码的深入检测。通过这些方法,能够有效识别内存马攻击。可根据不同场景或需求,在检测率与性能开销之间进行平衡,选择适合的检测方式,以实现最佳的检测效果。

然而,攻防对抗本质上是动态的,随着内存马技术的不断发展,新的攻击手段和技术也会不断涌现,现有的检测手段也可能会失效。因此,需要持续更新和调整检测策略,跟踪最新的攻击趋势和技术进展,不断搜集和优化检测特征,以提升系统的防御能力,降低安全风险。

# 网络安全 # 木马分析 # 木马病毒 # JAVA安全 # 内存木马
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 网宿安全演武实验室 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
secops
网宿安全演武实验室 LV.5
网宿科技-网宿安全演武实验室官方账号
  • 41 文章数
  • 80 关注者
大模型安全警报:你的AI客服正在泄露客户银行卡号
2025-03-27
信息安全风险管理简述(下):如何进行风险评估
2025-03-11
信息安全风险管理简述(上)
2025-03-11
文章目录