Transformer
该类里的transform方法将一个对象转化为另一个对象.如Runtime.class经过transform转化输出结果为class java.lang.Class
InvokerTransformer
通过查看InvokerTransformer的源码可以看出该类是通过反射创建一个新的对象实例.该类使用了transform接口如图所示:
cls获取传递进来的input对象值,例如传入runtime对象
cls.getMethod 以及method.invoke是利用java反射机制反射Runtime的getRuntime方法。
iMethodName表示得到的方法名, iParamTypes表示方法中使用的参数类型的数组
通过InvokerTransformer反射出了java.lang.Runtime.getRuntime()
执行命令的整个调用连为 java.lang.Runtime..getRuntime().invoke().exec()
可以通过该方式逐步调用:
成功代码执行
上述是整个反射链的过程
ChainedTransformer
可以看出该类重构了transform方法,将我们之前的调用链简化到一个方法中通过创建的Transformers数组循环反射执行。
如何构造出Runtime对象类型呢?
ConstantTransformer
可以看出该类对transformer重构,返回一个iConstant变量,该变量在ConstantTransformer(Object)方法中被赋值。
内部构造出了Runtime的对象类型
构造poc
成功执行
TransformedMap
该类实现了一个功能——将普通的Map转换为一个TransformedMap,可以通过该类绕过transform方法。
KeyTransfomer 表示key改变的操作 valueTransformer表示value改变时的操作
从这里可以看出 value是可控的,在decorate中赋值即可,于是有如下利用代码:
通过TransformedMap代替transform生成如下代码:
成功弹出计算器:
至此我们获取了一个完整的poc,剩下需要找一个可重写readObject方法的类并且调用了对map值进行修改操作。
在ysoserial反序列化工具利用的是 BadAttributeValueExpException 查看代码如下:
该代码重构了readObject方法,如果传入类型为map类型,则会调用map.toString()方法。这里并没有对map的key值进行修改操作,于是需要利用LazyMap,TiedMapEntry两个类来构造
LazyMap:尝试访问key的value如果key不在会把值put进去
TiedMapEntry:会把map和一个key进行绑定
利用LazyMap创建map对象,通过decotate方法设transfomer时的transformChain然后通过TiedMapEntry将map与不存在的key绑定,进而利用BadAttributeValueExpException创建一个map进行赋值。但是val是私有属性的,需要进行setAccessible(true)来访问私有变量。
至此完成整个exp编写:
参考链接
https://security.tencent.com/index.php/blog/msg/97
https://www.freebuf.com/news/150872.html
http://pupiles.com/java_unserialize2.html