cuamckuu / nfc-frog

Contactless EMV credit card reader
MIT License
292 stars 52 forks source link

Read in any mode causes segmentation fault #17

Closed liamhays closed 1 year ago

liamhays commented 2 years ago

I am attempting to use nfc-frog to read my own Visa card, and nfc-frog always segfaults no matter what mode it's in:

[Info] NFC reader: microBuilder.eu opened.
[Info] Searching card...
[Info] Searching card...
[Info] Searching card...
[Info] Searching card...
[Info] Searching card...
[Info] Searching card...

error   libnfc.driver.pn532_uart        Application level error detected
[Info] Response from SELECT PPSE: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00...(lots and lots of bytes)...Segmentation fault (core dumped)

I trimmed and line-wrapped the SELECT PPSE data, as it's about 9500 bytes (counted with str.split() in Python). It's also not all zeros, but it starts out with a large zero block. Given the large amount of data, which is different from the handful of bytes that the example video shows, I suspect that some buffer is overflowing and causing the segfault.

It is reading the same data on every attempt, so I think communication with the card is functional. I don't know why the "application level error" is getting printed.

cuamckuu commented 2 years ago

Hi, ensure that you pn532 works propperly. There are useful tools included in libnfc. Try something like nfc-pool or nfc-scan-device with you card first

liamhays commented 2 years ago

My board is definitely working, because running nfc-poll finds the board and the card and identifies it as an ISO 14443A target, then reads the ATQA, UID, and SAK fields. The UID changes on every read.

cuamckuu commented 2 years ago

Don't know how to reproduce it. Any advices are welcomed, also feel free to open PR if you could fix that issue

htodd commented 2 years ago

I can get this to segfault with my Apple Watch. I'm mostly a C programmer so I'm a bit stuck but I'll keep checking.

Edit: Of course after compiling with -g and running the program in gdb, no crash.

Edit2: More info from my end. I'm running this with an SCL3711 on a Raspberry Pi. Reading my VISA card, a proper read gives the sections:

[Info] Response from SELECT PPSE [Info] Response from SELECT APP [Info] Response from GET PROCESSING OPTIONS [Info] Response from READ RECORD from SFI2 record2 [Info] Response from READ RECORD from SFI2 record3 [Info] Response from READ RECORD from SFI2 record4

Messing around with various readers gave me another segfault with the sections:

[Info] Response from SELECT PPSE [Info] Response from SELECT APP [Info] Response from GET PROCESSING OPTIONS

and then 4779 bytes of data until the segmentation fault.

I got things to work again by unplugging and replugging in the SCL3711.

I'm going to see if I can enable core dumps and get it to fail again.

htodd commented 2 years ago

Core was generated by `./nfc-frog full'. Program terminated with signal SIGSEGV, Segmentation fault.

0 0x0000005565573400 in DeviceNFC::execute_command (this=0x7ff08363c0, command=0x7ff0836090 "@\001", size=7,

name=0x559e329380 "READ RECORD from SFI1 record60") at device_nfc.cpp:90

90 std::cout << HEX(ret.data[i]) << " "; (gdb) bt

0 0x0000005565573400 in DeviceNFC::execute_command (this=0x7ff08363c0, command=0x7ff0836090 "@\001", size=7,

name=0x559e329380 "READ RECORD from SFI1 record60") at device_nfc.cpp:90

1 0x0000005565573810 in DeviceNFC::read_record (this=0x7ff08363c0, sfi=1 '\001', record_number=60 '<') at device_nfc.cpp:161

2 0x0000005565571eb0 in brute_device_records (device=..., app=..., mode=full) at main.cpp:26

3 0x00000055655724b4 in main (argc=2, argv=0x7ff0836708) at main.cpp:108

liamhays commented 2 years ago

HEX() is defined in headers/tools.h as

// Macro to print unsigned chars in hexadecimal
#define HEX(c)                                                                 \
    std::hex << std::uppercase << std::setw(2) << std::setfill('0')            \
             << (unsigned int)c << std::dec

The line

std::cout << HEX(ret.data[i]) << " ";

references the local variable ret, which is of type struct APDU. That struct is:

struct APDU {
    size_t size;
    byte_t data[MAX_FRAME_LEN];
};

MAX_FRAME_LEN is 300. As I suspected, it is in fact a buffer overflow.

Increasing MAX_FRAME_LEN to larger values makes no difference. The maximum I tried was 1000000 (one million bytes), and it still segfaulted. I suspect the card is looping over all its data or generating new data at certain intervals.

nfc-frog is actually segfaulting for me with a different backtrace than @htodd's backtrace:

Program received signal SIGSEGV, Segmentation fault.
0x0000555555557e0d in DeviceNFC::execute_command (this=0x7fffffffdce0, command=0x7fffffffdbf0 "@\001", size=22, name=0x55555555d400 "SELECT PPSE") at device_nfc.cpp:90
90                      std::cout << HEX(ret.data[i]) << " ";
(gdb) bt
#0  0x0000555555557e0d in DeviceNFC::execute_command (this=0x7fffffffdce0, command=0x7fffffffdbf0 "@\001", size=22, 
    name=0x55555555d400 "SELECT PPSE") at device_nfc.cpp:90
#1  0x0000555555558541 in DeviceNFC::load_applications_list (this=0x7fffffffdce0) at device_nfc.cpp:176
#2  0x0000555555556c22 in main (argc=2, argv=0x7fffffffdf48) at main.cpp:106

load_applications_list() runs a SELECT PPSE command on the card, then parses the data. That SELECT PPSE command is the one returning the huge amount of data.

cuamckuu commented 2 years ago

This might be helpful: https://github.com/cuamckuu/nfc-frog/issues/11 there were Application level error too

adryd325 commented 2 years ago

I can reproduce (also using a Raspberry Pi). Here's the output with catchsegv of a read of an EMV test card. output.txt

ipopov commented 2 years ago

This method assigns the result of a call to pn53x_transceive to a variable of type size_t: https://github.com/cuamckuu/nfc-frog/blob/9a4699d0c6fa39da01674406002af8d7ebbae61f/device_nfc.cpp#L78-L80.

pn53x_transceive can return -1 in the case when it encounters an error: https://github.com/nfc-tools/libnfc/blob/3df7f25f11499fa788e40c41ee7b45582262c566/libnfc/drivers/pn532_uart.c#L409,L496.

So, the reason for the segfault is that a -1 is being interpreted as a max unsigned size_t.

The NFC Frog code should be changed to handle this error instead of segfaulting.

Now, why are we getting an application error, I'm not quite sure. It's generated here: https://github.com/nfc-tools/libnfc/blob/3df7f25f11499fa788e40c41ee7b45582262c566/libnfc/drivers/pn532_uart.c#L405-L410.

The PN532 manual states

c) Error at application level When the PN532 detects an error at the application level, it sends back the specific “Syntax Error frame” to the host controller (see §6.2.1.5, p: 31). An application level error may be due to one of the following reasons: • Unknown Command Code sent by the host controller in the command frame, • Unexpected frame length, • Incorrect parameters in the command frame.

I ran nfc-frog with LIBNFC_LOG_LEVEL=3 and saw:

debug   libnfc.chip.pn53x       InDataExchange
debug   libnfc.chip.pn53x       No timeout
debug   libnfc.bus.uart TX: 00 00 ff 17 e9 d4 40 01 00 a4 04 00 0e 32 50 41 59 2e 53 59 53 2e 44 44 46 30 31 00 8f 00 
debug   libnfc.bus.uart RX: 00 00 ff 00 ff 00 
debug   libnfc.chip.pn53x       PN53x ACKed
debug   libnfc.bus.uart RX: 00 00 ff 01 ff 
debug   libnfc.bus.uart RX: 7f 81 00 
error   libnfc.driver.pn532_uart        Application level error detected

I assume the PN532 is unhappy with something in the command

00 00 ff 17 e9 d4 40 01 00 a4 04 00 0e 32 50 41 59 2e 53 59 53 2e 44 44 46 30 31 00 8f 00 

which I cannot really parse by hand, as I'm not an expert in this chip; I was hoping to just use the library 🙂.

I'd be very happy if anyone can take this debugging further.

cuamckuu commented 2 years ago

Thanks @ipopov, great work! If you want, feel free to make pull request with fix to be listed in contributors

Ludeco27 commented 1 year ago

I need a programmer, to do track2 nfc simulation of payment in card machine contact me