内存马排查

前言

本文主主要是记录下网上大佬总结的内存马排查的一些方法,因为护网也临近了,相信不少师傅在面试的时候也是会设计到内存马排查的这些问题,因为内存马在攻防中是常见的手段,因此内存马排查也是应急人员需要掌握的技能,之前自己分析过一些内存马的原理,对于排查内存马一直没有什么太好的实战经验,所以就去网上搜刮了几篇文章,自己模拟真实环境进行学习了一波,主要是记录一下为后面的工作节省时间。

工具

这里主要介绍几款可以用来帮助排查的工具。

arthas

Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
https://github.com/alibaba/arthas

memshell-scanner

这款工具可以应对绝大数传统的内存马的查杀了。
https://github.com/c0ny1/java-memshell-scanner 原版
https://github.com/ruyueattention/java-memshell-scanner 二开版的

copagent (仅排查,只适用于 jdk1.8)

该工具能够在运行时获取 JVM 中加载的所有类信息,结合类的包名、类名、接口实现、注解标记等多维度特征进行静态筛选。针对潜在威胁类,copagent 进一步判断是否具备磁盘资源链接、是否包含特定的恶意关键字(如动态代理、Servlet Hook、命令执行等行为特征),从而识别可能存在的内存马组件。

对于检测出的可疑类,copagent 提供自动 dump 能力,便于安全分析人员进行反编译和人工复审,实现对内存马、恶意插件或注入类的快速定位与处置。
https://github.com/LandGrey/copagent

环境搭建

我搭建是利用的vulhub的CVE-2020-1938漏洞环境进行复现的

https://github.com/vulhub/vulhub

然后将webshell放进去

查杀

查杀思路

存马存在的一些可疑的特征。通常情况下更多的是使用以下特征去判断:
继承可能实现 Webshell 接口,例如 Servlet,Filter,Listener,Interceptor

1
2
3
4
5
javax.servlet.http.HttpServlet
org.springframework.web.servlet.handler.AbstractHandlerMapping
javax.servlet.Filter
javax.servlet.Servlet
javax.servlet.ServletRequestListener

高危 classloader 加载:查看 classloader 是不是 Templates 或 bcel 等

1
2
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$TransletClassLoader
com.sun.org.apache.bcel.internal.util.ClassLoader

而由 JSP 加载的内存马对应的 ClassLoader 则为 ClassLoader 为org.apache.jasper.servlet.JasperLoader

对应在arthas上的搜索命令可以使用如下命令搜索

1
2
3
4
5
6
7
8
9
10
11
12
sc -d javax.servlet.Servlet\*  

sc -d javax.servlet.Filter\*

sc -d javax.servlet.ServletRequestListener\*
​sc *jsp*
或者:
sc -d \* --interfaces javax.servlet.Servlet

sc -d \* --interfaces javax.servlet.Filter\*

sc -d \* --interfaces javax.servlet.ServletRequestListener\*\

这样会有个问题就是搜索结果太多需要加上 -n (可以跟一个较大的数) 参数

通过classloader定位,使用如下命令找到被该classloader加载的类

1
sc -d * --classloader <hashcode>

哥斯拉内存马

filter内存马

先来给他加一个filter内存马

启动arthas-boot.jar 进行排查,使用sc *.Filter过滤一下

可以使用 sc -d org.apache.coyote.deser.std.ThrowableDeserializer 详细看一下这个类的信息

可以看到哥斯拉自己的classloader,所以可以判定这个类应该是有问题的,具体看代码使用
jad org.apache.coyote.deser.std.ThrowableDeserializer反编译看

存在大量的反射,并且也是filter内存马的实现逻辑。

servlet内存马

同样的道理增加一个

然后我们使用 sc *.Servlet相关的,也可以利用mbean | grep "name=/"进行搜索url映射

可以看到名字就有问题,这时在重复以上步骤查看信息和反编译即可。

冰蝎内存马

连接成功,下面是排查过程

先看看classloader

可以看到两个恶意的loader,那么就可以里用上面所说的可以利用这个classloader去反向查恶意类

然后反向查

1
sc -d * --classloader 7aff6602

然后在反编译看下这个类

很明显的恶意类。

heapdump使用

有一种比较取巧的方法就是利用heapdump将内存dump出来直接搜索

1
strings test.hprof | grep "GET /
1
strings /var/cache/tomcat/temp/heapdump2022-10-19-12-464292342944555007800.hprof | grep -E "/webapps/.*?\!" | sort -u

jmap使用

这种方法主要是对前面三种的补充,我们会发现第二种和第三种其实都依靠agent attach到jvm里面,但是有些攻击者会使用对抗分析排查的手段,阻挠我们去attach,比如:冰蝎的反检测分析的手段,会干掉jvm线程之间的通信管道的建立要用到.java_pid\<pid>这个文件,阻止JVM进程通信,从而禁止了Agent的加载。Agent无法注入,上文提到的方法2、3就使用不了了,从而实现了反查杀

1
2
jps  
jmap -dump:format=b,file=<filename> <pid>

思路:内存马,不就是存在内存里面的吗,那我们直接把内存dump下来,然后在里面分析不就成了;这里我们需要思考,内存马在内存中可能的存在形式,jvm能够直接处理的应该是字节码文件class,所以我们可以尝试在内存中寻找字节码文件,字节码文件头的16进制特征:cafebabe;也可以直接搜恶意类可能出现的敏感词,shell 、memshell、eval、inject之类的;也可以查内存中遗留的访问记录,查看是否存在相关访问是内存马利用和链接的;

在知道被利用的接口是一个任意字节码加载接口的时候,我们可以直接对症下药,查看内存中是否遗留相关恶意字节码的base64编码(接口做了编码解码)
类字节码的base64头形式一般是:yv66vg(cafebabe00转化而来);

dump下来,还原class字节码文件,反编译,如下通过这番操作,我们拿到了注入内存马逻辑的class字节码实现:

参考: https://forum.butian.net/share/3774
https://ruyueattention.github.io/2023/07/02/Java%E5%86%85%E5%AD%98%E9%A9%AC3-%E5%86%85%E5%AD%98%E9%A9%AC%E6%9F%A5%E6%9D%80/
https://zgao.top/%E5%86%B0%E8%9D%8E%E3%80%81%E5%93%A5%E6%96%AF%E6%8B%89-%E5%86%85%E5%AD%98%E9%A9%AC%E5%BA%94%E6%80%A5%E6%8E%92%E6%9F%A5/