【蓝队】HW中盛行的Java内存马,如何全面检测?

news/2024/12/16 17:08:21/文章来源:https://www.cnblogs.com/o-O-oO/p/18610617

一、背景

1.1 Java内存马是什么?

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

1.2 Java类加载机制

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

1.3 内存马检测的必要性

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

二、检测

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

1、读取内存中的Class信息

2、对Class信息进行分析检测

检测大纲:

2.1 Class信息获取

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,能够把对应进程已加载的类全部读取出来。

代码示例:

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方式替代。

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

2.1.2 获取内容

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

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

2.2. Class信息检测

对获取到的Class信息进行检测,可以分为两个方面:
1、首先对Class进行筛选,识别风险类。

2、根据需求对全部类或者风险类的Class字节码内容进行检测。

2.2.1. Class风险类检测

1、 Web风险类检测

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

组件型内存马:仅需要针对内存中对应的Servlet、filter、Listener等组件进行分析即可。

JSP内存马:仅针对内存中实现HttpServlet的类进行分析即可。

agent型内存马:由于agent机制几乎可以改写内存中的任何类,可以hook的位置非常多,具体特征需跟着技术发展不断迭代更新。hook点一般都在Web调用的关键链路上。

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

  1. Web调用链分析:

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

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

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

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

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

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

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

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

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

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

  1. 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对象的引用关系,找到获取的链路。

获取方式举例如下:

2、Class基础信息检测

  1. classPath为空

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

1、getProtectionDomain().getCodeSource()为空

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

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

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

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

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

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

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

2.2.2. Class字节码检测

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

1、内存与磁盘字节码比对

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

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

代码示例:

2、敏感代码调用检测

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

高敏感的代码调用:

1、命令执行:

java.lang.Runtime#execjava.lang.ProcessBuilder#startjava.lang.UNIXProcess#forkAndExec...

2、JNI加载动态库:

java.lang.System#loadjava.lang.Runtime#load...

3、类加载:

java.lang.ClassLoader#defineClassjava.lang.reflect.Proxy#defineClass0sun.misc.Unsafe#defineAnonymousClassjava.lang.invoke.MethodHandles.Lookup#defineHiddenClass...

其他敏感代码调用:

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

3、反射调用检测

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

反射调用方式:

java.lang.reflect.Method#invokesun.reflect.NativeMethodAccessorImpl#invokejdk.internal.reflect.NativeMethodAccessorImpl#invoke0java.lang.invoke.LambdaMetafactory#metafactoryjava.lang.invoke.MethodHandle#invokejava.lang.invoke.MethodHandle#invokeExactjava.lang.invoke.MethodHandle#invokeWithArguments...

如何有效检测反射调用

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

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

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

三、总结

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

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

来源:【干货 | HW中盛行的Java内存马,如何全面检测?- FreeBuf网络安全行业门户】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/853849.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Express的使用笔记9 使用bcrypt算法给用户密码加密

先了解一下bcrypt算法,一种基于Blowfish密码学算法的密码散列函数,用于在密码存储时抵抗暴力破解攻击,通过在散列过程中加salt来提高安全性,salt是个随机生成的数据串,与密码一起被散列,使得即使两个相同的密码也会产生不同的散列值。bcrypt算法允许开发者指定工作因子(…

4.mysql中的存储过程

创建存储过程和函数 CREATE[DEFINER = {USER | CURRENT_USER}] # 定义者是谁PROCEDURE sp_name ([proc_parameter[,...]])[characteristic ...] routine_bodyCREATE [DEFINER = {USER | CURRENT_USER}]FUNCTION sp_name ([function_name[,...]])[characteristic ...] routine_…

印象笔记使用

vscode安装插件登录印象笔记,开通token点击插件页面的设置填写url和tokenctrl + shift + pever new - 新建笔记 ever open - 打开笔记 ever search - 搜索笔记 ever publish - 发布笔记 ever sync - 同步笔记新建笔记下载安装windows客户端,功能比网页端更全面客户端才能导出…

(BIBM-2024) 用于药物相互作用预测的可解释多视图注意网络

用于药物相互作用预测的可解释多视图注意网络 论文标题: Interpretable multi-view attention network for drug-drug interaction prediction 论文地址: https://ieeexplore.ieee.org/document/10385757 论文期刊: BIBM 2024 摘要 药物间相互作用(DDI)在药物发现中发挥着越来…

Volatility取证工具安装教程

linux安装vol2.6 1.准备工作 准备一台虚拟机,拥有python2版本(虚拟机以kali为例) 准备Volatility2.6安装包 volatilityfoundation/volatility: An advanced memory forensics framework 准备反编译库安装包 vext01/distorm3: distorm3 2.安装步骤详解(全程在root用户下操作…

[React]AntDesign 4.x 汉化

antd汉化,适用于4.x转载自:https://blog.csdn.net/weixin_43013802/article/details/132870349全局汉化,在main.ts中引入下面代码:import{ ConfigProvider }fromantd import locale from antd/locale/zh_CN; import dayjs/locale/zh-cn;ReactDOM.createRoot(document.getEl…

线性回归(linear regression)

其实线性回归不过就是在做两件事,画一条线并判断这条线到各个点的距离。 如下图:其中这条线便是距离各个点距离总和最小的直线。也就是e+u+w+b+a总和在直线为这个情况下最小。但是什么时候这条线是我们需要的线呢?-- 线到各个点最短的时候便是。 我们先理解一下什么是凹函数…

数据库安全性与权限管理

title: 数据库安全性与权限管理 date: 2024/12/16 updated: 2024/12/16 author: cmdragon excerpt: 数据库安全性与权限管理是保护数据不被未授权访问和操控的关键所在。通过实施有效的安全措施和细粒度的权限控制,可以确保数据库的完整性、机密性和可用性。 categories:前端…

数据整合+团队协作,电商选品效率提升100%!

选品快准狠!在线协同助力电商团队做出更聪明的决策 在电商行业,“选品”决定成败。无论是发现爆款、避开雷区,还是追踪最新趋势,每一个决策都离不开团队协作与信息整合。然而,大量的电商团队仍旧面临以下常见问题: - 决策过程拉长,错失销售机会。 - 数据不统一,选品思路…

xshell类似的工具,还有哪些Xshell类似的工具呢

Xshell是一款功能强大的远程连接工具,广泛用于SSH、Telnet和Rlogin协议,帮助用户轻松连接和管理远程服务器。然而,Xshell并不是唯一的远程连接工具,市面上还有其他一些类似的工具,能够提供类似甚至更丰富的功能。那么,除了Xshell,还有哪些类似的远程连接工具呢?以下将为…

SOA整车电子电气仿真测试解决方案

经纬恒润TESTBASE 硬件在环(HIL)仿真测试平台可以为SOA电子电气系统提供高效自动化测试的一站式解决方案,为SOA车型电子电气系统的测试验证提供有力保障。概述软件定义汽车时代,汽车电子软件的功能数量和复杂度与传统汽车相比有了爆炸式增长,并且还在不断提升。以中央+区域…

线程和进程

线程 什么是线程和进程? 何为进程? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。 在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进…