• shiro550反序列化漏洞


    前言

    很久以前的洞
    这次来写一下是复习一下之前的笔记
    也为了后面的无依赖链和cc链以及TemplatesImpl做铺垫

    分析

    首先是要知道这个漏洞的大致流程
    就是关于cookie的加密方式是AES这种对称的加密
    其中秘钥是写在框架代码中的,也就是硬编码
    这就是漏洞产生的原因

    首先就是getRememberedSerializedIdentity

    protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
    
            if (!WebUtils.isHttp(subjectContext)) {
                if (log.isDebugEnabled()) {
                    String msg = "SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a " +
                            "servlet request and response in order to retrieve the rememberMe cookie. Returning " +
                            "immediately and ignoring rememberMe operation.";
                    log.debug(msg);
                }
                return null;
            }
    
            WebSubjectContext wsc = (WebSubjectContext) subjectContext;
            if (isIdentityRemoved(wsc)) {
                return null;
            }
    
            HttpServletRequest request = WebUtils.getHttpRequest(wsc);
            HttpServletResponse response = WebUtils.getHttpResponse(wsc);
    
            String base64 = getCookie().readValue(request, response);
            // Browsers do not always remove cookies immediately (SHIRO-183)
            // ignore cookies that are scheduled for removal
            if (Cookie.DELETED_COOKIE_VALUE.equals(base64)) {
                return null;
            }
    
            if (base64 != null) {
                base64 = ensurePadding(base64);
                if (log.isTraceEnabled()) {
                    log.trace("Acquired Base64 encoded identity [" + base64 + "]");
                }
                byte[] decoded = Base64.decode(base64);
                if (log.isTraceEnabled()) {
                    log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes.");
                }
                return decoded;
            } else {
                //no cookie set - new site visitor?
                return null;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    从函数名可以看出这是获取cookie并进行处理的类,首先就是获取参数,就是cookie,然后再base64解码,返回结果

    发现在getRememberedPrincipals处调用了该函数

    在这里插入图片描述
    并调用了convertBytesToPrincipals来进行处理数据

    if (bytes != null && bytes.length > 0) {
                    principals = convertBytesToPrincipals(bytes, subjectContext);
                }
    
    • 1
    • 2
    • 3

    再来看下convertBytesToPrincipals的功能

    protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {
            if (getCipherService() != null) {
                bytes = decrypt(bytes);
            }
            return deserialize(bytes);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    很明显是实现了对数据的解密,然后再反序列化

    这里先来看下解密函数的实现

    先在接口处看下参数
    在这里插入图片描述
    第一个参数是解密的字段,第二个参数是解密的key,也就是秘钥
    正是我们前面提到的对称的加密方式AES

    public ByteSource decrypt(byte[] ciphertext, byte[] key) throws CryptoException {
    
            byte[] encrypted = ciphertext;
    
            //No IV, check if we need to read the IV from the stream:
            byte[] iv = null;
    
            if (isGenerateInitializationVectors(false)) {
                try {
                    //We are generating IVs, so the ciphertext argument array is not actually 100% cipher text.  Instead, it
                    //is:
                    // - the first N bytes is the initialization vector, where N equals the value of the
                    // 'initializationVectorSize' attribute.
                    // - the remaining bytes in the method argument (arg.length - N) is the real cipher text.
    
                    //So we need to chunk the method argument into its constituent parts to find the IV and then use
                    //the IV to decrypt the real ciphertext:
    
                    int ivSize = getInitializationVectorSize();
                    int ivByteSize = ivSize / BITS_PER_BYTE;
    
                    //now we know how large the iv is, so extract the iv bytes:
                    iv = new byte[ivByteSize];
                    System.arraycopy(ciphertext, 0, iv, 0, ivByteSize);
    
                    //remaining data is the actual encrypted ciphertext.  Isolate it:
                    int encryptedSize = ciphertext.length - ivByteSize;
                    encrypted = new byte[encryptedSize];
                    System.arraycopy(ciphertext, ivByteSize, encrypted, 0, encryptedSize);
                } catch (Exception e) {
                    String msg = "Unable to correctly extract the Initialization Vector or ciphertext.";
                    throw new CryptoException(msg, e);
                }
            }
    
            return decrypt(encrypted, key, iv);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    再来来看下解密的函数

    protected byte[] decrypt(byte[] encrypted) {
            byte[] serialized = encrypted;
            CipherService cipherService = getCipherService();
            if (cipherService != null) {
                ByteSource byteSource = cipherService.decrypt(encrypted, getDecryptionCipherKey());
                serialized = byteSource.getBytes();
            }
            return serialized;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里获取了解密的秘钥
    一直跟进到后面发现其就是常量并写在代码中

    在这里插入图片描述
    接着在跟进反序列化

    在这里插入图片描述

    是通过原生的readObject触发反序列化

    结尾

    这里就没有复现了
    知识整理一下以前的笔记
    可以用vulhub直接复现

  • 相关阅读:
    Angular 基础
    MindFusion.WinForms Pack 2022.R2
    swagger使用教程——快速使用swagger
    事务的隔离级别
    全功能知识付费源码系统微信小程序+H5+PC端一站通行,自定义你的小程序
    基于粒子群优化的BP神经网络算法
    iRDMA Flow Control Introduction
    渗透测试-apt攻击与防御系列-解决无Meterpreter Shell添加虚拟路由映射第一季
    (c语言)移位操作符
    Maven内网开发使用离线仓库
  • 原文地址:https://blog.csdn.net/m0_52367015/article/details/126089672