Hacker
Professional
- Messages
- 1,044
- Reaction score
- 804
- Points
- 113
Extracting card content and working with EMV commands can be interesting for more than just research purposes. There are several types of attacks on contactless bank cards, the implementation of which will be described under the cut.
Introduction
This year I got into the Summer of Hack 2019 internship at Digital Security and worked on the topic of researching contactless EMV cards. During the internship, I got to know better how bank cards work and create a new utility for working with contactless cards. A demonstration of the data reading mode can be found here.
Types of attacks
The card and the terminal communicate using the EMV standard (Europay + MasterCard + VISA), which was developed to improve the security of payments. In this regard, there are not many attack vectors for contactless cards. The article will focus on the following:
Such attacks are possible when interacting with the card according to the EMV standard. Many cards allow you to easily read the user's private information, in particular PAN, expiration date and the name of the holder. The read data is enough to bind a card in some online stores, for example, Amazon. And the obtained private data can be used for more personalized phishing or spamming.
A DoS attack is implemented in a similar way. Calling the necessary EMV commands allows you to overflow the internal transaction counter or simulate an incorrect PIN code entry, which leads to the card blocking.
Why reinvent the wheel?
Before starting the development, it was decided to study the existing solutions. In particular, the following were considered: RFIDIOt / ChAP.py, Jaccal, nfcmillionaire, PoC from conferences, “Ruby” script, Android apps / libs.
Most of the programs reviewed try to simulate the operation of a POS terminal and use dictionaries with the identifiers of the supported cards, so often such solutions will only work with Visa and MasterCard.
Another problem is reading a small piece of data instead of taking a full dump. Almost all programs try to parse as much EMV as possible on the fly and make mistakes when parsing.
If any of the problems is missing or not so pronounced, then most likely we are talking about an application / library for Android, and you will need a phone with an NFC reader, which not everyone has yet.
The described problems can be solved, for this you should:
Extracting data from the card
There are already articles that describe in detail the process of interaction between the card and the terminal, so I will try not to repeat myself and focus on the practical part.
To communicate with the card, we will use the PN532 reader because of the nice price and the libnfc library. Let's get down to business. The data on the map is organized as follows:
Environments -> Applications -> Files -> Records.
The purpose of reading is to get the data of all records, for this you need to go through the full chain, and the choice of the environment and application occurs only once at the beginning of communication.
The same process in terms of EMV commands:
Let's consider an example of forming one of the teams. The first command to select a non-contact environment is always the same and looks like this:
Answer example: 6F 23 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 11 BF 0C 0E 61 0C 4F 07 A0 00 00 00 03 10 10 87 01 01 90 00
To call the next command, we need to parse the answer the previous command.
We are interested in the application identifier AID. We remember it and form a new SELECT query, but this time we pass the received AID to the SELECT command, and not PPSE, as in the first command.
Example: 00 A4 04 00 07 A0 00 00 00 03 10 10 00
As mentioned earlier, it is important to obtain AID dynamically, and not to use a prepared dictionary, then your application will most likely be able to read different types of cards, for example, MIR cards.
After the application is selected, we can read the necessary records using the READ RECORD command and passing the file number and record number as parameters.
An example of forming a command: (for more details, see the standard. EMV Book1. 11.2 READ RECORD)
Example of a call: 00 B2 02 14 00
Note that not a full byte is allocated for the file number, respectively, there can be 31 files in total (2 ^ 5 - 1), but 255 records. Files from 1 to 10 are reserved for storage internal data, and the rest is reserved for storing the transaction log, if the card supports logging.
Now, using two nested loops, we can get the data of all the records in the map by calling READ RECORD for each pair. The enumeration process can be significantly accelerated if you pay attention to the status word returned by the map (the last two bytes of the response). The status can tell us that the file does not exist (SW = 0x6A82) or that there are no further entries in this file (SW = 0x6A83).
In practice, it turned out that it makes sense to consider only the case of a non-existent file, since sometimes there are maps that incorrectly use the status code for missing records. After reading the data, you can send it to one of the online parsers, I liked this one.
Fragment of data extracted from card records:
The data read is enough to bind the card in some online stores (mainly in foreign ones), and the information obtained can be used for a more personalized attack using social engineering.
We organize contactless DoS
Let's move on to the next type of attack. For DoS, there are at least 2 ways to implement it.
Slow way
To implement the slow method (the attack will take about 4 minutes), it is necessary to overflow the internal card transaction counter (ATC). To do this, you need to call:
Let's take a closer look at the steps. The choice of the contactless environment and application is similar to the point with data extraction, the only difference is that this time we need to process the response of the SELECT APPLICATION command.
We are interested in the PDOL field, since it will be needed for the subsequent call of the GET PROCESSING OPTIONS command, which will increment the transaction counter with each call.
In PDOL, the card asks us for information about the terminal and payment.
In the example above, the card asks us for:
Since we are implementing DoS, and not a real payment, we can not worry about the correctness of the values and just use the pre-prepared values that the card will accept. You can read more about the required values in the standard. (EMV Book 3. Annex A Data Elements Dictionary).
For the convenience of practical use, I give a table:
Having formed the data requested by the map, we are ready to call the GPO.
Example: 80 A8 00 00 12 83 10 79 00 40 80 00 00 00 10 00 00 82 3D DE 7A 01 24 00
Answer: 77 4F 82 02 20 00 94 0C 10 02 03 00 18 01 01 00 10 04 04 00 57 13 42 76 55 00 66 83 25 13 D2 00 52 01 14 89 36 20 00 00 1F 5F 20 02 20 2F 9F 10 07 06 01 11 03 80 20 00 9F 6C 02 30 00 9F 26 08 33 33 89 D5 70 A3 DF 37 9F 27 01 00 9F 36 02 02 48 90 00
Repeat the GPO call 65,536 times and the card is blocked. You can reduce the number of calls required by first reading the current ATC value with GET DATA.
Fast way
The fast method is much more convenient (and more dangerous), since it will take about 2 seconds to block the card, so a detailed analysis of the implementation details will remain behind the scenes.
The method is similar to the previous one, but this time it will be necessary to lower the counter of PIN attempts, instead of increasing the counter of transactions. The PIN Try Counter value can also be obtained via GET DATA, but in this case there will be no significant increase in speed.
Required operations:
Outcomes
During the internship, it turned out to create a new tool for working with contactless bank cards and solve several problems present in existing solutions, and the use of a cheap reader significantly reduces the cost of a research kit and can help to attract new people to research the security of contactless bank cards. The source code of the program is available on Github.
Author: cuamckuu
Introduction
This year I got into the Summer of Hack 2019 internship at Digital Security and worked on the topic of researching contactless EMV cards. During the internship, I got to know better how bank cards work and create a new utility for working with contactless cards. A demonstration of the data reading mode can be found here.
Types of attacks
The card and the terminal communicate using the EMV standard (Europay + MasterCard + VISA), which was developed to improve the security of payments. In this regard, there are not many attack vectors for contactless cards. The article will focus on the following:
- Linking someone else's card in the online store
- Auxiliary Step in Social Engineering
- Contactless DoS that turns a card into a brick
Such attacks are possible when interacting with the card according to the EMV standard. Many cards allow you to easily read the user's private information, in particular PAN, expiration date and the name of the holder. The read data is enough to bind a card in some online stores, for example, Amazon. And the obtained private data can be used for more personalized phishing or spamming.
A DoS attack is implemented in a similar way. Calling the necessary EMV commands allows you to overflow the internal transaction counter or simulate an incorrect PIN code entry, which leads to the card blocking.
Why reinvent the wheel?
Before starting the development, it was decided to study the existing solutions. In particular, the following were considered: RFIDIOt / ChAP.py, Jaccal, nfcmillionaire, PoC from conferences, “Ruby” script, Android apps / libs.
Most of the programs reviewed try to simulate the operation of a POS terminal and use dictionaries with the identifiers of the supported cards, so often such solutions will only work with Visa and MasterCard.
Another problem is reading a small piece of data instead of taking a full dump. Almost all programs try to parse as much EMV as possible on the fly and make mistakes when parsing.
If any of the problems is missing or not so pronounced, then most likely we are talking about an application / library for Android, and you will need a phone with an NFC reader, which not everyone has yet.
The described problems can be solved, for this you should:
- Determine map type dynamically, instead of using dictionaries
- Add multiple operating modes for full file reading
- Don't try to parse the EMV standard on the fly
- Use a cheap PN532 reader (~ $ 5)
Extracting data from the card
There are already articles that describe in detail the process of interaction between the card and the terminal, so I will try not to repeat myself and focus on the practical part.
To communicate with the card, we will use the PN532 reader because of the nice price and the libnfc library. Let's get down to business. The data on the map is organized as follows:
Environments -> Applications -> Files -> Records.
The purpose of reading is to get the data of all records, for this you need to go through the full chain, and the choice of the environment and application occurs only once at the beginning of communication.
The same process in terms of EMV commands:
- SELECT PPSE // Choose a contactless environment
- SELECT APPLICATION // Select an application by AID
- READ RECORD // Specify the file and record number
Let's consider an example of forming one of the teams. The first command to select a non-contact environment is always the same and looks like this:
Code:
byte_t const command[] = {
0x40, 0x01, // Pn532 InDataExchange
0x00, 0xA4, // SELECT ppse
0x04, 0x00, // P1:By name, P2:_
0x0e, // Lc: Data length
0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, // Data string:
0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, // 2PAY.SYS.DDF01 (PPSE)
0x00 // Le
};
Answer example: 6F 23 84 0E 32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 A5 11 BF 0C 0E 61 0C 4F 07 A0 00 00 00 03 10 10 87 01 01 90 00
To call the next command, we need to parse the answer the previous command.

We are interested in the application identifier AID. We remember it and form a new SELECT query, but this time we pass the received AID to the SELECT command, and not PPSE, as in the first command.
Example: 00 A4 04 00 07 A0 00 00 00 03 10 10 00
As mentioned earlier, it is important to obtain AID dynamically, and not to use a prepared dictionary, then your application will most likely be able to read different types of cards, for example, MIR cards.
After the application is selected, we can read the necessary records using the READ RECORD command and passing the file number and record number as parameters.
An example of forming a command: (for more details, see the standard. EMV Book1. 11.2 READ RECORD)
Code:
byte_t const sfi_param = (sfi << 3) | (1 << 2);
byte_t const command[] = {
0x40, 0x01, // Pn532 InDataExchange
0x00, 0xB2, // READ RECORD
record_number, sfi_param, // P1:record_number and P2:SFI
0x00 // Le
};
Example of a call: 00 B2 02 14 00
Note that not a full byte is allocated for the file number, respectively, there can be 31 files in total (2 ^ 5 - 1), but 255 records. Files from 1 to 10 are reserved for storage internal data, and the rest is reserved for storing the transaction log, if the card supports logging.
Now, using two nested loops, we can get the data of all the records in the map by calling READ RECORD for each pair. The enumeration process can be significantly accelerated if you pay attention to the status word returned by the map (the last two bytes of the response). The status can tell us that the file does not exist (SW = 0x6A82) or that there are no further entries in this file (SW = 0x6A83).
In practice, it turned out that it makes sense to consider only the case of a non-existent file, since sometimes there are maps that incorrectly use the status code for missing records. After reading the data, you can send it to one of the online parsers, I liked this one.
Fragment of data extracted from card records:

The data read is enough to bind the card in some online stores (mainly in foreign ones), and the information obtained can be used for a more personalized attack using social engineering.
We organize contactless DoS
Let's move on to the next type of attack. For DoS, there are at least 2 ways to implement it.
Slow way
To implement the slow method (the attack will take about 4 minutes), it is necessary to overflow the internal card transaction counter (ATC). To do this, you need to call:
- SELECT PPSE // Choose a contactless environment
- SELECT APPLICATION // Select an application
- GET DATA // Find out how much is left before ATC overflow (Optional)
- GET PROCESSING OPTIONS // Start conducting transactions
- GET PROCESSING OPTIONS // Repeat transactions until overflow
Let's take a closer look at the steps. The choice of the contactless environment and application is similar to the point with data extraction, the only difference is that this time we need to process the response of the SELECT APPLICATION command.

We are interested in the PDOL field, since it will be needed for the subsequent call of the GET PROCESSING OPTIONS command, which will increment the transaction counter with each call.
In PDOL, the card asks us for information about the terminal and payment.
In the example above, the card asks us for:
- 9F66 04 // Terminal transaction qualifier (4 bytes)
- 9F02 06 // Amount (6 bytes)
- 9F37 04 // Unpredictable number (4 bytes)
- 5F2A 02 // Transaction Currency code (2 bytes)
Since we are implementing DoS, and not a real payment, we can not worry about the correctness of the values and just use the pre-prepared values that the card will accept. You can read more about the required values in the standard. (EMV Book 3. Annex A Data Elements Dictionary).
For the convenience of practical use, I give a table:
Tag (Hex) | Description | Valid value (Hex) |
9F59 | Terminal Transaction Information | C8 80 00 |
9F5A | Terminal Transaction Type | 00 |
9F58 | Merchant Type Indicator | 01 |
9F66 | Terminal Transaction Qualifiers | 79 00 40 80 |
9F02 | Amount (authorized) | 00 00 00 10 00 00 |
9F03 | Amount (Other) | 00 00 00 00 00 00 |
9F1A | Terminal Country Code | 01 24 |
5F2A | Transaction Currency Code | 01 24 |
95 | Terminal Verification Results | 00 00 00 00 00 |
9A | Transaction Date | 19 01 01 |
9C | Transaction Type | 00 |
9F37 | Unpredictable Number | 82 3D DE 7A |
Having formed the data requested by the map, we are ready to call the GPO.
Example: 80 A8 00 00 12 83 10 79 00 40 80 00 00 00 10 00 00 82 3D DE 7A 01 24 00
Answer: 77 4F 82 02 20 00 94 0C 10 02 03 00 18 01 01 00 10 04 04 00 57 13 42 76 55 00 66 83 25 13 D2 00 52 01 14 89 36 20 00 00 1F 5F 20 02 20 2F 9F 10 07 06 01 11 03 80 20 00 9F 6C 02 30 00 9F 26 08 33 33 89 D5 70 A3 DF 37 9F 27 01 00 9F 36 02 02 48 90 00
Repeat the GPO call 65,536 times and the card is blocked. You can reduce the number of calls required by first reading the current ATC value with GET DATA.
Fast way
The fast method is much more convenient (and more dangerous), since it will take about 2 seconds to block the card, so a detailed analysis of the implementation details will remain behind the scenes.
The method is similar to the previous one, but this time it will be necessary to lower the counter of PIN attempts, instead of increasing the counter of transactions. The PIN Try Counter value can also be obtained via GET DATA, but in this case there will be no significant increase in speed.
Required operations:
- SELECT PPSE // Choose a contactless environment
- SELECT APPLICATION // Select an application
- GET DATA // Find out how many attempts to enter a PIN there are
- GET PROCESSING OPTIONS // Start a transaction
- VERIFY // And enter the wrong PIN
- VERIFY // Until the card is blocked
Outcomes
During the internship, it turned out to create a new tool for working with contactless bank cards and solve several problems present in existing solutions, and the use of a cheap reader significantly reduces the cost of a research kit and can help to attract new people to research the security of contactless bank cards. The source code of the program is available on Github.
Author: cuamckuu