CVE-2023-22515-Confluence访问控制漏洞-任意管理员创建
2023-11-07 / 共计4065 字
CVE-2023-22515-Confluence访问控制漏洞-任意管理员创建
夏季的遗憾终会在冬季圆满。
The regrets of summer will eventually be fulfilled in winter.
2023年10月4日,Confluence发布了一个“CVE-2023-22515 - Confluence 数据中心和服务器中的访问控制漏洞”的漏洞通告。刚出来的时候就了解了一下,但没有时间去对其做详细分析。漏洞出来都一个月了,这几天见缝插个针,强行抽出点时间,分析分析是怎么个回事,并写写任意管理员注册的EXP:
最终效果:
漏洞分析
先去atlassian官方下载Confluence源码,我这里使用的是Confluence8.4.2和Confluence8.4.3。
Confluence源码主要在/atlassian-confluence-8.4.2/confluence/WEB-INF/lib/com.atlassian.confluence_confluence-8.4.2.jar中,先查看一下8.4.2和8.4.3 jar更新情况,看看修改了哪些内容:
可以看到在更新中struts.xml中新增了struts.override.acceptedPatterns,并删除了server-info.action
新加了ReadOnlyApplicationConfig.class和ReadOnlySetupPersister,并且BootstrapStatusProviderlmpl.class中getApplicationConfig和getSetupPersister改成了ReadOnly
在ReadOnly中对seter与大部分方法进行了抛出异常处理UnsupportedOperationException(“Mutation not allowed”),看到这里,可以了解到Confluence是基于Struts2的,其实如果对Struts相关历史漏洞有所了解的话,那么该漏洞可能出现的位置可以猜个大概了:(之后去了解了一下,发现到这就可以猜个大概了) 根据官方给出的检测方法,可知最后是通过/setup/setupadministrator.action添加管理员用户:
那么先在strtus拦截器配置中找到/setup/setupadministrator.action所对应的拦截方法看看(/setup下存在默认拦截器validatingSetupStack):
在package:setup下找到setupadministrator.action,对应方法SetupAdministrator: 在/setup的默认拦截器validatingSetupStack下是setupStack,setupStack下又是setup拦截器
找到setup拦截器对应的com.atlassian.confluence.setup.actions.SetupCheckInterceptor,从名称猜测该Interceptor多半是/setup下检查是否已经setup:
跟进SetupCheckInterceptor看看,可以看到如果BootstrapUtils.getBootstrapManager().isSetupComplete() 和ContainerManager.isContainerSetup()都为true则表示已经完成setup了,那么就无法进入setupadministrator.action方法: 跟进isSetupComplete,其中会调用到applicationConfig.isSetupComplete(),而在更新对比中,getApplicationConfig()和这里的applicationConfig都是ApplicationConfiguration类,那么既然BootstrapStatusProviderlmpl可以获取ApplicationConfiguration类,那么只要将其中的setupComplete修改为false,那么就多半就可以绕过这里的isSetupComplete检测:
有了思路,那么现在就需要找一个有的地方有BootstrapStatusProviderlmpl,并设置setComplete为false从而打通利用链。结合Strtus2的Interceptor和confluence的interceptor,发现confluence存在一个<default-interceptor-ref>(strtus2并不是很了解,去su18那学习了一下,感兴趣的也可以看看):
defaultStack中的拦截器如下,这里主要关注params:
params对应方法com.atlassian.xwork.interceptors.SafeParametersInterceptor:
通过简单的调试,走了SafeParametersInterceptor下的doIntercept():
可以看到在before中有使用OGNL表达式,那么这里是不是可以通过OGNL表达式从而设置setupComplete=false:(实际上这里是不行的)
经过调试发现parameters在这里被过滤了:
在刚进入filterSafeParameters时确实获取了参数,但是经过isSafeParameterName时给过滤掉了:
isSafeParameterName代码如下:
其中过滤了actionErrors,actionMessages,还进行了EXCLUDE_CLASS_PATTERN,SAFE_PARAMETER_NAME_PATTERN,MAP_PARAMETER_PATTERN三个正则表达式的匹配,最后还调用了isSafeComplexParameterName:
可以看到isSafeComplexParameterName对参数进行了分隔,还进行了白名单限制,通过这一系列严格的过滤,这里的OGNL基本上的行不通了:
但是,还记得doIntercept中还调用了父类的doInercept吗:
public class SafeParametersInterceptor extends ParametersInterceptor{}
SafeParametersInterceptor继承于ParametersInterceptor,super.doIntercept()执行的是ParametersIntercepto下r的doInercept(),代码如下:
在进入setParameters中时参数并没有进行过滤,还是aaa.aa.aa=b:
在setParameters中的newStack.setParameter(name, value.getObject());
同样是使用的OGNL,可以看到aaa.aa.a=b在进入前没有被过滤掉,这里重新进行了参数获取,导致SafeParametersInterceptor中的before的过滤失效了,那么这里不就可以使用OGNL表达式进行漏洞利用了吗:
到这里一切都明朗了,这下只要找到一个action对应的类中存在或继承了BootstrapStatusProviderlmpl或获取了BootstrapStatusProviderlmpl,那么就可以完成利用了。既然在开头看到更新中删除了server-info.action,那么就先看看它吧,server-info对应com.atlassian.confluence.core.actions.ServerInfoAction方法:
查看ServerInfoAction中并没有我们需要的set方法,但是它继承了ConfluenceActionSupport,父类中若是存在也是可以利用的:
经过查看ConfluenceActionSupport中有个getBootstrapStatusProvider方法,就获取到了BootstrapStatusProviderImpl类:
在BootstrapStatusProviderImpl类的getApplicationConfig方法,即为漏洞修复的地方(ApplicationConfig类是ApplicationConfiguration的实现):
并且在ApplicationConfig中可以看到setSetupComplete方法,修改了setupComplete的值。到这里我们直接使用OGNL表达式修改bootstrapStatusProvider.applicationConfig.setupComplete的值为false就可以绕过SetupCheckInterceptor中的isSetupComplete() 校验,从而完成利用:
漏洞利用
至此,使用OGNL表达式,我们已经可以写出poc了:
/server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false
在没有使用poc前访问/setup/setupadministrator.action则是显示Setup is already complete:
访问/server-info.action?bootstrapStatusProvider.applicationConfig.setSetupComplete=false
:
再次访问/setup/setupadministrator.action,则不再是Setup is already complete(这里的Method Not Allowed只是setupadministrator.action不允许GET方法,使用POST即可创建管理员账号了):
最终的任意管理员注册的EXP已放Github。
文笔垃圾,技术欠缺,欢迎各位大师傅请斧正,非常感谢!
如果文章对您有帮助
欢迎关注公众号!
感谢您的支持!