Loading

JAVA安全基础之代理模式(二)

JAVA安全基础之代理模式(二)

上篇讲到静态代理模式,这时候我们发现,一个代理类只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。所以就有了动态代理

动态代理

动态代理的代理类,是在内存中构建代理对象,从而实现对目标对象的代理功能。

在这里我们需要知道两个类:1.InvocationHandler(接口)、2.Proxy(类)

来看下具体使用步骤

1.(接口)创建Person接口:

public interface Person {
    //上交班费
    void giveMoney();
}

2.(被代理类)Student类实现了Person接口。Student可以具体实施上交班费的动作。

public class Student implements Person{
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void giveMoney() {
        System.out.println(name + "上交了班费");
    }

    public String getName() {
        return name;
    }
}

3.(InvocationHandler类)创建一个对象ProxyHandler,实现了InvocationHandler接口。也要持有一个Student类对象(这里换成了Object)。他可以通过反射来执行Student类的giveMoney()方法

public class ProxyHandler implements InvocationHandler {
	//这里写的是Object类
    private Object object;

    public ProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("--------------begin-------------");
        //通过反射来调用被代理类的方法
        method.invoke(object, args);
        System.out.println("--------------end-------------");
        return null;
    }
}

InvocationHandler对象可以通过Proxy.newProxyInstance()来获得代理类对象,下面的proxyStudent就是代理类对象。

Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);

1.被动态代理的对象调用任意方法都是通过对应InvocationHandler#invoke方法中的method.invoke(object, args);中触发

2.代理对象每次执行方法都会放到InvocationHandler中的invoke去执行

4.测试动态代理:

public class ProxyTest {
    public static void main(String[] args) {
        //实例化被动态代理的对象
        Student student = new Student("xiaoming");
        //实例化实现了InvocationHandler接口的类
        InvocationHandler proxyHandler = new ProxyHandler(student);
        //创建代理类proxyStudent
        Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);
        //代理类对象调用被代理类的方法
        proxyStudent.giveMoney();
    }
}

运行结果:

image-20210625004421870

加入来了个新的代理类mon

public interface Mom {
    void here();
}
public class MomImpl implements Mom {
    @Override
    public void here() {
        System.out.println("mom来了");
    }
}

测试类应该这么写:

public class ProxyTest {
    public static void main(String[] args) {

        Student student = new Student("xiaoming");
        MomImpl mom = new MomImpl();

        InvocationHandler proxyHandler = new ProxyHandler(student);
        InvocationHandler momHandler = new ProxyHandler(mom);

        Person proxyStudent = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), proxyHandler);
        Mom proxyMon = (Mom) Proxy.newProxyInstance(MomImpl.class.getClassLoader(), MomImpl.class.getInterfaces(), momHandler);

        proxyStudent.giveMoney();
        proxyMon.here();
    }
}

运行结果:

image-20210625012949946

我们来用ysoserial中的CC1链来理解,是怎么利用动态代理特性来构造payload的

在CC1中,利用了动态代理特性来构造了攻击payload,我们来看下实现过程。

1.AnnotationInvocationHandler为一个InvocationHandler

image-20210626164349340

2.AnnotationInvocationHandler构造函数传入了被代理对象var2,赋值给了this.memberValues

image-20210626164442176

根据前面说的,被动态代理的对象调用任意方法都会通过对应InvocationHandler的invoke方法触发

也就是说this.memberValues调用方法会调用AnnotationInvocationHandler的invoke方法

【AnnotationInvocationHandler的invoke方法】

image-20210626164658398

在AnnotationInvocationHandler的readObject方法中调用了this.memberValues的方法

image-20210626164827035

所以会转到AnnotationInvocationHandler的invoke方法

image-20210626164658398

往下看到78行,在AnnotationInvocationHandler#invoke方法中,this.memberValues调用了get方法。

image-20210626165044426

而在CC1中,AnnotationInvocationHandler构造方法var2参数传入的是LazyMap对象,所以this.memberValues = LazyMap

进而会去调用LazyMap.get方法,完成cc链的构造

image-20210626165630409

欢迎关注我的公众号,同步更新喔

wx

posted @ 2021-06-26 17:01  Atomovo  阅读(150)  评论(0编辑  收藏  举报