注意到这里若抛出IllegalArgumentException异常,即可对target进行字符串拼接,进而触发target的toString
这种报错之后进行对象拼接字符串来打印异常信息的操作也不是第一次见了,比如Dubbo的CVE-2021-43297(https://paper.seebug.org/1814/),异常处理时进行了反序列化,并将反序列化得到的对象进行字符串拼接,隐式触发toString。
那么问题来了,如何触发IllegalArgumentException异常呢,这里相对好控制的只有target,因为外部的方法调用的method和args都是相对固定的。
结合JDK动态代理的特点,创建代理对象Proxy时传递了类加载器、接口数组、调用处理器,而target位于调用处理器中,InvocationHandler并不会检查这个target是否实现了接口定义的方法。因此不难想到只要委托代理的对象没有实现代理的接口中声明的方法,调用时就会抛出异常。
可以简单验证一下: 这里是对1这个对象进行调用Runtime的exec方法
报错了java.lang.IllegalArgumentException: object is not an instance of declaring class因此现在只要找一个类的readObject方法对某个接口声明的方法进行了调用,创建代理对象时传入该接口即可。
这里随便找了一个类java.util.Collections$SetFromMap,当然肯定还有其他利用类。 构造函数传入一个空的Map,接着反射修改m为Proxy代理对象,readObject时调用m.keySet时触发JdkDynamicAopProxy的invoke方法
没有评论