Extensions du noyau macOS & Kernelcaches

Reading time: 11 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

Informations de base

Kernel extensions (Kexts) sont des packages avec une .kext extension qui sont chargés directement dans l'espace kernel de macOS, fournissant des fonctionnalités supplémentaires au systÚme d'exploitation principal.

Statut de dépréciation & DriverKit / System Extensions

À partir de macOS Catalina (10.15) Apple a marquĂ© la plupart des KPI hĂ©ritĂ©s comme dĂ©prĂ©ciĂ©s et a introduit les frameworks System Extensions & DriverKit qui s'exĂ©cutent en user-space. Depuis macOS Big Sur (11) le systĂšme refusera de charger des kexts tiers qui dĂ©pendent de KPI dĂ©prĂ©ciĂ©s Ă  moins que la machine ne soit dĂ©marrĂ©e en mode Reduced Security. Sur Apple Silicon, l'activation des kexts nĂ©cessite Ă©galement que l'utilisateur :

  1. RedĂ©marre en Recovery → Startup Security Utility.
  2. SĂ©lectionne Reduced Security et coche “Allow user management of kernel extensions from identified developers”.
  3. RedĂ©marre et approuve le kext depuis System Settings → Privacy & Security.

Les drivers user-land écrits avec DriverKit/System Extensions réduisent dramatiquement la surface d'attaque parce que les crashes ou corruptions mémoire sont confinés à un processus sandboxé plutÎt qu'au kernel space.

📝 Depuis macOS Sequoia (15) Apple a supprimĂ© plusieurs KPI rĂ©seau et USB hĂ©ritĂ©s – la seule solution compatible Ă  long terme pour les fournisseurs est de migrer vers System Extensions.

Exigences

Évidemment, c'est si puissant qu'il est complexe de charger une kernel extension. Voici les exigences qu'une kernel extension doit remplir pour ĂȘtre chargĂ©e :

  • Lors de l'entrĂ©e en recovery mode, les kernel extensions doivent ĂȘtre autorisĂ©es Ă  ĂȘtre chargĂ©es :
  • La kernel extension doit ĂȘtre signĂ©e avec un certificat de signature de code kernel, qui ne peut ĂȘtre accordĂ© que par Apple. Apple examinera en dĂ©tail l'entreprise et les raisons de la demande.
  • La kernel extension doit aussi ĂȘtre notarisĂ©e, Apple pourra la vĂ©rifier pour malware.
  • Ensuite, l'utilisateur root est celui qui peut charger la kernel extension et les fichiers Ă  l'intĂ©rieur du package doivent appartenir Ă  root.
  • Pendant le processus d'upload, le package doit ĂȘtre prĂ©parĂ© dans un emplacement protĂ©gĂ© non-root : /Library/StagedExtensions (requiert la permission com.apple.rootless.storage.KernelExtensionManagement).
  • Enfin, lors de la tentative de chargement, l'utilisateur receive a confirmation request et, si acceptĂ©, l'ordinateur doit ĂȘtre redĂ©marrĂ© pour la charger.

Processus de chargement

Dans Catalina c'était comme suit : Il est intéressant de noter que le processus de vérification a lieu en userland. Cependant, seules les applications disposant de la permission com.apple.private.security.kext-management peuvent demander au kernel de charger une extension : kextcache, kextload, kextutil, kextd, syspolicyd

  1. kextutil cli démarre le processus de vérification pour le chargement d'une extension
  • Il communiquera avec kextd en envoyant via un Mach service.
  1. kextd vérifiera plusieurs éléments, comme la signature
  • Il communiquera avec syspolicyd pour vĂ©rifier si l'extension peut ĂȘtre chargĂ©e.
  1. syspolicyd affichera une invite à l'utilisateur si l'extension n'a pas été précédemment chargée.
  • syspolicyd rapportera le rĂ©sultat Ă  kextd
  1. kextd pourra finalement dire au kernel de charger l'extension

Si kextd n'est pas disponible, kextutil peut effectuer les mĂȘmes vĂ©rifications.

ÉnumĂ©ration & gestion (kexts chargĂ©s)

kextstat était l'outil historique mais il est déprécié dans les récentes versions de macOS. L'interface moderne est kmutil:

bash
# List every extension currently linked in the kernel, sorted by load address
sudo kmutil showloaded --sort

# Show only third-party / auxiliary collections
sudo kmutil showloaded --collection aux

# Unload a specific bundle
sudo kmutil unload -b com.example.mykext

L'ancienne syntaxe est toujours disponible à titre de référence :

bash
# (Deprecated) Get loaded kernel extensions
kextstat

# (Deprecated) Get dependencies of the kext number 22
kextstat | grep " 22 " | cut -c2-5,50- | cut -d '(' -f1

kmutil inspect peut Ă©galement ĂȘtre utilisĂ© pour extraire le contenu d'une Kernel Collection (KC) ou vĂ©rifier qu'un kext rĂ©sout toutes les dĂ©pendances de symboles :

bash
# List fileset entries contained in the boot KC
kmutil inspect -B /System/Library/KernelCollections/BootKernelExtensions.kc --show-fileset-entries

# Check undefined symbols of a 3rd party kext before loading
kmutil libraries -p /Library/Extensions/FancyUSB.kext --undef-symbols

Kernelcache

caution

Even though the kernel extensions are expected to be in /System/Library/Extensions/, if you go to this folder you won't find any binary. This is because of the kernelcache and in order to reverse one .kext you need to find a way to obtain it.

La kernelcache est une version prĂ©compilĂ©e et prĂ©liĂ©e du kernel XNU, avec les drivers essentiels et les kernel extensions. Elle est stockĂ©e dans un format compressĂ© et est dĂ©compressĂ©e en mĂ©moire lors du dĂ©marrage. La kernelcache permet un dĂ©marrage plus rapide en fournissant une version prĂȘte Ă  l'exĂ©cution du kernel et des drivers cruciaux, rĂ©duisant le temps et les ressources qui seraient autrement nĂ©cessaires pour charger et lier dynamiquement ces composants au dĂ©marrage.

Les principaux avantages de la kernelcache sont la vitesse de chargement et le fait que tous les modules sont prĂ©liĂ©s (pas d'impact au moment du chargement). Et une fois que tous les modules ont Ă©tĂ© prĂ©liĂ©s — KXLD peut ĂȘtre retirĂ© de la mĂ©moire de sorte que XNU cannot load new KEXTs.

tip

The https://github.com/dhinakg/aeota tool decrypts Apple’s AEA (Apple Encrypted Archive / AEA asset) containers — the encrypted container format Apple uses for OTA assets and some IPSW pieces — and can produce the underlying .dmg/asset archive that you can then extract with the provided aastuff tools.

Kernelcache local

Sur iOS il se trouve dans /System/Library/Caches/com.apple.kernelcaches/kernelcache ; sur macOS vous pouvez le trouver avec : find / -name "kernelcache" 2>/dev/null
Dans mon cas sur macOS je l'ai trouvé ici :

  • /System/Volumes/Preboot/1BAEB4B5-180B-4C46-BD53-51152B7D92DA/boot/DAD35E7BC0CDA79634C20BD1BD80678DFB510B2AAD3D25C1228BB34BCD0A711529D3D571C93E29E1D0C1264750FA043F/System/Library/Caches/com.apple.kernelcaches/kernelcache

Find also here the kernelcache of version 14 with symbols.

IMG4 / BVX2 (LZFSE) compressed

Le format IMG4 est un format conteneur utilisĂ© par Apple sur ses appareils iOS et macOS pour stocker et vĂ©rifier de maniĂšre sĂ©curisĂ©e des composants de firmware (comme la kernelcache). Le format IMG4 inclut un en-tĂȘte et plusieurs tags qui encapsulent diffĂ©rentes donnĂ©es, y compris la charge utile rĂ©elle (par exemple un kernel ou un bootloader), une signature, et un ensemble de propriĂ©tĂ©s de manifeste. Le format supporte la vĂ©rification cryptographique, permettant Ă  l'appareil de confirmer l'authenticitĂ© et l'intĂ©gritĂ© du composant de firmware avant de l'exĂ©cuter.

Il est généralement composé des éléments suivants :

  • Payload (IM4P) :
  • Souvent compressĂ© (LZFSE4, LZSS, 
)
  • Optionnellement chiffrĂ©
  • Manifest (IM4M) :
  • Contient la Signature
  • Dictionnaire supplĂ©mentaire de clĂ©s/valeurs
  • Restore Info (IM4R) :
  • Aussi connu sous le nom d'APNonce
  • EmpĂȘche la rĂ©utilisation de certaines mises Ă  jour
  • OPTIONAL: Usually this isn't found

Décompresser la kernelcache :

bash
# img4tool (https://github.com/tihmstar/img4tool)
img4tool -e kernelcache.release.iphone14 -o kernelcache.release.iphone14.e

# pyimg4 (https://github.com/m1stadev/PyIMG4)
pyimg4 im4p extract -i kernelcache.release.iphone14 -o kernelcache.release.iphone14.e

# imjtool (https://newandroidbook.com/tools/imjtool.html)
imjtool _img_name_ [extract]

# disarm (you can use it directly on the IMG4 file) - [https://newandroidbook.com/tools/disarm.html](https://newandroidbook.com/tools/disarm.html)
disarm -L kernelcache.release.v57 # From unzip ipsw

# disamer (extract specific parts, e.g. filesets) - [https://newandroidbook.com/tools/disarm.html](https://newandroidbook.com/tools/disarm.html)
disarm -e filesets kernelcache.release.d23

Disarm symboles du kernel

Disarm permet de symbolicate des fonctions du kernelcache en utilisant des matchers. Ces matchers sont juste des rÚgles de motifs simples (lignes de texte) qui indiquent à disarm comment reconnaßtre & auto-symbolicate les fonctions, les arguments et les panic/log strings à l'intérieur d'un binary.

En gros, vous indiquez la chaĂźne qu'utilise une fonction et disarm la trouvera et symbolicate it.

bash
You can find some `xnu.matchers` in [https://newosxbook.com/tools/disarm.html](https://newosxbook.com/tools/disarm.html) in the **`Matchers`** section. You can also create your own matchers.

Aller dans /tmp/extracted oĂč disarm a extrait les filesets

disarm -e filesets kernelcache.release.d23 # Always extract to /tmp/extracted cd /tmp/extracted JMATCHERS=xnu.matchers disarm --analyze kernel.rebuilt # Note that xnu.matchers is actually a file with the matchers


### Download

An **IPSW (iPhone/iPad Software)** is Apple’s firmware package format used for device restores, updates, and full firmware bundles. Among other things, it contains the **kernelcache**.

- [**KernelDebugKit Github**](https://github.com/dortania/KdkSupportPkg/releases)

In [https://github.com/dortania/KdkSupportPkg/releases](https://github.com/dortania/KdkSupportPkg/releases) it's possible to find all the kernel debug kits. You can download it, mount it, open it with [Suspicious Package](https://www.mothersruin.com/software/SuspiciousPackage/get.html) tool, access the **`.kext`** folder and **extract it**.

Check it for symbols with:

nm -a ~/Downloads/Sandbox.kext/Contents/MacOS/Sandbox | wc -l


- [**theapplewiki.com**](https://theapplewiki.com/wiki/Firmware/Mac/14.x)**,** [**ipsw.me**](https://ipsw.me/)**,** [**theiphonewiki.com**](https://www.theiphonewiki.com/)

Sometime Apple releases **kernelcache** with **symbols**. You can download some firmwares with symbols by following links on those pages. The firmwares will contain the **kernelcache** among other files.

To **extract** the kernel cache you can do:

Installer l'outil ipsw

brew install blacktop/tap/ipsw

Extraire uniquement le kernelcache depuis l'IPSW

ipsw extract --kernel /path/to/YourFirmware.ipsw -o out/

Vous devriez obtenir quelque chose comme:

out/Firmware/kernelcache.release.iPhoneXX

ou un payload IMG4: out/Firmware/kernelcache.release.iPhoneXX.im4p

Si vous obtenez un payload IMG4:

ipsw img4 im4p extract out/Firmware/kernelcache*.im4p -o kcache.raw


Another option to **extract** the files start by changing the extension from `.ipsw` to `.zip` and **unzip** it.

After extracting the firmware you will get a file like: **`kernelcache.release.iphone14`**. It's in **IMG4** format, you can extract the interesting info with:

[**pyimg4**](https://github.com/m1stadev/PyIMG4)**:**

pyimg4 im4p extract -i kernelcache.release.iphone14 -o kernelcache.release.iphone14.e


[**img4tool**](https://github.com/tihmstar/img4tool)**:**

img4tool -e kernelcache.release.iphone14 -o kernelcache.release.iphone14.e


pyimg4 im4p extract -i kernelcache.release.iphone14 -o kernelcache.release.iphone14.e


[**img4tool**](https://github.com/tihmstar/img4tool)**:**

img4tool -e kernelcache.release.iphone14 -o kernelcache.release.iphone14.e


### Inspecting kernelcache

Check if the kernelcache has symbols with

nm -a kernelcache.release.iphone14.e | wc -l


With this we can now **extract all the extensions** or the **one you are interested in:**

Lister toutes les extensions

kextex -l kernelcache.release.iphone14.e

Extraire com.apple.security.sandbox

kextex -e com.apple.security.sandbox kernelcache.release.iphone14.e

Extraire tout

kextex_all kernelcache.release.iphone14.e

Vérifier l'extension pour les symboles

nm -a binaries/com.apple.security.sandbox | wc -l



## Recent vulnerabilities & exploitation techniques

| Year | CVE | Summary |
|------|-----|---------|
| 2024 | **CVE-2024-44243** | Logic flaw in **`storagekitd`** allowed a *root* attacker to register a malicious file-system bundle that ultimately loaded an **unsigned kext**, **bypassing System Integrity Protection (SIP)** and enabling persistent rootkits. Patched in macOS 14.2 / 15.2.   |
| 2021 | **CVE-2021-30892** (*Shrootless*) | Installation daemon with the entitlement `com.apple.rootless.install` could be abused to execute arbitrary post-install scripts, disable SIP and load arbitrary kexts.  |

**Take-aways for red-teamers**

1. **Look for entitled daemons (`codesign -dvv /path/bin | grep entitlements`) that interact with Disk Arbitration, Installer or Kext Management.**
2. **Abusing SIP bypasses almost always grants the ability to load a kext → kernel code execution**.

**Defensive tips**

*Keep SIP enabled*, monitor for `kmutil load`/`kmutil create -n aux` invocations coming from non-Apple binaries and alert on any write to `/Library/Extensions`. Endpoint Security events `ES_EVENT_TYPE_NOTIFY_KEXTLOAD` provide near real-time visibility.

## Debugging macOS kernel & kexts

Apple’s recommended workflow is to build a **Kernel Debug Kit (KDK)** that matches the running build and then attach **LLDB** over a **KDP (Kernel Debugging Protocol)** network session.

### One-shot local debug of a panic

Créer un bundle de symbolication pour le dernier kernel panic

sudo kdpwrit dump latest.kcdata kmutil analyze-panic latest.kcdata -o ~/panic_report.txt


### Live remote debugging from another Mac

1. Download + install the exact **KDK** version for the target machine.
2. Connect the target Mac and the host Mac with a **USB-C or Thunderbolt cable**.
3. On the **target**:

sudo nvram boot-args="debug=0x100 kdp_match_name=macbook-target" reboot


4. On the **host**:

lldb (lldb) kdp-remote "udp://macbook-target" (lldb) bt # obtenir backtrace dans le contexte du kernel


### Attaching LLDB to a specific loaded kext

Identifier l'adresse de chargement du kext

ADDR=$(kmutil showloaded --bundle-identifier com.example.driver | awk '{print $4}')

Attacher

sudo lldb -n kernel_task -o "target modules load --file /Library/Extensions/Example.kext/Contents/MacOS/Example --slide $ADDR"