[java 反序列化] Commons Collections5,6反序列化漏洞

java的反序列化操作的函数

java有writeObject()函数可以来执行序列化操作

public class ser {
    public static void main(String[] args) throws Exception {
        String test = "ckj123";

        FileOutputStream fos = new FileOutputStream("ser.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(test);
        oos.close();

        FileInputStream fis = new FileInputStream("ser.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object result = ois.readObject();
        ois.close();
        System.out.println(result);
    }
}

这只是对一个字符串的序列化当然也可以对对象进行序列化
对象需要一个Serializable这个接口

import java.io.*;

class ckj123 implements Serializable{
    String test = "test";
}

public class ser {
    public static void main(String[] args) throws Exception {
        ckj123 test = new ckj123();

        FileOutputStream fos = new FileOutputStream("ser.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(test);
        oos.close();

        FileInputStream fis = new FileInputStream("ser.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        ckj123 result = (ckj123)ois.readObject();
        ois.close();
        System.out.println(result.test);

    }
}

当然也可以重写readObject



defaultReadObject是反序列化要执行的
就可以让他在反序列化的时候弹一个notepad

java的反射机制

学习Commons Collections得先了解一下java的反序列化
java里面执行命令的对象是Runtime

public class cmd {
    public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        runtime.exec("notepad.exe");
    }
}

就会跳出来一个记事本
这样也可以通过java的反射机制来执行

import java.lang.reflect.Method;

public class cmd {
    public static void main(String[] args) throws Exception {
        Runtime runtime = Runtime.getRuntime();
        Class cls = runtime.getClass();
        Method method = cls.getMethod("exec", String.class);
        method.invoke(runtime,"notepad.exe");
    }
}
image.png

也可以通过两次反射来实现

import java.lang.reflect.Method;

public class cmd {
    public static void main(String[] args) throws Exception {
        Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime",new Class[]{}).invoke(null);
        Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(runtime,"notepad.exe");
    }
}
getMethod("方法","方法类型");
invoke("对象实例","参数");

这样就可以任意命令执行了

Commons Collections

Commons Collections中刚好使用了一个反射
不过他把他们封装了一下
成为了一个对象
其中最重要的一个函数

    public O transform(final Object input) {
        if (input == null) {
            return null;
        }
        try {
            final Class<?> cls = input.getClass();
            final Method method = cls.getMethod(iMethodName, iParamTypes);
            return (O) method.invoke(input, iArgs);
        } catch (final NoSuchMethodException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
                                       input.getClass() + "' does not exist");
        } catch (final IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
                                       input.getClass() + "' cannot be accessed");
        } catch (final InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" +
                                       input.getClass() + "' threw an exception", ex);
        }
    }

可以发现getMethodinvoke两个函数都齐了
只需要iMethodName, iParamTypes, iArgs三个参数就行了
他的另外一个函数


刚刚好可以给这三个赋值了
那么来试一下

public class test {
   public static void main(String[] args) throws Exception {
       InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{new String("notepad.exe")});
       Object result = invokerTransformer.transform(Runtime.getRuntime()) ;
   }
}

都在了=。=

命令执行

看完上面的感觉和反序列化没什么关系呀
在mac上测试的时候发现只有Commons Collections 5 和 Commons Collections 6可以
可能是jdk1.8的原因

Commons Collections 5

ChainedTransformer的transformer可以调用每一个transformertransform函数
然后就可以用InvokerTransformer构造一个利用链

Lazymap在每一次调用get的时候都会调用transform函数调用ChainedTransformer的transform


factory通过初始化Lazymap的时候赋值了



TiedMapEntry的getValue函数中使用了get函数就可以调用LazyMap


TiedMapEntry的tostring函数又会调用getvalue


image.png

BadAttributeValueExpException的readobject会调用valObj的tostring函数


于是有了利用链

BadAttributeValueExpException -> readobject
  TiedMapEntry -> tostring
    Lazymap -> get
      ChainedTransformer -> transform
        InvokerTransformer -> transform

最后成功执行

Runtime runtime = Runtime.getRuntime();
        runtime.exec("calc.exe");

Commons Collections 6

有了Commons Collections 5的经验Commons Collections 6就好分析很多了

这次不用BadAttributeValueExpException了
跟了一下这次调用的还是
Lazymap -> get
ChainedTransformer -> transform
InvokerTransformer -> transform
不过 TiedMapEntry 使用的就不是tostring了

而是


这样就可以调用Lazymap的get函数了
那么是怎么来的呢=。=

hashmap的hash函数调用了key的hashcode
只要key可控就可以
可以找到



hashmap的put函数
key和value都是传进来的然后是public方法还会调用 hash(key)
完满
这下只要找一个readobject带有put函数的就行了
一个完美的函数hashset

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

        .... ....
        // Create backing HashMap
        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
               new LinkedHashMap<E,Object>(capacity, loadFactor) :
               new HashMap<E,Object>(capacity, loadFactor));

        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            @SuppressWarnings("unchecked")
                E e = (E) s.readObject();
            map.put(e, PRESENT);
        }
    }

可以看到他的map调用了put函数
而且使用了hashmap
不过进行了判断当前的map是否LinkedHashSet 如果不是就new一个hashmap


hashset的构造函数就是把map初始化hashmap

那么利用链也有了

 HashSet -> readobject
  HashMap -> put
   HashMap -> hash
    TiedMapEntry -> hashcode
      Lazymap -> get
       ChainedTransformer -> transform
        InvokerTransformer -> transform

get it!

后记

一直在想为啥传进来字符串foo就变成Runtime了

发现

原来在这里,不管传什么进来都还给你一样的=。=太坏了

到最后终于跟通了=。=
真不容易。。。
这个debug的时候还会提前跳出来计算机让我懵逼了一个礼拜



最后把断点下到这里才行=。=
然而跟的时候他一直走的是下面的else那一段让我懵逼好久
得自己下断点不能跟着跑(牢记牢记@!)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容