Java
  • About This Book
  • 🍖Prerequisites
    • 反射
      • 反射基本使用
      • 高版本JDK反射绕过
      • 反射调用命令执行
      • 反射构造HashMap
      • 方法句柄
    • 类加载
      • 动态加载字节码
      • 双亲委派模型
      • BCEL
      • SPI
    • RMI & JNDI
      • RPC Intro
      • RMI
      • JEP 290
      • JNDI
    • Misc
      • Unsafe
      • 代理模式
      • JMX
      • JDWP
      • JPDA
      • JVMTI
      • JNA
      • Java Security Manager
  • 👻Serial Journey
    • URLDNS
    • SerialVersionUID
    • Commons Collection 🥏
      • CC1-TransformedMap
      • CC1-LazyMap
      • CC6
      • CC3
      • CC2
    • FastJson 🪁
      • FastJson-Basic Usage
      • FastJson-TemplatesImpl
      • FastJson-JdbcRowSetImpl
      • FastJson-BasicDataSource
      • FastJson-ByPass
      • FastJson与原生反序列化(一)
      • FastJson与原生反序列化(二)
      • Jackson的原生反序列化利用
    • Other Components
      • SnakeYaml
      • C3P0
      • AspectJWeaver
      • Rome
      • Spring
      • Hessian
      • Hessian_Only_JDK
      • Kryo
      • Dubbo
  • 🌵RASP
    • JavaAgent
    • JVM
    • ByteCode
    • JNI
    • ASM 🪡
      • ASM Intro
      • Class Generation
      • Class Transformation
    • Rasp防御命令执行
    • OpenRASP
  • 🐎Memory Shell
    • Tomcat-Architecture
    • Servlet API
      • Listener
      • Filter
      • Servlet
    • Tomcat-Middlewares
      • Tomcat-Valve
      • Tomcat-Executor
      • Tomcat-Upgrade
    • Agent MemShell
    • WebSocket
    • 内存马查杀
    • IDEA本地调试Tomcat
  • ✂️JDBC Attack
    • MySQL JDBC Attack
    • H2 JDBC Attack
  • 🎨Templates
    • FreeMarker
    • Thymeleaf
    • Enjoy
  • 🎏MessageQueue
    • ActiveMQ CNVD-2023-69477
    • AMQP CVE-2023-34050
    • Spring-Kafka CVE-2023-34040
    • RocketMQ CVE-2023-33246
  • 🛡️Shiro
    • Shiro Intro
    • Request URI ByPass
    • Context Path ByPass
    • Remember Me反序列化 CC-Shiro
    • CB1与无CC依赖的反序列化链
  • 🍺Others
    • Deserialization Twice
    • A New Blazer 4 getter RCE
    • Apache Commons Jxpath
    • El Attack
    • Spel Attack
    • C3P0原生反序列化的JNDI打法
    • Log4j
    • Echo Tech
      • SpringBoot Under Tomcat
    • CTF 🚩
      • 长城杯-b4bycoffee (ROME反序列化)
      • MTCTF2022(CB+Shiro绕过)
      • CISCN 2023 西南赛区半决赛 (Hessian原生JDK+Kryo反序列化)
      • CISCN 2023 初赛 (高版本Commons Collections下其他依赖的利用)
      • CISCN 2021 总决赛 ezj4va (AspectJWeaver写字节码文件到classpath)
      • D^3CTF2023 (新的getter+高版本JNDI不出网+Hessian异常toString)
      • WMCTF2023(CC链花式玩法+盲读文件)
      • 第六届安洵杯网络安全挑战赛(CB PriorityQueue替代+Postgresql JDBC Attack+FreeMarker)
  • 🔍Code Inspector
    • CodeQL 🧶
      • Tutorial
        • Intro
        • Module
        • Predicate
        • Query
        • Type
      • CodeQL 4 Java
        • Basics
        • DFA
        • Example
    • SootUp ✨
      • Intro
      • Jimple
      • DFA
      • CG
    • Tabby 🔦
      • install
    • Theory
      • Static Analysis
        • Intro
        • IR & CFG
        • DFA
        • DFA-Foundation
        • Interprocedural Analysis
        • Pointer Analysis
        • Pointer Analysis Foundation
        • PTA-Context Sensitivity
        • Taint Anlysis
        • Datalog
Powered by GitBook
On this page
  • 代理模式
  • 静态代理
  • 动态代理
  • 动态代理在反序列化中的利用

Was this helpful?

  1. 🍖Prerequisites
  2. Misc

代理模式

PreviousUnsafeNextJMX

Last updated 7 months ago

Was this helpful?

代理模式

代理模式是Java的设计模式之一

  1. 代理类和委托类有相同接口

  2. 代理类负责为委托类预处理消息、过滤消息、转发消息、事后处理消息等

利用代理模式可以实现AOP

按照代理类生成的时期可分为静态代理(编译期生成)和动态代理(运行时动态生成)

静态代理

定义接口或父类,委托类和代理类一起实现相同的接口或继承相同的父类

// 定义一个接口
public interface Rental {
    public void sale();
}
// 委托类 实现接口方法
public class Entrust implements Rental{
    @Override
    public void sale() {
        System.out.println("出租房子");
    }
}
// 代理类
public class AgentRental implements Rental{
    private Rental target; // 被代理对象
    public AgentRental(Rental target) {
        this.target = target;
    }
    @Override
    public void sale() {
        System.out.println("房子出租价位有1k-3k"); // 增加新的操作
        target.sale(); // 调用Entrust委托类的sale方法
    }
}
public static void main(String[] args) {
    Entrust entrust = new Entrust();
    AgentRental agentRental = new AgentRental(entrust);
    agentRental.sale();
}

优点: 可以在不改变委托类源码的情况下,通过代理类来修改委托类的功能 缺点: 接口方法增删时,代理类需要跟着变,不易维护;代理类繁多时不好管理

动态代理

  • InvocationHandler 接口:提供调用代理操作代理类实现这个接口

  • Proxy类:动态构建代理类

实现过程

  1. 实现InvocationHandler接口,创建自定义调用处理器

  2. 获取委托类的ClassLoader、Interface、InvocationHandler

  3. newProxyInstance传入2中的参数,创建动态代理实例对象

  4. 通过代理对象调用目标方法

// 代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TestAgent implements InvocationHandler {
    // target变量为委托类对象
    private Object target;
    public TestAgent(Object target) {
        this.target = target;
    }
    // 实现 java.lang.reflect.InvocationHandler.invoke()方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 添加自定义的委托逻辑
        System.out.println("房子出租价位有1k-3k");
        // 调用委托类的方法(java底层封装好了)
        method.invoke(target,args);
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        // 获取委托类的实例对象
        Entrust testEntrust = new Entrust();
        // 获取委托类的CLassLoader
        ClassLoader classLoader = testEntrust.getClass().getClassLoader();
        // 获取委托类的所有接口
        Class[] interfaces = testEntrust.getClass().getInterfaces();
        // 获取一个调用处理器
        InvocationHandler invocationHandler = new TestAgent(testEntrust);
        // 查看生成的代理类
       		System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        System.out.println(System.getProperty("java.io.tmpdir"));
        // 创建代理对象
        Rental proxy = (Rental) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        // 调用代理对象的sale()方法
        proxy.sale();
    }
}

若要查看动态代理生成的类,JDK8之前用

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

JDK8及之后用

System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
// 或
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

可以在ProxyGenerator#saveGeneratedFiles中查看

运行之后会在当前目录下生成一个com/sun/proxy/$Proxy0

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Rental {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
		return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
    }

    public final String toString() throws  {
        return (String)super.h.invoke(this, m2, (Object[])null);
    }

    public final void sale() throws  {
        super.h.invoke(this, m3, (Object[])null);
    }

    public final int hashCode() throws  {
        uper.h.invoke(this, m0, (Object[])null);
    }

    static {
		m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
        m2 = Class.forName("java.lang.Object").getMethod("toString");
        m3 = Class.forName("Rental").getMethod("sale");
        m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    }
}

这个类继承了Proxy又实现了委托类的接口

静态代码块中它获取了Object的一些基本方法(equals、toString、hashCode)以及委托类接口的方法(sale)

这些方法的调用都是交给super.h(Proxy#InvocationHandler)调用处理器来处理(重写invoke即可)

动态代理在反序列化中的利用

InvocationHandler的invoke方法,不管外边执行什么方法,都会执行到invoke

目的调用 B.f 入口类 A 接收参数O A中有O.method 但method没有可利用的 若O是动态代理类,且O接收参数B、invoke方法中含有 B.f 则执行O.method时会自动执行 B.f

readObject -> 反序列化时自动执行 invoke -> 函数调用时自动执行

解决Jackson链不稳定问题:https://xz.aliyun.com/t/12846

image-20221226153617101
image-20240930153709171