Spring-AOP下toString新触发
Fir3proof WEB安全 222浏览 · 2025-04-01 09:27

前言

最近某个CTF线下赛的一道Java反序列化题,出现了很刁钻的黑名单 首先想到的是Jackson调用getter打TemplatesImpl,但是toString的入口几乎都被ban了(如下所示)

于是便有了下面的探索过程

JdkDynamicAopProxy破局

JdkDynamicAopProxy这个类最初用于解决Jackson链的不稳定触发(https://xz.aliyun.com/news/1229) 其实现了InvocationHandler,通过JDK的动态代理来实现AOP。具体来说,其接收一个AdvisedSupport对象作为自身的advised属性,这个对象有一个targetSource属性,包含了委托代理的目标对象,TargetSource#getTarget来获取目标对象。当代理对象调用方法时,会转交给调用处理器的invoke方法,最终就可以通过这个targetSource属性来调用实际目标对象所实现的方法。 需要注意的是,若目标对象的接口没有定义equals或hashCode方法,则会直接调用JdkDynamicAopProxy自己定制的equals或hashCode

接着往下走,若advised这个AOP配置对象中没有给当前调用的方法设置方法拦截器(chain为空),则直接调用目标对象实现的方法。

invokeJoinpointUsingReflection直接用反射调用了方法(反射调用方法的三要素:接收对象target,方法Method,参数数组args)

注意到这里若抛出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方法

POC编写

这里以Jackson打TemplatesImpl为例

image.png
图片加载失败


0 条评论
某人
表情
可输入 255

没有评论