
Lehrreicher Deep Dive in macOS-App-Bundles, Plist-Dateien und das Prozessverhalten von launchd, mit Hinweisen zur offensiven Sicherheit beim Verpacken von Payloads als .app-Dateien und zur Umgehung von Prozessbaum-Überwachung.
Der Wechsel zu macOS von Linux oder Windows kann sich anfühlen, als würde man in einem fremden neuen Land umherirren. Da Linux Open-Source ist und Windows gut dokumentiert und sehr beliebt ist (und macOS genau genommen keines von beidem ist), kann macOS manchmal herausfordernd sein. In diesem Blogbeitrag möchte ich einige der ersten Dinge besprechen, die einem auf macOS auffallen könnten - Apps, Apps überall!
Wenn man aus der Windows- oder Linux-Welt kommt, mag das Konzept von Apps seltsam erscheinen. Wir alle wissen, dass Threads "Ausführungseinheiten" sind und Prozesse Container für Threads mit eigenem Adressraum sind -- was steckt schon mehr dahinter? Nun, Prozesse werden selten in einzelnen Dateien ausgeliefert. Sowohl unter Windows als auch unter Linux gibt es viele Dinge, die Code möglicherweise benötigt, um zu funktionieren, einige davon sind:
.dll, .so). Zum Beispiel die C-Laufzeitbibliothek (msvcr<version>.dll unter Windows, libc-<version>.so) sowie andere Abhängigkeiten.PE, das Verzeichnisse besitzt - eines davon ist das Ressourcenverzeichnis (sogar gewissermaßen hier dokumentiert), das Ressourcen (Bilder, Zeichenketten und andere) enthalten kann. Ressourcen können natürlich auch dynamisch von der Festplatte geladen werden.PE-Datei selbst enthalten sein (lies hier) oder in Katalogdateien (d. h. extern).xml, ini, json) und die Windows-Registry.Nun, macOS legt großen Wert auf Application Bundles. Die Idee ist, (fast) alles, was das Programm zum Ausführen benötigt, in einer Verzeichnisstruktur zu bündeln - einschließlich Ressourcen, Lokalisierungsinformationen usw. Natürlich kann nicht alles sauber verpackt werden (wie zum Beispiel die C-Laufzeitbibliothek) - aber es bedeutet dennoch, dass die Dinge ordentlich gebündelt werden - keine Notwendigkeit, eine riesige Registry zu durchforsten oder Handbuchseiten für obskure Konfigurationsdateipfade zu lesen. Application Bundles sind einfach Verzeichnisse, die auf .app enden - auch wenn die Benutzeroberfläche die .app-Erweiterung (und die Tatsache, dass es sich um ein Verzeichnis handelt) verbirgt.
Aus der Perspektive eines Angreifers ist das interessant - da ein Application Bundle beliebige Symbole haben und die .app-Erweiterung verbergen kann, könnte das Ausliefern von Malware erreicht werden, indem man einen ahnungslosen Benutzer dazu bringt, auf eine solche App zu klicken. Denke zum Beispiel an eine Resume.app-Datei mit einem PDF-Symbol.
Die Verzeichnisstruktur eines Application Bundle kann leicht untersucht werden, offensichtlich anhand der integrierten App Calculator:
jbo@McJbo ~ % cd /System/Applications/Calculator.app
jbo@McJbo Calculator.app % ll
total 0
drwxr-xr-x 3 root wheel 96 Mar 17 21:34 .
drwxr-xr-x 43 root wheel 1376 Mar 17 21:34 ..
drwxr-xr-x 9 root wheel 288 Mar 17 21:34 Contents
jbo@McJbo Calculator.app % cd Contents
jbo@McJbo Contents % ll
total 16
drwxr-xr-x 9 root wheel 288 Mar 17 21:34 .
drwxr-xr-x 3 root wheel 96 Mar 17 21:34 ..
-rw-r--r-- 1 root wheel 2147 Mar 17 21:34 Info.plist
drwxr-xr-x 3 root wheel 96 Mar 17 21:34 MacOS
-rw-r--r-- 204 root wheel 8 Mar 17 21:34 PkgInfo
drwxr-xr-x 4 root wheel 128 Mar 17 21:34 PlugIns
drwxr-xr-x 54 root wheel 1728 Mar 17 21:34 Resources
drwxr-xr-x 3 root wheel 96 Mar 17 21:34 _CodeSignature
-rw-r--r-- 1 root wheel 461 Mar 17 21:34 version.plist
jbo@McJbo Contents % cd MacOS
jbo@McJbo MacOS % ll
total 344
drwxr-xr-x 3 root wheel 96 Mar 17 21:34 .
drwxr-xr-x 9 root wheel 288 Mar 17 21:34 ..
-rwxr-xr-x 1 root wheel 540912 Mar 17 21:34 Calculator
jbo@McJbo MacOS %
Wie du sehen kannst, ist Calculator.app ein Verzeichnis. Darunter befindet sich ein einzelnes Element - ein weiteres Verzeichnis namens Contents.
Unter Contents befinden sich mehrere Elemente:
Info.plist - enthält Metadaten über die App. Mehr dazu später.MacOS - enthält die Haupt-Executable der App (wie in der dritten Verzeichnisauflistung zu sehen ist).PkgInfo - optional. Eine Binärdatei, die Paketinformationen enthält.PlugIns - optional. Ein Verzeichnis, das Plugins für die App enthalten kann. Calculator hat zwei - eines für "Basic and Scientific" und eines für "Hexadecimal" (ich weiß wirklich nicht, warum sie diese Trennung vorgenommen haben, und es ist mir auch egal).Resources - optional. Wie der Name vermuten lässt, enthält es Ressourcen. Du findest dort möglicherweise mehrere Elemente, darunter eine .icns-Datei mit Symbolen sowie Verzeichnisse mit dem Suffix .lprroj, die mit der Lokalisierung zusammenhängen._CodeSignature - optional. Wie der Name vermuten lässt - enthält Informationen zur Codesignierung.version.plist - optional, enthält Versionsinformationen.Beachte, dass es nur sehr wenige Elemente gibt, die offiziell erforderlich sind. Tatsächlich können wir unsere erste eigene App erstellen, ohne auch nur etwas zu kompilieren!
Aber zuerst müssen wir die Datei Info.plist besprechen.
Je mehr man sich macOS ansieht, desto mehr dieser seltsamen Dateien findet man. Sie sind nichts weiter als hochtrabend bezeichnete Konfigurationsdateien.
Sie haben immer eine .plist-Erweiterung, die nur eine Kurzform ihres formalen Namens ist: Property list-Dateien.
Leider gibt es drei verschiedene plist-Formate, die von Apple gepflegt werden:
xml-Format, das für Menschen lesbar ist.json-Format, das nicht weit verbreitet ist.bplist als Magic erkennbar ist.Glücklicherweise gibt es ein Dienstprogramm namens plutil, das alle Formate unterstützt. Um eine plist-Datei auszugeben, verwende einfach plutil -p. Zum Beispiel:
jbo@McJbo Contents % plutil -p Info.plist | head -n 20
{
"BuildMachineOSBuild" => "22A380007"
"CFBundleDevelopmentRegion" => "English"
"CFBundleExecutable" => "Calculator"
"CFBundleGetInfoString" => "10.14, Copyright © 2000-2018, Apple Inc."
"CFBundleHelpBookFolder" => "Calculator.help"
"CFBundleHelpBookName" => "com.apple.Calculator.help"
"CFBundleIconFile" => "AppIcon"
"CFBundleIconName" => "AppIcon"
"CFBundleIdentifier" => "com.apple.calculator"
"CFBundleInfoDictionaryVersion" => "6.0"
"CFBundleName" => "Calculator"
"CFBundlePackageType" => "APPL"
"CFBundleShortVersionString" => "10.16"
"CFBundleSignature" => "????"
"CFBundleSupportedPlatforms" => [
0 => "MacOSX"
]
"CFBundleVersion" => "223"
"CTIgnoreUserFonts" => 1
jbo@McJbo Contents %
Es gibt auch in plutil eingebaute Konvertierungsfunktionen - die werden wir jetzt nicht vorführen.
Apple dokumentiert mehrere Anforderungen in der Info.plist einer App, aber es gibt nur sehr wenige Felder, die tatsächlich zwingend erforderlich sind. Hier sind einige interessante Felder:
CFBundleExecutable - der Name der Haupt-Executable, die sich erwartungsgemäß im Verzeichnis MacOS befindet.CFBundleIconFile - der Name der Symboldatei. Optional.CFBundleIdentifier - eine Kennung für das App-Bundle. Apple empfiehlt die Verwendung einer Reverse-DNS-Notation (z. B. com.apple.calculator).CFBundleName - der Bundle-Name.Mit diesem Wissen können wir unsere erste tolle eigene App erstellen, ohne auch nur zu programmieren! Schau es dir an:
#!/bin/zsh
# Create Bundle structure
mkdir -p ./MyApp.app/Contents/MacOS
# Create main executable file - a shell script in our case
cat <<EOF > ./MyApp.app/Contents/MacOS/MyApp
#!/bin/zsh
osascript -e 'tell app "Finder" to display dialog "Hello from MyApp!"'
EOF
chmod +x ./MyApp.app/Contents/MacOS/MyApp
# Create the Info.plist file
cat <<EOF > ./MyApp.app/Contents/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>MyApp</string>
<key>CFBundleIdentifier</key>
<string>com.myapp</string>
<key>CFBundleName</key>
<string>MyApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
</dict>
</plist>
EOF
Dadurch wird eine neue App namens MyApp erstellt - ein Klick darauf führt einfach das zsh-Skript (namens MyApp) aus.
Beachte, dass es osascript verwendet, einen AppleScript-Interpreter und eine ganze Büchse der Pandora, aber es wird nur einen Dialog anzeigen, der Hello from MyApp! sagt. Du könntest natürlich beliebigen Code in diese zsh-Shell-Datei schreiben. Neuere macOS-Versionen zeigen möglicherweise eine Eingabeaufforderung an, die darum bittet, zsh zu erlauben, osascript aufzurufen - wir werden in einem zukünftigen Beitrag besprechen, warum das passiert, aber beachte, dass nach einer ersten Freigabe keine erneute Abfrage erfolgt.
Das Starten einer App bedeutet, dass dennoch ein Prozess erzeugt wird - offensichtlich der, auf den CFBundleExecutable verweist. Unter welchem Prozess läuft er? Schauen wir uns das an:
jbo@McJbo ~ % open -a Calculator
jbo@McJbo ~ % ps -A -j | grep Calculator | grep -v grep
jbo 12067 1 12067 0 1 S ?? 0:00.41 /System/Applications/Calculator.app/Contents/MacOS/Calculator
jbo@McJbo ~ %
Der Befehl open entspricht einem Doppelklick auf die App Calculator - er ist ziemlich faszinierend, und wir werden ihn bald besprechen.
Jetzt, wo Calculator läuft, verwenden wir ps, um die laufenden Prozesse anzuzeigen. Wie erwartet ist /System/Applications/Calculator.app/Contents/MacOS/Calculator der Prozess, der läuft, und er hat eine PID von 12067. Allerdings ist seine Parent-Prozess-ID 1!
Die Prozess-ID 1 ist unter macOS /sbin/launchd. Es ist der "systemweite und benutzerbezogene Daemon-/Agent-Manager". Du kannst es dir wie services.exe vorstellen (wenn du aus der Windows-Welt kommst) oder wie systemd (wenn du mit Linux vertraut bist). Zusätzlich zur Verwaltung von Diensten (die unter macOS Launch Agents und Launch Daemons genannt werden) ist es auch der Parent aller Anwendungen, was einer der Gründe dafür ist, warum es eine Herausforderung ist, auf macOS einen aussagekräftigen Prozessbaum zu erhalten.
Interessanterweise kannst du die App Calculator trotzdem einfach als Prozess ausführen, indem du /System/Applications/Calculator.app/Contents/MacOS/Calculator direkt aufrufst, aber sie wird dann kein Kind von launchd sein:
jbo@McJbo ~ % /System/Applications/Calculator.app/Contents/MacOS/Calculator &
[1] 12502
jbo@McJbo ~ % 2023-04-04 15:54:22.987 Calculator[12502:1297087] XType: XTFontStaticRegistry is enabled by Info.plist.
jbo@McJbo ~ % ps -A -j | grep Calculator | grep -v grep
jbo 12502 951 12502 0 1 SN s000 0:00.31 /System/Applications/Calculator.app/Contents/MacOS/Calculator
jbo@McJbo ~ % echo $$
951
jbo@McJbo ~ %
Tatsächlich läuft Calculator einwandfrei, ist aber jetzt der Kindprozess unseres Terminals.
Ein wichtiger Punkt an dem beobachteten Verhalten ist, dass Angreifer es für verschiedene Zwecke nutzen könnten. Zum Beispiel können Angreifer leicht aus dem Prozessbaum ausbrechen, um Sicherheitstools zu umgehen, sowie Logik-Schwachstellen ausnutzen (lies meinen Write-up zur macOS-Sandbox-Escape-Schwachstelle, wenn du Zeit hast).
launchd hat noch andere interessante Aufgaben (lies über LaunchAgents und LaunchDaemons), aber die werden wir jetzt nicht besprechen.
Hier habe ich dir eine Art von Bundle gezeigt, aber es gibt noch viele mehr (keine vollständige Liste):
.app - dieses haben wir gesehen, das sind Application Bundles, die Container für Apps sind..framework - enthält Frameworks, also ladbare Bundles. Ja, unter macOS kannst du dlopen auf eine ladbare Datei (.dylib) aufrufen oder ein ganzes Framework-Bundle laden (mit Ressourcen, Code usw.)..kext - enthält Kernel Extensions, also ladbare Bundles, aber für den macOS-Kernel. In neueren OS-Versionen bemüht sich Apple wirklich sehr, die Anzahl der Kernel Extensions zu reduzieren..plugin - wie der Name vermuten lässt, ein Container für Plugins.Dies ist der erste einer Reihe kurzer Blogbeiträge, die darauf abzielen, Leuten den Übergang zur macOS-Forschung zu erleichtern. Das erste, was mir aus der Perspektive der offensiven Sicherheit auffiel, war, wie einfach es ist, Payloads in einer hübschen App-Struktur zu verpacken. So einfach ist es allerdings nicht - in den nächsten Blogbeiträgen werden wir entdecken, dass das Erlangen von Codeausführung aufgrund der vielen Sicherheitsfunktionen von macOS gar nicht so trivial ist.
Bleib dran!
Jonathan Bar Or (https://jonathanbaror.com)