作者:且听安全
原文链接:https://mp.weixin.qq.com/s/nCMtSD7QH8ai6fpurJBXTg
漏洞信息
最近 Confluence 官方通报了一个严重漏洞 CVE-2022-26134 :
从漏洞描述来看,这仍然是一个 OGNL 表达式注入漏洞。影响版本如下:
- from 1.3.0 before 7.4.17
- from 7.13.0 before 7.13.7
- from 7.14.0 before 7.14.3
- from 7.15.0 before 7.15.2
- from 7.16.0 before 7.16.4
- from 7.17.0 before 7.17.4,
- from 7.18.0 before 7.18.1
补丁描述:
主要是修改了 xwork-1.0.3-atlassian-10.jar
。下面将深入分析漏洞原理,并尝试绕过沙箱构造命令执行结果回显。
漏洞分析
新版本主要是修改了 xwork-1.0.3-atlassian-10.jar
。首先简单进行一下补丁对比:
改动的地方很多,但是最关键的地方位于 ActionChainResult#execute
函数,对提取 finalNamespace
和 finalActionName
的过程进行了更新。
Confluence 基于 Struts 架构进行开发。我们首先以登录请求为例,对 Confluence 请求处理的流程进行动态调试。访问 /login.action
,经过一系列 Filter
处理后,将进入Servlet 的分发器 ServletDispatcher
(本质上是其子类 ConfluenceServletDispatcher
对象):
分别通过函数 getNameSpace
、 getActionName
、 getRequestMap
、 getSessionMap
、 getApplicationMap
提取相应参数,对应关系如下:
getNameSpace(request)
->namespace
getActionName(request)
->actionName
getRequestMap(request)
->requestMap
getParameterMap(request)
->parameterMap
getSessionMap(request)
->sessionMap
getApplicationMap()
->applicationMap
然后调用 serviceAction
函数,进入子类 ConfluenceServletDispatcher
的 serviceAction
函数:
实例化 DefaultActionProxy
对象,调用其 execute
函数:
进入 DefaultActionInvocation#invoke
:
这里开始调用 Struts Interceptor 拦截器对象对请求进行处理, DefaultActionInvocation
对象拦截器集合 interceptors
一共有 32 个:
函数 invoke
尝试通过 next
获取下一个拦截器对象,然后调用其 intercept
方法,大部分 Interceptor
对象的 intercept
函数格式如下所示:
继续调用 DefaultActionInvocation#invoke
,从而形成迭代循环。但是在调试中我们发现也有特殊的一些 Interceptor
,比如 ConfluenceAccessInterceptor
:
当满足一定条件时并不会继续调用 DefaultActionInvocation#invoke
,而是返回字符串 notpermitted
,我们分析一下 isAccessPermitted
函数:
主要是通过请求的 *.action
和 methdName
,来判断当前用户 currentUser
是否有访问权限。也就是说,当访问一个无权访问的 *.action
时,DefaultActionInvocation#invoke
在迭代调用到 ConfluenceAccessInterceptor#intercept
后,将返回 notpermitted
并赋值给 resultCode
,从而跳出迭代。我们替换测试请求为 /index.action
:
当处理到 ConfluenceAccessInterceptor
拦截器时,将不会继续迭代调用下一个拦截器,而是继续往下走,进入 executeResult
函数:
进入 ActionChainResult#execute
:
提取 namespace
参数,并调用 translateVariables
函数,进入:
典型的 OGNL 表达式解析过程,前面分析中可知, namespace
参数通过 ServletDispatcher#getNameSpace
函数获取,查看定义:
可见 namespace
取值为请求 servletPath
最后一个 /
之前的部分。
根据上面正则表达式规则,要想触发 OGNL 解析,我们很容易构造出相应的 URL :
成功触发 OGNL 表达式注入。
沙箱绕过与命令执行
网上现在已经公开的一些利用方式简单粗暴,只能针对 v7.14 及以下系列有效,因为从 v7.15 系列开始,Confluence 在 OGNL 表达式解析时加入了沙箱设置:
进入 isSafeExpression
函数:
主要的黑名单如下:
(1) unsafePropertyNames
(2) unsafePackageNames
(3) unsafeMethodNames
0 = "getClass"
1 = "getClassLoader"
白名单 allowedClassNames
如下:
此外,对成员函数等也进行了检查( containsUnsafeExpression
函数 ):
小伙伴看到这里,应该很容易想到多种绕过的方法,感兴趣的小伙伴可以进入漏洞空间站进行交流。其中一种实现命令执行结果回显的方式如下(适用全部受影响的版本):
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1912/