
Analyse einer Logik-Schwachstelle im macOS SSH Client, die zur Offenlegung der Client-Passphrase gegenüber einem lokalen Angreifer führt.
Dieses Dokument enthält sowohl eine Analyse einer Logik-Schwachstelle, die im ssh-Binary auf macOS identifiziert wurde (meine erste Software-Sicherheitslücke!), als auch eine Patch-Analyse, die zeigt, wie Apple die Schwachstelle behoben hat. Ich meldete das Problem Apple über das Apple Security Bounty Programm Ende 2022, das später in macOS Ventura 13.5 behoben wurde und CVE-2023-42829 (🎉) ergab. Das Problem führt dazu, dass SSH-Passphrasen, die in der benutzerlokalen 'Login'-Keychain von macOS (in der Zugriffsgruppe com.apple.ssh.passphrases) gespeichert sind, einem lokalen Angreifer im Klartext offengelegt werden.
Haftungsausschluss:
Dieser Bericht dient ausschließlich zu Bildungszwecken, wobei verantwortungsvolle Offenlegungsprozesse eingehalten wurden. Die Analyse wird wie besehen angeboten, und jede weitere Veröffentlichung oder Nutzung dieser Informationen sollte sich an die Richtlinien für verantwortungsvolle Offenlegung halten.
Gepatchter High-Level-Ablauf
Nicht gepatchter High-Level-Ablauf
com.apple.private.security.clear-library-validation Berechtigung| Hardware | Betriebssystem-Software |
|---|---|
| MacBook Pro M1 2021 | /usr/bin/ssh @ macOS Ventura build 13.0.1 (22A400) |
Das folgende Proof-of-Concept veranschaulicht die relativ einfache Ausnutzbarkeit der Schwachstelle, indem eine dynamische Bibliothek an das -I-Flag des ssh-Binaries übergeben wird:
jamesd@local build % ssh -I /Users/jamesd/rome.dylib [email protected]
SSH-Private-Key-Passphrase -> 'SuperSecret!!@@$'
Lassen Sie uns darüber sprechen, wie dies entdeckt wurde und warum es passierte!
Es war einmal, als ich das ssh-Binary für etwas Harmloses verwendete und mich beim -i-Flag (zum Übergeben einer SSH-Identitätsdatei) mit dem -I-Flag vertippte und auf folgende Standardausgabe stieß:
jamesd@local build % ssh -I /Users/jamesd/.ssh/id_rsa something@somewhere
dlopen /Users/jamesd/.ssh/id_rsa failed: dlopen(/Users/jamesd/.ssh/id_rsa, 0x0002): tried: '/Users/jamesd/.ssh/id_rsa' (not a mach-o file), ...
...
Nachdem ich die Berechtigungen des ssh-Binaries überprüft hatte...
jamesd@local build % ldid -e /usr/bin/ssh # dump the entitlements of the /usr/bin/ssh binary
<key>com.apple.private.security.clear-library-validation</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>com.apple.ssh.passphrases</string>
</array>
...mein Interesse war geweckt – das Binary hat Berechtigungen, aus einer geschützten Keychain-Zugriffsgruppe (com.apple.ssh.passphrases) zu lesen, besitzt die com.apple.private.security.clear-library-validation-Berechtigung, und ssh versucht, meinen privaten Schlüssel zu dlopen()?
Wie sich herausstellt, unterstützt ssh die Authentifizierung gegenüber einem entfernten System über etwas namens pkcs11, einem Standard für kryptografische Operationen auf Hardware-Sicherheitsmodulen (HSMs) (https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-library.html).
Für die Zwecke dieses Berichts müssen wir uns nicht um die Einzelheiten von pkcs11 kümmern, abgesehen davon, dass der Client eine pkcs11-Bibliothek (dynamische Bibliothek) an ssh -I übergibt.
com.apple.private.security.clear-library-validation BerechtigungObwohl konzeptionell gleichwertig, unterscheidet sich com.apple.private.security.clear-library-validation von der vorherigen gleichwertigen Berechtigung (com.apple.security.cs.disable-library-validation), da com.apple.private.security.clear-library-validation erfordert, dass der csops()-Systemaufruf mit CS_OPS_CLEAR_LV aufgerufen wird, um die Bibliotheksvalidierung zu aktivieren/deaktivieren und so eine größere Kontrolle über die Prozessintegrität zur Laufzeit zu behalten (im Vergleich zu com.apple.private.security.clear-library-validation, das vermutlich das Laden jeder Bibliothek ohne Laufzeitkontrolle erlauben würde). (https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/kern_proc.c) (https://theevilbit.github.io/posts/com.apple.private.security.clear-library-validation/)
Da csops(CS_OPS_CLEAR_LV) vor dem dlopen() unserer Bibliothek aufgerufen wird, wird unsere Bibliothek einfach geladen und der Konstruktor ausgeführt, sodass wir eine bösartige dynamische Bibliothek, die als pkcs11-Bibliothek getarnt ist, bereitstellen und Code im Kontext von /usr/bin/ssh ausführen und die keychain-access-groups-Berechtigung nutzen können.
Vielleicht beinhaltete der Patch Überprüfungen des Binaries vor dem Aufruf von csops(), um nach bestimmten vertrauenswürdigen Signieridentitäten zu suchen?
Nein!
Nach der Veröffentlichung des Patches (22G74) verglich ich die unsichere Implementierung von pkcs11_add_provider() (die Methode, in der der Aufruf von dlopen() erfolgt) und sie schien mit der Patch-Version identisch zu sein – aber es fehlt eine Berechtigung in /usr/bin/ssh?
<?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>keychain-access-groups</key>
<array>
<string>com.apple.ssh.passphrases</string>
</array>
</dict>
</plist>
Aber Apple hat doch sicherlich nicht die pkcs11-Unterstützung aus SSH entfernt? Ich versuchte, die Schwachstelle mit meinem PoC erneut auszunutzen und stellte fest, dass meine Bibliothek zwar geladen wurde, aber nicht mehr aus der Keychain-Zugriffsgruppe lesen konnte und offenbar im Kontext von /usr/libexec/ssh-apple-pkcs11 (ein mir unbekanntes Binary) ausgeführt wurde, das die folgenden Berechtigungen besitzt:
<?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>com.apple.private.security.clear-library-validation</key>
<true/>
</dict>
</plist>