appears to work - using normal mifare sim init

working demo

works

seems to work so far

more cleanup and works

working copy

working, clean one more pass

cleanup continues

back in buisness babyyy

final cleanup before PR I hope
This commit is contained in:
n-hutton 2025-01-20 14:11:14 +00:00
parent 32f06db2e8
commit 3eb0238481
7 changed files with 367 additions and 603 deletions

View file

@ -27,19 +27,13 @@
// /!\ Printing Debug message is disrupting emulation,
// Only use with caution during debugging
// These are the old flags which have changed in master since this fork was created.
// Just a temp fix and not intended to go into master
#define FLAG_4B_UID_IN_DATA_OLD 0x02
#define FLAG_7B_UID_IN_DATA_OLD 0x04
#define FLAG_10B_UID_IN_DATA_OLD 0x08
#define FLAG_UID_IN_EMUL_OLD 0x10
#define FLAG_MF_MINI_OLD 0x80
#define FLAG_MF_1K_OLD 0x100
#define FLAG_MF_2K_OLD 0x200
#define FLAG_MF_4K_OLD 0x400
#define FLAG_FORCED_ATQA 0x800
#define FLAG_FORCED_SAK 0x1000
#define FLAG_CVE21_0430_OLD 0x2000
// indices into responses array copied from mifare sim init:
#define ATQA 0
#define SAK 1
#define SAKuid 2
#define UIDBCC1 3
#define UIDBCC2 8
#define UIDBCC3 13
#include "emvsim.h"
#include <inttypes.h>
@ -48,6 +42,7 @@
#include "BigBuf.h"
#include "string.h"
#include "mifareutil.h"
#include "mifaresim.h"
#include "fpgaloader.h"
#include "proxmark3_arm.h"
#include "protocols.h"
@ -57,322 +52,266 @@
#include "ticks.h"
#include "i2c_direct.h"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
// Hardcoded response to the reader for file not found, plus the checksum
static uint8_t filenotfound[] = {0x02, 0x6a, 0x82, 0x93, 0x2f};
// query and response that inserts PDOL so as to continue process...
static uint8_t fci_query[] = {0x02, 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00, 0x56, 0x3f};
static uint8_t fci_template[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15};
// TLV response for PPSE directory request
static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E };
static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59 };
// The WTX we want to send out... The format:
// 0xf2 is the command
// 0x0e is the time to wait (currently at max)
// The remaining bytes are CRC, precalculated for speed
static uint8_t extend_resp[] = {0xf2, 0x0e, 0x66, 0xb8};
// For reference, we have here the pay1 template we receive from the card, and the pay2 template we send back to the reader
// These can be inspected at https://emvlab.org/tlvutils/
// Note that the pay2 template is coded for visa ps in the UK - other countries may have different templates. Refer:
// https://mstcompany.net/blog/acquiring-emv-transaction-flow-part-3-get-processing-options-with-and-without-pdol
// Specifically, 9F5A: Application Program Identifier: 3108260826 might have to become 31 0840 0840 for USA for example.
// todo: see if this can be read from the card and automatically populated rather than hard coded
//static uint8_t fci_template_pay1[] = {0xff, 0x6f, 0x3b, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x30, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x11, 0x01, 0x01, 0xbf, 0x0c, 0x0b, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x17, 0x48};
static uint8_t fci_template_pay2[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15};
// This is the hardcoded response that a contactless card would respond with when asked to select PPSE.
// It is a TLV structure, and can be seen here:
// https://emvlab.org/tlvutils/?data=6f3e840e325041592e5359532e4444463031a52cbf0c2961274f07a0000000031010500a566973612044656269749f0a080001050100000000bf6304df200180
// The first byte is the class byte, and the payload is followed by 0x9000, which is the success code, and the CRC (precalculated)
static uint8_t pay2_response[] = { 0x03, 0x6f, 0x3e, 0x84, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0xa5, 0x2c, 0xbf, 0x0c, 0x29, 0x61, 0x27, 0x4f, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x63, 0x04, 0xdf, 0x20, 0x01, 0x80, 0x90, 0x00, 0x07, 0x9d};
static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *receivedCmd_copy, uint16_t receivedCmd_len_copy);
// SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf
// ATQA
static uint8_t rATQA_Mini[] = {0x04, 0x00}; // indicate Mifare classic Mini 4Byte UID
static uint8_t rATQA_1k[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID
static uint8_t rATQA_2k[] = {0x04, 0x00}; // indicate Mifare classic 2k 4Byte UID
static uint8_t rATQA_4k[] = {0x02, 0x00}; // indicate Mifare classic 4k 4Byte UID
typedef enum {
STATE_DEFAULT,
SELECT_PAY1,
SELECT_PAY1_AID,
REQUESTING_CARD_PDOL,
GENERATE_AC,
} SystemState;
// SAK
static uint8_t rSAK_Mini = 0x09; // mifare Mini
static uint8_t rSAK_1k = 0x08; // mifare 1k
static uint8_t rSAK_2k = 0x08; // mifare 2k with RATS support
static uint8_t rSAK_4k = 0x18; // mifare 4k
static SystemState currentState = STATE_DEFAULT;
static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level
static uint8_t rUIDBCC1b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level, last 4 bytes
static uint8_t rUIDBCC1b3[] = {0x00, 0x00, 0x00}; // UID 1st cascade level, last 3 bytes
static uint8_t rUIDBCC1b2[] = {0x00, 0x00}; // UID 1st cascade level, last 2 bytes
static uint8_t rUIDBCC1b1[] = {0x00}; // UID 1st cascade level, last byte
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level
static uint8_t rUIDBCC2b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 2st cascade level, last 4 bytes
static uint8_t rUIDBCC2b3[] = {0x00, 0x00, 0x00}; // UID 2st cascade level, last 3 bytes
static uint8_t rUIDBCC2b2[] = {0x00, 0x00}; // UID 2st cascade level, last 2 bytes
static uint8_t rUIDBCC2b1[] = {0x00}; // UID 2st cascade level, last byte
static uint8_t rUIDBCC3[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 3nd cascade level
static uint8_t rUIDBCC3b4[] = {0x00, 0x00, 0x00, 0x00}; // UID 3st cascade level, last 4 bytes
static uint8_t rUIDBCC3b3[] = {0x00, 0x00, 0x00}; // UID 3st cascade level, last 3 bytes
static uint8_t rUIDBCC3b2[] = {0x00, 0x00}; // UID 3st cascade level, last 2 bytes
static uint8_t rUIDBCC3b1[] = {0x00}; // UID 3st cascade level, last byte
// This is the main entry point for the EMV attack, everything before this has just been setup/handshaking.
// In order to meet the timing requirements, as soon as the proxmark sees a command it immediately
// caches the command to process and responds with a WTX
// (waiting time extension). When it get the response to this WTX, it can process the cached command through the I2C interface.
//
// The full flow is:
// 1. Handshake with RATS
// 2. Reader attempts to find out which payment environment the proxmark supports (may start with SELECT OSE for example)
// 3. Reader eventually makes a request for the PAY2 application (select PPSE) (contactless payment)
// 4. We read the PAY1 environment and transform it into PAY2 to respond
// 5. Reader will select AID we responded in step 4
// 6. We get the response from selecting the PAY1 AID and transform it into PAY2 response (fci template)
// - This is important as it contains the PDOL (processing data object list) which specifies the data which is
// signed by the card and sent to the reader to verify the transaction.
// 7. The reader will then issue 'get processing options' which seems to be used here to provide the fields to be signed
// as specified by the PDOL.
// 8. In contactless flow, GPO should at least return the Application Interchange Profile (AIP) and
// Application File Locator (AFL). However, here we return track 2 data, the cryptogram, everything. This completes the transaction.
// 9. To construct this final response, behind the scenes we need to interact with the card to make it think its completing a contact transaction:
// - Request PDOL to prime the card (response not used)
// - Rearrange the GPO data provided into a 'generate AC' command for the card
// - Extract the cryptogram, track 2 data and anything else required
// - Respond. Transaction is complete
void ExecuteEMVSim(uint8_t *receivedCmd, uint16_t receivedCmd_len, uint8_t *receivedCmd_copy, uint16_t receivedCmd_len_copy) {
uint8_t responseToReader[MAX_FRAME_SIZE] = {0x00};
uint16_t responseToReader_len;
static uint8_t rATQA[] = {0x00, 0x00}; // Current ATQA
static uint8_t rSAK[] = {0x00, 0x00, 0x00}; // Current SAK, CRC
static uint8_t rSAKuid[] = {0x04, 0xda, 0x17}; // UID incomplete cascade bit, CRC
// special print me
Dbprintf("\nrecvd from reader:");
Dbhexdump(receivedCmd_len, receivedCmd, false);
Dbprintf("");
// RATS answer for 2K NXP mifare classic (with CRC)
static uint8_t rRATS[] = {0x0c, 0x75, 0x77, 0x80, 0x02, 0xc1, 0x05, 0x2f, 0x2f, 0x01, 0xbc, 0xd6, 0x60, 0xd3};
// use annotate to give some hints about the command
annotate(&receivedCmd[1], receivedCmd_len-1);
//Dbprintf("Annotated: %s", explanation);
*uid_len = 0;
// This is a common request from the reader which we can just immediately respond to since we know we can't
// handle it.
if (receivedCmd[6] == 'O' && receivedCmd[7] == 'S' && receivedCmd[8] == 'E') {
Dbprintf("We saw OSE... ignore it!");
EmSendCmd(filenotfound, sizeof(filenotfound));
return;
}
// By default use 1K tag
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
rSAK[0] = rSAK_1k;
// We want to modify corrupted request
if ((receivedCmd_len > 5 && receivedCmd[0] != 0x03 && receivedCmd[0] != 0x02 && receivedCmd[1] == 0 && receivedCmd[4] == 0) || (receivedCmd[2] == 0xa8)) {
//if (receivedCmd[2] == 0xa8) {
Dbprintf("We saw signing request... modifying it into a generate ac transaction !!!!");
//by default RATS not supported
*rats_len = 0;
*rats = NULL;
currentState = GENERATE_AC;
// -- Determine the UID
// Can be set from emulator memory or incoming data
// Length: 4,7,or 10 bytes
memcpy(receivedCmd, (unsigned char[]){ 0x03, 0x80, 0xae, 0x80, 0x00, 0x1d }, 6);
// Get UID, SAK, ATQA from EMUL
if ((flags & FLAG_UID_IN_EMUL_OLD) == FLAG_UID_IN_EMUL_OLD) {
uint8_t block0[16];
emlGet(block0, 0, 16);
for (int i = 0; i < 29; i++) {
receivedCmd[6 + i] = receivedCmd[12 + i];
}
// If uid size defined, copy only uid from EMUL to use, backward compatibility for 'hf_colin.c', 'hf_mattyrun.c'
if ((flags & (FLAG_4B_UID_IN_DATA_OLD | FLAG_7B_UID_IN_DATA_OLD | FLAG_10B_UID_IN_DATA_OLD)) != 0) {
memcpy(datain, block0, 10); // load 10bytes from EMUL to the datain pointer. to be used below.
} else {
// Check for 4 bytes uid: bcc corrected and single size uid bits in ATQA
if ((block0[0] ^ block0[1] ^ block0[2] ^ block0[3]) == block0[4] && (block0[6] & 0xc0) == 0) {
flags |= FLAG_4B_UID_IN_DATA_OLD;
memcpy(datain, block0, 4);
rSAK[0] = block0[5];
memcpy(rATQA, &block0[6], sizeof(rATQA));
// clear final byte just in case
receivedCmd[35] = 0;
receivedCmd_len = 35 + 3; // Core command is 35, then there is control code and the crc
Dbprintf("\nthe command has now become:");
Dbhexdump(receivedCmd_len, receivedCmd, false);
}
// Seems unlikely
if (receivedCmd_len >= 9 && receivedCmd[6] == '1' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') {
Dbprintf("We saw 1PA... !!!!");
}
// Request more time for 2PAY and respond with a modified 1PAY request. We literally just change the 2 to a 1.
if (receivedCmd_len >= 9 && receivedCmd[6] == '2' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') {
Dbprintf("We saw 2PA... switching it to 1PAY !!!!");
receivedCmd[6] = '1';
currentState = SELECT_PAY1;
}
// We are selecting a short AID - assume it is pay2 aid
if (receivedCmd[2] == 0xA4 && receivedCmd[5] == 0x07) {
Dbprintf("Selecting pay2 AID");
currentState = SELECT_PAY1_AID;
}
static uint8_t rnd_resp[] = {0xb2, 0x67, 0xc7};
if (memcmp(receivedCmd, rnd_resp, sizeof(rnd_resp)) == 0) {
Dbprintf("We saw bad response... !");
return;
}
// We have received the response from a WTX command! Process the cached command at this point.
if (memcmp(receivedCmd, extend_resp, sizeof(extend_resp)) == 0) {
// Special case: if we are about to do a generate AC, we also need to
// make a request for pdol first (and discard response)...
if (receivedCmd_copy[1] == 0x80 && receivedCmd_copy[2] == 0xae) {
Dbprintf("We are about to do a generate AC... we need to request PDOL first...");
uint8_t pdol_request[] = { 0x80, 0xa8, 0x00, 0x00, 0x02, 0x83, 0x00 };
currentState = REQUESTING_CARD_PDOL;
CmdSmartRaw(0xff, &(pdol_request[0]), sizeof(pdol_request), (&responseToReader[0]), &responseToReader_len);
}
// Send the cached command to the card via ISO7816
// This is minus 3 because we don't include the first byte (prepend), plus we don't want to send the
// last two bytes (CRC) to the card.
// On the return, the first class byte must be the same, so it's preserved in responseToReader
CmdSmartRaw(receivedCmd_copy[0], &(receivedCmd_copy[1]), receivedCmd_len_copy - 3, (&responseToReader[0]), &responseToReader_len);
// Print the unadultered response we got from the card here
Dbprintf("The response from the card is ==> :");
Dbhexdump(responseToReader_len, responseToReader, false);
// We have passed the reader's query to the card, but before we return it, we need to check if we need to modify
// the response to 'pretend' to be a PAY2 environment.
// This is always the same response for VISA, the only currently supported card
if (currentState == SELECT_PAY1) {
Dbprintf("We saw a PAY1 response... modifying it to a PAY2 response !!!!");
if (!memcmp(&responseToReader[1], &pay1_response[0], sizeof(pay1_response)) == 0) {
Dbprintf("The response from the card is not a PAY1 response. This is unexpected and probably fatal.");
}
// Check for 7 bytes UID: double size uid bits in ATQA
else if ((block0[8] & 0xc0) == 0x40) {
flags |= FLAG_7B_UID_IN_DATA_OLD;
memcpy(datain, block0, 7);
rSAK[0] = block0[7];
memcpy(rATQA, &block0[8], sizeof(rATQA));
} else {
Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found"));
return false;
if (pay2_response[0] != responseToReader[0]) {
Dbprintf("The first byte of the PAY2 response is different from the request. This is unexpected and probably fatal.");
}
memcpy(responseToReader, &pay2_response[0], sizeof(pay2_response));
responseToReader_len = sizeof(pay2_response);
}
}
if (responseToReader[0] != 0xff && responseToReader[1] == 0x77 && true) {
Dbprintf("we have detected a generate ac response, lets repackage it!!");
Dbhexdump(responseToReader_len, responseToReader, false); // special print
// Tune tag type, if defined directly
// Otherwise use defined by default or extracted from EMUL
if ((flags & FLAG_MF_MINI_OLD) == FLAG_MF_MINI_OLD) {
memcpy(rATQA, rATQA_Mini, sizeof(rATQA));
rSAK[0] = rSAK_Mini;
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare Mini ATQA/SAK");
} else if ((flags & FLAG_MF_1K_OLD) == FLAG_MF_1K_OLD) {
memcpy(rATQA, rATQA_1k, sizeof(rATQA));
rSAK[0] = rSAK_1k;
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK (!!!!)");
} else if ((flags & FLAG_MF_2K_OLD) == FLAG_MF_2K_OLD) {
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
rSAK[0] = rSAK_2k;
*rats = rRATS;
*rats_len = sizeof(rRATS);
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 2K ATQA/SAK with RATS support");
} else if ((flags & FLAG_MF_4K_OLD) == FLAG_MF_4K_OLD) {
memcpy(rATQA, rATQA_4k, sizeof(rATQA));
rSAK[0] = rSAK_4k;
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 4K ATQA/SAK");
}
// 11 and 12 are trans counter.
// 16 to 24 are the cryptogram
// 27 to 34 is issuer application data
Dbprintf("atc: %d %d, cryptogram: %d ", responseToReader[11], responseToReader[12], responseToReader[13]);
// Prepare UID arrays
if ((flags & FLAG_4B_UID_IN_DATA_OLD) == FLAG_4B_UID_IN_DATA_OLD) { // get UID from datain
memcpy(rUIDBCC1, datain, 4);
*uid_len = 4;
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("MifareSimInit - FLAG_4B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_4B_UID_IN_DATA_OLD, flags, rUIDBCC1);
// then, on the template:
// 60 and 61 for counter
// 45 to 53 for cryptogram
// 35 to 42 for issuer application data
uint8_t template[] = { 0x00, 0x77, 0x47, 0x82, 0x02, 0x39, 0x00, 0x57, 0x13, 0x47,
0x62, 0x28, 0x00, 0x05, 0x93, 0x38, 0x64, 0xd2, 0x70, 0x92,
0x01, 0x00, 0x00, 0x01, 0x42, 0x00, 0x00, 0x0f, 0x5f, 0x34,
0x01, 0x00, 0x9f, 0x10, 0x07, 0x06, 0x01, 0x12, 0x03, 0xa0,
0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4,
0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02,
0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04,
0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff};
// save CUID
*cuid = bytes_to_num(rUIDBCC1, 4);
// BCC
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
if (g_dbglevel > DBG_NONE) {
Dbprintf("4B UID: %02x%02x%02x%02x", rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3]);
// do the replacement
template[0] = responseToReader[0]; // class bit 0
template[60] = responseToReader[10];
template[61] = responseToReader[11];
// Copy responseToReader[15..23] to template[45..53]
for (int i = 0; i <= 8; i++) {
template[45 + i] = responseToReader[15 + i];
}
// Copy responseToReader[26..32] to template[35..41]
for (int i = 0; i <= 6; i++) {
template[35 + i] = responseToReader[26 + i];
}
Dbprintf("\nrearranged is: ");
responseToReader_len = sizeof(template);
// We DO NOT add the CRC here, this way we can avoid a million penny payments!
// The CRC is calculated here, but doesn't include the class bit at the beginning, plus
// also obvisously doesn't include the CRC bytes itself.
AddCrc14A(&template[0], responseToReader_len - 2);
responseToReader_len = sizeof(template);
memcpy(responseToReader, &template[0], responseToReader_len);
Dbprintf("\nafter crc rearranged is: ");
Dbhexdump(responseToReader_len, &responseToReader[0], false); // special print
}
// Correct uid size bits in ATQA
rATQA[0] = (rATQA[0] & 0x3f) | 0x00; // single size uid
} else if ((flags & FLAG_7B_UID_IN_DATA_OLD) == FLAG_7B_UID_IN_DATA_OLD) {
memcpy(&rUIDBCC1[1], datain, 3);
memcpy(rUIDBCC2, datain + 3, 4);
*uid_len = 7;
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("MifareSimInit - FLAG_7B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_7B_UID_IN_DATA_OLD, flags, rUIDBCC1);
// save CUID
*cuid = bytes_to_num(rUIDBCC2, 4);
// CascadeTag, CT
rUIDBCC1[0] = MIFARE_SELECT_CT;
// BCC
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
if (g_dbglevel > DBG_NONE) {
Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x",
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3]);
// If we would return a PAY1 fci response, we instead return a PAY2 fci response
//if (responseToReader[1] == fci_template_pay1[1] && true) {
if (currentState == SELECT_PAY1_AID) {
Dbprintf("We saw a PAY1 response... modifying it to a PAY2 response for outgoing !!!!");
memcpy(responseToReader, fci_template_pay2, sizeof(fci_template_pay2));
responseToReader_len = sizeof(fci_template_pay2);
}
// Correct uid size bits in ATQA
rATQA[0] = (rATQA[0] & 0x3f) | 0x40; // double size uid
EmSendCmd(responseToReader, responseToReader_len);
} else if ((flags & FLAG_10B_UID_IN_DATA_OLD) == FLAG_10B_UID_IN_DATA_OLD) {
memcpy(&rUIDBCC1[1], datain, 3);
memcpy(&rUIDBCC2[1], datain + 3, 3);
memcpy(rUIDBCC3, datain + 6, 4);
*uid_len = 10;
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("MifareSimInit - FLAG_10B_UID_IN_DATA_OLD => Get UID from datain: %02X - Flag: %02X - UIDBCC1: %02X", FLAG_10B_UID_IN_DATA_OLD, flags, rUIDBCC1);
// save CUID
*cuid = bytes_to_num(rUIDBCC3, 4);
// CascadeTag, CT
rUIDBCC1[0] = MIFARE_SELECT_CT;
rUIDBCC2[0] = MIFARE_SELECT_CT;
// BCC
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
rUIDBCC3[4] = rUIDBCC3[0] ^ rUIDBCC3[1] ^ rUIDBCC3[2] ^ rUIDBCC3[3];
if (g_dbglevel > DBG_NONE) {
Dbprintf("10B UID: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3],
rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3],
rUIDBCC3[0], rUIDBCC3[1], rUIDBCC3[2], rUIDBCC3[3]
);
}
// Correct uid size bits in ATQA
rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid
} else {
Dbprintf("ERROR: " _RED_("UID size not defined"));
return false;
return;
}
if (flags & FLAG_FORCED_ATQA) {
rATQA[0] = atqa >> 8;
rATQA[1] = atqa & 0xff;
}
if (flags & FLAG_FORCED_SAK) {
rSAK[0] = sak;
}
if (g_dbglevel > DBG_NONE) {
Dbprintf("ATQA : %02X %02X", rATQA[1], rATQA[0]);
Dbprintf("SAK : %02X", rSAK[0]);
}
// clone UIDs for byte-frame anti-collision multiple tag selection procedure
memcpy(rUIDBCC1b4, &rUIDBCC1[1], 4);
memcpy(rUIDBCC1b3, &rUIDBCC1[2], 3);
memcpy(rUIDBCC1b2, &rUIDBCC1[3], 2);
memcpy(rUIDBCC1b1, &rUIDBCC1[4], 1);
if (*uid_len >= 7) {
memcpy(rUIDBCC2b4, &rUIDBCC2[1], 4);
memcpy(rUIDBCC2b3, &rUIDBCC2[2], 3);
memcpy(rUIDBCC2b2, &rUIDBCC2[3], 2);
memcpy(rUIDBCC2b1, &rUIDBCC2[4], 1);
}
if (*uid_len == 10) {
memcpy(rUIDBCC3b4, &rUIDBCC3[1], 4);
memcpy(rUIDBCC3b3, &rUIDBCC3[2], 3);
memcpy(rUIDBCC3b2, &rUIDBCC3[3], 2);
memcpy(rUIDBCC3b1, &rUIDBCC3[4], 1);
}
// Calculate actual CRC
AddCrc14A(rSAK, sizeof(rSAK) - 2);
#define TAG_RESPONSE_COUNT 18
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
{ .response = rSAK, .response_n = sizeof(rSAK) }, //
{ .response = rSAKuid, .response_n = sizeof(rSAKuid) }, //
// Do not reorder. Block used via relative index of rUIDBCC1
{ .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
{ .response = rUIDBCC1b4, .response_n = sizeof(rUIDBCC1b4)},
{ .response = rUIDBCC1b3, .response_n = sizeof(rUIDBCC1b3)},
{ .response = rUIDBCC1b2, .response_n = sizeof(rUIDBCC1b2)},
{ .response = rUIDBCC1b1, .response_n = sizeof(rUIDBCC1b1)},
// Do not reorder. Block used via relative index of rUIDBCC2
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
{ .response = rUIDBCC2b4, .response_n = sizeof(rUIDBCC2b4)},
{ .response = rUIDBCC2b3, .response_n = sizeof(rUIDBCC2b3)},
{ .response = rUIDBCC2b2, .response_n = sizeof(rUIDBCC2b2)},
{ .response = rUIDBCC2b1, .response_n = sizeof(rUIDBCC2b1)},
// Do not reorder. Block used via relative index of rUIDBCC3
{ .response = rUIDBCC3, .response_n = sizeof(rUIDBCC3) }, // Anticollision cascade3 - respond with 3th part of uid
{ .response = rUIDBCC3b4, .response_n = sizeof(rUIDBCC3b4)},
{ .response = rUIDBCC3b3, .response_n = sizeof(rUIDBCC3b3)},
{ .response = rUIDBCC3b2, .response_n = sizeof(rUIDBCC3b2)},
{ .response = rUIDBCC3b1, .response_n = sizeof(rUIDBCC3b1)}
};
// Prepare ("precompile") the responses of the anticollision phase.
// There will be not enough time to do this at the moment the reader sends its REQA or SELECT
// There are 18 predefined responses with a total of 53 bytes data to transmit.
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 53 * 8 data bits, 53 * 1 parity bits, 18 start bits, 18 stop bits, 18 correction bits -> need 571 bytes buffer
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 571
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
// modulation buffer pointer and current buffer free space size
uint8_t *free_buffer_pointer = free_buffer;
size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE;
for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) {
if (prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size) == false) {
Dbprintf("Not enough modulation buffer size, exit after %d elements", i);
return false;
}
}
*responses = responses_init;
// indices into responses array:
#define ATQA 0
#define SAK 1
#define SAKuid 2
#define UIDBCC1 3
#define UIDBCC2 8
#define UIDBCC3 13
return true;
// Send a request for more time, and cache the command we want to process
EmSendCmd(extend_resp, 4);
}
/**
*xxxxxxxxxxxxxxxxxx.
* EMVsim - simulate an EMV contactless card transaction by
*
*@param flags :
*@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ...
*@param flags: See pm3_cmd.h for the full definitions
*@param exitAfterNReads, exit simulation after n transactions (default 1)
*@param uid, UID - must be length 7
*@param atqa, override for ATQA, flags indicate if this is used
*@param sak, override for SAK, flags indicate if this is used
* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted)
*/
void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak) {
void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t atqa, uint8_t sak) {
tag_response_info_t *responses;
uint8_t cardSTATE = MFEMUL_NOFIELD;
uint8_t uid_len = 0; // 4, 7, 10
uint32_t cuid = 0, authTimer = 0;
uint32_t nr, ar;
uint8_t uid_len = 0; // 7
uint32_t cuid = 0;
uint8_t cardWRBL = 0;
uint8_t cardAUTHSC = 0;
uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication
uint32_t cardRr = 0;
uint32_t ans = 0;
uint32_t cardINTREG = 0;
uint8_t cardINTBLOCK = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
//uint32_t numReads = 0; //Counts numer of times reader reads a block
uint8_t receivedCmd[MAX_FRAME_SIZE] = {0x00};
uint8_t receivedCmd_copy[MAX_FRAME_SIZE] = {0x00};
uint8_t receivedCmd_dec[MAX_FRAME_SIZE] = {0x00};
//uint8_t convenient_buffer[64] = {0x00};
uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE] = {0x00};
uint8_t responseToReader[MAX_FRAME_SIZE] = {0x00};
uint16_t responseToReader_len;
uint16_t receivedCmd_len;
uint16_t receivedCmd_len_copy = 0;
@ -383,34 +322,28 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
uint8_t *rats = NULL;
uint8_t rats_len = 0;
// if fct is called with NULL we need to assign some memory since this pointer is passaed around
uint8_t datain_tmp[10] = {0};
if (datain == NULL) {
datain = datain_tmp;
// if fct is called with NULL we need to assign some memory since this pointer is passed around
uint8_t uid_tmp[10] = {0};
if (uid == NULL) {
uid = uid_tmp;
}
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
// This will be used in the reader-only attack.
//allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys
#define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7)
nonces_t ar_nr_resp[ATTACK_KEY_COUNT * 2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes
memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
uint8_t ar_nr_collected[ATTACK_KEY_COUNT * 2]; // *2 for 2nd attack type (moebius)
memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
bool gettingMoebius = false;
const tUart14a *uart = GetUart14a();
// free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM();
if (MifareSimInit(flags, datain, atqa, sak, &responses, &cuid, &uid_len, &rats, &rats_len) == false) {
// Print all arguments going into mifare sim init
Dbprintf("EMVsim: flags: %04x, uid: %p, atqa: %04x, sak: %02x", flags, uid, atqa, sak);
if (MifareSimInit(flags, uid, atqa, sak, &responses, &cuid, &uid_len, &rats, &rats_len) == false) {
BigBuf_free_keep_EM();
return;
}
// Print all the outputs after the sim init
Dbprintf("EMVsim: cuid: %08x, uid_len: %d, rats: %p, rats_len: %d", cuid, uid_len, rats, rats_len);
// We need to listen to the high-frequency, peak-detected path.
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
@ -420,8 +353,6 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
LED_D_ON();
ResetSspClk();
uint8_t *p_em = BigBuf_get_EM_addr();
int counter = 0;
bool finished = false;
bool button_pushed = BUTTON_PRESS();
@ -445,9 +376,6 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
int res = EmGetCmd(receivedCmd, sizeof(receivedCmd), &receivedCmd_len, receivedCmd_par);
if (res == 2) { //Field is off!
if ((flags & FLAG_CVE21_0430_OLD) == FLAG_CVE21_0430_OLD) {
p_em[1] = 0x21;
}
LEDsoff();
if (cardSTATE != MFEMUL_NOFIELD) {
Dbprintf("cardSTATE = MFEMUL_NOFIELD");
@ -600,17 +528,17 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
break;
}
memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len);
// all commands must have a valid CRC
if (!CheckCrc14A(receivedCmd_dec, receivedCmd_len)) {
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd_dec, receivedCmd_len);
if (!CheckCrc14A(receivedCmd, receivedCmd_len)) {
if (g_dbglevel >= DBG_EXTENDED)
Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd,
receivedCmd_len);
break;
}
// rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued
// BUT... ACK --> NACK
if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) {
if (receivedCmd_len == 1 && receivedCmd[0] == CARD_ACK) {
Dbprintf("[MFEMUL_WORK] ACK --> NACK !!");
EmSend4bit(CARD_NACK_NA);
FpgaDisableTracing();
@ -618,7 +546,7 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
}
// rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK)
if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) {
if (receivedCmd_len == 1 && receivedCmd[0] == CARD_NACK_NA) {
Dbprintf("[MFEMUL_WORK] NACK --> NACK !!");
EmSend4bit(CARD_ACK);
FpgaDisableTracing();
@ -626,7 +554,7 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
}
// case MFEMUL_WORK => CMD RATS
if (receivedCmd_len == 4 && receivedCmd_dec[0] == ISO14443A_CMD_RATS && receivedCmd_dec[1] == 0x80) {
if (receivedCmd_len == 4 && receivedCmd[0] == ISO14443A_CMD_RATS && receivedCmd[1] == 0x80) {
if (rats && rats_len) {
EmSendCmd(rats, rats_len);
FpgaDisableTracing();
@ -641,9 +569,9 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
}
// case MFEMUL_WORK => ISO14443A_CMD_NXP_DESELECT
if (receivedCmd_len == 3 && receivedCmd_dec[0] == ISO14443A_CMD_NXP_DESELECT) {
if (receivedCmd_len == 3 && receivedCmd[0] == ISO14443A_CMD_NXP_DESELECT) {
if (rats && rats_len) {
EmSendCmd(receivedCmd_dec, receivedCmd_len);
EmSendCmd(receivedCmd, receivedCmd_len);
FpgaDisableTracing();
if (g_dbglevel >= DBG_EXTENDED)
@ -658,111 +586,12 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
break;
}
// The WTX we want to send out...
//static uint8_t extend_resp[] = {0xf2, 0x01, 0x91, 0x40};
//static uint8_t extend_resp[] = {0xf2, 0x02, 0x0a, 0x72};
//static uint8_t extend_resp[] = {0xf2, 0x03, 0x83, 0x63};
//static uint8_t extend_resp[] = {0xf2, 0x04, 0x3c, 0x17};
//static uint8_t extend_resp[] = {0xf2, 0x05, 0x50, 0x6b};
//static uint8_t extend_resp[] = {0xf2, 0x06, 0x2e, 0x34};
//static uint8_t extend_resp[] = {0xf2, 0x07, 0xa7, 0x25};
//static uint8_t extend_resp[] = {0xf2, 0x08, 0x50, 0xdd}; // This works
//static uint8_t extend_resp[] = {0xf2, 0x09, 0xd9, 0xcc};
//static uint8_t extend_resp[] = {0xf2, 0x0a, 0x42, 0xfe};
//static uint8_t extend_resp[] = {0xf2, 0x0b, 0xcb, 0xef};
//static uint8_t extend_resp[] = {0xf2, 0x0c, 0x74, 0x9b};
//static uint8_t extend_resp[] = {0xf2, 0x0d, 0xfd, 0x8a};
static uint8_t extend_resp[] = {0xf2, 0x0e, 0x66, 0xb8};
// special print me
Dbprintf("\nrecvd from reader:");
Dbhexdump(receivedCmd_len, receivedCmd, false);
Dbprintf("");
// From this point onwards is where the 'magic' happens
ExecuteEMVSim(receivedCmd, receivedCmd_len, receivedCmd_copy, receivedCmd_len_copy);
// lets handle some obvious stuff here!
if (receivedCmd[6] == 'O' && receivedCmd[7] == 'S' && receivedCmd[8] == 'E') {
Dbprintf("We saw OSE... ignore it!");
//Full: 02 6a 82 93 2f
EmSendCmd(filenotfound, 5);
continue;
}
// rather than asing for more time, lets just send the response with the PDOL there too
// there are two of this for some reason?? Ach, this one is not at the card read level, that is why.
if (memcmp(&fci_query[0], receivedCmd, sizeof(fci_query)) == 0 && false) {
Dbprintf("***** returning fast FCI response...!");
//uint8_t modified_response[] = { 0x03, 0x77, 0x0e, 0x82, 0x02, 0x39, 0x80, 0x94, 0x08, 0x18, 0x01, 0x02, 0x01, 0x20, 0x01, 0x04, 0x00, 0x90, 0x00, 0x03, 0xec };
//uint8_t modified_response[] = { 0x03, 0x77, 0x0e, 0x82, 0x02, 0x39, 0x80, 0x94, 0x08, 0x18, 0x01, 0x02, 0x01, 0x20, 0x01, 0x04, 0x00, 0x90, 0x00, 0x03, 0xec };
EmSendCmd(&fci_template[0], sizeof(fci_template));
continue;
}
// We want to modify corrupted request
if ((receivedCmd_len > 5 && receivedCmd[0] != 0x03 && receivedCmd[0] != 0x02 && receivedCmd[1] == 0 && receivedCmd[4] == 0) || (receivedCmd[2] == 0xa8)) {
//if (receivedCmd[2] == 0xa8) {
Dbprintf("We saw signing request... modifying it into a generate ac transaction !!!!");
receivedCmd[0] = 0x03;
receivedCmd[1] = 0x80;
receivedCmd[2] = 0xae;
receivedCmd[3] = 0x80;
receivedCmd[4] = 0x00;
receivedCmd[5] = 0x1d;
for (int i = 0; i < 29; i++) {
receivedCmd[6 + i] = receivedCmd[12 + i];
}
// clear final byte just in case
receivedCmd[35] = 0;
receivedCmd_len = 35 + 3; // Core command is 35, then there is control code and hte crc
Dbprintf("\nthe command has now become:");
Dbhexdump(receivedCmd_len, receivedCmd, false);
}
// Seems unlikely
if (receivedCmd_len >= 9 && receivedCmd[6] == '1' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') {
Dbprintf("We saw 1PA... !!!!");
}
// Request more time for 2PAY and respond with a modified 1PAY request
if (receivedCmd_len >= 9 && receivedCmd[6] == '2' && receivedCmd[7] == 'P' && receivedCmd[8] == 'A') {
Dbprintf("We saw 2PA... switching it to 1PAY !!!!");
receivedCmd[6] = '1';
}
static uint8_t rnd_resp[] = {0xb2, 0x67, 0xc7};
if (memcmp(receivedCmd, rnd_resp, sizeof(rnd_resp)) == 0) {
Dbprintf("We saw bad response... !");
continue;
}
// We have received the response from a WTX command! Process the cached command at this point.
if (memcmp(receivedCmd, extend_resp, sizeof(extend_resp)) == 0) {
// Special case: if we are about to do a generate AC, we also need to
// make a request for pdol...
if (receivedCmd_copy[1] == 0x80 && receivedCmd_copy[2] == 0xae) {
Dbprintf("We are about to do a generate AC... we need to request PDOL first...");
uint8_t pdol_request[] = { 0x80, 0xa8, 0x00, 0x00, 0x02, 0x83, 0x00 };
CmdSmartRaw(0xff, &(pdol_request[0]), sizeof(pdol_request), (&responseToReader[0]), &responseToReader_len);
}
// This is minus 3 because we don't include the first byte (prepend), plus we don't want to send the
// last two bytes (CRC) to the card
CmdSmartRaw(receivedCmd_copy[0], &(receivedCmd_copy[1]), receivedCmd_len_copy - 3, (&responseToReader[0]), &responseToReader_len);
EmSendCmd(responseToReader, responseToReader_len);
Dbprintf("Sent delayed command to card...");
continue;
}
// Send a request for more time, and cache the command we want to process
EmSendCmd(extend_resp, 4);
// copy the command and its length (minus 1???)
// We want to keep a copy of the command we just saw, because we will process it once we get the
// WTX response
Dbprintf("Caching command for later processing... its length is %d", receivedCmd_len);
memcpy(receivedCmd_copy, receivedCmd, receivedCmd_len);
receivedCmd_len_copy = receivedCmd_len;
@ -785,3 +614,71 @@ void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t a
set_tracing(false);
BigBuf_free_keep_EM();
}
// annotate iso 7816
void annotate(uint8_t *cmd, uint8_t cmdsize) {
if (cmdsize < 2) {
return;
}
// From https://mvallim.github.io/emv-qrcode/docs/EMV_v4.3_Book_3_Application_Specification_20120607062110791.pdf
// section 6.3.2
switch (cmd[1]) {
case ISO7816_APPLICATION_BLOCK: {
Dbprintf("APPLICATION BLOCK");
break;
}
case ISO7816_APPLICATION_UNBLOCK: {
Dbprintf("APPLICATION UNBLOCK");
break;
}
case ISO7816_CARD_BLOCK: {
Dbprintf("CARD BLOCK");
break;
}
case ISO7816_EXTERNAL_AUTHENTICATION: {
Dbprintf("EXTERNAL AUTHENTICATE");
break;
}
case ISO7816_GENERATE_APPLICATION_CRYPTOGRAM: {
Dbprintf("GENERATE APPLICATION CRYPTOGRAM");
break;
}
case ISO7816_GET_CHALLENGE: {
Dbprintf("GET CHALLENGE");
break;
}
case ISO7816_GET_DATA: {
Dbprintf("GET DATA");
break;
}
case ISO7816_GET_PROCESSING_OPTIONS: {
Dbprintf("GET PROCESSING OPTIONS");
break;
}
case ISO7816_INTERNAL_AUTHENTICATION: {
Dbprintf("INTERNAL AUTHENTICATION");
break;
}
case ISO7816_PIN_CHANGE: {
Dbprintf("PIN CHANGE");
break;
}
case ISO7816_READ_RECORDS: {
Dbprintf("READ RECORDS");
break;
}
case ISO7816_SELECT_FILE: {
Dbprintf("SELECT FILE");
break;
}
case ISO7816_VERIFY: {
Dbprintf("VERIFY");
break;
}
default: {
Dbprintf("NOT RECOGNISED");
break;
}
}
}

View file

@ -25,5 +25,6 @@
#define AUTHKEYNONE 0xff
void EMVsim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak);
void annotate(uint8_t *cmd, uint8_t cmdsize);
#endif

View file

@ -36,11 +36,6 @@
#include "i2c.h"
#include "i2c_direct.h"
static uint8_t fci_template[] = {0x02, 0x6f, 0x5e, 0x84, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0xa5, 0x53, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x38, 0x18, 0x9f, 0x66, 0x04, 0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03, 0x9c, 0x01, 0x9f, 0x37, 0x04, 0x5f, 0x2d, 0x02, 0x65, 0x6e, 0x9f, 0x11, 0x01, 0x01, 0x9f, 0x12, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0xbf, 0x0c, 0x13, 0x9f, 0x5a, 0x05, 0x31, 0x08, 0x26, 0x08, 0x26, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0xd8, 0x15};
static uint8_t pay1_response[] = { 0x6F, 0x1E, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59 };
static uint8_t pay2_response[] = { 0x03, 0x6f, 0x3e, 0x84, 0x0e, 0x32, 0x50, 0x41, 0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44, 0x46, 0x30, 0x31, 0xa5, 0x2c, 0xbf, 0x0c, 0x29, 0x61, 0x27, 0x4f, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x50, 0x0a, 0x56, 0x69, 0x73, 0x61, 0x20, 0x44, 0x65, 0x62, 0x69, 0x74, 0x9f, 0x0a, 0x08, 0x00, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x63, 0x04, 0xdf, 0x20, 0x01, 0x80, 0x90, 0x00, 0x07, 0x9d};
static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint8_t *output, uint16_t *olen) {
LED_D_ON();
@ -50,9 +45,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
// check if alloacted...
smartcard_command_t flags = p->flags;
//if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
//clear_trace();
if ((flags & SC_LOG) == SC_LOG)
set_tracing(true);
else
@ -65,10 +57,9 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
if ((flags & SC_SELECT) == SC_SELECT) {
smart_card_atr_t card;
bool gotATR = GetATR(&card, true);
//reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
if (gotATR == false) {
Dbprintf("No ATR received...\n");
//reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
goto OUT;
}
}
@ -92,8 +83,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
);
if (res == false && g_dbglevel > 3) {
//DbpString(I2C_ERROR);
//reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
Dbprintf("SmartCardDirectSend: I2C_BufferWrite failed\n");
goto OUT;
}
@ -109,11 +98,8 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
}
if (len == 2 && resp[1] == 0x61) {
//Dbprintf("Data to be read: len = %d\n", len);
//Dbprintf("\n");
uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, resp[2]};
//smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + sizeof(cmd_getresp));
payload->flags = SC_RAW | SC_LOG;
payload->len = sizeof(cmd_getresp);
@ -129,8 +115,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
resp[2] = 0x82;
AddCrc14A(resp, 3);
//Dbhexdump(5, &resp[0], false); // special print
//EmSendCmd(&resp[0], 5);
memcpy(output, resp, 5);
*olen = 5;
}
@ -142,9 +126,6 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
resp[2] = 0x82;
AddCrc14A(resp, 3);
//Dbhexdump(5, &resp[0], false); // special print
//EmSendCmd14443aRaw(&resp[0], 5);
//EmSendCmd(&resp[0], 5);
memcpy(output, resp, 5);
*olen = 5;
FpgaDisableTracing();
@ -154,108 +135,23 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
Dbprintf("***** sending it over the wire... len: %d =>\n", len);
resp[1] = prepend;
// if we have a generate AC request, lets extract the data and populate the template
if (resp[1] != 0xff && resp[2] == 0x77) {
Dbprintf("we have detected a generate ac response, lets repackage it!");
Dbhexdump(len, &resp[1], false); // special print
// 11 and 12 are trans counter.
// 16 to 24 are the cryptogram
// 27 to 34 is issuer application data
Dbprintf("atc: %d %d, cryptogram: %d ", resp[11], resp[12], resp[13]);
// then, on the template:
// 61 and 62 for counter
// 46 to 54 for cryptogram
// 36 to 43 for issuer application data
uint8_t template[] = { 0x00, 0x00, 0x77, 0x47, 0x82, 0x02, 0x39, 0x00, 0x57, 0x13, 0x47, 0x62, 0x28, 0x00, 0x05, 0x93, 0x38, 0x64, 0xd2, 0x70, 0x92, 0x01, 0x00, 0x00, 0x01, 0x42, 0x00, 0x00, 0x0f, 0x5f, 0x34, 0x01, 0x00, 0x9f, 0x10, 0x07, 0x06, 0x01, 0x12, 0x03, 0xa0, 0x20, 0x00, 0x9f, 0x26, 0x08, 0x56, 0xcb, 0x4e, 0xe1, 0xa4, 0xef, 0xac, 0x74, 0x9f, 0x27, 0x01, 0x80, 0x9f, 0x36, 0x02, 0x00, 0x07, 0x9f, 0x6c, 0x02, 0x3e, 0x00, 0x9f, 0x6e, 0x04, 0x20, 0x70, 0x00, 0x00, 0x90, 0x00, 0xff, 0xff};
// do the replacement
template[1] = resp[1]; // class bit
template[61] = resp[11];
template[62] = resp[12];
template[46] = resp[16];
template[47] = resp[17];
template[48] = resp[18];
template[49] = resp[19];
template[50] = resp[20];
template[51] = resp[21];
template[52] = resp[22];
template[53] = resp[23];
template[54] = resp[24];
template[36] = resp[27];
template[37] = resp[28];
template[38] = resp[29];
template[39] = resp[30];
template[40] = resp[31];
template[41] = resp[32];
template[42] = resp[33];
Dbprintf("\nrearranged is: ");
len = sizeof(template);
Dbhexdump(len, &template[0], false); // special print
AddCrc14A(&template[1], len - 3);
Dbprintf("\nafter crc rearranged is: ");
Dbhexdump(len, &template[0], false); // special print
Dbprintf("\n");
//EmSendCmd(&template[1], len-1);
memcpy(output, &template[1], len - 1);
*olen = len - 1;
BigBuf_free();
return;
}
//Dbhexdump(len, &resp[1], false); // special print
AddCrc14A(&resp[1], len);
Dbhexdump(len + 2, &resp[1], false); // special print
// Check we don't want to modify the response (application profile response)
//uint8_t modifyme[] = {0x03, 0x77, 0x0e, 0x82, 0x02};
Dbhexdump(len + 2, &resp[1], false);
BigBuf_free();
if (prepend == 0xff) {
Dbprintf("pdol request, we can can the response...");
Dbprintf("pdol request, we can ignore the response...");
return;
}
if (memcmp(&resp[2], &pay1_response[0], sizeof(pay1_response)) == 0 && true) {
Dbprintf("Switching out the pay1 response for a pay2 response...");
//EmSendCmd(&pay2_response[0], sizeof(pay2_response));
memcpy(output, &pay2_response[0], sizeof(pay2_response));
*olen = sizeof(pay2_response);
} else if (memcmp(&resp[1], &fci_template[0], 2) == 0 && true) {
Dbprintf("***** modifying response to have full fci template...!");
//EmSendCmd(&fci_template[0], sizeof(fci_template));
memcpy(output, &fci_template[0], sizeof(fci_template));
*olen = sizeof(fci_template);
} else {
//Dbprintf("***** not modifying response...");
//EmSendCmd(&resp[1], len + 2);
memcpy(output, &resp[1], len + 2);
*olen = len + 2;
}
memcpy(output, &resp[1], len + 2);
*olen = len + 2;
BigBuf_free();
//memcpy(saved_command, &resp[1], len+2);
//saved_command_len = len+2;
//EmSendCmd14443aRaw(&resp[1], len+2);
//FpgaDisableTracing();
//EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
}
//reply_ng(CMD_SMART_RAW, PM3_SUCCESS, resp, len);
OUT:
//BigBuf_free();
//set_tracing(false);
LEDsoff();
}
@ -269,7 +165,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
dlen = data[4] + 5;
}
//smart_card_raw_t *payload = calloc(1, sizeof(smart_card_raw_t) + dlen);
smart_card_raw_t *payload = (smart_card_raw_t *)BigBuf_calloc(sizeof(smart_card_raw_t) + dlen);
if (payload == NULL) {
Dbprintf("failed to allocate memory");
@ -285,7 +180,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
bool use_t0 = true;
if (active || active_select) {
payload->flags |= (SC_CONNECT | SC_CLEARLOG);
if (active_select)
payload->flags |= SC_SELECT;
@ -296,7 +190,6 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
payload->flags |= SC_WAIT;
payload->wait_delay = timeout;
}
//Dbprintf("SIM Card timeout... %u ms", payload->wait_delay);
if (dlen > 0) {
if (use_t0)
@ -305,66 +198,7 @@ int CmdSmartRaw(const uint8_t prepend, const uint8_t *data, int dlen, uint8_t *o
payload->flags |= SC_RAW;
}
////uint8_t *buf = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
//uint8_t *buf = BigBuf_calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
//if (buf == NULL) {
// Dbprintf("failed to allocate memory");
// free(payload);
// return PM3_EMALLOC;
//}
//clearCommandBuffer();
//SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen);
//for (int i = 0; i < dlen; i++) {
// Dbprintf("%02x ", data[i]);
//}
SmartCardDirectSend(prepend, payload, output, olen);
//if (reply == false) {
// Dbprintf("failed to talk to smart card!!!");
// goto out;
//}
//// reading response from smart card
//int len = smart_response(buf, PM3_CMD_DATA_SIZE);
//if (len < 0) {
// free(payload);
// free(buf);
// return PM3_ESOFT;
//}
//if (buf[0] == 0x6C) {
// // request more bytes to download
// data[4] = buf[1];
// memcpy(payload->data, data, dlen);
// clearCommandBuffer();
// SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + dlen);
// len = smart_response(buf, PM3_CMD_DATA_SIZE);
// data[4] = 0;
//}
//if (decode_tlv && len > 4) {
// TLVPrintFromBuffer(buf, len - 2);
//} else {
// if (len > 2) {
// Dbprintf("Response data:");
// Dbprintf(" # | bytes | ascii");
// Dbprintf("---+-------------------------------------------------+-----------------");
// print_hex_break(buf, len, 16);
// }
//}
//memcpy(buffer, buf, len);
//out:
//free(payload);
//free(buf);
return PM3_SUCCESS;
}

View file

@ -198,7 +198,8 @@ static uint8_t MifareMaxSector(uint16_t flags) {
}
}
static bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
bool MifareSimInit (uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
//static bool MifareSimInitX(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len) {
uint8_t uid_tmp[10] = {0};
// SPEC: https://www.nxp.com/docs/en/application-note/AN10833.pdf
@ -293,6 +294,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t s
rSAK[0] = rSAK_1k;
if (g_dbglevel > DBG_NONE) Dbprintf("Enforcing Mifare 1K ATQA/SAK");
} else if (IS_FLAG_MF_SIZE(flags, MIFARE_2K_MAX_BYTES)) {
Dbprintf("We got this to happen!!!\n");
memcpy(rATQA, rATQA_2k, sizeof(rATQA));
rSAK[0] = rSAK_2k;
*rats = rRATS;

View file

@ -21,6 +21,7 @@
#define __MIFARESIM_H
#include "common.h"
#include "mifare.h"
#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
@ -42,5 +43,6 @@
#define AUTHKEYNONE 0xff
void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t atqa, uint8_t sak);
bool MifareSimInit(uint16_t flags, uint8_t *uid, uint16_t atqa, uint8_t sak, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t **rats, uint8_t *rats_len);
#endif

View file

@ -643,21 +643,21 @@ static int CmdEMVSmartToNFC(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int uid_len = 0;
int uidlen = 0;
uint8_t uid[7] = {0};
CLIGetHexWithReturn(ctx, 2, uid, &uid_len);
CLIGetHexWithReturn(ctx, 2, uid, &uidlen);
if (uid_len == 0) {
if (uidlen == 0) {
PrintAndLogEx(SUCCESS, "No UID provided, using default.");
uint8_t default_uid[7] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
memcpy(uid, default_uid, sizeof(default_uid));
uid_len = sizeof(default_uid);
} else if (uid_len != 7) {
uidlen = sizeof(default_uid);
} else if (uidlen != 7) {
PrintAndLogEx(FAILED, "UID must be 7 bytes long.");
return PM3_EINVARG;
}
PrintAndLogEx(SUCCESS, "UID length is %d", uid_len);
PrintAndLogEx(SUCCESS, "UID length is %d", uidlen);
bool testMode = arg_get_lit(ctx, 1);
bool show_apdu = true;
@ -670,7 +670,7 @@ static int CmdEMVSmartToNFC(const char *Cmd) {
CLIParserFree(ctx);
// todo: check this is relevant for us.
// todo for PR: check this is relevant for us.
SetAPDULogging(show_apdu);
struct {
@ -681,14 +681,33 @@ static int CmdEMVSmartToNFC(const char *Cmd) {
uint8_t sak;
} PACKED payload;
memcpy(payload.uid, uid, uid_len);
payload.flags = 0x1204;
memcpy(payload.uid, uid, uidlen);
// Set up the flags for 2K mifare sim with RATS
uint16_t flags = 0;
FLAG_SET_UID_IN_DATA(flags, uidlen);
if (IS_FLAG_UID_IN_EMUL(flags)) {
PrintAndLogEx(WARNING, "Invalid parameter for UID");
CLIParserFree(ctx);
return PM3_EINVARG;
}
FLAG_SET_MF_SIZE(flags, MIFARE_2K_MAX_BYTES);
//snprintf(csize, sizeof(csize), "2K with RATS");
//k_sectors_cnt = MIFARE_2K_MAXSECTOR; // todo: delete
flags |= FLAG_ATQA_IN_DATA;
flags |= FLAG_SAK_IN_DATA;
payload.flags = flags;
//payload.flags = 0x1204;
payload.exitAfter = 0x1;
payload.atqa = 0x0;
payload.sak = 0x20;
clearCommandBuffer();
SendCommandNG(0x0386, (uint8_t *)&payload, sizeof(payload));
SendCommandNG(CMD_HF_ISO14443A_EMV_SIMULATE, (uint8_t *)&payload, sizeof(payload));
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort simulation");

View file

@ -490,6 +490,15 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define ISO7816_GET_CHALLENGE 0x84
#define ISO7816_MANAGE_CHANNEL 0x70
#define ISO7816_APPLICATION_BLOCK 0x1E
#define ISO7816_APPLICATION_UNBLOCK 0x18
#define ISO7816_CARD_BLOCK 0x16
#define ISO7816_GENERATE_APPLICATION_CRYPTOGRAM 0xAE
#define ISO7816_GET_PROCESSING_OPTIONS 0xA8
#define ISO7816_PIN_CHANGE 0x24
#define ISO7816_PIN_CHANGE 0x24
#define ISO7816_GET_RESPONSE 0xC0
// ISO7816-4 For response APDU's