macOS Dirty NIB

Reading time: 9 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Dirty NIB refers to abusing Interface Builder files (.xib/.nib) inside a signed macOS app bundle to execute attacker-controlled logic inside the target process, thereby inheriting its entitlements and TCC permissions. This technique was originally documented by xpn (MDSec) and later generalized and significantly expanded by Sector7, who also covered Apple’s mitigations in macOS 13 Ventura and macOS 14 Sonoma. For background and deep dives, see the references at the end.

TL;DR ‱ Before macOS 13 Ventura: replacing a bundle’s MainMenu.nib (or another nib loaded at startup) could reliably achieve process injection and often privilege escalation. ‱ Since macOS 13 (Ventura) and improved in macOS 14 (Sonoma): first‑launch deep verification, bundle protection, Launch Constraints, and the new TCC “App Management” permission largely prevent post‑launch nib tampering by unrelated apps. Attacks may still be feasible in niche cases (e.g., same‑developer tooling modifying own apps, or terminals granted App Management/Full Disk Access by the user).

Que sont les fichiers NIB/XIB

Les fichiers Nib (abrĂ©viation de NeXT Interface Builder) sont des graphes d'objets d'interface utilisateur sĂ©rialisĂ©s utilisĂ©s par les apps AppKit. Les versions rĂ©centes de Xcode stockent des .xib XML Ă©ditables qui sont compilĂ©s en .nib lors de la compilation. Une app typique charge son interface principale via NSApplicationMain() qui lit la clĂ© NSMainNibFile dans l’Info.plist de l’app et instancie le graphe d'objets Ă  l'exĂ©cution.

Points clés qui permettent l'attaque :

  • Le chargement d'un NIB instancie des classes Objective‑C arbitraires sans exiger qu'elles implĂ©mentent NSSecureCoding (le chargeur de nib d'Apple retombe sur init/initWithFrame: lorsque initWithCoder: n'est pas disponible).
  • Les Cocoa Bindings peuvent ĂȘtre abusĂ©es pour appeler des mĂ©thodes lors de l'instanciation des nibs, y compris des appels chaĂźnĂ©s ne nĂ©cessitant aucune interaction de l'utilisateur.

Processus d'injection Dirty NIB (point de vue de l'attaquant)

Le flux classique avant Ventura :

  1. Créer un .xib malveillant
  • Ajouter un objet NSAppleScript (ou d'autres classes "gadget" comme NSTask).
  • Ajouter un NSTextField dont le title contient le payload (par ex., AppleScript ou des arguments de commande).
  • Ajouter un ou plusieurs objets NSMenuItem cĂąblĂ©s via bindings pour appeler des mĂ©thodes sur l'objet cible.
  1. Déclenchement automatique sans clics de l'utilisateur
  • Utiliser les bindings pour dĂ©finir le target/selector d'un menu et ensuite invoquer la mĂ©thode privĂ©e _corePerformAction afin que l'action se dĂ©clenche automatiquement lors du chargement du nib. Cela supprime le besoin pour un utilisateur de cliquer sur un bouton.

Exemple minimal d'une chaßne de déclenchement automatique à l'intérieur d'un .xib (abrégée pour plus de clarté):

xml
<objects>
<customObject id="A1" customClass="NSAppleScript"/>
<textField id="A2" title="display dialog \"PWND\""/>
<!-- Menu item that will call -initWithSource: on NSAppleScript with A2.title -->
<menuItem id="C1">
<connections>
<binding name="target" destination="A1"/>
<binding name="selector" keyPath="initWithSource:"/>
<binding name="Argument" destination="A2" keyPath="title"/>
</connections>
</menuItem>
<!-- Menu item that will call -executeAndReturnError: on NSAppleScript -->
<menuItem id="C2">
<connections>
<binding name="target" destination="A1"/>
<binding name="selector" keyPath="executeAndReturnError:"/>
</connections>
</menuItem>
<!-- Triggers that auto‑press the above menu items at load time -->
<menuItem id="T1"><connections><binding keyPath="_corePerformAction" destination="C1"/></connections></menuItem>
<menuItem id="T2"><connections><binding keyPath="_corePerformAction" destination="C2"/></connections></menuItem>
</objects>

Ceci permet l'exécution arbitraire d'AppleScript dans le processus cible lors du chargement du nib. Des chaßnes avancées peuvent :

  • Instancier des classes AppKit arbitraires (par ex., NSTask) et appeler des mĂ©thodes sans argument comme -launch.
  • Appeler des selectors arbitraires avec des arguments objet via l'astuce de binding ci‑dessus.
  • Charger AppleScriptObjC.framework pour effectuer un pont vers Objective‑C et mĂȘme appeler certaines APIs C sĂ©lectionnĂ©es.
  • Sur les systĂšmes plus anciens qui incluent encore Python.framework, effectuer un pont vers Python puis utiliser ctypes pour appeler des fonctions C arbitraires (recherche de Sector7).
  1. Remplacer le nib de l’application
  • Copier target.app dans un emplacement accessible en Ă©criture, remplacer, par ex., Contents/Resources/MainMenu.nib par le nib malveillant, et lancer target.app. Avant Ventura, aprĂšs une Ă©valuation Gatekeeper unique, les lancements suivants n'effectuaient que des vĂ©rifications de signature superficielles, donc les ressources non exĂ©cutables (comme .nib) n'Ă©taient pas revĂ©rifiĂ©es.

Exemple de payload AppleScript pour un test visible :

applescript
set theDialogText to "PWND"
display dialog theDialogText

Protections modernes de macOS (Ventura/Monterey/Sonoma/Sequoia)

Apple a introduit plusieurs mitigations systémiques qui réduisent drastiquement la viabilité de Dirty NIB sur les versions récentes de macOS:

  • VĂ©rification approfondie au premier lancement et protection du bundle (macOS 13 Ventura)
  • Au premier lancement de n’importe quelle app (quarantinĂ©e ou non), une vĂ©rification de signature approfondie couvre toutes les ressources du bundle. Ensuite, le bundle devient protĂ©gĂ© : seules les apps du mĂȘme dĂ©veloppeur (ou explicitement autorisĂ©es par l’app) peuvent modifier son contenu. Les autres apps requiĂšrent la nouvelle permission TCC “App Management” pour Ă©crire dans le bundle d’une autre app.
  • Launch Constraints (macOS 13 Ventura)
  • Les apps fournies par Apple ou le systĂšme ne peuvent pas ĂȘtre copiĂ©es ailleurs puis lancĂ©es ; cela rend impossible l’approche “copy to /tmp, patch, run” pour les apps systĂšme.
  • AmĂ©liorations dans macOS 14 Sonoma
  • Apple a durci App Management et corrigĂ© des contournements connus (p. ex. CVE‑2023‑40450) signalĂ©s par Sector7. Python.framework a Ă©tĂ© retirĂ© plus tĂŽt (macOS 12.3), rompant certaines chaĂźnes d’escalade de privilĂšges.
  • Modifications de Gatekeeper/Quarantine
  • Pour une discussion plus complĂšte des changements de Gatekeeper, de la provenance et de l’évaluation qui ont impactĂ© cette technique, voir la page rĂ©fĂ©rencĂ©e ci‑dessous.

Implication pratique ‱ Sur Ventura+ vous ne pouvez gĂ©nĂ©ralement pas modifier le .nib d’une app tierce Ă  moins que votre processus n’ait App Management ou ne soit signĂ© par le mĂȘme Team ID que la cible (p.ex., outils de dĂ©veloppement). ‱ Accorder App Management ou Full Disk Access Ă  des shells/terminaux rouvre effectivement cette surface d’attaque pour tout ce qui peut exĂ©cuter du code dans le contexte de ce terminal.

Gérer les Launch Constraints

Les Launch Constraints empĂȘchent l’exĂ©cution de nombreuses apps Apple depuis des emplacements non par dĂ©faut Ă  partir de Ventura. Si vous dĂ©pendiez de workflows pré‑Ventura comme copier une app Apple dans un rĂ©pertoire temporaire, modifier MainMenu.nib, puis la lancer, attendez‑vous Ă  ce que cela Ă©choue sur >= 13.0.

ÉnumĂ©ration des cibles et des nibs (utile pour la recherche / systĂšmes hĂ©ritĂ©s)

  • Localiser les apps dont l’UI est basĂ©e sur des .nib :
bash
find /Applications -maxdepth 2 -name Info.plist -exec sh -c \
'for p; do if /usr/libexec/PlistBuddy -c "Print :NSMainNibFile" "$p" >/dev/null 2>&1; \
then echo "[+] $(dirname "$p") uses NSMainNibFile=$( /usr/libexec/PlistBuddy -c "Print :NSMainNibFile" "$p" )"; fi; done' sh {} +
  • Trouver des ressources nib candidates Ă  l'intĂ©rieur d'un bundle:
bash
find target.app -type f \( -name "*.nib" -o -name "*.xib" \) -print
  • Valider en profondeur les code signatures (Ă©chouera si vous avez modifiĂ© les ressources et n'avez pas re-signĂ©) :
bash
codesign --verify --deep --strict --verbose=4 target.app

Remarque : Sur les versions modernes de macOS vous serez également bloqué par bundle protection/TCC lorsque vous tenterez d'écrire dans le bundle d'une autre app sans autorisation appropriée.

Détection et conseils DFIR

  • Surveillance de l'intĂ©gritĂ© des fichiers sur les ressources de bundle
  • Surveillez les changements de mtime/ctime de Contents/Resources/*.nib et d'autres ressources non‑exĂ©cutables dans les apps installĂ©es.
  • Journaux unifiĂ©s et comportement des processus
  • Surveillez l'exĂ©cution AppleScript inattendue Ă  l'intĂ©rieur des apps GUI et les processus chargeant AppleScriptObjC ou Python.framework. Exemple :
bash
log stream --info --predicate 'processImagePath CONTAINS[cd] ".app/Contents/MacOS/" AND (eventMessage CONTAINS[cd] "AppleScript" OR eventMessage CONTAINS[cd] "loadAppleScriptObjectiveCScripts")'
  • Analyses proactives
  • ExĂ©cutez pĂ©riodiquement codesign --verify --deep sur les apps critiques pour vous assurer que les ressources restent intactes.
  • Contexte de privilĂšges
  • Auditez qui/quoi a TCC “App Management” ou Full Disk Access (en particulier les terminaux et agents de gestion). Retirer ces droits des shells Ă  usage gĂ©nĂ©ral empĂȘche de rĂ©activer trivialement les altĂ©rations de type Dirty NIB.

Renforcement défensif (développeurs et défenseurs)

  • PrivilĂ©giez une UI programmatique ou limitez ce qui est instanciĂ© depuis des nibs. Évitez d'inclure des classes puissantes (par ex., NSTask) dans les graphes de nib et Ă©vitez les bindings qui invoquent indirectement des selectors sur des objets arbitraires.
  • Adoptez le hardened runtime avec Library Validation (dĂ©jĂ  standard pour les apps modernes). Bien que cela n'empĂȘche pas Ă  lui seul l'injection via nib, cela bloque le chargement facile de code natif et force les attaquants Ă  des payloads uniquement scripting.
  • Ne demandez pas et ne dĂ©pendez pas de permissions larges App Management dans les outils Ă  usage gĂ©nĂ©ral. Si MDM nĂ©cessite App Management, isolez ce contexte des shells pilotĂ©s par l'utilisateur.
  • VĂ©rifiez rĂ©guliĂšrement l'intĂ©gritĂ© du bundle de votre app et faites en sorte que vos mĂ©canismes de mise Ă  jour autorĂ©parent les ressources du bundle.

Learn more about Gatekeeper, quarantine and provenance changes that affect this technique:

macOS Gatekeeper / Quarantine / XProtect

References

  • xpn – DirtyNIB (article original avec exemple Pages) : https://blog.xpnsec.com/dirtynib/
  • Sector7 – Bringing process injection into view(s): exploiting all macOS apps using nib files (April 5, 2024) : https://sector7.computest.nl/post/2024-04-bringing-process-injection-into-view-exploiting-all-macos-apps-using-nib-files/

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks