Java反序列化漏洞二

CommonsBeanutils利用链

前置知识

PriorityQueue => getter

CB链使用PriorityQueue作为入口,在CC链中我们知道PriorityQueue.readObject()会触发xxxComparator.compare(),比如CC2中的TransformingComparator.compare()。在CB链中触发的是BeanComparator.compare()

可以看到BeanComparator.compare()会触发任意property的getter方法,而property就是BeanComparator的构造属性。

1
new PriorityQueue(2,new BeanComparator(<property>)).readObject() ==> queueArray[i].get<property>()

getter => ?

既然能够触发到任意getter方法,能够利用的getter有哪些呢?这里给出

  • TemplatesImpl.getoutputProperties()

    • TemplatesImpl.getoutputProperties()不必多说,在CC链中我们也提到它可以触发newTransformer
  • JdbcRowSetImpl.getdatabaseMetaData()

    • JdbcRowSetImpl.getdatabaseMetaData()则不同,它会调用到connect()方法最终得到一个JNDI注入点InitialContext.lookup()

​ 其中DataSourceName可以使用JdbcRowSetImpl.setDataSourceName(jndiURL)来设置。

CB1

  • DEP:commons-beanutils:1.9.2&&commons-collections:3.1
  • IN:PriorityQueue.readObject()
  • OUT:queueArray[i].getoutputProperties()
  • SINK:Templates
1
2
3
4
5
6
7
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDownUsingComparator()
BeanComparator.compare()
PropertyUtils.getProperty(o, property) ==> two obj invoke getter: o1&&o2
o.getoutputProperties()
<Templates>

CB2(noCC)

剥离CC依赖

CBnoCC与CB1的区别就在于剥除了对于commons-collections的依赖,起因是CB1中的BeanComparator如果使用BeanComparator(String property)这个重载就会使用ComparableComparator这个类,而这个类是在CC里的:

因此换成下面那个重载即可,寻找jdk中Comparator的子类,发现String.CASE_INSENSITIVE_ORDER也就是CaseInsensitiveComparator这个java.lang.String中的静态内部类是符合要求的,基于此重构BeanComparator即可,其余不变。

1
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
  • DEP:commons-beanutils:1.9.2
  • IN:PriorityQueue.readObject()
  • OUT:queueArray[i].getoutputProperties()
  • SINK:Templates
1
2
3
4
5
6
7
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDownUsingComparator()
BeanComparator.compare()
PropertyUtils.getProperty(o, property) ==> two obj invoke getter: o1&&o2
o.getoutputProperties()
<Templates>

CB3

前面已经提到了如何剥离CC依赖,由于这不会对利用过程有任何影响,因此这条链也可以去除CC的依赖。

  • DEP:commons-beanutils:1.9.2
  • IN:PriorityQueue.readObject()
  • OUT:queueArray[i].getdatabaseMetaData()
  • SINK:InitialContext.lookup()
1
2
3
4
5
6
7
8
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDownUsingComparator()
BeanComparator.compare()
PropertyUtils.getProperty(o, property) ==>two obj invoke getter: o1.gettr()&&o2.getter()
JdbcRowSetImpl.getdatabaseMetaData()
JdbcRowSetImpl.connect()
InitialContext.lookup()

Rome利用链

有关Rome链的一些补充

前置知识

? => getter

调用到Rome中的BeanIntrospector.getPropertyDescriptors(this._beanClass)即可任意getter,其中有两个类存在此调用:

  • ToStringBean.toString(String prefix)

  • EqualsBean.beanEquals()

? => obj.toString()

  • BadAttributeValueExpException.readObject()

    CC链里已经讲过,BadAttributeValueExpException可以触发任意类的toString()。

  • EqualsBean.beanHashCode()

    想要触发beanHashCode()就需要触发hashCode(),CC链中也提到**HashMap.readObject()**可以触发任意类的hashcode()方法。

    1
    2
    3
    4
    HashMap.readObject()
    HashMap.hash()
    ObjectBean.hashcode()
    EqualsBean.beanHashCode()

? => obj.beanEquals()

HashMap.readObject()同样可以触发任意Map的equals()方法,借助AbstractMap即可触发任意类的equals()方法:

1
2
3
4
5
6
HashMap.readObject()
HashMap.putVal()
AbstractMap.equals()
EqualsBean.equals()
EqualsBean.beanEquals()

Rome1

  • DEP:rome:1.0
  • IN:HashMap.readObject()
  • OUT:ToStringBean.toString()
  • SINK:Templates
1
2
3
4
5
6
7
8
HashMap.readObject()
HashMap.hash()
ObjectBean.hashcode()
EqualsBean.beanHashCode()
ObjectBean.toString()
ToStringBean.toString()
BeanIntrospector.getPropertyDescriptors() ==> getter
<Templates>

Rome2

  • DEP:rome:1.0
  • IN:BadAttributeValueExpException.readObject()
  • OUT:ToStringBean.toString()
  • SINK:Templates
1
2
3
4
5
BadAttributeValueExpException.readObject()
ObjectBean.toString()
ToStringBean.toString()
BeanIntrospector.getPropertyDescriptors() ==> getter
<Templates>

Rome3

  • DEP:rome:1.0
  • IN:HashMap.readObject()
  • OUT:EqualsBean.beanEquals()
  • SINK:Templates
1
2
3
4
5
6
7
HashMap.readObject()
HashMap.putVal()
AbstractMap.equals()
EqualsBean.equals()
EqualsBean.beanEquals()
BeanIntrospector.getPropertyDescriptors() ==> getter
<Templates>

AspectJweaver利用链

前置知识

这条链前半部分依然是触发到LazyMap.get(),因此这部分可以用CC链中已有的内容随意改造。后半部分LazyMap.get()触发到的是一个位于org.aspectj.weaver.tools.cache的特殊Map的put()方法,也就是静态内部类SimpleCache$StoreableCachingMap.put()。这个内部类会继续调用writeToPath()最终直接写入任意文件至任意路径。

AspectJweaver1

  • DEP:aspectjweaver:1.9.2&&commons-collections:3.2.2
  • IN:HashSet.readObject()
  • OUT:LazyMap.get()
  • SINK:FileOutputStream.write()
1
2
3
4
5
6
7
8
9
HashSet.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
SimpleCache$StorableCachingMap.put()
SimpleCache$StorableCachingMap.writeToPath()
FileOutputStream.write()

C3P0利用链

前置知识

观察类com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase的序列化与反序列化过程。

PoolBackedDataSourceBase.writeObject()

如果捕捉到NotSerializableException异常就会进入下方红框的处理逻辑,indirectForm(this.connectionPoolDataSource)返回了ReferenceSerialized对象:

因此序列化的过程可以将connectionPoolDataSource转换为ReferenceSerialized并写入ObjectOutputStream。

PoolBackedDataSourceBase.readObject()

首先会调用getObject,也就是我们写入的ReferenceSerialized.getObject()

然后直接调用到InitialContext.lookup(this.contextName)

C3P0-1

  • DEP:c3p0:0.9.5.2 && mchange-commons-java:0.2.11
  • IN:PoolBackedDataSourceBase.readObject()
  • OUT:ReferenceSerialized.getObject()
  • SINK:RegistryContext.lookup()
1
2
3
PoolBackedDataSourceBase.readObject()
ReferenceIndirector$ReferenceSerialized.getObject()
RegistryContext.lookup()

Java反序列化漏洞二
http://example.com/2023/06/01/Java反序列化漏洞二/
Author
springtime
Posted on
June 1, 2023
Licensed under