Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序,用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞
Shiro的反序列化漏洞有Shiro-550
与Shiro-721
知道已经登陆用户的合法cookie且目标服务器含有可利用的攻击链就可以进行漏洞利用
漏洞原理
1、shiro-721用到的加密方式是AES-128-CBC
,而且其中的ase加密的key基本猜不到了,是系统随机生成的
2、这种加密方式容易受到Padding Oracle Attack(填充提示攻击)
,利用有效的RememberMe Cookie作为Padding Oracle Attack的前缀,然后精心构造 RememberMe Cookie 值来实现反序列化漏洞攻击
3、利用该漏洞可以破解出密文的明文以及将明文加密成密文,该漏洞存在条件如下:
(1)、攻击者能够获取到密文(基于分组密码模式),以及IV向量
(通常附带在密文前面,初始化向量)
(2)、攻击者能够修改密文触发解密过程,解密成功和解密失败存在差异性
利用过程
Apache Shiro框架提供了记住我的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie,cookie的key为RememberMe,cookie的值是经过相关信息进行序列化,然后使用AES加密(对称),最后再使用Base64编码处理
服务端在接收cookie时:
1、检索RememberMe Cookie的值
2、Base64解码
3、AES解密(加密密钥硬编码)
4、进行反序列化操作(未过滤处理)
5、攻击者可以使用Shiro的默认密钥构造恶意序列化对象进行编码来伪造用户的Cookie,服务端反序列化时触发漏洞,从而执行命令
影响版本
1.2.5,
1.2.6,
1.3.0,
1.3.1,
1.3.2,
1.4.0-RC2,
1.4.0,
1.4.1
1、在vulfocus平台进行复现,打开登录链接
2、Shiro框架默认指纹特征
在请求包的Cookie中?rememberMe字段赋任意值,收到返回包的 Set-Cookie 中存在?rememberMe=deleteMe?字段,说明目标有使用Shiro框架,可以进一步测试
3、为了让复现起来更简单,这里直接上工具,该工具Github上也有
操作逻辑:
1)、确定请求方式,输入URL地址
2)、直接选择爆破密钥,一旦爆破成功,便会直接返回指定密钥
3)、选择爆破利用链及回显,同样,爆破成功便如图
4、命令执行,直接输入需要执行的命令,也可以反弹shell
第二种复现方式:
就是将其中的remember Me
字段复制下来输入到工具中进行利用
java -jar ysoserial.jar CommonsBeanutils1 "touch /tmp/123" > payload.class
也就是调用ysoserial.jar
和这个利用链CommonsBeanutils1
,"touch /tmp/123"
这个就是要执行的命令,输入到payload.class
文件里
python shiro_exp.py http://192.168.171.137:8080/login.jsp LIO2vKStP5R4NN+TLY0Bgfrz+3sacQHB1BfrOheCVAHeFAGtRsX9JW24tCvcedluOxZwFPoOSs7/tA0fK+UJ9ylRjLIT87NIN1smV22TVqdQ4vSJXB42IQCTV1mDA2CwlDpoeem6M4qY2SeB4JwIpV+iUwNJoOj+NfWeX3/lLZHkoCnsR5TCm6GrHyhdaDZYK0BAJNXFQ9658sJGAF1fztcfR0pYD9RtX26iLW73+D0pd3x6DhPQB7euA4uhUZ3Ue8RoOK3jTqxHC3U5n0DIMpc1RWlHVzUyHjejFAPXCReV+7ds/dWr+b5XlgP9/7ajmi2+6dqr2apVaIhEMC5SP4X4Y+QZw3wS6w76pD1vT8JSlG6l+h4+tIRuS4/gbUzX8GhmPCtw2MBMS/xZ2FsjvTPexdPLEf+114qo4152aNNcXul4zN3czLlve+otlqd5E/WyhhbBA2+EFk+Pewnsq2g2sS53s57H9BcWhXHkcwf0cIrkOXAn9a9xfkkm1HH9 payload.class
然后利用Shiro的Exp,填充remember Me
字段,最后加上个payload.class
文件
最终可获得加密的payload,将payload加上rememberMe在之前的页面重放,前面设置的命令就会被执行
没有使用这种方式复现,有工具肯定使用工具舒服嘛
首先要知道密码都是字符,一个字符也就是1个byte,aes加密的时候会将字符进行分组并填充,有可能是每8字节一组,也可能是16字节一组
但是密码不可能恰好填满每个组,可能第一组填满了,第二组只有一个字符,这时候就需要进行填充
如果明文密码分组完后刚好不需要填充,那么会额外添加一个组,这个组的数据全部都是0xXX,这个数据是多少取决于aes加密是多少个字节为一组的。具体举例如下:
假设密码为一个1,且加密算法中分组的逻辑是8个字节,因为1只占1个字节,所以第一组中还有7个字节是空的,这时候第一组中的数据为:
1 0x07 0x07 0x07 0x07 0x07 0x07 0x07
如果明文恰好不需要填充,比如是8个2,且分组逻辑还是8个字节为一组,那么分完组的明文如下:
第一组:
2 2 2 2 2 2 2 2
第二组:
0x08 0x08 0x08 0x08 0x08 0x08 0x08 0x08
综上,填充的逻辑是,一定会填充数据,区别是填充一个组还是填充几位,如果分组后的明文最后一组中有N字节没有数据就填充0x0N
同时,如果分组后刚好合适,那么额外添加一个组,且这个组的明文数据一定全是0xXX,0xXX是多少取决于aes加密的分组逻辑与填充了多少个数据
注意:如果解密出的明文的结尾不是符合规律的0xXX,那么系统会判断解密失败
CBC主要是引入一个初始化向量(IV)来加强密文的随机性,保证相同明文通过相同的密钥加密的结果不一样,Shiro的IV
通过源码我们可知是16byte的,因此分组也是16byte一组
CBC加密过程:
思路过程:
1、明文经过填充后,根据密码分为不同的组,以组的方式对数据进行处理
2、初始化向量(IV)首先和第一组明文进行XOR(异或)操作,得到得值称为middle
3、采用密钥key,对middle进行加密生成第一组的密文
4、第一组加密的密文作为第二组的初始向量(IV),参与第二组明文的异或操作
5、依次执行块加密,最后将每一块的密文拼接成最终的密文
注意:由于初始化向量(IV)每次加密都是随机的,所以IV经常会被放在密文的前面,解密时先获取前面的IV,再对后面的密文进行解密,密文的第一组就是IV
CBC解密过程:
思路过程:
1、将密文进行分组(按照加密采用的分组大小),前面的第一组是初始化向量IV,从第二组开始才是真正的密文
2、使用加密密钥对密文的第一组进行解密,得到Middle,第一组中只要密文不变,那么Middle一定不会改变
3、将Middle和初始化向量IV进行异或,得到该组的明文
4、前一块密文是后一块密文的IV,通过异或中间值,得到明文
5、块全部解密完成后,拼接得到明文,密码算法校验明文的格式(填充格式是否正确)
6、校验通过得到明文,校验失败得到密文
1、升级shiro到1.4.2及以上
2、rememberMe功能的AES密钥泄露,会导致反序列化漏洞,建议修改默认AES密钥
🍺参考文章:
1、shiro 721 反序列化漏洞复现与原理以及Padding Oracle Attack攻击加解密原理
2、Padding Oracle Attack(填充提示攻击)详解及验证