基于javaAgent内存马检测查杀指南_集群智慧网络安全云
全国客户服务热线:4006-054-001 疑难解答:159-9855-7370(7X24受理投诉、建议、合作、售前咨询),173-0411-9111(售前),155-4267-2990(售前),座机/传真:0411-83767788(售后),微信咨询:543646
企业服务导航

基于javaAgent内存马检测查杀指南

发布日期:2024-05-24 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370


基于javaAgent内存马检测查杀指南

文章来源:宽字节安全 新版冰蝎的内存马使用基于javaagnet技术实现,在昨天的文章中,我只谈了怎么还原被修改的内存马。但是在检测这块,我并没有详细说明,其实这块我也不太清楚。不过经过我昨日连夜分析javaagent相关技术资料,找到一种检测javaagent内存马比较通用的方法。分享给大家,希望让hw蓝队的小同学做应急响应的时候,不被甲方问倒。当然,清除javaagent内存马是一个比较有挑战的任务,如果您感觉在不重启目标服务器的情况下很难完成该项任务,请与我们联系。 1 基础 我们先介绍以下什么是java agent,也就是JVM Instrumentation 。 JDK™5.0中引入包java.lang.instrument。 该包提供了一个Java编程API,可以用来开发增强Java应用程序的工具,例如监视它们或收集性能信息。使用  Instrumentation,开发者可以构建一个独立于应用程序的代理程序(Agent),用来监测和协助运行在 JVM  上的程序,甚至能够替换和修改某些类的定义。有了这样的功能,开发者就可以实现更为灵活的运行时虚拟机监控和 Java  类操作了,这样的特性实际上提供了一种虚拟机级别支持的 AOP 实现方式,使得开发者无需对 JDK 做任何升级和改动,就可以实现某些 AOP  的功能了。 简单来讲,该项技术赋予我们可以动态修改JVM中已加载类的字节码的能力而不需要重启JVM。内存马正是利用这点,修改中间件的处理逻辑。 通过JVM Instrumentation 去修改一个已经加载的类的字节码,我们可以认为需要两个关键API retransformClasses(Class… classes) throws UnmodifiableClassException; void redefineClasses(ClassDefinition… definitions) throws ClassNotFoundException, UnmodifiableClassException; 这两个函数的主要区别,用人话来讲 retransform class 可以简单理解为回滚操作,具体回滚到哪个版本,这个需要看情况而定,下面不管那种情况都有一个前提,那就是javaagent已经要求要有retransform的能力了: 如果类是在第一次加载的的时候就做了transform,那么做retransform的时候会将代码回滚到transform之后的代码 如果类是在第一次加载的的时候没有任何变化,那么做retransform的时候会将代码回滚到最原始的类文件里的字节码 如果类已经加载了,期间类可能做过多次redefine(比如被另外一个agent做过),但是接下来加载一个新的agent要求有retransform的能力了,然后对类做redefine的动作,那么retransform的时候会将代码回滚到上一个agent最后一次做redefine后的字节码。 redefineClasses 对参数代码的类进行重新定义。针对的是已经加载的类。 2 检测 冰蝎内存马通过修改javax.servlet.http.HttpServlet#service方法,添加自己的处理逻辑,也就是内存马。 我们整理一下冰蝎的添加流程 通过javaassist获取javax.servlet.http.HttpServlet类的字节码 向service方法添加字节码 清除javaassist缓存,调用redefineClass重新定义修改后的HttpServlet字节码 这样,http中间件在处理每个http链接的时候,就会调用修改后的httpservlet方法。如果发现处理的url为内存马需要响应的url,则执行webshell处理流程,否则隐藏不执行任何操作。 冰蝎在添加完内存马后,会将已经落地的javaagent文件删除。这也给我们检测代码了很大的挑战。 添加完内存马后在控制台打印的内容 在JVM中,同一个类是允许被javaagent动态修改多次的。而且在java中,在retransform方法被调用的时候,jvm会将类的字节码作为参数传递给用户的Transform转换类。 在这里有一个大坑,也就是在调用retransformClass方法的时候参数中的字节码并不是调用redefineClass后被修改的类的字节码。对于冰蝎来讲,我们根本无法获取被冰鞋修改后类的字节码,这一点才是冰蝎最骚的地方。 我们自己写javaagent清除内存马的时候,同样也是无法获取到被redefineClass修改后的字节码,只能获取到被retransformClass修改后的字节码。通过javaassist等asm工具获取到类的字节码,也只是读取磁盘上响应类的字节码,而不是jvm中的字节码。这也就是我说清除容易,检测难的缘由。 在应急响应的时候,客户需要我们有确切的证据去证明服务器被注入内存马。没有证据证明服务器被植入内存马,客户难道允许我们直接运行清除内存马的工具? 所以这个检测的重点在于,怎么安全地获取到JVM运行的类的字节码以供我们分析。(在这里我们只谈oracle jvm,其他jvm暂且不谈,有需要的同学后台联系我) 幸好我发现了sa-jdi.jar这个jvm提供的小工具。 sa-jdi.jar  Hotspot 的 Serviceability Agent  是个很强大的JVM 监控工具集合(这里简称SA),我们可以通过SA 提供的Java API(sa-jdi.jar)做事情。 使用方法很简单,打开,输入jvm的进程,点击菜单栏的tools-class broswer查看当前jvm中已经加载并被java Instrumentation修改后的类。然后搜索你认为可能被植入内存马的类 点击你关心的方法,比如service方法,就可以查看该方法的字节码。 如图是冰蝎的内存马,修改后的类的字节码。我们可以发现可读性很差,别急,我们可以使用 https://github.com/hengyunabc/dumpclass 工具来dump类至指定的文件夹。运行如图 现在可以做真正地溯源工作了。 3 清除 清楚工作是最简单的,在前面我们也说过,通过javaassist就可以很方便地获取磁盘上未经内存马修改的类的字节码。通过retransformClass方法重新定义类即可。 我们首先需要编写一个javaagent,然后注入到目标中间件即可。在这里不分中间件类型,只需要知道被修改的类名即可 3.1 周瑜内存马的清理 项目地址。 https://github.com/threedr3am/ZhouYu 该类内存马的特征在于阻止后续javaagent加载的方式,防止webshell被查杀。我们来看一下代码 在这里其实不影响随后javaagent加载的。原因在于,javaagent修改类的字节码的关键在于用户需要编写继承自java.lang.instrument.ClassFileTransformer,去完成修改字节码的工作。而周瑜内存马的方法在于,如果发现某个类继承自ClassFileTransformer,则将其字节码修改为空。但是在这里并不会影响JVM加载一个新的javaagent。周瑜内存马该功能只会破坏 rasp的正常工作。 周瑜内存马正常通过javaagent加载并查杀即可,不会受到任何影响的。或者,我们也可以通过redefineClass的方法去修改类的字节码。 注意,检测方法不会影响线上业务。向线上业务加载javaagent有可能会直接导致目标JVM 出现异常而导致服务宕机,请慎重实用工具

基于javaAgent内存马检测查杀指南