对 Fury 不熟悉,首先简要分析一下技术原理,参考官方说明文档如下:
Fury Java 序列化指南
https://fury.apache.org/zh-CN/docs/guide/java_object_graph_guide/
Fury#serialize 序列化时,会调用 org.apache.fury.Fury#writeData ,对于 Object 对象将通过 classInfo.getSerializer 获取序列化对象,然后利用 write 完成写入:
对 feilong 和 hutool 进行审计,找到一个潜在的二次反序列化的触发点 cn.hutool.core.io.IoUtil#readObj :
-> org.apache.fury.Fury#deserialize
-> java.util.PriorityQueue#siftUpUsingComparator
-> com.feilong.core.util.comparator.PropertyComparator#compare
-> cn.hutool.core.map.MapProxy#invoke [Proxy.newProxyInstance]
-> cn.hutool.core.convert.Convert#convert
-> cn.hutool.core.convert.Convert#convertWithCheck
-> cn.hutool.core.convert.ConverterRegistry#convert
-> cn.hutool.core.convert.ConverterRegistry#convertSpecial
-> cn.hutool.core.convert.AbstractConverter#convert
-> cn.hutool.core.convert.impl.BeanConverter#convertInternal
-> cn.hutool.core.util.ObjectUtil#deserialize
-> cn.hutool.core.util.SerializeUtil#deserialize
-> cn.hutool.core.io.IoUtil#readObj
-> cn.hutool.core.io.ValidateObjectInputStream#readObject [黑白名单为null]
从前面分析可知,利用 hutool 中的 MapProxy 动态代理, Fury 反序列化可以触发 Java 原生二次反序列化,并且不受黑白名单的影响。下面需要寻找一条可利用的 gadget 链。通过审计在 feilong 中找到了 PropertyComparator#compare ,该函数会调用 PropertyUtil#getProperty ,与 CommonsBeanutils 和 Commons Collections2 利用方式类似,可以触发任意 Getter 方法:
组合 TemplatesImpl#getOutputProperties 构造出新的 gadget 链:
-> java.util.PriorityQueue#readObject
-> com.feilong.core.util.comparator.PropertyComparator#compare
-> com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties
组合二次反序列化和新的原生 gadget ,构建完整 RCE 利用链如下:
触发过程如下:
getOutputProperties:506, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeMethod:1922, PropertyUtilsBean (com.feilong.lib.beanutils) [2]
getSimpleProperty:1095, PropertyUtilsBean (com.feilong.lib.beanutils)
getSimpleProperty:1079, PropertyUtilsBean (com.feilong.lib.beanutils)
getProperty:825, PropertyUtilsBean (com.feilong.lib.beanutils)
getProperty:162, PropertyUtils (com.feilong.lib.beanutils)
getDataUseApache:89, PropertyValueObtainer (com.feilong.core.bean)
obtain:70, PropertyValueObtainer (com.feilong.core.bean)
getProperty:577, PropertyUtil (com.feilong.core.bean)
compare:430, PropertyComparator (com.feilong.core.util.comparator)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:796, PriorityQueue (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1185, ObjectStreamClass (java.io)
readSerialData:2345, ObjectInputStream (java.io)
readOrdinaryObject:2236, ObjectInputStream (java.io)
readObject0:1692, ObjectInputStream (java.io)
readObject:508, ObjectInputStream (java.io)
readObject:466, ObjectInputStream (java.io)
readObj:615, IoUtil (cn.hutool.core.io)
readObj:582, IoUtil (cn.hutool.core.io)
readObj:563, IoUtil (cn.hutool.core.io)
deserialize:65, SerializeUtil (cn.hutool.core.util)
deserialize:594, ObjectUtil (cn.hutool.core.util)
convertInternal:81, BeanConverter (cn.hutool.core.convert.impl)
convert:58, AbstractConverter (cn.hutool.core.convert)
convert:288, ConverterRegistry (cn.hutool.core.convert)
convert:307, ConverterRegistry (cn.hutool.core.convert)
convertWithCheck:765, Convert (cn.hutool.core.convert)
convert:718, Convert (cn.hutool.core.convert)
convert:689, Convert (cn.hutool.core.convert)
invoke:147, MapProxy (cn.hutool.core.map)
getDigester:-1, $Proxy0 (com.sun.proxy)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeMethod:1922, PropertyUtilsBean (com.feilong.lib.beanutils) [1]
getSimpleProperty:1095, PropertyUtilsBean (com.feilong.lib.beanutils)
getSimpleProperty:1079, PropertyUtilsBean (com.feilong.lib.beanutils)
getProperty:825, PropertyUtilsBean (com.feilong.lib.beanutils)
getProperty:162, PropertyUtils (com.feilong.lib.beanutils)
getDataUseApache:89, PropertyValueObtainer (com.feilong.core.bean)
obtain:70, PropertyValueObtainer (com.feilong.core.bean)
getProperty:577, PropertyUtil (com.feilong.core.bean)
compare:430, PropertyComparator (com.feilong.core.util.comparator)
siftUpUsingComparator:669, PriorityQueue (java.util)
siftUp:645, PriorityQueue (java.util)
offer:344, PriorityQueue (java.util)
add:321, PriorityQueue (java.util)
readSameTypeElements:694, AbstractCollectionSerializer (org.apache.fury.serializer.collection)
generalJavaRead:672, AbstractCollectionSerializer (org.apache.fury.serializer.collection)
readElements:595, AbstractCollectionSerializer (org.apache.fury.serializer.collection)
read:73, CollectionSerializer (org.apache.fury.serializer.collection)
read:28, CollectionSerializer (org.apache.fury.serializer.collection)
readDataInternal:972, Fury (org.apache.fury)
readRef:865, Fury (org.apache.fury)
deserialize:797, Fury (org.apache.fury)
deserialize:718, Fury (org.apache.fury)
由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用本人负责,公众号及文章作者不为此承担任何责任。
原文始发于微信公众号(自在安全):AliyunCTF2025 题解之 Jtools Fury 反序列化利用分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论