zoukankan      html  css  js  c++  java
  • java反序列化提取payload之Xray高级版的shiro回显poc的提取过程

    本文中xray高级版shiro payload来源于雷石安全实验室公众号发布的shiroExploit.jar

    感谢雷石安全实验室,雷石安全实验室牛逼

    本文主要描述如何从shiro的payload中提取有效payload。该方法适合从各种java反序列化漏洞中提取payload

    0x01 前言

    某日小伙伴发来雷石安全实验室的shiro利用工具,据称payload提取自xray。利用如下

    0x02 反编译雷石利用工具

    首先拖入idea中反编译,查看如何利用payload。代码如下

    t是遍历数组的下标变量

    不得不说,当我看到这人写的代码时,心中一万个草泥马飘过。第一次看到这样遍历数组的方式!!!!再看一下变量命名,浓郁地乡村非主流风格。雷石安全实验室写的代码,自带混淆,牛皮。

    payload呢,原来是xray已经生成并加密的,一共430个。所以我们的问题变为如何从这430个已加密的payload中提取未加密的内容

    0x03 shiro payload解密

    根据shiro漏洞的原理,shiro的cookie通过如下方式加密, key为kPH+bIxk5D2deZiIxcaaaA==解码后的内容

    base64Encode(iv+aes(java serialize object))
    

    而java反序列化后的数据,以aced开头。于是我们可以使用shiro默认密钥,批量解密上面的430个key。如果正常解密,且解密后的数据以正确的magic number开头。则保存文件。代码如下

        public static String bytesToHex(byte[] bytes) {
            StringBuffer sb = new StringBuffer();
            for(int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(bytes[i] & 0xFF);
                if(hex.length() < 2){
                    sb.append(0);
                }
                sb.append(hex);
            }
            return sb.toString();
        }
    
        public static byte[] decrypt(byte[] cipherTextBytes, byte[] pwdBytes, byte[] iv) {
            try {
    // 1 获取解密密钥
                SecretKeySpec keySpec = new SecretKeySpec(pwdBytes, ENCRY_ALGORITHM);
    // 2 获取Cipher实例
                Cipher cipher = Cipher.getInstance(CIPHER_MODE);
    // 查看数据块位数 默认为16(byte) * 8 =128 bit
    // System.out.println("数据块位数(byte):" + cipher.getBlockSize());
    // 3 初始化Cipher实例。设置执行模式以及加密密钥
                IvParameterSpec iv1 = new IvParameterSpec(iv);//使用CBC模式,需要一个向量iv,可增加加密算法的强度
                cipher.init(Cipher.DECRYPT_MODE, keySpec, iv1);
    // 4 执行
                byte[] clearTextBytes = cipher.doFinal(cipherTextBytes);
    // 5 返回明文字符集
                return clearTextBytes;
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
    // 解密错误 返回null
            return null;
        }
    
        public static void main(String... args) throws IOException {
            for(int i = 0; i< xray.cookie.length; i++){
                String payload = xray.payloads(i);
                System.out.println(payload);
                byte[] rawpayloadBytes = Base64.decode(payload);
                byte[] key = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");
                int ivSize = key.length;
                byte[] iv = new byte[ivSize];
                System.arraycopy(rawpayloadBytes, 0, iv, 0, ivSize);
                byte[] payloadBytes = new byte[rawpayloadBytes.length - ivSize];
                System.arraycopy(rawpayloadBytes, ivSize, payloadBytes, 0, payloadBytes.length);
                    byte[] result = EncryptUtil.decrypt(payloadBytes, key, iv);
                    if (result != null){
                        String hexResult = bytesToHex(result);
                        if (hexResult.startsWith("aced")) {
                            System.out.println(payload);
                            new FileOutputStream(new File("res.ser")).write(result);
                        }
                    }
            }
        }
    

    结果通过010editor查看如下

    0x04 查看java反序列化数据

    通过SerializationDumper工具即可查看

    shiro中通过反序列化漏洞回显,需要执行自定义的java代码。查看ysoserial代码,执行自定义代码,需要通过com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的方式,编写一个继承自该类的class,读取字节码并设置_bytecodes,代码如下

    所以我们的重点在于如何提取bytecode数组中的内容。而serializationDumper默认只打印数组中的值。

    查看一下serializationDumper工具是如何读取array数组的,代码如下

    首先读取array的size,然后调(byte)cd.getClassName().charAt(1)去读取array的类型,再调用readBytesField方法读取每一项具体的值,代码如下

    	/*******************
    	 * Read a byte field.
    	 ******************/
    	private void readByteField() {
    		byte b1 = this._data.pop();
    		if(((int)b1) >= 0x20 && ((int)b1) <= 0x7e) {
    			//Print with ASCII
    			this.print("(byte)" + b1 + " (ASCII: " + ((char)b1) + ") - 0x" + this.byteToHex(b1));
    		} else {
    			//Just print byte value
    			this.print("(byte)" + b1 + " - 0x" + this.byteToHex(b1));
    		}
    	}
    

    所以只需要魔改一下读取数组的地方即可,并写入文件。

    0x05 利用

    已经集成到shiro综合利用工具中,可以选择gadget以及生成方式,不过目前只集成16个key。

    参考

    1. https://mp.weixin.qq.com/s/fZhL-GjoXLPqAIKBKCC_fg
  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/potatsoSec/p/13378295.html
Copyright © 2011-2022 走看看