2015-02-16 4 views
19

Ich habe gelesen über Cycript und Cydia Substrate und wie sie für Code-Injection-Angriffe auf eine iOS-App verwendet werden können. Code wie dieser sollte Sie erschrecken, wenn Sie in einer Hochsicherheitsumgebung arbeiten. (Ignorieren Sie die/etc/passwd Teil, man denke nur an die Fähigkeit originalmessage mit crackedMessage zu ersetzen.)Ist Swift anfällig für Code-Injektion?

cy# MS.hookFunction(fopen, function(path, mode) { 
cy>  if (path == "/etc/passwd") 
cy>   path = "/var/passwd-fake"; 
cy>  var file = (*oldf)(path, mode); 
cy>  log.push([path, mode, file]); 
cy>  return file; 
cy> }, oldf) 

ich einen Blog zu lesen (was ich nicht gespeichert haben), die sagte, dass Swift nicht so war anfällig wie Objective-C, da es nicht so dynamisch war. Dann noch einmal, ich habe auch gelesen, dass Sie method swizzling in Swift tun können, so ist es mir nicht klar, ob Swift Schutz gegen Code-Injection-Angriffe bietet.

Ist Swift anfällig für Code-Injection-Angriffe?

Antwort

36

Schließlich gibt es keine Möglichkeit zu verhindern, dass jemand Ihr Programm entführt, wenn Sie es auf seinem Gerät laufen lassen. Es gibt Möglichkeiten, es schwieriger zu machen, aber es gibt keine Möglichkeit, es unmöglich zu machen.

ich diese großen Möglichkeiten der Injektion von Code in eine Anwendung denken:

  • Objective-C-Methoden mit der Laufzeit Swizzling;
  • Swizzling virtueller Swift-Methoden durch Analysieren der ausführbaren Datei und Berechnen der richtigen Bits zum Ändern;
  • Ändern von Anrufzielen;
  • Swizzling importierter Symbole durch Ändern von Stub-Zielen;
  • Verwenden von dyld, um Bibliotheken zwangsweise zu laden oder zu ändern, welche Bibliotheken Ihr Programm lädt;
  • ersetzt die Bibliotheken, gegen die Ihr Programm verknüpft ist.

Und es gibt keinen 100% effektiver Weg, eine diese in einer Umgebung zu verhindern, dass der Benutzer vollständig kontrolliert. Sie sollten entscheiden, ob Sie sich Sorgen machen oder nicht, abhängig von Ihrem Bedrohungsmodell.

Swizzling Objective-C Laufzeit-Verfahren mit dem

Method Swizzling ist eine Technik, in dem Sie die Implementierung eines Verfahrens zur Laufzeit mit beliebigem, verschiedenem Code zu ändern (in der Regel für einen anderen Zweck). Häufige Anwendungsfälle sind das Umgehen von Prüfungen oder das Protokollieren von Parametern.

Das Swizzling in Objective-C war eine große Sache, weil die Laufzeit Metadaten benötigt, die jede Methode und jedes Instanzfeld identifizieren. Ich kenne keine andere Sprache, die mit dem nativen Maschinencode kompiliert wird und so viele Metadaten enthält. Wenn Sie etwas wie -[AccessControl validatePassword:] haben, machen Sie es einfach für die bösen Jungs. Mit method_setImplementation ist dies nur zu betteln.

Da Swift-Klassen von Objective-C-Klassen erben können, ist dies immer noch etwas, worauf Sie achten müssen. Neue Methoden für Klassen, die von einer Objective-C-Klasse erben, werden jedoch nur dann der Objective-C-Laufzeit ausgesetzt, wenn sie das @objc-Attribut besitzen (oder wenn die Klasse selbst das Attribut @objc hat), wodurch die Angriffsfläche im Vergleich zu Objective eingeschränkt wird -C.

Darüber hinaus kann der Swift-Compiler die Objective-C-Laufzeit umgehen, um Swift-Methoden aufzurufen, die nicht mit dynamic markiert wurden, selbst wenn sie mit @objc markiert wurden.Dies bedeutet, dass Swizzling in einigen Fällen nur für Anrufe möglich ist, die über Objective-C versendet werden.

Und natürlich ist es völlig unmöglich, wenn Ihre Klasse oder Methode der Objective-C-Laufzeit nicht ausgesetzt ist.

Swizzling virtuelle Methoden Swift durch die ausführbare Datei Parsen und die richtigen Bits herauszufinden, müssen Sie die Objective-C-Laufzeit-Implementierungen tauschen Methode nicht jedoch

zu ändern. Swift verfügt weiterhin über virtuelle Tabellen für seine virtuellen Methoden und befindet sich seit Februar 2015 im Segment __DATA der ausführbaren Datei. Es ist beschreibbar, also sollte es möglich sein, Swift virtuelle Methoden zu swizzle, wenn Sie die richtigen Bits zum Ändern herausfinden können. Es gibt keine praktische API dafür.

C++ - Klassen können ebenfalls geändert werden, aber Swift-Methoden sind standardmäßig virtuell, die Angriffsfläche ist viel größer. Der Compiler kann Methoden als Optimierung devirtualisieren, wenn er keine Überschreibung findet, sich aber auf Compiler-Optimierungen als Sicherheitsfunktion verlässt.

Standardmäßig sind die implementierten Swift-Executables strip ped. Informationen für nicht-public/open Symbole werden verworfen, und das macht die Identifizierung der Symbole, die Sie ändern möchten, im Vergleich zu Objective-C viel schwieriger. Public/open Symbole werden nicht entfernt, da angenommen wird, dass andere externe Codeclients sie möglicherweise benötigen.

Wenn jedoch jemand herausfindet, welche Funktionsimplementierung er auslagern möchte, muss er lediglich die Adresse der neuen Implementierung in den richtigen virtuellen Tabellensteckplatz schreiben. Sie werden wahrscheinlich ihren eigenen Mach-O-Parser erstellen müssen, aber das ist sicherlich nicht außerhalb der Reichweite der Leute, die Dinge wie Cyclin machen.

Schließlich reduzieren final Methoden dieses Risiko, da der Compiler sie nicht über die Vtable aufrufen muss. Auch struct Methoden sind niemals virtuell.

Ändern Rufzielen

Wenn alles andere fehlschlägt, kann der Angreifer immer noch zu Fuß durch Ihre Maschinencode und ändern Sie die bl oder call Operanden-Befehl, um überall würden sie besser gefällt. Dies ist komplizierter und ziemlich schwer/unmöglich, mit einer automatisierten Methode 100% richtig zu machen, besonders wenn Symbole fehlen, aber jemand, der genug ist, wird es schaffen. Sie entscheiden, ob jemand es irgendwann für Ihre Bewerbung als lohnend empfinden wird.

Dies funktioniert für virtuelle und nicht-virtuelle Methoden. Es ist jedoch extrem schwierig, dies zu tun, wenn der Compiler Inline aufruft.

Swizzling importierte Symbol Symbole durch Ändern Stub Ziele

importierte Symbol, unabhängig von der Sprache geschrieben es wurde und wird und die Sprache aus verwendet wird ist, ist anfällig für Swizzling. Dies liegt daran, dass externe Symbole zur Laufzeit gebunden sind. Wenn Sie eine Funktion aus einer externen Bibliothek verwenden, generiert der Compiler einen Eintrag in einer Nachschlagetabelle. Dies ist ein Beispiel dafür, was ein Aufruf an fopen aussehen könnte, wenn Sie die ausführbare Datei in C-Code zurückgegeben:

FILE* locate_fopen(const char* a, const char* b) { 
    fopen_stub = dyld->locate("fopen"); // find actual fopen and replace stub pointer to it 
    return fopen_stub(a, b); 
} 

FILE* (*fopen_stub)(const char*, const char*) = &locate_fopen; 

int main() { 
    FILE* x = fopen_stub("hello.txt", "r"); 
} 

Der erste Aufruf fopen_stub die tatsächlichen fopen findet und ersetzt die Adresse mit ihm durch fopen_stub hingewiesen.Auf diese Weise muss dyld nicht die Tausenden von externen Symbolen auflösen, die von Ihrem Programm und seinen Bibliotheken verwendet werden, bevor es überhaupt gestartet wird. Dies bedeutet jedoch, dass ein Angreifer fopen_stub durch die Adresse einer Funktion ersetzen kann, die er stattdessen aufrufen möchte. Dies ist, was Ihr CyScript-Beispiel tut.

Kurz von Ihrem eigenen Linker und dynamischen Linker, ist Ihr einziger Schutz gegen diese Art von Angriff, keine geteilten Bibliotheken oder Frameworks zu verwenden. Dies ist keine praktikable Lösung in einer modernen Entwicklungsumgebung, so dass Sie wahrscheinlich damit umgehen müssen.

Es könnte Möglichkeiten geben, sicherzustellen, dass Stubs dorthin gehen, wo Sie sie erwarten, aber es wäre irgendwie flockig, und diese Überprüfungen können immer von einem entschlossenen Angreifer ausgeführt werden nop. Darüber hinaus können Sie diese Überprüfungen nicht einfügen, bevor Sie über gemeinsam genutzte Bibliotheken keine Kontrolle über importierte Symbole haben. Diese Überprüfungen wären ebenfalls nutzlos, wenn der Angreifer sich dazu entschließen würde, die gemeinsam genutzte Bibliothek einfach durch eine zu ersetzen, die sie kontrollieren.

Nebenbei können Launch-Verschlüsse dyld 3 diese Lookup-Tabellen durch vorgebundene Informationen ersetzen. Ich denke nicht, dass Launch-Closures derzeit schreibgeschützt sind, aber es sieht so aus, als könnten sie irgendwann sein. Wenn dies der Fall ist, werden die Swizzling-Symbole schwieriger.

dyld Verwendung zu erzwingen Last Bibliotheken oder zu ändern, die Ihr Programm lädt Bibliotheken

Dyld supports kraft dem Laden von Bibliotheken in der ausführbaren Datei. Diese Funktion kann verwendet werden, um fast jedes importierte Symbol zu ersetzen, das von der ausführbaren Datei verwendet wird. Mag nicht das normale ? Schreiben Sie eine dylib, die es neu definiert!

Dyld wird nicht mit dieser Methode zusammenarbeiten, wenn die ausführbare Datei als eingeschränkt markiert ist. Es gibt three ways diesen Status zu erreichen (suchen Sie nach pruneEnvironmentVariables):

  • das setuid Bit oder dem setgid-Bit für die ausführbare Datei ermöglichen;
  • mit dem Code signiert sein und die Berechtigung "Nur eingeschränkt eingeschränkt" für OS X haben;
  • haben einen Abschnitt namens __restrict in einem Segment namens __RESTRICT.

können Sie erstellen den __restrict Abschnitt und das __RESTRICT Segment mit dem folgenden "Other Linker Flags":

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null 

Beachten Sie, dass alle diese ziemlich leicht zu brechen. Die Bits setuid und setgid sind einfach zu löschen, wenn der Benutzer die Ausführungsumgebung steuert, eine Codesignatur kann leicht entfernt werden, und der Abschnitt oder das Segment muss nur umbenannt werden, um den eingeschränkten Status ebenfalls zu entfernen.

die Bibliotheken austauschen, die Ihr Programm Links gegen

Wenn alles andere fehlschlägt, kann ein Angreifer noch die gemeinsamen Bibliotheken ersetzen, die ausführbare Datei verwendet, um es zu tun, was sie wollen. Du hast keine Kontrolle darüber.

tl; dr

in einer Swift Anwendung Injizieren Code ist schwieriger, als es für eine Objective-C-Anwendung, aber es ist immer noch möglich. Die meisten Methoden, die zum Einfügen von Code verwendet werden können, sind sprachunabhängig. Das bedeutet, dass keine Sprache für mehr Sicherheit sorgt.

Zum größten Teil gibt es nichts, was Sie tun können, um sich davor zu schützen. Solange der Benutzer die Ausführungsumgebung steuert, wird Ihr Code auf seinem System als Gast ausgeführt, und er kann damit fast alles machen, was er möchte.

+0

fantastische Aktualisierung Ihrer ursprünglichen Antwort! Vielen Dank. –

0

Sie sprechen über Code-Injektionen auf jailbroken iOS-Geräten. Ganz einfach: Der Benutzer hat seinen Betriebssystemschutz entfernt, so dass jetzt alles möglich ist. Keine Sicherheit. Wenn der Benutzer diesen Schutz nicht freiwillig entfernt hat, ist es unmöglich, in den Adressraum einer Anwendung zu gelangen.