Agent内存马的自动分析与查杀(一)

简介: Agent内存马的自动分析与查杀

出发点是Java Agent内存马的自动分析与查杀,实际上其他内存马都可以通过这种方式查杀

本文主要的难点主要是以下三个,我会在文中逐个解答

  1. 如何dumpJVM真正的当前的字节码
  2. 如何解决由于LAMBDA表达式导致非法字节码无法分析的问题
  3. 如何对字节码进行分析以确定某个类是内存马

基于静态分析动态,打破规则之道                            -- Java King 对本文的评价

背景

对于Java内存马的攻防一直没有停止,是Java安全领域的重点

回顾TomcatSpring内存马:FilterController等都需要注册新的组件

针对于需要注册新组件的内存马查杀起来比较容易:

例如c0ny1师傅的java-memshell-scanner项目,利用了Tomcat API删除添加的组件。优点在于一个简单的JSP文件即可查看所有的组件信息,结合人工审查(类名和ClassLoader等信息)对内存马进行查杀,也可以对有风险的Class进行dump后反编译分析

或者LandGrey师傅基于Alibaba Arthas编写的copagent项目,分析JVM中所有的Class,根据危险注解和类名等信息dump可疑的组件,结合人工反编译后进行分析


但实战中,可能并不是以上这种注册新组件的内存马

例如师傅们常用的冰蝎内存马,是Java Agent内存马。以下这段是冰蝎内存马一段代码,简单分析后可以发现冰蝎内存马是利用Java Agent注入到javax.servlet.http.HttpServletservice方法中,这是JavaEE的规范,理论上部署在Tomcat的都要符合这个规范,简单来理解这是Tomcat处理请求最先且总是经过的地方,在该类加入内存马的逻辑,可以保证稳定触发

0720a98a5016990af0494aea8a84c82d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

类似的逻辑,可以使用Java Agent将内存马注入org.apache.catalina.core.ApplicationFilterChain类中,该类位于Filter链头部,也就是说经过Tomcat的请求都会交经过该类的doFilter方法处理,所以在该方法中加入内存马逻辑,也是一种稳定触发的方式(据说这是老版本冰蝎内存马的方式)

还可以对类似的类进行注入,例如org.springframework.web.servlet.DispatcherServlet类,针对于Spring框架的底层进行注入。或者一些巧妙的思路,比如注入Tomcat自带的Filter之一org.apache.tomcat.websocket.server.WsFilter类,这也是Java Agent内存马可以做到的


上文简单地介绍了各种内存马的利用方式与普通内存马的查杀,之所以最后介绍Java Agent内存马的查杀,是因为比较困难。宽字节安全的师傅提出查杀思路:基于javaAgent内存马检测查杀指南

引用文章讲到Java Agent内存马检测的难点:

调用retransformClass方法的时候参数中的字节码并不是调用redefineClass后被修改的类的字节码。对于冰蝎来讲,根本无法获取被冰蝎修改后的字节码。我们自己写Java Agent清除内存马的时候,同样也是无法获取到被redefineClass修改后的字节码,只能获取到被retransformClass修改后的字节码。通过JavaassistASM工具获取到类的字节码,也只是读取磁盘上响应类的字节码,而不是JVM中的字节码

宽字节安全的师傅找到了一种检测手段:sa-jdi.jar

借用公众号师傅的图片,这是一个GUI工具,可以查看JVM中所有已加载的类。区别在于这里获取到的是真正的当前的字节码,而不是获取到原始的,本地的字节码,所以是可以查看被Java Agent调用redefineClass后被修改的类的字节码。进一步可以dump下来认为存在风险的类然后反编译人工审核

f438bb946a834eaf9896fff648e7cd5c_640_wx_fmt=other&wxfrom=5&wx_lazy=1&wx_co=1.jpg


介绍

以上是背景,接下来介绍我做了些什么,能够实现怎样的效果

不难看出,以上内存马查杀手段都是半自动结合人工审核的方式,当检测出内存马后

是否可以找到一种方式,做到一条龙式服务:

  • 检测(同时支持普通内存马和Java Agent内存马的检测)
  • 分析(如何确定该类是内存马,仅根据恶意类名和注解等信息不完善)
  • 查杀(当确定内存马存在,如何自动地删除内存马并恢复正常业务逻辑)

大致看来,实现起来似乎不难,然而实际中遇到了很多坑,接下来我会逐个介绍


SA-JDI分析

我尝试通过Java Agent技术来获取当前的字节码,发现如师傅所说拿不到被修改的字节码

所以为了可以检测Agent马需要从sa-jdi.jar本身入手,想办法dump得到当前字节码(这样不止可以分析被修改了字节码的Agent马也可以分析普通类型的内存马)

注意到其中一个类:sun.jvm.hotspot.tools.jcore.ClassDump并通过查资料发现该类功能正是dump当前的Class(根据类名也可猜测出)其中的main方法提供一个dump class的命令行工具

于是我想了一些办法,用代码实现了命令行工具的功能,并可以设置一个Filter

ClassDump classDump = new ClassDump();
// my filter
classDump.setClassFilter(filter);
classDump.setOutputDirectory("out");
// protected start method
Class<?> toolClass = Class.forName("sun.jvm.hotspot.tools.Tool");
Method method = toolClass.getDeclaredMethod("start", String[].class);
method.setAccessible(true);
// jvm pid
String[] params = new String[]{String.valueOf(pid)};
try {
   method.invoke(classDump, (Object) params);
} catch (Exception ignored) {
   logger.error("unknown error");
   return;
}
logger.info("dump class finish");
// detach
Field field = toolClass.getDeclaredField("agent");
field.setAccessible(true);
HotSpotAgent agent = (HotSpotAgent) field.get(classDump);
agent.detach();

上文提到设置一个Filter是用于确定需要对哪些类进行dump操作(dump过多会导致性能等问题)

public class NameFilter implements ClassFilter {
   @Override
   public boolean canInclude(InstanceKlass instanceKlass) {
       String klassName = instanceKlass.getName().asString();
       // 在黑名单中的类需要dump
       if (blackList.contains(klassName)) {
           return true;
      }
       // 包含了关键字的类也需要dump
       for (String k : Constant.keyword) {
           if (klassName.contains(k)) {
               return true;
          }
      }
       return false;
  }
}

以上包含了类的黑名单和关键字:

  • 黑名单:Java Agent内存马通常会Hook的地方,需要dump下来进行分析
  • 关键字:类名如果出现memshellshell等关键字认为可能是普通内存马,需要分析
public class Constant {
   // BLACKLIST (Analysis Target)
   // CLASS_NAME#METHOD_NAME
   public static List<String> blackList = new ArrayList<>();
   // SHELL KEYWORD
   public static List<String> keyword = new ArrayList<>();
   static {
       blackList.add("javax/servlet/http/HttpServlet#service");
       blackList.add("org/apache/catalina/core/ApplicationFilterChain#doFilter");
       blackList.add("org/springframework/web/servlet/DispatcherServlet#doService");
       blackList.add("org/apache/tomcat/websocket/server/WsFilter#doFilter");
       keyword.add("shell");
       keyword.add("memshell");
       keyword.add("agentshell");
       keyword.add("exploit");
       keyword.add("payload");
       keyword.add("rebeyond");
       keyword.add("metasploit");
  }
}

另外如果想在Maven项目中加入JDK/lib下的依赖,需要特殊配置

<dependency>
   <groupId>sun.jvm.hotspot</groupId>
   <artifactId>sa-jdi</artifactId>
   <version>jdk-8</version>
   <scope>system</scope>
   <systemPath>${env.JAVA_HOME}/lib/sa-jdi.jar</systemPath>
</dependency>

在打包成工具Jar包时默认情况下不会加入system scope的依赖,所以需要特殊处理

<artifactId>maven-assembly-plugin</artifactId>
<configuration>
   <appendAssemblyId>false</appendAssemblyId>
   <descriptors>
       <descriptor>assembly.xml</descriptor>
   </descriptors>
   <archive>
       <manifest>
           <mainClass>org.sec.Main</mainClass>
       </manifest>
   </archive>
</configuration>

编写assembly.xml文件

<!-- 省略部分 -->
<dependencySets>
   <dependencySet>
       <outputDirectory>/</outputDirectory>
       <unpack>true</unpack>
       <scope>system</scope>
   </dependencySet>
</dependencySets>

接着就可以通过代码的方式,根据黑名单和关键字来确定需要dump哪些类然后进行dump操作了

我在测试中遇到一个小问题,值得分享:HttpServlet是正常可以dump的但是ApplicationFilterChain类没有找到。这是因为SpringBoot的懒加载问题,需要手动请求下某个接口就可以了


相关文章
|
10天前
|
存储 安全 Java
synchronized原理-字节码分析、对象内存结构、锁升级过程、Monitor
本文分析的问题: 1. synchronized 字节码文件分析之 monitorenter、monitorexit 指令 2. 为什么任何一个Java对象都可以成为一把锁? 3. 对象的内存结构 4. 锁升级过程 (无锁、偏向锁、轻量级锁、重量级锁) 5. Monitor 是什么、源码查看(hotspot虚拟机源码) 6. JOL工具使用
|
3天前
|
Java
堆内存的溢出案例分析
堆内存的溢出案例分析
4 0
|
3天前
|
JSON 数据管理 测试技术
自动化测试工具Selenium Grid的深度应用分析深入理解操作系统的内存管理
【5月更文挑战第28天】随着互联网技术的飞速发展,软件测试工作日益复杂化,传统的手工测试已无法满足快速迭代的需求。自动化测试工具Selenium Grid因其分布式执行特性而受到广泛关注。本文旨在深入剖析Selenium Grid的工作原理、配置方法及其在复杂测试场景中的应用优势,为测试工程师提供高效测试解决方案的参考。
|
8天前
|
Kubernetes 安全 Go
对于阿里开源混沌工程工具chaosblade-box-agent心跳报错问题的分析与解决
摘要: 本文记录了一个由chaosblade-box平台后台发现的偶发的chaosblade-box-agent不发送心跳的问题,从报错日志入手,结合chaosblade-box-agent源码进行分析,最终解决问题并修复打包的过程。
219 7
|
17天前
|
人工智能 测试技术 API
【AIGC】LangChain Agent(代理)技术分析与实践
【5月更文挑战第12天】 LangChain代理是利用大语言模型和推理引擎执行一系列操作以完成任务的工具,适用于从简单响应到复杂交互的各种场景。它能整合多种服务,如Google搜索、Wikipedia和LLM。代理通过选择合适的工具按顺序执行任务,不同于链的固定路径。代理的优势在于可以根据上下文动态选择工具和执行策略。适用场景包括网络搜索、嵌入式搜索和API集成。代理由工具组成,每个工具负责单一任务,如Web搜索或数据库查询。工具包则包含预定义的工具集合。创建代理需要定义工具、初始化执行器和设置提示词。LangChain提供了一个从简单到复杂的AI解决方案框架。
337 3
|
17天前
|
存储 Arthas 监控
JVM工作原理与实战(三十):堆内存状况的对比分析
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了堆内存状况的对比分析、产生内存溢出的原因等内容。
16 0
|
17天前
|
缓存 Linux
linux性能分析之内存分析(free,vmstat,top,ps,pmap等工具使用介绍)
这些工具可以帮助你监视系统的内存使用情况、识别内存泄漏、找到高内存消耗的进程等。根据具体的问题和需求,你可以选择使用其中一个或多个工具来进行内存性能分析。注意,内存分析通常需要综合考虑多个指标和工具的输出,以便更好地理解系统的行为并采取相应的优化措施。
41 6
|
17天前
|
机器学习/深度学习 分布式计算 数据处理
Spark是一个基于内存的通用数据处理引擎,可以进行大规模数据处理和分析
【5月更文挑战第2天】Spark是一个基于内存的通用数据处理引擎,可以进行大规模数据处理和分析
29 3
|
17天前
|
人工智能 自然语言处理 搜索推荐
【AGI】智能体简介及场景分析
【4月更文挑战第14天】AI时代,智能体的意义,使用场景及对未来的意义
59 1
|
17天前
|
监控 Unix Windows
Zabbix【部署 04】 Windows系统安装配置agent及agent2
Zabbix【部署 04】 Windows系统安装配置agent及agent2
230 0