文章目录
微信公众号:信安文摘
1. 前言
平时遇到可RCE的点,都是借助工具一键注入内存马,但对其中的原理并没有很清楚的了解。本文主要跟随前辈大佬的学习笔记,以Tomcat为例,初探Java内存马的实现原理。
2. 基础知识
2.1 servlet 和 filter
Servlet
主要的作用是可以动态地生产Web页面,他执行在客户端请求和服务器响应的之间。比较简单地理解就是,一个路由URL,就会有对应的servlet对这个路由进行处理。
Filter 是一段可以复用的代码,它用来拦截HTTP请求、响应、进行一些处理和转换。常见一些Javaweb项目会在 Filter 位置创建一些XSS拦截器或者SQL拦截器,用来统一处理SQL注入漏洞或者XSS漏洞。Filter 无法产生一个请求或者响应,它只能针对某一资源的请求或者响应进行修改。
2.2 servlet 和 filter 的生命周期
Servlet:
Servlet 的生命周期开始于Web容器的启动时,它就会被载入到Web容器内存中,直到Web容器停止运行或者重新装入servlet时候结束。这里也就是说明,一旦Servlet被装入到Web容器之后,一般是会长久驻留在Web容器之中。
- 装入:启动服务器时加载Servlet的实例
- 初始化:web服务器启动时或web服务器接收到请求时,或者两者之间的某个时刻启动。初始化工作有init()方法负责执行完成
- 调用:从第一次到以后的多次访问,都是只调用doGet()或doPost()方法
- 销毁:停止服务器时调用destroy()方法,销毁实例
Filter:
自定义Filter的实现,一定要求javax.servlet.Filter下的三个方法的实现,它们分别是init()
、doFilter()
、destroy()
- 启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;
- 每一次请求时都只调用方法doFilter()进行处理;
- 停止服务器时调用destroy()方法,销毁实例。
2.3 Tomcat 的 Container – 容器组件
Tomcat中的 Container作用:
用于封装和管理 Servlet,以及具体处理Request请求,在Connector内部包含了4个子容器:
Engine,实现类为 org.apache.catalina.core.StandardEngine
Host,实现类为 org.apache.catalina.core.StandardHost
Context,实现类为 org.apache.catalina.core.StandardContext
Wrapper,实现类为 org.apache.catalina.core.StandardWrapper
这四个字容器实际上是自上向下的包含关系:
Engine:最顶层容器组件,其下可以包含多个 Host。
Host:一个 Host 代表一个虚拟主机,其下可以包含多个 Context。
Context:一个 Context 代表一个 Web 应用,其下可以包含多个 Wrapper。
Wrapper:一个 Wrapper 代表一个 Servlet。
关系图如下(借用参考文章的图):
对于tomcat的目录来说,webapps目录
对应的就是 Host
组件,下面的 cas
和 manager
等一个个webapp对应的就是 Context
组件,Wrapper 就是容器内的 Servlet了
2.4 Tomcat中的启动加载顺序
加载过程在 Tomcat 的org.apache.catalina.core.StandardContext#startInternal()
:
@Override
protected synchronized void startInternal() throws LifecycleException {
//设置webappLoader 代码省略
//Standard container startup 代码省略
try {
// Set up the context init params
mergeParameters();
// Configure and call application event listeners
if (ok) {
if (!listenerStart()) {
log.error(sm.getString("standardContext.listenerFail"));
ok = false;
}
}
// Configure and call application filters
if (ok) {
if (!filterStart()) {
log.error(sm.getString("standardContext.filterFail"));
ok = false;
}
}
// Load and initialize all "load on startup" servlets
if (ok) {
if (!loadOnStartup(findChildren())){
log.error(sm.getString("standardContext.servletFail"));
ok = false;
}
}
// Start ContainerBackgroundProcessor thread
super.threadStart();
} finally {
// Unbinding thread
unbindThread(oldCCL);
}
}
从代码中可以看到,加载顺序 context-param->listeners->filters->servlets :
- 首先初始化 context-param 节点:
mergeParameters()
- 接着配置和调用 listeners 并开始监听:
listenerStart()
- 然后配置和调用 filters ,filters 开始起作用:
filterStart()
- 最后加载和初始化配置在 load on startup 的 servlets:
loadOnStartup(findChildren())
3. 内存马技术实现介绍
从 servlet3.0 开始,提供了动态注册 Servlet 、filter 、Listener,这里重点关注 Servlet
和 filter
,因为 Servlet 能够帮助我们接受 request 请求和 response 响应,并且针对传入内容进行操作,filter 也是可以做得到的。
相关函数如下:
<T extends Filter>createFilter(Java.lang.Class<T> clazz)
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);
java