文章参考于:
xray社区(微信公众号)
由于文章只是大概说了思路,没有详细的进行操作说明,故有了此文
通过393行传入subjectContext,调用getRememberedSerializedIdentity函数,该函数位内org/apache/shiro/web/mgt/CookieRememberMeManager.java:
该段函数含义为取cookie里的rememberMe参数,然后进行解码为字节数组
整体流程:
随后进入红箭头指向的这一步,convertBytesToPrincipals函数用shiro里的key对传入的参数进行解密等一系列操作,跟进convertBytesToPrincipals函数
发现调用了decrypt函数进行解密,继续跟进:
这里489行调用了key进行解密,当然,这里肯定是得不到结果的,因为传入的key是错误的,那么我们回过头,去看整体的函数,就会被
这里捕捉异常
进入onRememberedPrincipalFailure函数
进入forgetIdentity函数
继续跟进removeFrom方法:
355行加入了value,这里
1 | DELETED_COOKIE_VALUE |
即为deleteMe参数
这里用gadget进行rce,多出来了一个deleteMe参数,为什么呢
之前的流程不需要看,直接进入convertBytesToPrincipals函数,return deserialize
跟进deserialize函数
看到getSerializer函数,跟进
发现是PrincipalCollection类型的才会不报错,显然,gadget实际上并不是继承PrincipalCollection类型的,所以这里会报错
但是在做类型转换之前,先进入了DefaultSerializer#deserialize 进行反序列化处理,等处理结束返回 deserialized 时候,进行类型转换自然又回到了上面提到的类型转换异常,我们 key 不正确的情况下的 catch 异常捕获的逻辑里,后面的流程就和上述一样了
这里就是反序列化rce的触发点
那么总结一下上面的两种情况,要想达到只依赖shiro自身进行key检测,只需要满足两点:
1.构造一个继承 PrincipalCollection 的序列化对象。
2.key正确情况下不返回 deleteMe ,key错误情况下返回 deleteMe 。
基于这两个条件下 SimplePrincipalCollection 这个类自然就出现了,这个类可被序列化,继承了 PrincipalCollection 。
构造POC实际上也很简单,构造一个这个空对象也是可以达到效果的。(这里的org.apache.shiro.subject.SimplePrincipalCollection需自己进行获取导入)
1 | package example; |
就会看到文件夹下多出一个payload文件,里面存储的即为序列化数据
这里我用到的生成rememberMe的脚本如下:
1 | import sys |
用生成的rememberMe参数去请求:
随意进行更改rememberMe的key变成错误的key,重新生成
rememberMe=deleteMe字段出来了