EventListenerList,UndoManager,Vector::toString利用链
生成序列化payload的exp
因为edits属性是在UndoManager的父类里面,所以getFieldValue()函数加了一个没有在当前类中找到就在传入的class参数中找。
EventListenerList::readObject(注意断点的那两处要强制步入)
进入add()
调试可以看到add的参数t是生成序列化payload的exp中的这一步中的Map.class,i是这一步中的undoManager
因为Map.class不是UndoManager的子类,所以进入报错代码块,即上图的上图,此时就调用了i,t的toString方法。
Map::toString不重要,我们看UndoManager::toString
进入super.toString
此时edits::toString()被调用了
edits是UndoManager父类CompoundEdit的属性,在实例化UndoManager的时候就会自动调用其父类的无参构造器,所以edits被赋值为Vector实例。
所以edits::toString实际上调用的是Vector::toString
由于java的动态绑定机制,iterator()实际上是调用的Vector::iterator(),所以这个toString函数遍历了Vector的elementdata属性,并且调用了其toString方法
而生成序列化payload的exp中的Vector.add()就是往elementdata中添加成员,所以我们就可以选择要触发哪个类的toString方法
toString->getter(POJONode)
若我们想调用某个类的getter方法,只需要将pojonode的实例放进Vector.add()里面,再把要触发的getter的目标类放进pojonode的构造函数里面,但要记得去除pojonode父类valuenode的父类BaseJsonNode的writeReplace()方法,不然的话反序列化的时候会检查反序列化的类是否实现了writeReplace()这个方法,会报错
调用PojoNode::toString之前的链子如上文所说。
PojoNode本身没有toString方法,但它的爷爷类BaseJsonNode有,
这里调用了ObjectWriter::writeValueAsString方法,类似于ObjectMapper::writeValueAsString,将对象序列化成Json字符串,在此过程中会遍历对象的getter方法。但具体实现有点复杂,就不跟进了
1 | serializeAsField:689, BeanPropertyWriter (com.fasterxml.jackson.databind.ser)serializeFields:774, BeanSerializerBase (com.fasterxml.jackson.databind.ser.std)serialize:178, BeanSerializer (com.fasterxml.jackson.databind.ser)_serialize:480, DefaultSerializerProvider (com.fasterxml.jackson.databind.ser)serializeValue:319, DefaultSerializerProvider (com.fasterxml.jackson.databind.ser)_writeValueAndClose:4568, ObjectMapper (com.fasterxml.jackson.databind)writeValueAsString:3821, ObjectMapper (com.fasterxml.jackson.databind) |
这是大致调用栈,找一找名字差不多的,跟进一下就是了,我成功跟到了目标类的getter方法里面
H2Revenge
反序列化脚本
1.sql
1 | CALL FILE_WRITE(X'16进制数据',‘/tmp/exp.so’); |
c文件
1 |
|
将c编译成.so文件。
用hexed将.so文件的16进制导出为.hex文件,复制里面的值到1.sql里
vps成功收到GET /1.sql,但没反弹shell,复现失败(我试了另一种方法,成功了)。
失败原因是h2根本没有FILE_WRITE这个方法
明天学学第二种方法
未成功
https://blog.csdn.net/Err0r233/article/details/146484415
成功
https://exp10it.io/2025/03/nctf-2024-web-writeup/#h2revenge
成功方法
利用ClassPathXmlApplicationContext类
这是其中一个构造函数
这个构造函数可以远程加载恶意的xml文档。
调用这个构造函数会实例化xml文档中的bean,如果还设置了init-Method,还会在实例化后调用指定的method.
这就是这道题对应的evil.xml
1 |
|
恶意sql文件
1 | CREATE ALIAS CLASS_FOR_NAME FOR 'java.lang.Class.forName(java.lang.String)'; |
为什么要调用unescapeValue()?因为在sql中url_str是varchar类型,而在ClassPathXmlApplicationContext构造函数需要的是Object类型,UnescapeValue()这个函数就是将String转换为Object
About this Post
This post is written by DashingBug, licensed under CC BY-NC 4.0.