Weblogic cve-2020-14645 JNDI注入分析

1 前言

近日,Oracle官方发布安全更新,在此前的CVE-2020-2883 将 extract 方法存在危险操作的 MvelExtractor 和 ReflectionExtractor 两个类加入到了黑名单中,因此我们只需要继续找一个 extract 方法存在危险操作的类即可绕过补丁,这里找到的是 Weblogic 12.2.1.4.0 Coherence 组件特有的类 com.tangosol.util.extractor.UniversalExtractor,因此只能影响 Weblogic 12.2.1.4.x。

漏洞影响范围: Oracle WebLogic Server 12.2.1.4.0

附上本文内容的参考链接: T3反序列化 Weblogic12.2.1.4.0 JNDI注入

2 漏洞分析

先附上反序列化的调用链图

图片[1]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

熟悉前几个coherence 反序列化漏洞的同学就应该知道,本次漏洞其实是找到了一个新的Extractor函数,但是受限于该函数影响,UniversalExtractor函数只存在于Oracle WebLogic Server 12.2.1.4.0版本中,这与oracle发布的更新公告其实有一点出入,公告里似乎显示的影响全版本,这里就不再计较这些,开始进行漏洞分析。

漏洞入口点在com.tangosol.util.extractor.UniversalExtractor第66行的extract函数,这里的oTarget变量可控,为了更好地展示代码,以下图直接以debug时的图作为过程来说明。

图片[2]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

第70行传入m_cacheTarget变量,但是该变量为transient修饰,因此不可经过反序列化控制,这也就导致在73行判断targetPrev一定为null,进入到else处的代码,跟进extractComplex函数,

图片[3]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

这里有几个函数需要具体跟进以下,第一个就是184行的getCanonicalName函数

图片[4]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

87行getValueExtractorCanonicalName就跳过不看了,返回一定为空,进入到89行,继续跟进computeValueExtractorCanonicalName函数

图片[5]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

这里我传入的是getDatabaseMetaData(),第17行判断aoParam是否为空,这里有经验的就能够猜到在后续的invoke里,一定会带上这里的aoParam,那么在这种情况下,我们后面构造的反射调用一定要是无参函数,这里其实是一个非常大的限制,非常像fastjson找setxxx的无参构造函数;19行判断sName是否以()结尾,如果不是则直接返回函数名,最后进入到sName的判断,这里判断比较简单,就是查看该函数是否以get/is为开头的函数,最后将前缀和后缀去掉,返回小写函数名。

看到这里总结下调用函数的条件:无参构造;函数名以get/is为开头。

图片[3]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

那么这里返回到extractComplex函数,继续看185行的isPropertyExtractor函数,该函数默认返回为true,那么在下面的if判断中会默认进入到187行的判断语句中,这里跟进到findMethod函数,认真看前面的同学其实大概就能够猜到了,这里通过对BEAN_ACCESSOR_PREFIXES的遍历,然后对函数名进行拼接,也就是说对返回的sCName进行get/is的拼接,然后到clzTarget中去寻找该函数是否存在,所以这里一条函数反射调用的链隐隐约约就已经能够看出来了。

图片[7]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

跟进到findMethod后对sName函数进行查找,如果存在返回Method。回到前面的调用图,203行就会对m_cacheTarget变量进行赋值,最后进入206行进行反射调用

图片[8]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

这里安全客原文也给出了链,调用JdbcRowSetImpl.getDatabaseMetaData(),那么下面来看看该函数的写法

JNDI触发点函数位于JDK的内置类中com.sun.rowset.JdbcRowSetImpl中

图片[9]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

这里必须符合前面的函数构造条件,发现均符合,然后跟进connect函数

图片[10]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

这里326行可以看到通过getDataSourceName函数进行jndi的查询,然后lookup触发JNDI注入,那么到这里其实整条链就已经一目了然。

poc如上面的代码所示,通过setDataSourceName设定jndi地址,配合上marshalsec就能够进行JNDI注入。

但是在安全客的原文里作者提到了会有两次compare函数,通过第一次compare来改变UniversalExtractor的内部变量,这里其实指的就是改变m_cacheTarget变量,在上图的extractComplex函数中可以看到203行对m_cacheTarget进行了赋值,那么我们跟进37行代码,也就是第二次的compare来看看会有什么不同

图片[11]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

图片[12]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

在第二次的compare你会发现这里的m_cacheTarget变量已经被重新赋值了,不再为null,第一次compare中由于为null,所以会进入到76行的分支,而在这里,由于m_cacheTarget不为空,那么就会进入到73行的判断,首先targetPrev不为空,另外类名一致性检查也能过去了,都为JdbcRowSetImpl,所以最后进入到74行的代码,由于targetPrev.isMap()返回false,所以进入到后面的函数反射调用,这里其实就等同于前面第一次的反射调用,只是触发点位置不一样,也能触发JNDI注入漏洞。

图片[13]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

3 后记

可能会有同学跟我想法一样,这个漏洞已经懂了,然后开启SimpleHTTPServer,准备调试,这时候就会发现你的JNDI服务端代码有问题,本身来说这个漏洞也不算复杂,但是笔者花了大量时间来调试JNDI服务端的代码,因为代码一旦有问题,整个序列化过程就会报错,笔者在这里至少发现两个坑,第一个坑就是JNDI需要返回实例,如果实例为空那么getDatabaseMetaData中就会报错,第二坑就是JdbcRowSetImpl中的getConnection和getMetadata,这里一旦返回为空,就会出现NullPointer报错,导致序列化中断,第三个坑就是getMetadata返回的数据会转化为Comparable类型,一旦类型转化报错,整个序列化过程也走不下去。

这里就附上笔者的JNDI服务端代码,其中mysql这个jar包是会默认存在于weblogic的lib里,实际上也可以找JDK原生DataSource,这样可能效果更好。

简单来说就是自己定义了一个返回实例,该实例必须是DataSource类型,通过在getConnection函数中返回了一个自定义的Connection类,最后调用该类的getMetadata函数时返回为空,那么就可以转化为Compareable类型,从而生成序列化文件。

图片[14]-Weblogic cve-2020-14645 JNDI注入分析-安全小百科

相关推荐: beef+msf实现内网渗透

在内网渗透方面,最为大众所知道的就是xp系统的ms08067漏洞,通过这个漏洞可以对未打上补丁的xp系统实现getshell,但是经过笔者发现,这种漏洞攻击在被攻击机开上windows防火墙的时候是没用的(连ping都会被拒绝),但是arp+dns欺骗仍然是可…

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论