macOS Kernel Extensions & Kernelcaches
Reading time: 10 minutes
tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Podstawowe informacje
Kernel extensions (Kexts) to pakiety z rozszerzeniem .kext, które są ładowane bezpośrednio do przestrzeni jądra macOS, dostarczając dodatkową funkcjonalność dla głównego systemu operacyjnego.
Status wycofania & DriverKit / System Extensions
Począwszy od macOS Catalina (10.15) Apple oznaczyło większość starych KPI jako deprecated i wprowadziło frameworki System Extensions & DriverKit, które działają w user-space. Od macOS Big Sur (11) system operacyjny będzie odmawiać ładowania third-party kextów korzystających ze zdeprecjonowanych KPI, chyba że maszyna zostanie uruchomiona w trybie Reduced Security. Na Apple Silicon włączenie kextów dodatkowo wymaga od użytkownika:
- Reboot do Recovery → Startup Security Utility.
- Wybrania Reduced Security i zaznaczenia “Allow user management of kernel extensions from identified developers”.
- Restartu i zatwierdzenia kexta w System Settings → Privacy & Security.
Sterowniki user-land napisane przy użyciu DriverKit/System Extensions znacząco zmniejszają powierzchnię ataku, ponieważ awarie lub uszkodzenia pamięci są ograniczone do sandboxowanego procesu zamiast przestrzeni jądra.
📝 From macOS Sequoia (15) Apple has removed several legacy networking and USB KPIs entirely – the only forward-compatible solution for vendors is to migrate to System Extensions.
Wymagania
Oczywiście, to jest tak potężne, że załadowanie kernel extension jest skomplikowane. Oto wymagania, które rozszerzenie jądra musi spełnić, żeby mogło zostać załadowane:
- When entering recovery mode, kernel extensions must be allowed to be loaded:
.png)
- Rozszerzenie jądra musi być podpisane certyfikatem podpisu kodu jądra, który może być wydany tylko przez Apple. Apple dokładnie sprawdzi firmę i powody, dla których jest to potrzebne.
- Rozszerzenie musi być także notarizowane; Apple będzie mogło je sprawdzić pod kątem malware.
- Następnie, użytkownik root jest tym, który może załadować rozszerzenie jądra, a pliki wewnątrz pakietu muszą należeć do root.
- Podczas procesu uploadu, pakiet musi być przygotowany w chronionej lokalizacji niebędącej rootem:
/Library/StagedExtensions(wymaga nadania uprawnieniacom.apple.rootless.storage.KernelExtensionManagement). - W końcu, przy próbie załadowania, użytkownik receive a confirmation request i, jeśli zaakceptuje, komputer musi zostać zrestartowany, aby go załadować.
Proces ładowania
W Catalina wyglądało to tak: Warto zauważyć, że proces weryfikacji odbywa się w userland. Jednak tylko aplikacje z nadanym uprawnieniem com.apple.private.security.kext-management mogą zażądać od jądra załadowania rozszerzenia: kextcache, kextload, kextutil, kextd, syspolicyd
kextutilcli uruchamia proces weryfikacji przed załadowaniem rozszerzenia
- Będzie komunikować się z
kextdwysyłając za pomocą Mach service.
kextdsprawdzi kilka rzeczy, takich jak signature
- Będzie komunikować się z
syspolicyd, aby sprawdzić, czy rozszerzenie może zostać załadowane.
syspolicydpoprosi użytkownika o potwierdzenie, jeśli rozszerzenie nie było wcześniej załadowane.
syspolicydprzekaże wynik dokextd
kextdw końcu będzie mógł polecić jądru załadowanie rozszerzenia
Jeśli kextd nie jest dostępne, kextutil może wykonać te same kontrole.
Enumeracja & zarządzanie (załadowane kexts)
kextstat był historycznym narzędziem, ale jest przestarzały w nowszych wydaniach macOS. Nowoczesnym interfejsem jest kmutil:
# 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
Starsza składnia jest nadal dostępna jako odniesienie:
# (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 może być również wykorzystany do zrzucenia zawartości Kernel Collection (KC) lub weryfikacji, że kext rozwiązuje wszystkie zależności symboli:
# 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
Chociaż rozszerzenia jądra są zwykle oczekiwane w /System/Library/Extensions/, jeśli wejdziesz do tego folderu nie znajdziesz żadnego pliku binarnego. Dzieje się tak z powodu kernelcache i aby poddać pojedynczy .kext reverse engineeringowi, musisz znaleźć sposób na jego pozyskanie.
The kernelcache jest wstępnie skompilowaną i wstępnie powiązaną wersją jądra XNU, wraz z niezbędnymi sterownikami urządzeń (drivers) i kernel extensions. Jest przechowywany w skomprymowanym formacie i jest dekompresowany do pamięci podczas procesu uruchamiania. Kernelcache przyspiesza czas rozruchu, mając gotową do uruchomienia wersję jądra i kluczowych sterowników, co zmniejsza czas i zasoby, które w przeciwnym razie byłyby potrzebne do dynamicznego ładowania i linkowania tych komponentów podczas startu.
Główne korzyści z kernelcache to szybsze ładowanie oraz to, że wszystkie moduły są wstępnie powiązane (brak opóźnień przy ładowaniu). A gdy wszystkie moduły zostały wstępnie powiązane — KXLD może zostać usunięty z pamięci, więc XNU nie może załadować nowych KEXTów.
tip
Narzędzie https://github.com/dhinakg/aeota odszyfrowuje kontenery AEA (Apple Encrypted Archive / AEA asset) używane przez Apple dla zasobów OTA i niektórych części IPSW — i może wygenerować podstawowy .dmg/asset archive, który następnie możesz rozpakować za pomocą dostarczonych narzędzi aastuff.
Local Kerlnelcache
W iOS znajduje się w /System/Library/Caches/com.apple.kernelcaches/kernelcache, w macOS możesz go znaleźć poleceniem: find / -name "kernelcache" 2>/dev/null
W moim przypadku w macOS znalazłem go w:
/System/Volumes/Preboot/1BAEB4B5-180B-4C46-BD53-51152B7D92DA/boot/DAD35E7BC0CDA79634C20BD1BD80678DFB510B2AAD3D25C1228BB34BCD0A711529D3D571C93E29E1D0C1264750FA043F/System/Library/Caches/com.apple.kernelcaches/kernelcache
Zobacz także tutaj kernelcache wersji 14 z symbolami.
IMG4 / BVX2 (LZFSE) compressed
Format pliku IMG4 jest formatem kontenera używanym przez Apple w urządzeniach iOS i macOS do bezpiecznego przechowywania i weryfikacji komponentów firmware (np. kernelcache). Format IMG4 zawiera nagłówek i kilka tagów, które enkapsulują różne fragmenty danych, w tym rzeczywisty payload (np. jądro lub bootloader), podpis oraz zestaw właściwości manifestu. Format obsługuje weryfikację kryptograficzną, pozwalając urządzeniu potwierdzić autentyczność i integralność komponentu firmware przed jego wykonaniem.
Zazwyczaj składa się z następujących komponentów:
- Payload (IM4P):
- Często skompresowany (LZFSE4, LZSS, …)
- Opcjonalnie zaszyfrowany
- Manifest (IM4M):
- Zawiera Signature
- Dodatowy słownik Key/Value
- Restore Info (IM4R):
- Znany również jako APNonce
- Zapobiega ponownemu odtwarzaniu (replay) niektórych aktualizacji
- OPTIONAL: Zwykle tego nie ma
Decompress the Kernelcache:
# 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
Symbole jądra dla Disarm
Disarm pozwala symbolikować funkcje z kernelcache przy użyciu matchers. Te matchery to po prostu proste reguły wzorców (linie tekstu), które mówią disarm, jak rozpoznawać i automatycznie symbolikować funkcje, argumenty oraz panic/log strings wewnątrz binarki.
Czyli zasadniczo wskazujesz łańcuch znaków, którego używa funkcja, a disarm go znajdzie i symbolicate it.
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.
Przejdź do /tmp/extracted, gdzie disarm wyodrębnił 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:
Zainstaluj narzędzie ipsw
brew install blacktop/tap/ipsw
Wyodrębnij tylko kernelcache z IPSW
ipsw extract --kernel /path/to/YourFirmware.ipsw -o out/
Powinieneś otrzymać coś takiego:
out/Firmware/kernelcache.release.iPhoneXX
or an IMG4 payload: out/Firmware/kernelcache.release.iPhoneXX.im4p
Jeśli otrzymasz 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:**
Wypisz wszystkie rozszerzenia
kextex -l kernelcache.release.iphone14.e
Wyodrębnij com.apple.security.sandbox
kextex -e com.apple.security.sandbox kernelcache.release.iphone14.e
Wyodrębnij wszystko
kextex_all kernelcache.release.iphone14.e
Sprawdź rozszerzenie pod kątem symboli
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
Utwórz pakiet symbolikacji dla najnowszego zrzutu paniki
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 # pobierz backtrace w kernel context
### Attaching LLDB to a specific loaded kext
Zidentyfikuj adres załadowania kexta
ADDR=$(kmutil showloaded --bundle-identifier com.example.driver | awk '{print $4}')
Dołącz
sudo lldb -n kernel_task -o "target modules load --file /Library/Extensions/Example.kext/Contents/MacOS/Example --slide $ADDR"
HackTricks