内存🐎的检测与排查
文章目录
- 内存🐎的检测与排查
- 查杀Java Web filter型内存马
- 0x01 内存马简历史
- 0x02 查杀思路
- 0x03 内存马的识别
- 0x04 内存马的查杀
查杀Java Web filter型内存马
0x01 内存马简历史
其实内存马由来已久,早在17年n1nty师傅的《Tomcat源码调试笔记-看不见的shell》中已初见端倪,但一直不温不火。后经过rebeyong师傅使用agent技术加持后,拓展了内存马的使用场景,然终停留在奇技淫巧上。在各类hw洗礼之后,文件shell明显气数已尽。内存马以救命稻草的身份重回大众视野。特别是今年在shiro的回显研究之后,引发了无数安全研究员对内存webshell的研究,其中涌现出了LandGrey师傅构造的Spring controller内存马。至此内存马开枝散叶发展出了三大类型:
- servlet-api类
-
- filter型
-
- servlet型
- spring类
-
- 拦截器
-
- controller型
- Java Instrumentation类
-
- agent型
0x02 查杀思路
利用Java Agent技术遍历所有已经加载到内存中的class。先判断是否是内存马,是则进入内存查杀。
0x03 内存马的识别
1.filter名字很特别【弱特征】
内存马的Filter名一般比较特别,有shell
或者随机数等关键字。这个特征稍弱,因为这取决于内存马的构造者的习惯,构造完全可以设置一个看起来很正常的名字。
2.filter优先级是第一位【弱特征】
为了确保内存马在各种环境下都可以访问,往往需要把filter匹配优先级调至最高,这在shiro反序列化中是刚需。但其他场景下就非必须,只能做一个可疑点。
对于一个web工程的filter过滤器,一般有两种方式放入项目中:
1、在web.xml里面配置
之前我们控制多个filter的执行顺序是通过web.xml中控制filter的位置来控制的,放在上面的会比放在下面的先执行,如下“用户登录检查过滤器”会比“接口日志过滤器”先执行。
<!-- 用户登录检测过滤器 -->
<filter><filter-name>UserLoginFilter</filter-name><filter-class>net.tfgzs.demo.filter.UserLoginFilter</filter-class>
</filter>
<filter-mapping><filter-name>UserLoginFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
<!--接口日志过滤器-->
<filter><filter-name>ApiLog</filter-name><filter-class>net.tfgzs.demo.filter.ApiLog</filter-class>
</filter>
<filter-mapping><filter-name>ApiLog</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
2、@WebFilter注解
注解里面没有提供可以控制执行顺序的参数,通过实践发现如果想要控制filer的执行顺序可以 通过控制filter的文件名的首字母来 来控制。
比如:
UserLoginFilter.java 和 ApiLog.java 这两个文件里面分别是“用户登录检查过滤器”和“接口日志过滤器”,因为这两个文件的 首字母A排U之前 ,导致每次执行的时候都是先执行“接口日志过滤器”再执行“用户登录检查过滤器”。
3.对比web.xml中没有filter配置【强特征】
内存马的Filter是动态注册的,所以在web.xml中肯定没有配置,这也是个可以的特征。但servlet 3.0引入了@WebFilter
标签方便开发这动态注册Filter。这种情况也存在没有在web.xml中显式声明,这个特征可以作为较强的特征。
4.特殊classloader加载【弱特征】
我们都知道Filter也是class,也是必定有特定的classloader加载。一般来说,正常的Filter都是由中间件的WebappClassLoader加载的。反序列化漏洞喜欢利用TemplatesImpl和bcel执行任意代码。所以这些class往往就是以下这两个:
-
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl$TransletClassLoader
-
com.sun.org.apache.bcel.internal.util.ClassLoader
这个特征是一个特别可疑的点了。当然了,有的内存马还是比较狡猾的,它会注入class到当前线程中,然后实例化注入内存马。这个时候内存马就有可能不是上面两个classloader。
5.对应的classloader路径下没有class文件【强特征】
所谓内存马就是代码驻留内存中,本地无对应的class文件。所以我们只要检测Filter对应的ClassLoader目录下是否存在class文件。
private static boolean classFileIsExists(Class clazz){if(clazz == null){return false;}String className = clazz.getName();String classNamePath = className.replace(".", "/") + ".class";URL is = clazz.getClassLoader().getResource(classNamePath);if(is == null){return false;}else{return true;}
}
6.Filter的doFilter方法中有恶意代码【强特征】
我们可以把内存中所有的Filter的class dump出来,使用fernflower
等反编译工具分析看看,是否存在恶意代码,比如调用了如下可疑的方法:
-
java.lang.Runtime.getRuntime
-
defineClass
-
invoke
-
…
不难分析,内存马的命门在于5
和6
。简单说就是Filter型内存马首先是一个Filter类,同时它在硬盘上没有对应的class文件。若dump出的class还有恶意代码,那是内存马无疑。
0x04 内存马的查杀
java-memshell-scanner
通过jsp脚本扫描并查杀各类中间件内存马,比Java agent要温和一些。
未注入内存马之前:
注入内存马后:
点击kill,杀掉内存马
再次访问已经无法执行命令
tomcat有一个work目录,里面存放了页面的缓存,访问的jsp都会编译(从 work里进入Catalina后的如localhost站点文件夹下的项目,我们可以看到那些jsp页面会被编译成应该是servlet文件,下次再来 访问时,就直接运行servlet类就可以向客户端反应响应页面了,所以有的博客说第一次访问时会比较慢,是因为新发布上去的页面在第一个人访问时,会先 编译成servlet文件,所以慢了,一旦编译好,那么除非jsp页面修改,不然下次访问直接运行servlet就可以响应用户,所以快),编译后的文件都会存储在work目录下。而tomcat显示的目录,都会从这个缓存里找编译后的jsp对应的class文件。所以当清空了work目录后,该过程将会从新来过。