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/

输入正确的账号密码,root/secret,成功登录
若登录时勾选了Remember Me,返回包Set-Cookie含有一个rememberMe字段

0x02 Way To Attack
使用CC6利用链生成一个序列化Payload
使用Shiro默认Key进行加密
将密文作为rememberMe的Cookie发送给服务端
但是却报错了

找到异常信息的最后一个,org.apache.shiro.io.ClassResolvingObjectInputStream
这个类是ObjectInputStream的子类,重写了resolveClass方法 resolveClass是反序列化中用来查找类的方法 对比父类ObjectInputStream的resolveClass
都调用了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?