Remember Me反序列化 CC-Shiro

0x01 Env Build

为了让浏览器或服务器重启后用户不丢失登录状态,Shiro支持将持久化信息序列化并加密后保存在Cookie的rememberMe字段中,下次读取时进行解密再反序列化。

Shiro 1.2.5版本之前内置了一个默认且固定的加密Key,导致攻击者可以伪造任意的rememberMe Cookie,进而触发反序列化漏洞。

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.2.4</version>
</dependency>

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>1.2.4</version>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.30</version>
</dependency>

index.html

login.html

shiro.ini

web.xml

mvn package 将项目打包成war包,放在Tomcat的webapps目录下。然后访问 http://localhost:8080/CC-SHIRO/

image-20230128130313064

输入正确的账号密码,root/secret,成功登录

若登录时勾选了Remember Me,返回包Set-Cookie含有一个rememberMe字段

image-20230128130414775

0x02 Way To Attack

  1. 使用CC6利用链生成一个序列化Payload

  2. 使用Shiro默认Key进行加密

  3. 将密文作为rememberMe的Cookie发送给服务端

但是却报错了

image-20230128131027720

找到异常信息的最后一个,org.apache.shiro.io.ClassResolvingObjectInputStream

这个类是ObjectInputStream的子类,重写了resolveClass方法 resolveClass是反序列化中用来查找类的方法 对比父类ObjectInputStreamresolveClass

都调用了forName来寻找类,但子类用的是 org.apache.shiro.util.ClassUtils#forName 父类用的是Java原生的 Class.forName

[Lorg.apache.commons.collections.Transformer;org.apache.commons.collections.Transformer 由于涉及到Tomcat对类加载的处理逻辑,这里不深入探究 结论是这样的:

如果反序列化流中包含非Java自身的数组,则会出现无法加载类的错误

由于CC6用到了Transformer数组,不是Java自身的数组,导致这条链无法利用

0x03 CommonsCollectionsShiro

接下来就要利用到TemplatesImpl来动态加载恶意字节码了

CC6中有一个类TiedMapEntry,构造器接收Map和Object key getValue方法调用了map的get方法,传入key

还记得CC1中的LazyMap,懒加载方式,在调用其get方法时会触发transform

可以看到key是会被传入transform方法的,那我们就根本不需要Transformer数组的第一个ConstantTransformer来传递对象,这边key可以直接传入,我们可以直接利用InvokeTransformer

HashMap.readObject => HashMap.hash => key.hashCode TiedMapEntry.hashCode => TiedMapEntry.getValue => map.get(key) => LazyMap.get(TemplatesImpl) => InvokerTransformer.transform(TemplatesImpl) => newTransformer()

Last updated

Was this helpful?