Joshua Drake hat sich mit der Sicherheit von Android auf der Black Hat 2015 USA beschäftigt. Da das Android Open Source Project (AOSP) sehr viel Code enthält, den man unmöglich komplett durchsehen kann, hat sich Joshua einen kleinen Teil beispielhaft herausgepickt, der auf 95% aller Geräte läuft und potentiell gefährlich ist, weil er von außen angreifbar ist: Das Stagefright Multimedia Framework. Die anderen 5% sind nicht gefährdet, weil Stagefright erst mit Android 2.2 eingeführt wurde.
Joshua hat in dem Stagefright Framework eine Unmenge an Implementierungsfehlern gefunden, die von direkter Remote-Code-Execution bis zum simplen Denial of Service reichen. Er hat auch Exploits dafür vorgeführt. Das hat viele Android-User zu Recht erschreckt, vor allem, weil bei den meisten die von Google bereitgestellten Bugfixes niemals auf ihrem Endgerät ankommen werden, da die jeweiligen Smartphone-Hersteller und Mobilfunk-Betreiber die Patches nicht in ihre Android-Version einbauen. Das ist der Preis der sogenannten Freiheit bei Android: Jeder kann damit mehr oder weniger machen, was er will, oder eben auch mal gar nichts. Die Hersteller und Carrier entscheiden sich in der Regel für "gar nichts", weil sie keinen finanziellen Nutzen in Bugfixes sehen, sondern nur Aufwand.
Wenn man dann noch weiß, daß das Stagefright-Framework nur eine von über 200 (teils proprietären) Libraries ist, die in Androids Media-Software geladen wird auf einem Samsung Galaxy S6, dann ist damit zu rechnen, daß es sich mit den Stagefright-Bugs nur um die Spitze des Eisbergs handelt.
Meine Nachfrage auf Twitter, wo denn das White Paper und das Vortrags-Video bleiben, hat Joshua zwar favorisiert, aber bislang ist beides noch nicht auf der Black Hat Seite veröffentlicht worden.
Inzwischen gibt es die Folien aus seinem Vortrag.
Die Berichte über die Stagefright-Bugs sorgten schon Tage vor ihrer Präsentation für Furore. Da kam das Posting von Adrian Ludwig über Address Space Layout Randomisation (ASLR) und andere in Android verbaute Exploit-Erschwerungen (Mitigations) als rettender Strohhalm dem einen oder anderen User und Redakteur gerade recht nach dem Motto: Ok, es gibt furchtbare Security-Bugs in Android und wir werden die Patches nie auf unserem Gerät sehen, aber wir haben ja ASLR in Android und ha-ha, darum können uns die pösen Purschen nichts tun.
Daß auch die aktuell neueste Version von Android, Lollipop 5.1.1, betroffen ist, kann man auf der Seite von Joshuas Firma sehen, wo sie Screenshots davon zeigen.
Offenbar war der erste Patch-Versuch von Google fehlerhaft.
Inzwischen hat sogar Googles Project Zero einen Exploit für einen der Stagefright-Bugs veröffentlicht, der auf Android 5.0+ läuft. Schöner Kommentar darin: "I knew that ASLR on 32-bit was always a bit shaky; but I didn’t think it was this broken." (Ich wußte, daß ASLR auf 32-Bit immer etwas wackelig ist, aber ich hatte nicht erwartet, daß es dermaßen kaputt ist.)
An dieser Stelle hören die anderen auf. Hier fängt aber das, um was es mir hier geht, erst an: ASLR in Android und auf Android-Geräten ist wertloser Dreck. ASLR ist per se schon überall mehr Selbstbetrug als eine wirkliche Hilfe, aber Google hat es auf Android, obwohl vollständig ab Android 4.1 umgesetzt, dermaßen mit seiner Android-Architektur verbockt, daß ASLR auf dieser Plattform noch wertloser ist als anderswo.
ASLR hat auf Android mehrere Probleme: Unvollständigkeit, 32 Bit und Zygote. Außerdem noch Sicherheits-Probleme in der neuen Android Runtime (ART) und dem System Allocator.
Android-Versionen vor 4.0 hatten nur Stack-Randomisation, Android 4.0 hatte ASLR in mehr Bereichen, unter anderem für mmap, das Dateien und Geräte im Speicher abbildet. Erst mit 4.1 wurden der Heap, der Linker und das User-Land, also die Apps, mit ASLR-Support ausgestattet. Bei den Programmen geht das über speicherpositions-unabhängigen Code, Position Independent Executables (PIE).
Läuft ein Bereich ohne ASLR, ist ASLR insgesamt nutzlos, weil eine Stelle mit Code, die ein Exploit anspringen kann ausreicht. Wer also eine Android-Version vor 4.1 benutzt, kann sich getrost als ASLR-frei betrachten.
Erst seit Ende 2014 gibt es vereinzelte 64 Bit Android Smartphones. Und erst Android 5.0 L (Lollipop), ebenfalls Ende 2014, brachte 64-Bit auf Software-Seite.
Im Android Hacker's Handbook kann man auf Seite 418 nachlesen, daß ASLR unter anderem durch den begrenzten 32-Bit-Adreßraum leicht zu umgehen ist. Das ist eine Tatsache, die ich aus aus anderen Quellen kenne und eine allgemeingültige Regel: ASLR ist auf 32-Bit ziemlich witzlos, weil die Zufälligkeit (Entropie) einfach zu klein ist. Das wird auch bei Copperhead, einer Android-Fork, die die Sicherheitsprobleme des normalen Android beheben möchte, explizit erwähnt: Die meisten Android-Geräte sind 32-Bit, was Brute-Force-Attacken sehr praktikabel macht. Man probiert die möglichen Adressen einfach alle durch. Vergleiche hierzu Details aus ASLR Cargo Cult Security.
Neben zu wenig Zufälligkeit, sind Informationslecks ein Problem für ASLR. Wenn man auf irgendeine Weise Hinweise zum Speicher-Layout bekommen kann, und seien es nur Teile einer Speicher-Adresse, dann erleichtert das den Angriff deutlich. Solche Info-Leaks hat Android in seiner ureigensten Architektur dank Zygote eingebaut.
Im Gegensatz zum typischen Unix-Vorgehen wie unter OS X / iOS oder GNU/Linux werden bei Android neue Prozesse nicht über fork() und exec() gestartet, sondern rein als Kopie des Zyogte-Prozesses nur mit fork(). Die jeweilige Kopie hat das gleiche Address Space Layout wie das Original. Konsequenterweise haben also alle Apps und die meisten System-Dienste unter Android die gleichen ASLR-Basis-Adressen.
Bei einem traditionellem Unix-Programmstart wie unter OS X / iOS oder GNU/Linux hat jeder Prozeß ein unterschiedliches Speicher-Layout, weil die Menge der verwendeten Basis-Adressen pro Prozeß durch exec() individuell festegelegt wird. Android macht dieses exec() jedoch nicht, um Speicherverbrauch und Programmstartzeit einzusparen. Würde Android es sicher und gescheit machen, bräuchte jeder Prozeß zwischen 3 und 15 MB mehr Speicher und zwischen 1 und 2 Sekunden mehr Starttzeit auf einem Nexus 5. Da haben sie am falschen Ende auf Kosten der Sicherheit gespart.
Ein Informations-Leck irgendwo kompromittiert dann alle Apps und das System, denn selbst Systemprozesse haben dank Zygote gemeinsame Basisadressen mit normalen User-Programmen. Bei anderen Unix-artigen Systemen werden die Basis-Adressen durch ASLR auch bei jedem erneutem Start desselben Programms neu zufällig vergeben, aber nicht so bei Android. Dank Zygote hat jedes Programm immer wieder bei jedem Start dieselben Adressen. Ein offensichtliches Problem, wenn man doch mit ASLR zufällig Adressen möchte und nicht immer und überall dieselben.
Das bedeutet: Selbst neueste und zukünftige Android-Versionen verraten und verkaufen und kompromittieren ihr eigenes ASLR durch eine Fehlentscheidung in der Anroid-Architektur, die für immer gleiche Adresse sorgt.
Zygote ruiniert nicht nur ASLR, sondern sorgt auch in anderer Hinsicht für Unsicherheit: Zygote läuft unter root und jedes gestartete Programm dann auch erstmal solange bis es per setuid (set user id) einen anderen User bekommt. Android läßt in der Regel jede App unter einem anderen Unix-User laufen als Pseudo-Sandbox-Funktion. Das Starten unter root erlaubt dann die problemlose beliebige Nutzung von setuid, um auf den Ziel-User zu wechseln. Dieser Start unter Root für jedes Programm ließ sich auch schon für Angriffe ausnutzen, wie man in Android Hacker's Handbook nachlesen kann. Dort verweisen sie unter anderem auf den Zimperlich Exploit.
Für weitere Informationen zu ASLR und Zyogote kann ich den Artikel The State of ASLR on Android Lollipop. Investigating the state of ASLR on Android, how Zygote breaks it, and how we fixed it in our ROM empfehlen sowie das Android Hacker's Handbook.
Die Copperhead-Variante von Android beschäftigt sich ausschließlich mit dem Beheben von Fehlern in der Sicherheits-Architektur vom normalen Android. Und das Ausbügeln von Schwächen in der Implementierung von Androids ASLR sind ein Punkt davon.
In neueren Android-Versionen ist Android von Bytecode und dem Just-in-Time-Compiler zu generiertem nativem Code bei Programm-Intallation und der Android Runtime (ART) gewechselt.
Wie bei Copperhead beschrieben wird die zufällige Basis-Adresse für ein Programm und damit auch für den Garbage-Collected-Heap direkt daneben durch einen Code berechnet, der selbst auf 64-Bit-Systemen nur 12-Bit Entropie bietet.
Diese 4096 Möglichkeiten sind albern wenig. Besser wäre es, wenn Android eine kryptographisch besser geeignete Quelle für die zufällige Adresßfestlegung benutzen würde wie arc4random(), was Teil von Bionic ist in Android. Was ART hier jedoch macht, bietet dem Angreifer alles, was er benötigt, um die Kontrolle über den angegriffenen Prozeß (z. B. über die Stagefright-Lücken) zu bekommen, und die Wirksamkeit von ASLR auf Android zu schwächen.
Vor Lollipop benutzte Android nur das gute alte dlmalloc, einen bewährten General Purpose Allocator, der zwar selbst kein Randomisation vornimmt, aber auch nicht die Entropie des Kernels verschlechtert hat. Bei Lollipop wurde ein komprimierender Garbage Collector mit ART eingeführt. Für nicht-bewegliche, ASLR-untaugliche Heap-Objekte, wurde auch weiterhin dlmalloc verwendet und ein separater Heap. Für bessere Performance in Bionic wurde jedoch malloc durch jemalloc ersetzt für bewegliche Heap-Objekte.
Im Gegensatz zu dlmalloc reduziert jemalloc jedoch die Entropie (Zufälligkeit) des Heaps, was ein Seiteneffekt ist, den man sich für die reduzierte Fragmentierung des Speichers eingefangen hat. Je nach Version verliert man hier zwischen 6 und 10 Bit an Entropie.
Selbst in Android-Versionen, die ASLR bieten, ist die Implementierung nicht gut genug. Durch das untypische Design der Android-Plattform, das von traditionellem Unix und GNU/Linux abweicht, wurden viele generelle Probleme eingeführt, die andere Systeme nicht haben. Dadurch wird Androids ASLR, das Exploits wie die gegen Stagefright abmildern könnte, zu stark geschwächt. Google geht diese Sicherheitsprobleme bewußt ein, um mehr Geschwindigkeit herauszuholen und weniger Speicher zu verbrauchen.
Und noch kürzer: Auch Android-Versionen, die volles ASLR haben, sind nicht sicher vor Angriffen, die z. B. durch die Stagefright-Lücken möglich sind.