
Blogbeitrag, der die macOS App Sandbox, Entitlements via codesign und Sandbox-Escape-Techniken mit launchd, LaunchAgents und Quarantine-Attributen untersucht.
In Fortsetzung meiner Blogpost-Serie über meinen Wechsel zu macOS möchte ich ein wenig über die App-Sandbox von macOS sprechen.
Es wird dringend empfohlen, zuerst den Blogpost zur macOS-App-Struktur zu lesen – ich setze voraus, dass der Leser den Unterschied zwischen Apps und Prozessen (Tasks) kennt, ein wenig über launchd weiß und dessen Beziehung zum Starten von Apps versteht.
Als ich zum ersten Mal von der macOS-Sandbox erfuhr, versuchte ich naiv, ein bösartiges Word-Makro zu erstellen.
Dies ist (immer noch) ein sehr verbreiteter Einstiegsvektor im Windows-Ökosystem, und ich wollte sehen, ob ich einfach Prozesse starten und generell Chaos anrichten konnte.
Nun, auf macOS sind die Dinge nicht so einfach – ich konnte zum Beispiel Prozesse ausführen, aber sie schienen nicht viel bewirken zu können.
Beim Ablegen von Dateien erhielt ich immer den kryptischen Fehler Operation not permitted – was ist da los?
Ich begann, mich ein wenig über macOS und Word zu belesen und stieß auf diesen ausgezeichneten Blogpost von Adam Chester (arbeitet bei MDSec). Ich kann den Blogpost nur wärmstens empfehlen, aber ich fasse die Erkenntnisse hier zusammen:
macOS hatte früher ein funktionierendes Dienstprogramm namens sandbox-exec, das Befehle in einer Sandbox ausführte. Obwohl es veraltet ist, konnte es einiges verdeutlichen. Auf der Manpage sieht man, dass es ein profile erhält, woraus wir schließen können, dass Sandbox-Regeln in Profilen gepflegt werden. Diese Profile können in verschiedenen Formen auftreten – als Dateien, vordefinierte Namen oder sogar als literale Zeichenketten.
Die Manpages besagen außerdem, dass Entwickler die App-Sandbox-Funktion verwenden sollten. Als ich mehr darüber las, verstand ich, dass die Sandbox-Regeln in die Binärdatei eingebettet sind, in unserem Fall unter /Application/Microsoft Word.app/Contents/MacOS/Microsoft Word (falls Ihnen das fremd erscheint, lesen Sie meinen Blogpost zur macOS-App-Struktur).
Auch wenn man sie leicht von Hand extrahieren kann, verwendet man am besten ein Werkzeug: codesign:
```jbo@McJbo ~ % codesign -dv --entitlements - /Applications/Microsoft\ Word.app/Contents/MacOS/Microsoft\ Word
Executable=/Applications/Microsoft Word.app/Contents/MacOS/Microsoft Word
Identifier=com.microsoft.Word
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=351454 flags=0x10000(runtime) hashes=10972+7 location=embedded
Signature size=8980
Timestamp=Apr 10, 2023 at 8:09:50 AM
Info.plist entries=52
TeamIdentifier=UBF8T346G9
Runtime Version=13.1.0
Sealed Resources version=2 rules=13 files=28766
Internal requirements count=1 size=180
[Dict]
[Key] com.apple.application-identifier
[Value]
[String] UBF8T346G9.com.microsoft.Word
[Key] com.apple.developer.aps-environment
[Value]
[String] production
[Key] com.apple.developer.team-identifier
[Value]
[String] UBF8T346G9
[Key] com.apple.security.app-sandbox
[Value]
[Bool] true
...
[Key] com.apple.security.temporary-exception.files.absolute-path.read-only
[Value]
[Array]
[String] /Library/Preferences/com.microsoft.office.licensingV2.plist
[String] /Library/Application Support/Microsoft/
...
[Key] com.apple.security.temporary-exception.sbpl
[Value]
[Array]
[String] (allow file-read* file-write* (require-all (vnode-type REGULAR-FILE) (regex #"(^|/)~\$[^/]+$")) )
[String] (deny file-write* (subpath (string-append (param "_HOME") "/Library/Application Scripts")) (subpath (string-append (param "_HOME") "/Library/LaunchAgents")) )
[Key] com.apple.security.temporary-exception.shared-preference.read-only
[Value]
[Array]
[String] com.ThomsonResearchSoft.EndNote
...
Das ist eine Menge Stoff, also halten wir einige allgemeine Punkte fest:
-dv, was für display und verbose steht. Dann zeigt --entitlements die Entitlements an, die mit der App oder der Binärdatei verknüpft sind (ja, codesign kann mit beiden arbeiten). Wir werden uns in einem anderen Blogpost mit Entitlements befassen, aber für den Moment sagen wir, sie spiegeln die Fähigkeiten der App wider, und eines davon besagt, dass die App in einer Sandbox läuft (com.apple.security.app-sandbox hat den booleschen Wert True).plists geschimpft habe (wieder in meinem [Blogpost zur macOS-App-Struktur]), könnte vermuten, dass das Schlüssel-Wert-Dictionary eine Darstellung einer Property List ist – und damit richtig liegen.com.apple.security.temporary-exception.files.absolute-path.read-only ein Array von absoluten Pfaden, die die App lesen darf.com.apple.security.temporary-exception.sbpl ist hier – er dient dazu, diese notorischen temporären Dateien ~$whatever.docx zu erzeugen, die Word so sehr liebt.In dem MDSec-Blogpost von 2018, den ich vorhin erwähnt habe, existierte der Teil deny file-write* unter com.apple.security.temporary-exception.sbpl noch nicht, was es Makros erlaubte, Dateien mit beliebigem Inhalt wie /Library/LaunchAgents/~$evil.plist zu erstellen. Warum führt das zum Sandbox-Escape?
LaunchAgents und LaunchDaemons sind ein bekannter (legitimer) Persistenzmechanismus in macOS. Ich habe sie bereits erwähnt, aber man kann sie sich wie Dienste vorstellen (wenn man aus der Windows-Welt kommt) – LaunchDaemons starten, wenn das Betriebssystem bootet (und laufen daher außerhalb der Benutzersitzung), während LaunchAgents starten, wenn sich ein Benutzer anmeldet.
Interessanterweise werden beide in einfachen plist-Dateien beschrieben. Hier ein Beispiel für meinen OneDrive-Updater:
jbo@McJbo ~ % plutil -p /Library/LaunchAgents/com.microsoft.OneDriveStandaloneUpdater.plist
{
"Label" => "com.microsoft.OneDriveStandaloneUpdater"
"Program" => "/Applications/OneDrive.app/Contents/StandaloneUpdater.app/Contents/MacOS/OneDriveStandaloneUpdater"
"ProgramArguments" => [
]
"RunAtLoad" => 1
"StartInterval" => 86400
}
Diese LaunchAgents und LaunchDaemons werden von launchd gestartet (erinnern Sie sich an diesen Prozess?) und umgehen dadurch die Sandbox, da launchd nicht wusste, ob die plist von einem sandboxed-Prozess abgelegt wurde oder nicht (und selbst wenn es das wüsste – woher sollte es wissen, welche Sandbox-Regeln anzuwenden sind?).