Read & Fuzz contactless smart cards with HydraNFC v2 (Part 2)

In short, this post explains how to initialize an ISO 14443-A smart card with short or standard frame thanks to the hydra NFC v2 console. Straightforwardly, you will be able to send correct commands or  ill-formed command to fuzz a cardIn a next post, we will see how to initialize an ISO 14443-B smart card and how to build TPDUs commands.

ISO 14443

In a previous post, we saw how to connect automatically to a smart card, and then exchange APDUs commands. But, how to initialize a card and what is the communication protocol used to transmit the APDU? In this post, we will focus on the ISO 14443 norm since most of the banking smart cards use it (as well electronic passport). More especially, we will talk about the initialization of an ISO 14443-A card with the Hydra NFC v2 console.

Within this norm, a card can be the A or the B type. Four parts explain it:

  • ISO 14443 Part 1 & 2.
    • It explains how the signal must be modulated. We won’t talk about it in this post.
  • ISO 14443 Part 3.
    • It defines the initialization sequence which is different between type A & B.
    • It explains how a communication frame must be built.
  • ISO 14443 Part 4. It defines the transmission protocol based on the Transport Data Protocol Unit (TPDU) which is common to type A & B:
    • It details initialization commands for instance when the card indicates its communication capacity (communication speed, block size), and the reader can indicate which one to use.
    • How to exchange data thanks to the TPDUs.

ISO 14443-A Initialization sequence

We connect with picocom (but you could use putty as well).

$ picocom -b 115200 /dev/ttyACM0
Type [C-a] [C-h] to see available commands
Terminal ready

This time, we don’t enter in “nfc” menu, but in “dnfc”.

> dnfc
HydraNFC Shield v2 initialized with success.
Device: SPI2
GPIO resistor: floating
Mode: master
Frequency: 10.50mhz (160khz, 320khz, 650khz, 1.31mhz, 2.62mhz, 5.25mhz, 21mhz)
Polarity: 0
Phase: 1
Bit order: MSB first

If we type “help”, we see there is a lot of commands! This menu can be considered as the low-level command sandbox . Don’t worry, we will not use all the commands!

dnfc2> help
Configuration: spi2 [frequency (value hz/khz/mhz)]
Interaction: [cs-on/cs-off] <read/write (value:repeat)> [exit]
   show           Show DNFCv2 parameters
   frequency      Set SPI Bus frequency
   trigger        Setup DNFCv2 SPI2 trigger
   set-nfc-mode   Set NFC Mode and TX/RX BitRate in kbit/s
   get-nfc-mode   Get NFC Mode
   rf-off-on      Set RF field off/on
   reqa           Send ISO 14443-A REQA
   wupa           Send ISO 14443-A WUPA
   send           Send bytes according to the selected mode
   send-auto      Send bytes according to the selected mode and add the two-bytes CRC
   nfc-transp     Enter NFC Transparent Mode
   nfc-stream     Enter NFC Stream Mode
   read           SPI Read byte (repeat with :<num>)
   hd             SPI Read byte (repeat with :<num>) and print hexdump
   write          SPI Write byte (repeat with :<num>)
   <integer>      SPI Write byte (repeat with :<num>)
   <string>       SPI Write string
   cs-on          SPI Alias for "chip-select on"
   cs-off         SPI Alias for "chip-select off"
   [              SPI Alias for "chip-select on"
   ]              SPI Alias for "chip-select off"
   &              Delay 1 usec (repeat with :<num>)
   %              Delay 1 msec (repeat with :<num>)
   ~              SPI Write a random byte (repeat with :<num>)
   A              Toggle AUX[0](PC4) high
   a              Toggle AUX[0](PC4) low
   @              Read AUX[0](PC4)
   exit           Exit DNFCv2 mode

Let see the “set-nfc-mode” command.

dnfc2> help set-nfc-mode
Set NFC Mode and TX/RX BitRate in kbit/s
   nfc-mode       Set NFC Mode
   nfc-mode-tx_br Set TX BitRate
	BR_106=0, BR_212=1, BR_424=2, BR_848=3, BR_52p97=235, BR_26p48=236, BR_1p66=237
   nfc-mode-rx_br Set RX BitRate
	BR_106=0, BR_212=1, BR_424=2, BR_848=3, BR_52p97=235, BR_26p48=236, BR_1p66=237

We select ISO 14443-A type: the reader will send data with the modulation required by the type A. We keep the default bitrate for transmission and reception.

dnfc2> set-nfc-mode nfc-mode 1
nfc-mode = 1
nfc-mode-tx_br = 0
nfc-mode-rx_br = 0
rfalSetMode OK

We deactivate/activate the RF field to restart our card.

dnfc2> rf-off-on

First, the REQA command is sent to detect a card. It is a short frame meaning only 7 coding bits are sent. To ease your understanding, we will not talk about the “protocol bits” in this post, as the start/stop bits and so on. The REQA value is 0x26.

dnfc2> reqa
04 00

Our card is detected since we receive a response: the Answer To Request, named ATQA!

Anti-collision sequence

Once a card was detected, we must execute an anti-collision sequence to select it: the reader asks the card UID, and then send it back to confirm that it wants to talk with it. Another aim of this sequence is to be able to correctly select a specific card when several cards answered the REQA. We will not cover this case, and consider that only one card was detected.

Now, the communication is based on a standard frame, meaning packet of full bytes (ie 8 bits) are sent. Most of the time, a two-byte Cyclic Redundancy Check error code is added at the end of the data to check their integrity. It is specific to the type A, so we named it CRC_A. It is defined in ISO/IEC 13239. Once again, we make a little approximation about the standard frame, it means we do not take about the start/end bit, as well the parity bit. We just talk about coding bit.

First, we send the Select Cascade Level 1 command:

Select Cascade Level 1 commandThe high nibble 2 means we send 2 bytes. The low nibble means we add 0 bits in the command. For instance, if the value was 23, it means we would send 2*8 + 3 = 11 bits.

We use the send command to communicate them to the card. This command sends only the given bytes according to the selected mode.

dnfc2> send 9320
B9 CC 13 71 17 

We received the first 4 UID bytes of the card.

Card UIDBCC. It corresponds to the xor
of the 4 previous bytes.
B9 CC 13 7117Hum… Nothing, because we do not
display it for the moment :). We will
add an option to display it or not.

Now, we send back a Select Cascade Level 1 command with the UID to indicate that we want to select this card. This time, we must add a CRC_A in the command. To avoid computing yourself the CRC, you can use the send-auto command that will automatically compute and add the CRC according to the selected mode.

Select Cascade Level 1 commandThis time we send
7 bytes (without including the
The card UID + BCCAutomatically

We receive the SAK (Select Acknowledge) indicating the anti-collision sequence is finished.

dnfc2> send-auto 9370B9CC137117
20Not displayed

The third bit of the SAK equals 0: it means we received the full card UID. In fact, it size could be 4, 7 or 10 bytes. In this case, we shall have used Select Cascade Level 2 or 3 commands.

Request for answer to select (RATS)

Ok, so the reader and the card agreed to talk together. Now, the reader can inform the card about its communication preferences with the RATS command. It enables to indicate to the card:

  • the Frame Size for proximity coupling Device Integer (FSDI) (high nibble). This integer indicates the maximum frame size that we’ll be sent by the reader (Frame Size for proximity coupling Device or FSD). It is typically the thing you would like to set to its lowest value, and then send a frame with a bigger value 🙂 .
FSD (in bytes)16243240486496128256RFU
  • the CID. It enables to indicate the channel number. We set it to 0.
Start byteParameterCRC A
E000 (High nibble: FSDI, low nibble CID) Automatically

We send the command.

dnfc2> send-auto E000 
0A 78 80 82 02 20 63 CB A3 A0

The card answers with the Answer to select (ATS) its communication options: its frame size, the presence of specific bytes, communication speed…

0ALength of the full command (this byte included) without the CRC_A
787: Bytes TA1/TB1/TC1 transmitted
8: FSCI. It is like the FDSI but for the card. So, it tells the reader that it can send up to 256 bytes.
80TA1. It indicates the card supported communication speed.
82TB1. It deals with delay between the frames.
02TC1. It indicates if optional byte will be present in the TPDU header.
20 63 CB A3 A0Historical bytes. It can gives other information about the card.
CRC_ANot displayed

Protocol and parameter selection request (PPS)

Finally, the reader can send a PPS to customize the communication speed. We send here a default value where no modification is done (and the speed modification is not implemented in this command).

dnfc2> send-auto D001          

The card acknowledges our parameters. And now, we are ready to send TPDUs!

In fact, all the initialization sequence was done automatically done with the connect command that we saw in the previous post. Do you remember?

> nfc
NFCv2> connect
> 26
< 04 00 
> 93 20 
< B9 CC 13 71 17 
> 93 70 B9 CC 13 71 17 
< 20 
> E0 00 
< 0A 78 80 82 02 20 63 CB A3 A0 
> D0 01 
< D0 
ISO 14443-A card detected.

Another fun fact, the ISO 14443-A norm is used for the electronic passport. If you try to connect twice to your passport for instance with the connect command in the nfc menu, you will see the UID is not the same:

NFCv2> connect
> 26
< 04 00 
> 93 20 
< 08 99 8B 85 9F 
[Line removed...]
NFCv2> connect
> 26
< 04 00 
> 93 20 
< 08 46 13 2C 71 
[Line removed...]

It is weird. First time, the card UID is 99 8B 85 9F, and the second time it is 46 13 2C 71. A card UID is supposed be static, no? Yes, but for anonymity reason, and to prevent tracing someone with its ePassport UID, it is mandatory that the returned value is random.

What next?

We saw that we can perform the initialization sequence of an ISO 14443-A card within the Hydra NFC v2 menu:

  • We can send short frame like the REQA.
  • We can send raw standard frame, with or without the automatic computation of the CRC_A. So, you can send correct frame, or random data to fuzz the card.

In a next post, we will send:

  • How to initialize an ISO 14443-B smartcards.
  • How to build TPDUs.
  • And how to script all these commands with Python.

Leave a Reply