shiro反序列化漏洞分析

分析源码

我们去源码里面去找找,搜索rememberMe:

shiro反序列化漏洞分析_第1张图片

发现有一个 CookieRememberMeManager 这个类,看名字就知道他多半就是处理 RememberMe 的逻辑,所以根据该类查看它干了什么

shiro反序列化漏洞分析_第2张图片

这里继承 AbstractRememberMeManager 类,AbstractRememberMeManager 提供了创建和验证这些令牌的方法,以及配置cookie属性的方法。

shiro反序列化漏洞分析_第3张图片

这是CookieRememberMeManager类的构造函数。首先创建一个名为“rememberMe”的SimpleCookie对象,并将其设置为HttpOnly。然后,将cookie的最大生存期设置为一年,以确保用户在一年内不需要重新登录。最后,将cookie对象赋值给类中的cookie属性。这个构造函数的作用是创建一个CookieRememberMeManager对象,并设置默认的“记住我”cookie配置。如果需要更改cookie的配置,可以使用其他构造函数或通过setter方法来更改属性。

继续往下看,感觉这里是重点有没有.......

shiro反序列化漏洞分析_第4张图片

看类名可以知道此类用于将序列化后的用户身份信息存储到cookie中。

在方法中,首先通过WebUtils.isHttp(subject)方法判断Subject对象是否为HTTP-aware实例。如果不是,则返回并忽略记住我操作。如果Subject对象是HTTP-aware实例,就可以获取到HttpServletRequest和HttpServletResponse对象,从而可以设置cookie。

接下来是对这些对象执行的操作:

  1. 通过WebUtils.getHttpRequest(subject)方法获取HttpServletRequest对象。
  2. 通过WebUtils.getHttpResponse(subject)方法获取HttpServletResponse对象。
  3. 将序列化后的用户身份信息进行Base64编码。
  4. 创建一个新的SimpleCookie对象,并将其值设置为Base64编码后的身份信息。
  5. 将新的cookie对象保存到HttpServletRequest和HttpServletResponse对象中。

所以这个方法的作用是将序列化后的用户身份信息存储到cookie中,并将其保存到HTTP响应中,以便在用户下一次访问网站时自动登录。

方法调用的跟踪

接下来去查看一下该方法在什么地方被调用(快捷键:Ctrl+Alt+Shift+F7)

shiro反序列化漏洞分析_第5张图片

左下角如果有弹框的话,将所以选项勾上,下拉范围选项框选择所有。

shiro反序列化漏洞分析_第6张图片

在这可以看到该类继承的 AbstractRememberMeManager 类调用了该方法。

shiro反序列化漏洞分析_第7张图片

发现这个方法被 rememberIdentity 方法给调用了。

shiro反序列化漏洞分析_第8张图片

在这里会发现 rememberIdentity 方法会被 onSuccessfulLogin 方法给调用,跟踪到这一步,就看到了 onSuccessfulLogin 登录成功的方法。

shiro反序列化漏洞分析_第9张图片

当登录成功后会调用 AbstractRememberMeManage.onSuccessfulLogin 方法,该方法主要实现了生成加密的RememberMe Cookie,然后将RememberMe Cookie设置为用户的Cookie值。在rememberSerializedIdentity 方法里面去实现了。

shiro反序列化漏洞分析_第10张图片

回到 onSuccessfulLogin 这个地方,这里看到调用了 isRememberMe 很显而易见得发现这个就是一个判断用户是否选择了Remember Me选项。

shiro反序列化漏洞分析_第11张图片

另一方面  rememberIdentity 方法会调用 rememberSerializedIdentity 方法,到这里为止,我们已经接触到序列化了。

shiro反序列化漏洞分析_第12张图片

继续跟踪,有一个叫 getRememberedPrincipals 的方法调用getRememberedSerializedIdentity。看名字就知道 getRememberedPrincipals 是一个取得Remember验证的方法。

shiro反序列化漏洞分析_第13张图片

这里我们再跟进getRememberedPrincipals 方法,(快捷键:Ctrl+Alt+h)

shiro反序列化漏洞分析_第14张图片

我们继续跟踪 convertBytesToPrincipals方法

因为 convertBytesToPrincipals方法就是处理getRememberedPrincipals 方法 的东西,看名字应该是进行字节转换的。 

shiro反序列化漏洞分析_第15张图片

该方法首先检查是否存在加密服务,如果存在,则使用密钥对字节数组进行解密。接着,该方法使用"deserialize"方法将字节数组序列化。

我们可以先看反序列化

shiro反序列化漏洞分析_第16张图片

发现有一个反序列化入口 readObject() 这里就是要利用的点

然后看解码那个地方他的逻辑是如何的

shiro反序列化漏洞分析_第17张图片

 

该方法名为"decrypt",有一个参数:"encrypted",代表需要解密的字节数组。

该方法首先将需要解密的字节数组赋值给一个名为"serialized"的新的字节数组。然后,该方法通过调用"getCipherService"方法获取加密服务,如果加密服务存在,则用"getDecryptionCipherKey"方法获取解密密钥,并使用加密服务对字节数组进行解密。解密后,将解密后的结果赋值给"serialized"字节数组。最后,该方法返回"serialized"字节数组,即解密后的结果。

在这里我们需要关注俩个点,接口的抽象方法,有两个参数

第一个是要解密的数据

第二个参数就是解密的key了,这个是我们十分关心的,所以我们跟进第二个参数

shiro反序列化漏洞分析_第18张图片

跟踪返回 decryptionCipherKey

shiro反序列化漏洞分析_第19张图片跟踪 setDecryptionCipherKey 方法

shiro反序列化漏洞分析_第20张图片

 跟踪 setCipherKey 方法

你可能感兴趣的:(javascript,开发语言,ecmascript)