Transformer

该类里的transform方法将一个对象转化为另一个对象.如Runtime.class经过transform转化输出结果为class java.lang.Class

Pasted Graphi

InvokerTransformer

通过查看InvokerTransformer的源码可以看出该类是通过反射创建一个新的对象实例.该类使用了transform接口如图所示:
Pasted Graphic 1

cls获取传递进来的input对象值,例如传入runtime对象

cls.getMethod 以及method.invoke是利用java反射机制反射Runtime的getRuntime方法。

iMethodName表示得到的方法名, iParamTypes表示方法中使用的参数类型的数组
Pasted Graphic 2

通过InvokerTransformer反射出了java.lang.Runtime.getRuntime()
Pasted Graphic 3

执行命令的整个调用连为 java.lang.Runtime..getRuntime().invoke().exec()
可以通过该方式逐步调用:
Pasted Graphic 4

成功代码执行
Pasted Graphic 5

上述是整个反射链的过程

ChainedTransformer

Pasted Graphic 6

可以看出该类重构了transform方法,将我们之前的调用链简化到一个方法中通过创建的Transformers数组循环反射执行。

如何构造出Runtime对象类型呢?

ConstantTransformer

Pasted Graphic 7

可以看出该类对transformer重构,返回一个iConstant变量,该变量在ConstantTransformer(Object)方法中被赋值。
Pasted Graphic 8
Pasted Graphic 9

内部构造出了Runtime的对象类型

构造poc
Pasted Graphic 10

成功执行
Pasted Graphic 11

TransformedMap

该类实现了一个功能——将普通的Map转换为一个TransformedMap,可以通过该类绕过transform方法。
Pasted Graphic 12

KeyTransfomer 表示key改变的操作 valueTransformer表示value改变时的操作
Pasted Graphic 13

从这里可以看出 value是可控的,在decorate中赋值即可,于是有如下利用代码:
Pasted Graphic 14

通过TransformedMap代替transform生成如下代码:
Pasted Graphic 15

成功弹出计算器:
Pasted Graphic 16

至此我们获取了一个完整的poc,剩下需要找一个可重写readObject方法的类并且调用了对map值进行修改操作。

在ysoserial反序列化工具利用的是 BadAttributeValueExpException 查看代码如下:
Pasted Graphic 19

该代码重构了readObject方法,如果传入类型为map类型,则会调用map.toString()方法。这里并没有对map的key值进行修改操作,于是需要利用LazyMap,TiedMapEntry两个类来构造
LazyMap:尝试访问key的value如果key不在会把值put进去
Pasted Graphic 20

TiedMapEntry:会把map和一个key进行绑定
Pasted Graphic 21

利用LazyMap创建map对象,通过decotate方法设transfomer时的transformChain然后通过TiedMapEntry将map与不存在的key绑定,进而利用BadAttributeValueExpException创建一个map进行赋值。但是val是私有属性的,需要进行setAccessible(true)来访问私有变量。

至此完成整个exp编写:
Pasted Graphic 22

参考链接

https://security.tencent.com/index.php/blog/msg/97

https://www.freebuf.com/news/150872.html

http://pupiles.com/java_unserialize2.html