542 words
3 minutes
CVE-2023-22518 Critical Privilege Escalation Vulnerability in Atlassian's Confluence

Vulnerability Overview#

Confluence contains an authorization validation flaw. An attacker can send crafted requests to gain server privileges and potentially achieve remote command execution.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!!!! WARNING: Testing this vulnerability may cause irreversible data loss. !!!! !!!! Please only test in a dedicated lab environment. !!!!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Analysis#

As with the previous Confluence issues, I started by diffing the patches:

There are many changes, but one eye-catching pattern is that many class files gained two new annotations, which look like permission-related hardening:

image-20231031183544278

So what is websudo?

WebSudo is a security feature in Atlassian Confluence. Its purpose is to ensure that users re-validate their credentials before performing sensitive operations, improving overall security.
When a logged-in user tries to perform an action with significant impact (e.g., changing system settings, installing plugins), Confluence asks the user to re-enter their password to confirm identity. This re-confirmation mechanism is called WebSudo.
It’s called WebSudo because it’s similar to sudo.

This suggests the core issue is around authorization. According to the Chaitin advisory, Confluence misused Struts namespace inheritance, leading to partial authorization bypass, and exploitation can cause data loss.

While diffing I initially followed a wrong path: I thought about abusing bootstrap to switch Confluence to an attacker-controlled database (I didn’t fully understand what bootstrap does at the time). But that wouldn’t explain irreversible data loss; the advisory sounds more like “overwriting” something:

image-20231102142344827

Since we’re talking about permissions, here’s relevant Struts background:

https://struts.apache.org/core-developers/namespace-configuration

image-20231101024742977

In practice, Confluence doesn’t only check default; it recursively walks the inherited namespace chain until default. So we look for a namespace that inherits from admin. In struts.xml, there is this:

image-20231102135950080

This indicates the json namespace can resolve to admin, which matches the advisory’s “misused inheritance leading to partial auth bypass.”

Next, we need to find a privileged feature that can “break data.” I didn’t want to read all the official docs, so… thanks to AI:

Backup/restore is a good candidate:

image-20231102143651277

After a few create/restore tests, it’s clear that restore can reset the admin password (it’s a backup, after all).

Create a backup and download it. Then search for restore-related actions. After some trial and error, I located an action:

image-20231102143924658

Try accessing it via the json namespace. You get some interesting output (note: use POST):

image-20231102144319982

It lists many backup files I created. But there is a pitfall: when I tried uploading a crafted archive, the response looked like this:

image-20231102144656162

Strange: I created a site backup, but it says I’m trying to restore a space. After several failed attempts, I went back to the code and searched for the error message:

image-20231102144818992

Setting a breakpoint in SetupRestoreAction.class, you can see the root cause: validate() checks whether exportScope equals ALL, but the UI-created backup uses SITE — and there is no ALL package from the UI!

image-20231102152808970

(At this point, changing it to ALL might already work.)

But I wanted to understand where ALL is supposed to come from. Looking at Confluence backup UI, there are only two options:

image-20231102154048341

image-20231102154111144

So we need another endpoint:

image-20231102161124328

When logged in, visiting json/backup.action generates a chunked backup that includes the ALL label. Craft the archive again:

image-20231102161312582

You can see the redirect matches what struts.xml defines. Note the synchronous=true setting: after sending the request, wait a moment and Confluence will import the backup. The existing admin credentials will be overwritten by the backup contents.

RCE#

RCE can be achieved by chaining with historical issues; it’s a common pattern, so I won’t repeat it here.

CVE-2023-22518 Critical Privilege Escalation Vulnerability in Atlassian's Confluence
https://springkill.github.io/en/posts/cve-2023-22518-critical-privilege-escalation-vulnerability-in-atlassian-s-confluence/
Author
SpringKill
Published at
2023-11-07
License
CC BY-NC-SA 4.0