In my previous post about NFC Contactless Cards, we had a brief introduction mentioning NFC payment methods, and how to implement APDUs commands to generate a connection to obtain basic information.
In this post, I will explain one of the most important attacks against NFC and contactless cards that many malicious attackers implement to obtain critical information. The techniques that I will write about are not limited and could be modified to work against different platforms or brands.
Also this post will try to clarify this debate:
A girl asked a tricky question: “It’s possible to downgrade NFC contactless card info to its plain magstripe info?”
— Salvador Mendoza🇲🇽 (@Netxing) September 22, 2017
In order to figure this out, we should be able to read the records for the SFIs. For reference, let me use the same image & idea from my previous NFC post:
This is the main idea: “You can quickly select an ADF with the Application Identifier (AID). So we obtained the AID from the previous post: Application Identifier(AID = A0000000031010)
Within an ADF(Application Definition Files), you can select AEFs(Application Elementary Files) with the Short File Identifier (SFI).”
This is the tricky part: let’s say that we already have the AID(A0000000031010) which could be a VISA Debit/Credit contactless card; this gives us access to get information from the SFI, but we need to get somehow the “route” or id for the records. With the AID, we can narrow what kind of structure the card has. This changes depending of the card’s manufacturer(Visa, Mastercard, Amex…)
Adam Laurie implements in his library a brute force attack against the files/records:
We have two nested loops: 1..31 and inside 1..256. This means that the card could have 31 SFIs and 256 records inside each SFI. We are talking about 7650 possible combinations!
The read_record function creates a combined APDU command with the data of the two cycles to request data from the card.
When the variable sfi = 1 and p1 = 1:
READ_RECORD = [0x00, 0xb2] //Constant to read records
p2 = (1 << 3) + 4 // p2 = 12
le = 0x00
apdu = READ_RECORD + [p1,p2,le] // apdu = 0x00, 0xb2, 0x01, 0x0c, 0x00
With this APDU command, we are ready to request a record.
This attack with all different combinations could be effective when we do not have any previous information about the card, but in this case, we do. We know that it is a VISA Debit/Credit, and its AID is A0000000031010. So we can narrow our brute force range to do it in seconds. We know that the card is using the Visa payWave technology for contactless cards; as result, we can reduce dramatically our attack.
Peter Fillmore have some specific examples to make brute force attacks depending of the card technology payWave, paypass…: https://github.com/peterfillmore/RFIDIOt
Instead of checking for every combination, Peter knew where each card saves its records:
Peter reduced drastically the search spectrum splitting the code in different files depending on the contactless technology. However, I implemented a different approach: just one file to attack all the “logic” SFIs positions. So let’s grab some information, running a brute forcing attack against processing options in Samsung Pay NFC.
Brute forcing SFIs(Short File Identifier) in less than 5 seconds. Same technique applies for other AIDs pic.twitter.com/2ehDprzWqh
— Salvador Mendoza🇲🇽 (@Netxing) September 14, 2017
Now the question: “It’s possible to downgrade NFC contactless card info to its plain magstripe info?”
I am going to use a Wells Fargo Credit Card to try to answer this question:
Reading the magstripe data with an USB card reader, we can get the track 1(made some modification to keep my card “safe”) but I left the discretionary(last) part of the magstripe:
%BXXXXX24505XXXXXX^GALVAN/SALVADOR M^XXXX201100001010000000816000000?
201 = Service Code
100001010000000816000000 = Original discretionary data
We will try to obtain this data from Wells Fargo Credit Card using the contactless technology with USB ACR122u:
Some of the most important information are the Cardholder Name(5f20) and the Discretionary data(9f1f):
5f20 Cardholder Name(17 bytes): GALVAN/SALVADOR M
9f1f Track 1 Discretionary Data(24 bytes): 100001010000000138000000
Original track 1:
%BXXXXX24505XXXXXX^GALVAN/SALVADOR M^XXXX201100001010000000816000000?
With the new Cardholder/discretionary data, we are just 3 digits away from the original track 1!
%BXXXXX24505XXXXXX^GALVAN/SALVADOR M^XXXX201100001010000000138000000?
So how we can get the original 3 digits?
How the cryptogram plays its role?
We should discuss these questions in a future post.
On the question regarding the track data, there is basically no way you can derive the CVC1 value from the magnetic stripe track 2, by just reading the EMV data (without having the key used to derive both values to begin with).
In terms of the role played by the cryptogram, you can’t derive a valid value by just reading the card data. You would need the key, which you can’t get.
LikeLiked by 1 person