0x00 前言#
按照我个人的理解来说其实只要能拿到Request 和Response对象即可进行回显的构造,当然这也是众多方式的一种。也是目前用的较多的方式。比如在Tomcat 全局存储的Request 和Response对象,进行获取后则可以在tomcat这个容器下进行回显。而某些漏洞的方式会从漏洞的位置去寻找存储Request 和Response对象的地方。
0x01 Tomcat通用回显#
根据Litch1师傅的思路来寻找request,response对象全局存储的位置基于全局储存的新思路 | Tomcat的一种通用回显方法研究
根据该文章思路得知,在Tomcat启动的时候会调用该位置的dorun方法
由图可见,调用栈会来到创建Http11Processor对象这一步,Http11Processor继承AbstractProcessor类。而AbstractProcessor类中可见有Request,Response这两对象。并且为final修饰的,赋值后不可被更改。
那么此时我们只需要获取到这个Http11Processor对象即可获取到Request,Response。继续跟进查看Http11Processor对象在哪进行存储。
调用this.register将前面创建的Http11Processor对象进行传递。而后调用processor.getRequest().getRequestProcessor()获取RequestInfo。
调用获取到的RequestInfo,这里为rp。rp的setGlobalProcessor将global进行传递,而setGlobalProcessor方法里面会调用
global.addRequestProcessor将rp添加进去。
跟进进去发现,processors为一个ArrayList,里面存储RequestInfo类型的数据。
所以整体的思路下来我们需要获取AbstractProtocol$ConnectionHandler类 -> 获取global变量 ->RequestInfo->Request–>Response。
再往后需要寻找存储AbstractProtocol类或继承AbstractProtocol类的子类。
这里寻找到的是Connector成员变量中为protocolHandler属性的值,而 Http11AprProtocol类实现了该接口。
所以获取request的处理请求是
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(HttpServletRe