ManTou
发布于 IP属地安徽省

Shrio 550 和 721 漏洞的加密算法分析

Shrio550是大家比较熟悉的一个,因此本文侧重与Shrio721的产生原因 本文只做漏洞分析,未作漏洞复现

在学习Shrio漏洞时,只知道如何使用工具,不知道其中的底层原理,网上的文章对于Shrio721的底层分析又少之又少
https://www.cnblogs.com/Smile3306/p/18984943 作者也是看这个文章才弄明白Shrio的底层原理的,如果看不懂作者的描述,可访问此链接学习

什么是Shrio

Shrio是一个主流的JAVA安全框架,不依赖任何容器,可在JAVASE,JAVAEE项目运行

主要功能为对用户进行身份认证授权会话管理加密等

Shrio核心组件

a. UsernamepasswordToken :封装用户登录信息,并用来创建Token

b. SecurityManager :负责安全认证和授权,Shrio核心部分

c. Subject :Shrio中的一个抽象概念,把当前用户当作主体

d. Realm :自定义模块,一般包含验证和授权的逻辑

e. AuthenticationInfo :用户角色信息集合,认证时使用,有哪些角色

f. AuthorizationInfo :用户权限信息集合,授权时使用,有哪些权限

g. DefaultWebSecurityManager :安全管理器,Realm注入进来才能生效

h. ShrioFilterFactorBean :具体的操作执行,项目入口,数据流中枢

Shrio550 (CVE-2016-4437)
漏洞成因

将反序列化的key硬编码在代码中,并且直接将用户cookie中的iv进行解密,从而导致攻击者可直接利用任意iv和伪造恶意密文

漏洞影响范围

Apache Shrio <=1.2.4

漏洞原理

Shrio默认使用硬编码的AES密钥KeykPH+bIxk5D2deZiIxcaaaA==和IV(16个0x00)进行加密remremberMe Cookie

攻击者可利用默认密钥和任意iv加密序列化数据
服务器利用Cookie中的iv和服务器的Key进行解密

注意:任意iv,虽然服务器加密是利用IV(16个0x00),但是服务器解密是提取Cookie中的IV进行解密

Shrio721 (CVE-2019-12422)
漏洞成因

AES-128-CBC在解密时会先对解密的明文进行验证是否符合PSCK5Padding

通过Padding Oracle Attack得到中间值,然后就可伪造恶意明文,通过与中间值异或得到恶意密文

漏洞影响范围

1.2.5 <=Apache Shrio < 1.4.2

漏洞原理

解密过程中中间值的出现弱化了加密时对于Key的依赖,对于攻击者来说,只需要得到对应的中间值,就相当于可以伪造密文,伪造明文

image.png

○ 在服务器视角下,先解出中间值3之后跟密文2异或得到明文3,之后判断明文3的填充规则是否符合PKCS5Padding规则 符合 返回200 不符合 异常

○ 那么就可以根据改变密文,根据服务器响应得出中间值数据,那么就可以改变明文,跟中间值异或得到恶意的明文

Padding Oracle Attack (POA)
爆破密文

密文2 ==CipherText

中间值3 ==TmpKey

公式:0x01= CipherText[16] ⊕ TmpKey[16]
通用公式:0x0n .... 0x0n= CipherText[16-(n-1)] .... CipherText[16] ⊕ TmpKey[16-(n-1)] ....TmpKey[16]

最多需要爆破256次

最后利用0x0n .... 0x0n 和 CipherText进行异或即可得到TmpKey

误判

我们只知道服务器校验是否合法,但有种特殊情况

在爆破TmpKey[16]位时,本来我们想要达到0x01=CipherText[16] ⊕ TmpKey[16]

但恰好发生 0x02 0x02 = CipherText[15] CipherText[15] ⊕ TmpKey[15] TmpKey[16]
这个时候服务器也会返回200

这样的情况有十六种0x0f .... 0x0f
P(0x0n fault)=(1/256)^n =》 P(fault)≈1/(256×255)=1/65280

扩充明文组

以上原理只能控制256(密文分组-1)个字符,对于攻击来说根本不够

我们伪造密文4,无论是否合理,服务器都会对这个分组密文解密,得到中间值4

由于密文4不合理那么中间值4也不合理,但是没关系,我们只需要修改密文3,爆破中间值4就行了

这样我们就从原本的:
IV+C1+C2+C3 (可控值:明文2+明文3 16*2=32字节)

变为(扩容1组)

IV+新C1+新C2+新C3+C4 (可控值:明文2+明文3+明文4 16*3=48字节)

同理(扩容2组)

IV+新C1+新C2+新C3+新C4+C5(可控值:明文2+明文3+明文4+明文5 16*4=64字节)

理论可以扩容到Shrio上限,但每扩容一个分组,增加16256次爆破

举例

假如我们原本登录成功得到一个正确Cookie:

Set-Cookie:rememberMe=Base64(IV+CipherText)
rememberMe=Base64(0x00 ... 0x00 0x01 ... 0x01 0x02 ... 0x02)

通过分组得到:
IV = 0x00 0x00 ... 0x00 C1 = 0x01 0x01 ... 0x01 C2 = 0x02 0x02 ... 0x02

现在按扩容到C4构造:

IV = 0x00 0x00 ... 0x00 C1 = 0x01 0x01 ... 0x01 C2 = 0x02 0x02 ... 0x02
C3 = 0x03 0x03 ... 0x03 C4 = 0x04 0x04 ... 0x04 (C3,C4 写任意值AES都能解密)

将rememberMe=Base64(IV+C1+C2+C3+C4)作为请求头发送给服务器

服务器会先解密C4,假设得到C4的中间值4(攻击者未知):

中间值4 = F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

1、获取中间值

爆破倒数第一位

保持C4不变,首先改变C3的最后一个字节C3[16],比如改为0xDD
令rememberMe=Base64(00 ... 00|01 ... 01|02 ... 02|03 ... DD|04 ... 04)

服务器视角:

判断错误:

让0xDD与中间值4[16]的0xFF异或(攻击者不可视),结果得到的不是0x01,所以返回 “密码不正确、校验不合格”的相关内容(不考虑误报),如状态码500 (攻击者只能看到响应信息)

判断正确:

而当C3[16]遍历到 0xFE 时:
0x01 = 中间值4[16] 异或 0xFE
服务器返回“密码不正确、校验合格”的相关内容,如状态码301,那么就得到:
中间值4[16] = 0x01 异或 0xFE
= 0xFF

2、伪造明文

因为公式:
明文 = C3 异或 中间值4

而中间值4是已知的,所以公式:新C3 = 伪造明文4 异或 中间值4

我们伪造一个明文:helloword

步骤 1:

把“helloword”变成 16 字节明文
明文4 = 68 65 6C 6C 6F 77 6F 72 64 07 07 07 07 07 07 07

步骤 2:

计算新 C3(16 字节)

新C3[i] = 明文4[i] 异或 中间值4[i]

得到(示例值,按位计算即可):

新C3 = 97 93 9F 9F 9A 81 9A 8E 9B F8 F8 F8 F8 F8 F8 F8

3、截断

得到新的C3,现在要进行C3位置的爆破操作,改变C2,
固定新C3,去掉C4

该过程发送的Cookie值去掉C4

原Cookie:
IV + C1 + C2 + C3 + C4
00 ... 00 01 ... 01 02 ... 02 03 ... 03 04 ... 04

现Cookie:
IV + C1 + C2 + 新C3
00 ... 00 01 ... 01 02 ... 02 97 93 9F 9F 9A 81 9A 8E 9B F8 F8 F8 F8 F8 F8 F8

4、重复获取中间值

该阶段固定伪造出C4位置明文的新C3,遍历C2的值,去获取新C3的中间值,从而伪造C3位置的明文

浏览 (32)
点赞 (2)
收藏
打赏
评论