一条抽象的equals触发链
2023-08-29 19:40:33

前文

为什么抽象呢,因为他是个抽象类,所以很抽象
在NEEPUCTF2023中的一道题 NoMap中,就用到了这个链子,很遗憾,网络上没找到几篇wp,看了Boogiepop师傅的,还有官方的,我操作了两天都没能成功复现,官方使用了agent去修改jdk内置类,但是我确实不会,一点都看不懂,看Boogiepop师傅的,他是直接将内置类的源码在当前目录下重写了一遍,因为jdk会先调用当前目录下的类?大概把?这个我也不太清楚,希望懂这方面的师傅留言或者加我教学一下。
但是我在复现的过程中发现,是走不进去的,用javassist修改也是,之前有这样操作过jackson链子,但是这次jdk内置类失败了,大概是不能这样修改jdk内置类吧,后面联想到php的序列化,我就直接将数据流写入文件,使用16进制工具直接修改,结果就成功了。
这里只讲链子的具体调用,因为题目实际上就这个考点,剩下的就是经典的jackson+springboot高版本内存马,这里就不细致讲解了。

参考链接:
https://boogipop.com/2023/05/21/NeepuCTF2023%20%E5%85%AC%E5%BC%80%E8%B5%9B%20Writeup/
https://github.com/R1ckyZ/My-CTF-Challenges/blob/main/NEEPUCTF%202023/No%20Map/solve/Solve.java

AbstractAction调用链

javax.swing.AbstractAction#readObject -> 
	javax.swing.AbstractAction#putValue ->
		javax.swing.AbstractAction#firePropertyChange -> 
			java.lang.Object#equals

想要使用需要重写writeObject,但是我不会,或者说我自己的方法失败了。
这里得用agent技术去修改jdk内置类,直接javassist没办法的,所以就讲解一下自己的方法

//signObject为jackson触发的getter,上面太长了就不写了
	POJONode jsonNodes = new POJONode(signedObject);
    XString xString = new XString("111");
    SwingPropertyChangeSupport swingPropertyChangeSupport = new SwingPropertyChangeSupport("11");
    StyledEditorKit.AlignmentAction alignmentAction = new StyledEditorKit.AlignmentAction("111",1);
    
    Field field = Class.forName("javax.swing.AbstractAction").getDeclaredField("changeSupport");
    field.setAccessible(true);
    field.set(alignmentAction,swingPropertyChangeSupport);
    alignmentAction.putValue("key1",xString);
    alignmentAction.putValue("key2",jsonNodes);

	//这里是我自己写的工具类,大概含义就是将类序列化后的bytes写入指定文件
    tools.serialize_file(alignmentAction,"serialize1");

将字节码写入文件,手动去更改key2,把key2改成key1,这样才能进入反序列化 //后续会说
image.png

writeObject

大概讲一下,这个类的writeObject前的一些操作
在alignmentActioin初始化时,子类的构造函数会不断调用父类的构造函数,一直到达AbstractAction,进行一次putValue操作,

StyledEditorKit.AlignmentAction alignmentAction = new StyledEditorKit.AlignmentAction(“Aecous”,1);

image.png
image.png
image.png
image.png
Action.NAME为固定的Name,name为我们的第一参数,进入putValue
image.png
上面会进行一系列的table创建,判断是否存在键值等等操作,由于是新参数,所以将其put进arrayTable中

使用alignmentAction.putValue,将恶意键值也添加进arrayTable中
image.png
image.png
image.png
最后在序列化时,进入ArrayTable.writeArrayTable
image.png
image.png
会先将键值对的数量写入,我们一共存入了3对,接着把键与值依次写入结束

readObject

接着是反序列化
image.png
readObject时,会先读取键值对的次数,并且进行putValue调用读取的键值对
image.png
image.png
put key1 => XString
我们通过修改16进制,将POJOnode对应的key2改成了key1
image.png
判断出已存在key1,取出了oldValue XString,newValue为POJOnode 一起传入了firePropertyChange函数
image.png
image.png

反射为changeSupport 赋值
image.png
当changeSupport !=null时,会往后执行

(oldValue != null && newValue != null && oldValue.equals(newValue))

就可以触发XString.equals(POJOnode)
image.png
最后调用POJOnode.toString触发任意getter调用

Prev
2023-08-29 19:40:33
Next