freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Z3专栏 | 正版URLDNS+CommonsCollections1预习
2021-12-15 21:14:39
所属地 辽宁省

前言

上一篇演示了如何构造dns查询的序列化payload

这个利用链是在网上找的,其实java还有很多被挖掘出的利用链

ysoserial库是别人写好的库,包含了至今公开的所有反序列化利用链
可以通过看它的源码,来学习java反序列化利用链

上篇文章的案例,构造dns查询payload,在ysoserial库中也有写好的,更完善的利用链

这篇来看下ysoserial库是如何实现URLDNS利用链的

正版URLDNS

// 先导入URLDNS类
import ysoserial.payloads.URLDNS;

看一下ysoserial的URLDNS如何构造payload
步骤基本上和上一篇我们分析的一样
注意有下面两个区别

  1. 在上一篇,构造URL对象时,为了防止在构造payload时发出dns请求,先将hashCode设为非-1的值,然后添加进HashMap,再把hashCode改为-1
    而ysoserial写了一个空的URLStreamHandler类用来实例化URLStreamHandler接口
    这样在构造payload时触发的就是SilentURLStreamHandler里的空方法(SilentURLStreamHandler继承自URLStreamHandler,实例化后,赋值给了URLStreamHandler对象,所以在反序列化时,还是URLStreamHandler类型)
    而反序列化时,调用的仍是URL对象自动生成的handler(URLStreamHandler类型),触发dns查询

  2. ysoserial还写了一个Reflections类
    Reflections类的方法可以绕过作用域的限制(怎么绕过在反射篇里已经分析过了),无视作用域修改、获取变量值,调用方法、构造函数等

URLDNS作为反序列化学习的第一站,很好入门,
后面会学习ysoserial库的CommonCollections系列

万事开头难,所以在正式学习CommonCollections系列前,先学习下p神简化版的CommonCollections1,做一下下一篇正版CommonCollections1的预习

简化版CommonCollections1

先看下下面代码

// 代码来自p神的知识星球
public class Collections {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.getRuntime()),
                new InvokerTransformer("exec", new Class[]{String.class},
                new Object[]{"calc"}),
        };

        Transformer transformerChain = new
                ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap, null,
                transformerChain);
        outerMap.put("test", "xxxx");
    }
}

运行就会弹出计算器
什么时候触发的命令执行呢?去掉最后一行outerMap.put("test", "xxxx");试试
没有计算器弹出,看来是最后一步outerMap.put触发了命令执行

调试下看看,发现执行这里弹出了计算器
跟进
再跟进this.valueTransformer.transform(object)
遍历iTransformers,用transform方法处理object
第一个transform返回了Runtime对象
第二个transform通过反射,执行了exec函数,导致命令执行

现在再回来看一下代码,
第一步先创建了一个Transformer对象数组,三个元素分别是Runtime,exec,calc
Transformer是做什么的?
Transformer是接口,只声明了一个函数Object transform(Object var1);
ConstantTransformer和InvokerTransformer是实现了Transformer接口的类
ConstantTransformer是什么?
看下它的构造方法和transform方法
相当于构造时给它传入什么对象,调用transform就能获得什么对象
InvokerTransformer是什么?
看下它的构造方法和transform方法
先看构造方法
从参数名上来看,构造函数是:函数名、函数参数类型、函数参数
再看transform方法
参数是一个对象,然后直接通过反射调用对象的函数,这个函数是调用构造方法时指定的

这就解释得通了,在outerMap.put("test", "xxxx");时,把value值扔进transformers数组的第一个元素的transform方法,再把返回值扔给第二个元素的transform方法
第一个元素返回值是Runtime对象,第二个元素transform方法调用了Runtime的exec导致命令执行
所以,只要调用put方法,就会导致命令执行

再看这部分代码
跟进TransformedMap.decorate,看看做了什么
参数为:Map、keyTransformer、valueTransformer
很容易联想到,这个方法是对map进行处理的,Transformer是转换工具的意思
TransformedMap.decorate应该是对map的key和value进行处理,key使用keyTransformer处理,value使用valueTransformer处理

猜测使用场景是这样:
map为{"1":1,"2":2,"3":3}
使用TransformedMap.decorate,对map处理,假设valueTransformer作用是计算传入参数的平方,然后返回,传入keyTransformer为null,即不对key处理
则,最终得到的处理后的map是{"1":1,"2":4,"3":9}

Map是接口,TransformedMap.decorate返回的对象,实现了put方法
如图,每添加一个键值对,都要经过transform处理

那ChainedTransformer是做什么的?
看一下它的源码
构造函数是Transformer数组
看代码是将transformer数组串联起来了,接力处理数据
相当于工厂的流水线,例如扔过来一个水瓶,第一个Transformer加水,第二个Transformer拧瓶盖,第三个Transformer贴包装,然后返回成品矿泉水

现在在回头看一下完整的代码流程

流程分析

  1. 创建两个Transformer,第一个返回一个Runtime对象,第二个通过反射调用对象的指定方法

  2. 使用ChainedTransformer,把1中的两个Transformer串联起来,生成新的Transformer返回

  3. 使用TransformedMap,构造一个map(这个map的put方法是TransformedMap实现的,每次调用put都会使value经过2中构造好的Transformer)

  4. 调用map.put方法,value值传入1中的第一个Transformer,调用了串联的transform方法:获得Runtime对象--->Runtime对象反射调用Runtime对象的exec方法,导致命令执行

这就是简化版的CommonsCollections1了,看懂了代码,其实很简单

思考

但是,这是代码执行时调用put方法触发rce,怎么构造恶意反序列化数据才能让它在反序列化时导致命令执行?
上一篇中经过分析,HashMap对象在反序列化的过程是,先创建个空HashMap对象,然后再把键值对put进去,就会导致发出dns请求
本例中的outerMap对象是TransformedMap生成的
我在测试时,试着将outerMap序列化,结果
为什么?
因为outerMap是Map类型,Map类型没有继承Serializable接口,而上一篇用的是HashMap,继承了Serializable接口,
那把代码改一下
序列化成功,
但是反序列化时候没有命令执行成功,为什么?

根据上面案例,总结出,只要调用outerMap的put方法,就会导致命令执行,而HashMap在反序列化时会调用put方法(在上一篇分析过的)
所以反序列化map.bin就会造成命令执行?
错,"只要调用outerMap的put方法,就会导致命令执行",这里的put方法是由TransformedMap实现的,而反序列化时调用的是HashMap的put方法,HashMap的put方法不会调用Transformer,也就不会命令执行

那怎么构造?

看下正版CommonsCollections1是怎么实现的吧
下篇讲

# java漏洞 # java # java反序列化 # Java代码审计 # JAVA安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录