Weblogic Server远程代码执行漏洞(CVE-2021-2109)调试分析

 

一、漏洞背景

1.JNDI的基本应用

​ JNDI是Java Naming and Directory Interface(JAVA命名和目录接口)的英文简写,它是为JAVA应用程序提供命名和目录访问服务的API(Application Programing Interface,应用程序编程接口)。

2.命名的概念与应用

​ JNDI中的命名(Naming),就是将Java对象以某个名称的形式绑定(binding)到一个容器环境(Context)中,以后调用容器环境(Context)的查找(lookup)方法又可以查找出某个名称所绑定的Java对象。在真实的项目应用中,通常是由系统程序或框加程序先将资源对象绑定到JNDI环境中,以后在该系统或框架中运行的模块程序就可以从JNDI环境中查找这些资源对象了。例如,Tomcat服务器在启动时可以创建一个连接到某种数据库系统的数据源(DataSource)对象,并将该数据源(DataSource)对象绑定到JNDI环境中,以后在这个Tomcat服务器中运行的Servlet和JSP程序就可以从JNDI环境中查询出这个数据源(DataSource)对象进行使用,而不用关心数据源(DataSource)对象是如何创建出来的,这种方式极大地增强了系统的可维护性,当数据库系统的连接参数发生变更时,这只是Tomcat系统管理员一个人要关心的事情,而与所有的应用程序开发人员无关。
​ 容器环境(Context)本身也是一个Java对象,它也可以通过一个名称绑定到另一个容器环境(Context)中。将一个Context对象绑定到另外一个Context对象中,这就形成了一种父子级联关系,多个Context对象最终可以级联成一种树状结构,树中的每个Context对象中都可以绑定若干个Java对象

 

二、漏洞分析

1.环境搭建

靶场采用 https://github.com/QAX-A-Team/WeblogicEnvironment 一键速成

工具采用 https://github.com/welk1n/JNDI-Injection-Exploit/blob/master/README-CN.md

准备好Burpsuite和IDEA就可以愉快的进行远程调试了~

2.漏洞调试

在public JndiBindingHandle(String objectIdentifier) 和 public JndiBindingHandle(String context, String binding, String server)中可以看到一些初始化操作。

返回newInstance(args) 是实例化

此时key的值是POC中的_nfpb,

当_nfpb不满足结尾是handle的条件,来到检测他的下一位是否满足结尾是handle的条件。

此时,_pageLable也不满足,则继续检查下一位key JNDIBindingPageGeneral.

这里满足了结尾是handle为结尾的条件

往下走,这里根据request请求的参数生产handle对象,通过(Handle)ConvertUtils.convert(HttpParsing.unescape((String)queryMap.get(key), enc), Handle.class);

ObjectType在这里需要被过滤

每个handle都有类型,但是这里objectType 不是null 且 handle被实例化所以这里其实是没做过滤的,我们的JNDIBindingPortlethandle的值就被存进handle了。所以这个方法中就可以在为handle结尾的key中传入任意的值。

在handle不为空的情况下进去看,

在这里取第0位的Component,” ldap://x.x.x”

出来在getBinding做了判断,当context不为空的时候,返回context + . +getBinding() 的值,而getBinding()取的是getComponent(1); 出来以后 ,name 的值就有了

来到JNDIBindingAction.execute的代码,当serverMBean不为空的时候,lookup函数可以被利用。

这里的context, biding, server连起来拼成了ldap://x.x.x.x/classname 的地址,servername则是 AdminServer。ser

ServerName 在这里就可以建立Connect,比如RMI连接

c不为空的时候,c会去查找context 拼接’.’拼接bindName,原本POC里面的 ; 在这里被替换成了点

进入上面提到的lookup函数后,有一个run方法,其中TreeNode childNode = new TreeNode(name + “Node”, name, this.contextPath + “/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=” + bindingHandle, root);

进入后在toString()方法中生成字符串做了格式转换,可以放到URL中。

将特殊符号 %做转换

得出来的treeNode 为/console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle%28%22ejb.mgmt%3BMEJB%3BAdminServer%22%29,

urldeocde完为/console/consolejndi.portal?_pageLabel=JNDIBindingPageGeneral&_nfpb=true&JNDIBindingPortlethandle=com.bea.console.handles.JndiBindingHandle(“ejb.mgmt;MEJB;AdminServer”) 将生成好的treenode加到列表里

在setComponents(String[] components)可以看到sb 的取值由context, binding,server构成,而在一系列append后,sb的取值最终变成context;binding;server的结构,也就是ldap://x.x.x;x/class;AdminServer

3.漏洞复现

 

三、参考链接

https://mp.weixin.qq.com/s/wX9TMXl1KVWwB_k6EZOklw

https://www.t00ls.net/thread-59454-1-1.html

(完)