mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-22 17:32:33 +00:00
feat(standalone): add EmvPng as a new standalone mode (EMV Visa w/ fixed ARQC)
Introduce EmvPng module under Proxmark3 standalone. EMV Visa (ISO14443-4) emulation with fixed ARQC (educational/lab use). Derived from MSDSal’s standalone mode (Salvador Mendoza), adapted for EMV Visa.
This commit is contained in:
1 parent
c1441eb2ab
commit
cba6faf2c3
5 files changed
+613
-2
No files matched your search
@@ -137,12 +137,15 @@ define KNOWN_STANDALONE_DEFINITIONS
|
||||
| DANKARMULTI | Load multiple standalone modes. |
|
||||
| | - Daniel Karling |
|
||||
+----------------------------------------------------------+
|
||||
| HF_EMVPNG | Read and emulate EMV Visa cards |
|
||||
| | - Davi Mikael (Penegui) |
|
||||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON
|
||||
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG HF_EMVPNG
|
||||
STANDALONE_MODES += DANKARMULTI
|
||||
STANDALONE_MODES_REQ_BT := HF_CARDHOPPER HF_REBLAY
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
|
||||
@@ -161,6 +161,10 @@ endif
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_ST25_TEAROFF,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_st25_tearoff.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_EMVPNG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_EMVPNG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_emvpng.c
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = dankarmulti.c
|
||||
|
||||
@@ -0,0 +1,603 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//-----------------------------------------------------------------------------
|
||||
// Project: EmvPng — EMV Emulator (fixed ARQC) – derived from MSDSal
|
||||
//
|
||||
// Copyright (C) 2023-2025 Davi Mikael C. R. (penegui)
|
||||
// Modifications: EMV emulation with fixed ARQC for educational/lab use.
|
||||
//
|
||||
// Based on:
|
||||
// MSDSal by Salvador Mendoza (salmg.net)
|
||||
// Copyright (C) 2020 Salvador Mendoza
|
||||
// Copyright (C) Proxmark3 contributors — see AUTHORS.md
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation, either version 3 of the License, or (at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the full license text.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Description:
|
||||
// Code derived from MSDSal and adapted for EMV testing with a fixed ARQC
|
||||
// in controlled environments. Educational use only.
|
||||
//-----------------------------------------------------------------------------
|
||||
// by Penegui
|
||||
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
#include "iso14443a.h"
|
||||
#include "protocols.h"
|
||||
#include "cmd.h"
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF - Reading Visa cards & Emulating a Visa EMV Transaction(ISO14443) - (Penegui)");
|
||||
}
|
||||
|
||||
/* This standalone implements two different modes: reading and emulating.
|
||||
*
|
||||
* The initial mode is reading with LED A as guide.
|
||||
* In this mode, the Proxmark expects a Visa Card,
|
||||
* and will act as card reader. Trying to find track 2.
|
||||
*
|
||||
* If the Proxmark found a track 2, it will change to emulation mode (LED C) automatically.
|
||||
* During this mode the Proxmark will behave as card, emulating a Visa EMV transaction
|
||||
* using the pre-saved track2 from the previous reading.
|
||||
*
|
||||
* It is possible to jump from mode to another by simply pressing the button.
|
||||
* However, to jump from reading to emulation mode, the LED C as to be on, which
|
||||
* means having a track 2 in memory.
|
||||
*
|
||||
* Keep pressing the button down will quit the standalone cycle.
|
||||
*
|
||||
* LEDs:
|
||||
* LED A = in reading mode
|
||||
* LED C = in emulation(a track 2 in memory) mode
|
||||
* LED A + LED C = in reading mode, but you can jump back to emulation mode by pressing the button
|
||||
* LED B = receiving/sending commands, activity
|
||||
*
|
||||
*
|
||||
* Reading or emulating ISO-14443A technology is not limited to payment cards. This example
|
||||
* was not only designed to make a replay attack, but to open new possibilities in the ISO-14443A
|
||||
* technologies. Be brave enough to share your knowledge & inspire others. Salvador Mendoza.
|
||||
*/
|
||||
|
||||
// Default GET PROCESSING
|
||||
static uint8_t ppdol [255] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00};
|
||||
|
||||
// Generate GET PROCESSING
|
||||
static uint8_t treatPDOL(const uint8_t *apdu) {
|
||||
|
||||
uint8_t plen = 7;
|
||||
|
||||
// PDOL Format: 80 A8 00 00 + (PDOL Length+2) + 83 + PDOL Length + PDOL + 00
|
||||
for (uint8_t i = 1; i <= apdu[0]; i++) { // Magic stuff, the generation order is important
|
||||
if (apdu[i] == 0x9F && apdu[i + 1] == 0x66) { // Terminal Transaction Qualifiers
|
||||
ppdol[plen] = 0xF6;
|
||||
ppdol[plen + 1] = 0x20;
|
||||
ppdol[plen + 2] = 0xC0;
|
||||
ppdol[plen + 3] = 0x00;
|
||||
plen += 4;
|
||||
i += 2;
|
||||
} else if (apdu[i] == 0x9F && apdu[i + 1] == 0x1A) { // Terminal Country Code
|
||||
ppdol[plen] = 0x9F;
|
||||
ppdol[plen + 1] = 0x1A;
|
||||
plen += 2;
|
||||
i += 2;
|
||||
} else if (apdu[i] == 0x9F && apdu[i + 1] == 0x02) { // Authorized amount
|
||||
ppdol[plen] = 0x00;
|
||||
ppdol[plen + 1] = 0x00;
|
||||
ppdol[plen + 2] = 0x00;
|
||||
ppdol[plen + 3] = 0x00;
|
||||
ppdol[plen + 4] = 0x01;
|
||||
ppdol[plen + 5] = 0x00;
|
||||
plen += 6;
|
||||
i += 2;
|
||||
} else if (apdu[i] == 0x9F && apdu[i + 1] == 0x03) { // Secondary / cashback amount
|
||||
ppdol[plen] = 0x00;
|
||||
ppdol[plen + 1] = 0x00;
|
||||
ppdol[plen + 2] = 0x00;
|
||||
ppdol[plen + 3] = 0x00;
|
||||
ppdol[plen + 4] = 0x00;
|
||||
ppdol[plen + 5] = 0x00;
|
||||
plen += 6;
|
||||
i += 2;
|
||||
}else if (apdu[i] == 0x5F && apdu[i + 1] == 0x2A) { // Transaction Currency Code
|
||||
ppdol[plen] = 0x5F;
|
||||
ppdol[plen + 1] = 0x2A;
|
||||
plen += 2;
|
||||
i += 2;
|
||||
} else if (apdu[i] == 0x9A) { // Transaction Date
|
||||
ppdol[plen] = 0x9A;
|
||||
ppdol[plen + 1] = 0x9A;
|
||||
ppdol[plen + 2] = 0x9A;
|
||||
plen += 3;
|
||||
i += 1;
|
||||
} else if (apdu[i] == 0x95) { // Terminal Verification Results
|
||||
ppdol[plen] = 0x95;
|
||||
ppdol[plen + 1] = 0x95;
|
||||
ppdol[plen + 2] = 0x95;
|
||||
ppdol[plen + 3] = 0x95;
|
||||
ppdol[plen + 4] = 0x95;
|
||||
plen += 5;
|
||||
i += 1;
|
||||
} else if (apdu[i] == 0x9C) { // Transaction Type
|
||||
ppdol[plen] = 0x9C;
|
||||
plen += 1;
|
||||
i += 1;
|
||||
} else if (apdu[i] == 0x9F && apdu[i + 1] == 0x37) { // Unpredictable Number
|
||||
ppdol[plen] = 0x9F;
|
||||
ppdol[plen + 1] = 0x37;
|
||||
ppdol[plen + 2] = 0x9F;
|
||||
ppdol[plen + 3] = 0x37;
|
||||
plen += 4;
|
||||
i += 2;
|
||||
} else { // To the others, add "0" to complete the format depending on its range
|
||||
uint8_t u = apdu[i + 2];
|
||||
while (u > 0) {
|
||||
ppdol[plen] = 0;
|
||||
plen += 1;
|
||||
u--;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
ppdol[4] = (plen + 2) - 7; // Length of PDOL + 2
|
||||
ppdol[6] = plen - 7; // Real length
|
||||
plen++; // +1 because the last 0
|
||||
ppdol[plen] = 0x00; // Add the last 0 to the challenge
|
||||
return plen;
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
StandAloneMode();
|
||||
DbpString(_YELLOW_(">>") "Reading Visa cards & Emulating a Visa EMV Transaction a.k.a. EmvPng Started " _YELLOW_("<<"));
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
//For reading process
|
||||
iso14a_card_select_t card_a_info;
|
||||
|
||||
uint8_t apdubuffer[MAX_FRAME_SIZE] = { 0x00 };
|
||||
|
||||
//Specific for Visa cards: select ppse, select Visa AID, GET PROCESSING, SFI
|
||||
uint8_t ppse[20] = {
|
||||
0x00, 0xA4, 0x04, 0x00, 0x0e, 0x32, 0x50, 0x41,
|
||||
0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44,
|
||||
0x46, 0x30, 0x31, 0x00
|
||||
};
|
||||
uint8_t visa[13] = {
|
||||
0x00, 0xA4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00,
|
||||
0x00, 0x03, 0x10, 0x10, 0x00
|
||||
};
|
||||
|
||||
uint8_t processing [8] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
|
||||
uint8_t sfi[5] = {0x00, 0xb2, 0x01, 0x0c, 0x00};
|
||||
|
||||
uint8_t *apdus[4] = {ppse, visa, processing, sfi};
|
||||
uint8_t apduslen[4] = { sizeof(ppse), sizeof(visa), sizeof(processing), sizeof(sfi)};
|
||||
|
||||
uint8_t pdol[50], plen = 8;
|
||||
|
||||
bool existpdol;
|
||||
|
||||
|
||||
// - EMV token card format -
|
||||
//
|
||||
// Card number.............. 4412 3456 0578 1234
|
||||
// Expiration date.......... 17/11
|
||||
// Service code............. 201
|
||||
// Discretionary data....... 0000030000991
|
||||
// Pin verification value... 0000
|
||||
// CVV / iCvv............... 030
|
||||
// Trailing................. 000991
|
||||
|
||||
// 44 12 34 56 05 78 12 34 D 1711 2 01 00 00 03 00 00 99 1
|
||||
char token[19] = {0x44,0x12,0x34,0x56,0x05,0x78,0x12,0x34,0xd1,0x71,0x12,0x01,0x00,0x00,0x03,0x00,0x00,0x99,0x1f};
|
||||
// It is possible to initialize directly the emulation mode, having "token" with data and set "chktoken" = true ;)
|
||||
//
|
||||
//char token[19] = {0x00};
|
||||
bool chktoken = true;
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 1024
|
||||
|
||||
// UID 4 bytes(could be 7 bytes if needed it)
|
||||
uint8_t flags = FLAG_4B_UID_IN_DATA;
|
||||
// in case there is a read command received we shouldn't break
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
uint8_t visauid[7] = {0x01, 0x02, 0x03, 0x04};
|
||||
memcpy(data, visauid, 4);
|
||||
|
||||
// to initialize the emulation
|
||||
uint8_t tagType = 11; // 11 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
tag_response_info_t *responses;
|
||||
uint32_t cuid = 0;
|
||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
||||
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
|
||||
uint8_t pages = 0;
|
||||
|
||||
// command buffers
|
||||
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
|
||||
|
||||
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
|
||||
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
|
||||
|
||||
// to know the transaction status
|
||||
uint8_t prevCmd = 0;
|
||||
|
||||
// handler - command responses
|
||||
tag_response_info_t dynamic_response_info = {
|
||||
.response = dynamic_response_buffer,
|
||||
.response_n = 0,
|
||||
.modulation = dynamic_modulation_buffer,
|
||||
.modulation_n = 0
|
||||
};
|
||||
|
||||
// States for standalone
|
||||
#define STATE_READ 0
|
||||
#define STATE_EMU 1
|
||||
|
||||
uint8_t state = STATE_READ;
|
||||
|
||||
// Checking if the user wants to go directly to emulation mode using a hardcoded track 2
|
||||
if (chktoken == true && token[0] != 0x00) {
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a Visa card...");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
// exit from RunMod, send a usbcommand.
|
||||
if (data_available()) break;
|
||||
|
||||
// Was our button held down or pressed?
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
|
||||
|
||||
if (button_pressed == BUTTON_HOLD)
|
||||
break;
|
||||
else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
// pressing one time change between reading & emulation
|
||||
if (state == STATE_READ) {
|
||||
if (chktoken == true && token[0] != 0x00) {
|
||||
// only change to emulation if it saved a track 2 in memory
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]"));
|
||||
} else
|
||||
DbpString(_YELLOW_("!!") "Nothing in memory to emulate");
|
||||
} else {
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]"));
|
||||
}
|
||||
}
|
||||
|
||||
SpinDelay(500);
|
||||
|
||||
if (state == STATE_READ) {
|
||||
LED_A_ON();
|
||||
if (chktoken)
|
||||
LED_C_ON();
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
|
||||
|
||||
DbpString(_YELLOW_("+") "Found ISO 14443 Type A!");
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
chktoken = false;
|
||||
LED_C_OFF();
|
||||
LED_B_ON();
|
||||
uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apduslen[i], false, apdubuffer, NULL);
|
||||
|
||||
if (apdulen > 0) {
|
||||
DbpString(_YELLOW_("[ ") "Proxmark command" _YELLOW_(" ]"));
|
||||
Dbhexdump(apduslen[i], apdus[i], false);
|
||||
DbpString(_GREEN_("[ ") "Card answer" _GREEN_(" ]"));
|
||||
Dbhexdump(apdulen - 2, apdubuffer, false);
|
||||
DbpString("----");
|
||||
|
||||
for (uint8_t u = 0; u < apdulen; u++) {
|
||||
if (i == 1) {
|
||||
|
||||
// check for PDOL
|
||||
if (apdubuffer[u] == 0x9F && apdubuffer[u + 1] == 0x38) {
|
||||
for (uint8_t e = 0; e <= apdubuffer[u + 2]; e++)
|
||||
pdol[e] = apdubuffer[u + e + 2];
|
||||
|
||||
// generate a challenge
|
||||
plen = treatPDOL(pdol);
|
||||
apdus[2] = ppdol;
|
||||
apduslen[2] = plen;
|
||||
existpdol = true;
|
||||
}
|
||||
|
||||
|
||||
} else if (i == 3) {
|
||||
|
||||
|
||||
// find track 2
|
||||
if (apdubuffer[u] == 0x57 && apdubuffer[u + 1] == 0x13 && !chktoken) {
|
||||
chktoken = true;
|
||||
memcpy(&token, &apdubuffer[u + 2], 19);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 1) {
|
||||
DbpString(_GREEN_("[ ") "Challenge generated" _GREEN_(" ]"));
|
||||
Dbhexdump(plen, existpdol ? ppdol : processing, false);
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Error reading the card");
|
||||
}
|
||||
LED_B_OFF();
|
||||
}
|
||||
|
||||
if (chktoken) {
|
||||
DbpString(_RED_("[ ") "Track 2" _RED_(" ]"));
|
||||
Dbhexdump(19, (uint8_t *)token, false);
|
||||
DbpString(_YELLOW_("!!") "Card number");
|
||||
Dbhexdump(8, (uint8_t *)token, false);
|
||||
DbpString("---");
|
||||
LED_C_ON();
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
|
||||
} else if (state == STATE_EMU) {
|
||||
LED_A_OFF();
|
||||
LED_C_ON();
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the emulation process!");
|
||||
SpinDelay(500);
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n" _YELLOW_("!!") "Waiting for a Visa card...");
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
// command length
|
||||
int len = 0;
|
||||
// to check emulation status
|
||||
int retval = PM3_SUCCESS;
|
||||
bool odd_reply = true;
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
for (;;) {
|
||||
LED_B_OFF();
|
||||
// clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
DbpString(_YELLOW_("!!") "Emulator stopped");
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
tag_response_info_t *p_response = NULL;
|
||||
LED_B_ON();
|
||||
|
||||
// dynamic_response_info will be in charge of responses
|
||||
dynamic_response_info.response_n = 0;
|
||||
|
||||
//Dbprintf("receivedCmd: %02x\n", receivedCmd);
|
||||
// received a REQUEST
|
||||
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) {
|
||||
odd_reply = !odd_reply;
|
||||
if (odd_reply) {
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
}
|
||||
|
||||
// received a HALT
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
|
||||
//DbpString(_YELLOW_("+") "Received a HALT");
|
||||
p_response = NULL;
|
||||
|
||||
// received a WAKEUP
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
|
||||
//DbpString(_YELLOW_("+") "WAKEUP Received");
|
||||
prevCmd = 0;
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
|
||||
// received request for UID (cascade 1)
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) {
|
||||
//DbpString(_YELLOW_("+") "Request for UID C1");
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
|
||||
// received a SELECT (cascade 1)
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) {
|
||||
//DbpString(_YELLOW_("+") "Request for SELECT S1");
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
|
||||
// received a RATS request
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
|
||||
DbpString(_YELLOW_("+") "Request for RATS");
|
||||
prevCmd = 0;
|
||||
//p_response = &responses[RESP_INDEX_RATS];
|
||||
|
||||
static uint8_t rRATS[] = { 0x13, 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66, 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00, 0x90, 0x00 };
|
||||
|
||||
memcpy(&dynamic_response_info.response[0], rRATS, sizeof(rRATS));
|
||||
dynamic_response_info.response_n = sizeof(rRATS);
|
||||
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
|
||||
// emulate a Visa EMV(Magnetic stripe data) card
|
||||
if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
// depending on card reader commands, the Proxmark will answer to fool the reader
|
||||
// respond with PPSE
|
||||
if (receivedCmd[2] == 0xA4 && receivedCmd[6] == 0x32 && prevCmd == 0) {
|
||||
uint8_t ppsea[72] = {
|
||||
0x6F, 0x44, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59,
|
||||
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46,
|
||||
0x30, 0x31, 0xA5, 0x32, 0xBF, 0x0C, 0x2F, 0x61,
|
||||
0x16, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03,
|
||||
0x10, 0x10, 0x87, 0x01, 0x01, 0x9F, 0x12, 0x07,
|
||||
0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x4F, 0x61,
|
||||
0x15, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03,
|
||||
0x20, 0x10, 0x87, 0x01, 0x02, 0x9F, 0x12, 0x06,
|
||||
0x44, 0x45, 0x42, 0x49, 0x54, 0x4F, 0x90, 0x00
|
||||
};
|
||||
memcpy(&dynamic_response_info.response[1], ppsea, sizeof(ppsea));
|
||||
dynamic_response_info.response_n = sizeof(ppsea) + 1;
|
||||
prevCmd++;
|
||||
|
||||
// respond Visa AID
|
||||
} else if (receivedCmd[2] == 0xA4 && receivedCmd[10] == 0x03 && receivedCmd[11] == 0x10 && prevCmd == 1) {
|
||||
uint8_t visauid_long[101] = {
|
||||
0x6F, 0x61, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00,
|
||||
0x03, 0x10, 0x10, 0xA5, 0x56, 0x50, 0x0C, 0x56,
|
||||
0x49, 0x53, 0x41, 0x20, 0x43, 0x52, 0x45, 0x44,
|
||||
0x49, 0x54, 0x4F, 0x87, 0x01, 0x01, 0x9F, 0x12,
|
||||
0x07, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54, 0x4F,
|
||||
0x5F, 0x2D, 0x08, 0x70, 0x74, 0x65, 0x73, 0x65,
|
||||
0x6E, 0x66, 0x72, 0x9F, 0x11, 0x01, 0x01, 0x9F,
|
||||
0x38, 0x18,
|
||||
// Tag 9F66 - Decodificador TTQ (Qualificadores de Transação de Terminal)
|
||||
0x9F, 0x66, 0x04,
|
||||
0x9F, 0x02, 0x06,
|
||||
0x9F, 0x03, 0x06, 0x9F, 0x1A, 0x02, 0x95, 0x05,
|
||||
0x5F, 0x2A, 0x02, 0x9A, 0x03, 0x9C, 0x01, 0x9F,
|
||||
0x37, 0x04, 0xBF, 0x0C, 0x0E, 0x9F, 0x5A, 0x06,
|
||||
0x52, 0x09, 0x86, 0x00, 0x76, 0x30, 0x42, 0x03,
|
||||
0x41, 0x08, 0x63, 0x90, 0x00
|
||||
};
|
||||
memcpy(&dynamic_response_info.response[1], visauid_long, sizeof(visauid_long));
|
||||
dynamic_response_info.response_n = sizeof(visauid_long) + 1;
|
||||
prevCmd++;
|
||||
|
||||
// GET PROCESSING
|
||||
} else if (receivedCmd[1] == 0x80 && receivedCmd[2] == 0xA8 && receivedCmd[6] == 0x83 && prevCmd == 2) {
|
||||
uint8_t processing_long_last[8] = {0x77, 0x5f, 0x82, 0x02, 0x20, 0x00, 0x57, 0x13};
|
||||
uint8_t processing_long_rest[72] = {
|
||||
0x5f, 0x20, 0x0c, 0x50, 0x41, 0x59, 0x57, 0x41,
|
||||
0x56, 0x45, 0x2f, 0x56, 0x49, 0x53, 0x41, 0x5f,
|
||||
0x34, 0x01, 0x00,
|
||||
// Tag 9F10 - Issuer Application Data (IAD) Decoder
|
||||
0x9f, 0x10, 0x07, 0x06, 0x01, 0x12, 0x03, 0xa0, 0x20, 0x00,
|
||||
//assinatura ARQC Estatica
|
||||
0x9f, 0x26, 0x08, 0xcb, 0x44, 0x0d, 0x86, 0x1a, 0xa8, 0x33, 0x1d,
|
||||
//que tipo de assinatura
|
||||
0x9f, 0x27, 0x01, 0x80,
|
||||
|
||||
0x9f, 0x36, 0x02, 0x0f,
|
||||
0x57, 0x9f, 0x5d, 0x06, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00,
|
||||
// Tag 9F6C - Decodificador CTQ (Qualificadores de Transação de Cartão)
|
||||
0x9f, 0x6c, 0x02, 0x00, 0x80,
|
||||
// Tag 9F6E - Form Factor Indicator (Third Party Data Decoder)
|
||||
0x9f, 0x6e, 0x04, 0x20, 0x70, 0x00, 0x00,
|
||||
|
||||
0x90, 0x00
|
||||
};
|
||||
|
||||
uint8_t processing_long[99];
|
||||
|
||||
memcpy(&processing_long[0], processing_long_last, sizeof(processing_long_last));
|
||||
memcpy(&processing_long[8], token, sizeof(token));
|
||||
memcpy(&processing_long[27], processing_long_rest, sizeof(processing_long_rest));
|
||||
|
||||
memcpy(&dynamic_response_info.response[1], processing_long, sizeof(processing_long));
|
||||
dynamic_response_info.response_n = sizeof(processing_long) + 1;
|
||||
prevCmd++;
|
||||
|
||||
// SFI
|
||||
} else if (receivedCmd[1] == 0x00 && receivedCmd[2] == 0xB2 && prevCmd == 3) {
|
||||
uint8_t last[4] = {0x70, 0x15, 0x57, 0x13};
|
||||
uint8_t statusapdu[2] = {0x90, 0x00};
|
||||
uint8_t card[25];
|
||||
memcpy(&card[0], last, sizeof(last));
|
||||
memcpy(&card[4], token, sizeof(token));
|
||||
memcpy(&card[23], statusapdu, sizeof(statusapdu));
|
||||
memcpy(&dynamic_response_info.response[1], card, sizeof(card));
|
||||
dynamic_response_info.response_n = sizeof(card) + 1;
|
||||
prevCmd++;
|
||||
|
||||
} else {
|
||||
uint8_t finished[2] = {0x6f, 0x00};
|
||||
memcpy(&dynamic_response_info.response[1], finished, sizeof(finished));
|
||||
dynamic_response_info.response_n = sizeof(finished) + 1;
|
||||
if (prevCmd == 5) {
|
||||
prevCmd = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Received unknown command!");
|
||||
if (prevCmd < 4) {
|
||||
memcpy(dynamic_response_info.response, receivedCmd, len);
|
||||
dynamic_response_info.response_n = len;
|
||||
} else {
|
||||
dynamic_response_info.response_n = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
|
||||
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
|
||||
DbpString("----");
|
||||
|
||||
// add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||
dynamic_response_info.response_n += 2;
|
||||
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
SpinDelay(500);
|
||||
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!");
|
||||
continue;
|
||||
}
|
||||
p_response = &dynamic_response_info;
|
||||
}
|
||||
|
||||
if (p_response != NULL) {
|
||||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
|
||||
set_tracing(false);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
LEDsoff();
|
||||
}
|
||||
@@ -146,6 +146,7 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo
|
||||
| HF_TMUDFORD | Read and emulate ISO15693 card UID - Tim Mudford
|
||||
| HF_UNISNIFF | Combined 14a/14b/15 sniffer with runtime selection & extra save options
|
||||
| HF_YOUNG | Mifare sniff/simulation - Craig Young
|
||||
| HF_EMVPNG | EMV Read and emulation - Davi Mikael (Penegui)
|
||||
| DANKARMULTI | Standalone mode that bakes together multiple other standalone modes. - dankar
|
||||
|
||||
By default `STANDALONE=LF_SAMYRUN`.
|
||||
|
||||
@@ -32,7 +32,7 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf"
|
||||
# cf armsrc/Standalone/Makefile.hal
|
||||
STANDALONE_MODES=(LF_SKELETON)
|
||||
STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE)
|
||||
STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG)
|
||||
STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG HF_EMVPNG)
|
||||
STANDALONE_MODES+=(DANKARMULTI)
|
||||
STANDALONE_MODES_REQ_BT=(HF_CARDHOPPER HF_REBLAY)
|
||||
STANDALONE_MODES_REQ_SMARTCARD=()
|
||||
|
||||
Reference in new issue
Block a user