本文假设你对Java基本数据结构、Java反序列化、高级特性(反射、动态代理)等有一定的了解。

背景

YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP。java -jar ysoserial.jar 可以直接查看payload适用环境及其适用版本。

关于此工具的背景,我引用P神的《Java安全漫游》文章对其的描述:

2015年Gabriel Lawrence (@gebl)和Chris Frohoffff (@frohoffff)在AppSecCali上提出了利⽤Apache Commons Collections来构造命令执⾏的利⽤链,并在年底因为对Weblogic、JBoss、Jenkins等著名应⽤的利⽤,⼀⽯激起千层浪,彻底打开了⼀⽚Java安全的蓝海。⽽ysoserial就是两位原作者在此议题中释出的⼀个⼯具,它可以让⽤户根据⾃⼰选择的利⽤链,⽣成反序列化利⽤数据,通过将这些数据发送给⽬标,从⽽执⾏⽤户预先定义的命令。

下载工具源码发现主要payload生成逻辑都在ysoserial.payloads包下面:

接下来主要针对 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,调试一下看下调用链。

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 会实现两个空方法?

首先第一个问题,这一行代码是干嘛的,为什么要将URL对象中的hashcode通过反射的方式设置为-1呢,URL对象中的hash code本身就是-1,为什么要这么做?

​ 其实通过代码中的注释我们也能知道,在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、openConnection两个方法进行空操作,进而在生产payload对象时就不会发器dns请求了。

刚开始看到这里的时候我比较疑惑,重写了这两个方法到时候在使用这个payload去利用的时候不就没发正常发起DNS请求了吗,那这样做意义何在?原来我忽略了一个东西,在URL类中,URLStreamHandler被transient关键字标记,transient标记的属性在序列化时不会带入序列化的数据里面,这样在生成payload或者调试的时候不会发起DNS请求,但又不影响payload的正常使用,非常巧妙。

总结

URLDNS是一个不需要依赖其他包的反序列化利用,且调用过程比较简单,只会在HashMap与StreamHandler之间调用,稍微需要注意的也就是亮点,一个为什么要将hashcode最后通过反射的方式置为-1,另一个是为什么重写过StreamHandler两个方法为空操作后仍然能在凡序化后正常发起dns请求。

虽然URLDNS这条链很简单,但其实它做不了什么,仅仅只能帮助我们判断这个地方可能存在用户可控的凡序列化问题,仍然不能进行进一步的利用,那要怎么才能利用乃至RCE呢? 下一专题Common-collections1 就来帮助我们解决这个问题。

YsoSerial 工具常用Payload分析之URLDNS的更多相关文章

  1. YsoSerial 工具常用Payload分析之CC1

    前文介绍了最简单的反序列化链URLDNS,虽然URLDNS本身不依赖第三方包且调用简单,但不能做到漏洞利用,仅能做漏洞探测,如何才能实现RCE呢,于是就有Common-collections1-7.C ...

  2. YsoSerial 工具常用Payload分析之CC5、6(三)

    前言 这是common-collections 反序列化的第三篇文章,这次分析利用链CC5和CC6,先看下Ysoserial CC5 payload: public BadAttributeValue ...

  3. YsoSerial 工具常用Payload分析之Common-Collections7(四)

    前言 YsoSerial Common-Collection3.2.1 反序列化利用链终于来到最后一个,回顾一下: 以InvokerTranformer为基础通过动态代理触发AnnotationInv ...

  4. YsoSerial 工具常用Payload分析之Common-Collections2、4(五)

    前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...

  5. YsoSerial 工具常用Payload分析之CC3(二)

    这是CC链分析的第二篇文章,我想按着common-collections的版本顺序来介绍,所以顺序为 cc1.3.5.6.7(common-collections 3.1),cc2.4(common- ...

  6. Java应用常用性能分析工具

    Java应用常用性能分析工具 好的工具有能有效改善和提高工作效率或加速分析问题的进度,笔者将从事Java工作中常用的性能工具和大家分享下,如果感觉有用记得投一票哦,如果你有好的工具也可以分享给我 工具 ...

  7. Fiddler抓取https请求 & Fiddler抓包工具常用功能详解

    Fiddler抓取https请求 & Fiddler抓包工具常用功能详解   先来看一个小故事: 小T在测试APP时,打开某个页面展示异常,于是就跑到客户端开发小A那里说:“你这个页面做的有问 ...

  8. SoapUI、Jmeter、Postman三种接口测试工具的比较分析

    前段时间忙于接口测试,也看了几款接口测试工具,简单从几个角度做了个比较,拿出来与诸位分享一下吧.各位如果要转载,请一定注明来源,最好在评论中告知博主一声,感谢.本报告从多个方面对接口测试的三款常用工具 ...

  9. SoapUI、Jmeter、Postman三种接口测试工具的比较分析——灰蓝

    前段时间忙于接口测试,也看了几款接口测试工具,简单从几个角度做了个比较,拿出来与诸位分享一下吧.各位如果要转载,请一定注明来源,最好在评论中告知博主一声,感谢.本报告从多个方面对接口测试的三款常用工具 ...

随机推荐

  1. CPU消耗,跟踪定位理论与实践

    CPU消耗,跟踪定位理论与实践 一.性能指标之资源指标定位方案 1.打tprof报告方法 抓取perfpmr文件 60秒. perfpmr.sh 60 从结果文件中取出tprof.sum 或直接抓取t ...

  2. Technology Document Guide of TensorRT

    Technology Document Guide of TensorRT Abstract 本示例支持指南概述了GitHub和产品包中包含的所有受支持的TensorRT 7.2.1示例.Tensor ...

  3. windows 设置nginx开机自启动

    将Nginx设置为Windows服务 需要借助"Windows Service Wrapper"小工具,项目地址: https://github.com/kohsuke/winsw ...

  4. JVM快速入门(上)

    前言 根据狂神说的JVM快速入门做了以下笔记,讲的很好的一个博主,给小伙伴们附上视频链接狂神说JVM快速入门    接下来我按照他所讲的内容给大家记录一些重点! 一.JVM体系结构 .java经由ja ...

  5. 并发王者课-铂金1:探本溯源-为何说Lock接口是Java中锁的基础

    欢迎来到<并发王者课>,本文是该系列文章中的第14篇. 在黄金系列中,我们介绍了并发中一些问题,比如死锁.活锁.线程饥饿等问题.在并发编程中,这些问题无疑都是需要解决的.所以,在铂金系列文 ...

  6. Java课程设计-算术运算测试(D级) 齐鲁工业大学 计科20-1 王瀚垠 202003010033

    Java课程设计-算术运算测试(D级) 齐鲁工业大学 计科20-1 王瀚垠 202003010033 目录 1.项目简介 2.项目采用技术 3.功能需求分析 4.项目亮点 5.项目功能架构图和UML类 ...

  7. MySQL 数据库设计的“奥秘”

    2 MySQL 数据库设计的"奥秘" [主题]逻辑设计:数据类型与 Schema 所谓"万丈高楼平地起",一个稳固的建筑离不开扎实的基础.同样,良好的的「逻辑设 ...

  8. Java基础-封装和继承

    @ 目录 Java基础知识(封装和继承) 一. 封装 1.1 封装的目的 1.2 封装的好处 1.3 封装的步骤 1.4 封装的例子 1.5 小结 二. 继承 2.1 继承的介绍 2.2 生活中的继承 ...

  9. Windows批处理文件编写宝典

    原贴:批处理新手入门导读 现在的教程五花八门,又多又杂.如何阅读,从哪里阅读,这些问题对新手来说,都比较茫然. 这篇文章的目的就是帮助新手理清学习顺序,快速入门.进步 1.如果你从来没有接触甚至没有听 ...

  10. Docker安装运行Portainer

    基本简介 Portainer是一个轻量级的docker环境管理UI,可以用来管理docker宿主机和docker swarm集群.他的轻量级,轻量到只要个不到100M的docker镜像容器就可以完整的 ...