Various improvements on the Mifare1kSimulation. Fixed issue with tracebuffer not being cleared, fixed issue with 'static' errors, added modes for doing reader-only attack, added interactive mode, added possibility to set UID from cmdline, either 7-byte or 4-byte. See http://www.proxmark.org/forum/viewtopic.php?id=1529 and http://www.proxmark.org/forum/viewtopic.php?id=1649&p=3 for some more background and discussion

This commit is contained in:
martin.holst@gmail.com 2014-01-31 21:17:34 +00:00
parent af1caf6e4a
commit d2f487af9c
3 changed files with 556 additions and 411 deletions

View file

@ -1926,7 +1926,7 @@ void ReaderMifare(bool first_try)
static uint8_t mf_nr_ar3;
uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + FREE_BUFFER_OFFSET);
traceLen = 0;
iso14a_clear_trace();
tracing = false;
byte_t nt_diff = 0;
@ -1974,7 +1974,7 @@ void ReaderMifare(bool first_try)
LED_B_OFF();
LED_C_OFF();
for(uint16_t i = 0; TRUE; i++) {
WDT_HIT();
@ -2113,18 +2113,22 @@ void ReaderMifare(bool first_try)
tracing = TRUE;
}
//-----------------------------------------------------------------------------
// MIFARE 1K simulate.
//
//-----------------------------------------------------------------------------
void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
/**
*MIFARE 1K simulate.
*
*@param flags :
* FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK
* 4B_FLAG_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that
* 7B_FLAG_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that
* FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later
*@param exitAfterNReads, exit simulation after n blocks have been read, 0 is inifite
*/
void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain)
{
int cardSTATE = MFEMUL_NOFIELD;
int _7BUID = 0;
int vHf = 0; // in mV
//int nextCycleTimeout = 0;
int res;
// uint32_t timer = 0;
uint32_t selTimer = 0;
uint32_t authTimer = 0;
uint32_t par = 0;
@ -2132,60 +2136,83 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
uint8_t cardWRBL = 0;
uint8_t cardAUTHSC = 0;
uint8_t cardAUTHKEY = 0xff; // no authentication
//uint32_t cardRn = 0;
uint32_t cardRr = 0;
uint32_t cuid = 0;
uint32_t rn_enc = 0;
//uint32_t rn_enc = 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 read a block
uint8_t* receivedCmd = eml_get_bigbufptr_recbuf();
uint8_t *response = eml_get_bigbufptr_sendbuf();
static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID
uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID
uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62};
uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!!
uint8_t rSAK[] = {0x08, 0xb6, 0xdd};
uint8_t rSAK1[] = {0x04, 0xda, 0x17};
static uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62};
static uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!!
static uint8_t rSAK[] = {0x08, 0xb6, 0xdd};
static uint8_t rSAK1[] = {0x04, 0xda, 0x17};
uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
static uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
// static uint8_t rAUTH_NT[] = {0x1a, 0xac, 0xff, 0x4f};
static uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
//Here, we collect UID,NT,AR,NR,UID2,NT2,AR2,NR2
// This can be used in a reader-only attack.
// (it can also be retrieved via 'hf 14a list', but hey...
uint32_t ar_nr_responses[] = {0,0,0,0,0,0,0,0};
uint8_t ar_nr_collected = 0;
// clear trace
traceLen = 0;
iso14a_clear_trace();
tracing = true;
// Authenticate response - nonce
uint32_t nonce = bytes_to_num(rAUTH_NT, 4);
// get UID from emul memory
emlGetMemBt(receivedCmd, 7, 1);
_7BUID = !(receivedCmd[0] == 0x00);
if (!_7BUID) { // ---------- 4BUID
rATQA[0] = 0x04;
emlGetMemBt(rUIDBCC1, 0, 4);
//-- Determine the UID
// Can be set from emulator memory, incoming data
// and can be 7 or 4 bytes long
if(flags & FLAG_4B_UID_IN_DATA)
{
// 4B uid comes from data-portion of packet
memcpy(rUIDBCC1,datain,4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
} else { // ---------- 7BUID
}else if(flags & FLAG_7B_UID_IN_DATA)
{
// 7B uid comes from data-portion of packet
memcpy(&rUIDBCC1[1],datain,3);
memcpy(rUIDBCC2, datain+3, 4);
_7BUID = true;
}
else
{
// get UID from emul memory
emlGetMemBt(receivedCmd, 7, 1);
_7BUID = !(receivedCmd[0] == 0x00);
if (!_7BUID) { // ---------- 4BUID
emlGetMemBt(rUIDBCC1, 0, 4);
} else { // ---------- 7BUID
emlGetMemBt(&rUIDBCC1[1], 0, 3);
emlGetMemBt(rUIDBCC2, 3, 4);
}
}
/*
* Regardless of what method was used to set the UID, set fifth byte and modify
* the ATQA for 4 or 7-byte UID
*/
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
if(_7BUID)
{
rATQA[0] = 0x44;
rUIDBCC1[0] = 0x88;
emlGetMemBt(&rUIDBCC1[1], 0, 3);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
emlGetMemBt(rUIDBCC2, 3, 4);
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
}
// -------------------------------------- test area
// -------------------------------------- END test area
// start mkseconds counter
StartCountUS();
@ -2193,19 +2220,23 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
SpinDelay(200);
if (MF_DBGLEVEL >= 1) Dbprintf("Started. 7buid=%d", _7BUID);
if (MF_DBGLEVEL >= 1) {
if (!_7BUID) {
Dbprintf("4B UID: %02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3]);
}else
{
Dbprintf("7B UID: (%02x)%02x%02x%02x%02x%02x%02x%02x",rUIDBCC1[0] , rUIDBCC1[1] , rUIDBCC1[2] , rUIDBCC1[3],rUIDBCC2[0],rUIDBCC2[1] ,rUIDBCC2[2] , rUIDBCC2[3]);
}
}
// calibrate mkseconds counter
GetDeltaCountUS();
while (true) {
bool finished = false;
while (!BUTTON_PRESS() && !finished) {
WDT_HIT();
if(BUTTON_PRESS()) {
break;
}
// find reader field
// Vref = 3300mV, and an 10:1 voltage divider on the input
// can measure voltages up to 33000 mV
@ -2216,56 +2247,54 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_A_ON();
}
}
if(cardSTATE == MFEMUL_NOFIELD) continue;
if (cardSTATE != MFEMUL_NOFIELD) {
res = EmGetCmd(receivedCmd, &len, RECV_CMD_SIZE); // (+ nextCycleTimeout)
if (res == 2) {
cardSTATE = MFEMUL_NOFIELD;
LEDsoff();
continue;
}
if(res) break;
//Now, get data
res = EmGetCmd(receivedCmd, &len, RECV_CMD_SIZE); // (+ nextCycleTimeout)
if (res == 2) { //Field is off!
cardSTATE = MFEMUL_NOFIELD;
LEDsoff();
continue;
}else if(res == 1) break;//return value 1 means button press
// REQ or WUP request in ANY state and WUP in HALTED state
if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) {
selTimer = GetTickCount();
EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52));
cardSTATE = MFEMUL_SELECT1;
// init crypto block
LED_B_OFF();
LED_C_OFF();
crypto1_destroy(pcs);
cardAUTHKEY = 0xff;
continue;
}
//nextCycleTimeout = 0;
// if (len) Dbprintf("len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]);
if (len != 4 && cardSTATE != MFEMUL_NOFIELD) { // len != 4 <---- speed up the code 4 authentication
// REQ or WUP request in ANY state and WUP in HALTED state
if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) {
selTimer = GetTickCount();
EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52));
cardSTATE = MFEMUL_SELECT1;
// init crypto block
LED_B_OFF();
LED_C_OFF();
crypto1_destroy(pcs);
cardAUTHKEY = 0xff;
}
}
switch (cardSTATE) {
case MFEMUL_NOFIELD:{
break;
}
case MFEMUL_HALTED:{
break;
}
case MFEMUL_NOFIELD:
case MFEMUL_HALTED:
case MFEMUL_IDLE:{
break;
}
case MFEMUL_SELECT1:{
// select all
if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL received");
EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1));
break;
}
if (MF_DBGLEVEL >= 4 && len == 9 && receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 )
{
Dbprintf("SELECT %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
}
// select card
if (len == 9 &&
(receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) {
if (!_7BUID)
EmSendCmd(rSAK, sizeof(rSAK));
else
@ -2285,6 +2314,51 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
break;
}
case MFEMUL_AUTH1:{
if( len != 8)
{
cardSTATE_TO_IDLE();
break;
}
uint32_t ar = bytes_to_num(receivedCmd, 4);
uint32_t nr= bytes_to_num(&receivedCmd[4], 4);
//Collect AR/NR
if(ar_nr_collected < 2){
if(ar_nr_responses[ar_nr_collected*4+2] != ar)
{// Avoid duplicates
ar_nr_collected++;
ar_nr_responses[ar_nr_collected*4] = cuid;
ar_nr_responses[ar_nr_collected*4+1] = nonce;
ar_nr_responses[ar_nr_collected*4+2] = ar;
ar_nr_responses[ar_nr_collected*4+3] = nr;
}
}
// --- crypto
crypto1_word(pcs, ar , 1);
cardRr = nr ^ crypto1_word(pcs, 0, 0);
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x",cardRr, prng_successor(nonce, 64));
//Shouldn't we respond anything here?
// Right now, we don't nack or anything, which causes the
// reader to do a WUPA after a while. /Martin
cardSTATE_TO_IDLE();
break;
}
ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
num_to_bytes(ans, 4, rAUTH_AT);
// --- crypto
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
LED_C_ON();
cardSTATE = MFEMUL_WORK;
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sector=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer);
break;
}
case MFEMUL_SELECT2:{
if (!len) break;
@ -2308,86 +2382,44 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
// i guess there is a command). go into the work state.
if (len != 4) break;
cardSTATE = MFEMUL_WORK;
goto lbWORK;
}
case MFEMUL_AUTH1:{
if (len == 8) {
// --- crypto
rn_enc = bytes_to_num(receivedCmd, 4);
crypto1_word(pcs, rn_enc , 1);
cardRr = bytes_to_num(&receivedCmd[4], 4) ^ crypto1_word(pcs, 0, 0);
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH FAILED. cardRr=%08x, succ=%08x", cardRr, prng_successor(nonce, 64));
cardSTATE_TO_IDLE();
break;
}
ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
num_to_bytes(ans, 4, rAUTH_AT);
// --- crypto
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
cardSTATE = MFEMUL_AUTH2;
} else {
cardSTATE_TO_IDLE();
}
if (cardSTATE != MFEMUL_AUTH2) break;
}
case MFEMUL_AUTH2:{
LED_C_ON();
cardSTATE = MFEMUL_WORK;
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED. sec=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer);
break;
//goto lbWORK;
//intentional fall-through to the next case-stmt
}
case MFEMUL_WORK:{
lbWORK: if (len == 0) break;
if (cardAUTHKEY == 0xff) {
// first authentication
if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
authTimer = GetTickCount();
if (len == 0) break;
cardAUTHSC = receivedCmd[1] / 4; // received block num
cardAUTHKEY = receivedCmd[0] - 0x60;
bool encrypted_data = (cardAUTHKEY != 0xFF) ;
// --- crypto
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(nonce, 4, rAUTH_AT);
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
// --- crypto
// last working revision
// EmSendCmd14443aRaw(resp1, resp1Len, 0);
// LogTrace(NULL, 0, GetDeltaCountUS(), 0, true);
cardSTATE = MFEMUL_AUTH1;
//nextCycleTimeout = 10;
break;
}
} else {
if(encrypted_data)
{
// decrypt seqence
mf_crypto1_decrypt(pcs, receivedCmd, len);
// nested authentication
if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
authTimer = GetTickCount();
cardAUTHSC = receivedCmd[1] / 4; // received block num
cardAUTHKEY = receivedCmd[0] - 0x60;
// --- crypto
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(ans, 4, rAUTH_AT);
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
// --- crypto
cardSTATE = MFEMUL_AUTH1;
//nextCycleTimeout = 10;
break;
}
}
if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) {
authTimer = GetTickCount();
cardAUTHSC = receivedCmd[1] / 4; // received block num
cardAUTHKEY = receivedCmd[0] - 0x60;
crypto1_destroy(pcs);//Added by martin
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
if (!encrypted_data) { // first authentication
if (MF_DBGLEVEL >= 2) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state
num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce
}
else{ // nested authentication
if (MF_DBGLEVEL >= 2) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d",receivedCmd[1] ,receivedCmd[1],cardAUTHKEY );
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(ans, 4, rAUTH_AT);
}
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
//Dbprintf("Sending rAUTH %02x%02x%02x%02x", rAUTH_AT[0],rAUTH_AT[1],rAUTH_AT[2],rAUTH_AT[3]);
cardSTATE = MFEMUL_AUTH1;
break;
}
// rule 13 of 7.5.3. in ISO 14443-4. chaining shall be continued
// BUT... ACK --> NACK
if (len == 1 && receivedCmd[0] == CARD_ACK) {
@ -2401,39 +2433,63 @@ lbWORK: if (len == 0) break;
break;
}
// read block
if (len == 4 && receivedCmd[0] == 0x30) {
if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
if(len != 4) break;
if(receivedCmd[0] == 0x30 // read block
|| receivedCmd[0] == 0xA0 // write block
|| receivedCmd[0] == 0xC0
|| receivedCmd[0] == 0xC1
|| receivedCmd[0] == 0xC2 // inc dec restore
|| receivedCmd[0] == 0xB0) // transfer
{
if (receivedCmd[1] >= 16 * 4)
{
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on out of range block: %d (0x%02x), nacking",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
break;
}
if (receivedCmd[1] / 4 != cardAUTHSC)
{
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd[0],receivedCmd[1],cardAUTHSC);
break;
}
}
// read block
if (receivedCmd[0] == 0x30) {
if (MF_DBGLEVEL >= 2) {
Dbprintf("Reader reading block %d (0x%02x)",receivedCmd[1],receivedCmd[1]);
}
emlGetMem(response, receivedCmd[1], 1);
AppendCrc14443a(response, 16);
mf_crypto1_encrypt(pcs, response, 18, &par);
EmSendCmdPar(response, 18, par);
numReads++;
if(exitAfterNReads > 0 && numReads == exitAfterNReads)
{
Dbprintf("%d reads done, exiting", numReads);
finished = true;
}
break;
}
// write block
if (len == 4 && receivedCmd[0] == 0xA0) {
if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
if (receivedCmd[0] == 0xA0) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd[1],receivedCmd[1]);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
//nextCycleTimeout = 50;
cardSTATE = MFEMUL_WRITEBL2;
cardWRBL = receivedCmd[1];
break;
}
// works with cardINTREG
}
// increment, decrement, restore
if (len == 4 && (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2)) {
if (receivedCmd[1] >= 16 * 4 ||
receivedCmd[1] / 4 != cardAUTHSC ||
emlCheckValBl(receivedCmd[1])) {
if (receivedCmd[0] == 0xC0 || receivedCmd[0] == 0xC1 || receivedCmd[0] == 0xC2) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (emlCheckValBl(receivedCmd[1])) {
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
@ -2445,17 +2501,13 @@ lbWORK: if (len == 0) break;
if (receivedCmd[0] == 0xC2)
cardSTATE = MFEMUL_INTREG_REST;
cardWRBL = receivedCmd[1];
break;
}
// transfer
if (len == 4 && receivedCmd[0] == 0xB0) {
if (receivedCmd[1] >= 16 * 4 || receivedCmd[1] / 4 != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
if (receivedCmd[0] == 0xB0) {
if (MF_DBGLEVEL >= 2) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd[0],receivedCmd[1],receivedCmd[1]);
if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd[1]))
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
@ -2466,20 +2518,23 @@ lbWORK: if (len == 0) break;
}
// halt
if (len == 4 && (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00)) {
if (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00) {
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_HALTED;
if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED. Selected time: %d ms", GetTickCount() - selTimer);
break;
}
// command not allowed
if (len == 4) {
// RATS
if (receivedCmd[0] == 0xe0) {//RATS
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
// command not allowed
if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
// case break
break;
}
@ -2541,10 +2596,43 @@ lbWORK: if (len == 0) break;
// add trace trailer
memset(rAUTH_NT, 0x44, 4);
LogTrace(rAUTH_NT, 4, 0, 0, TRUE);
if(flags & FLAG_INTERACTIVE)// Interactive mode flag, means we need to send ACK
{
//May just aswell send the collected ar_nr in the response aswell
cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4);
}
if(flags & FLAG_NR_AR_ATTACK)
{
if(ar_nr_collected > 1)
{
Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:");
Dbprintf("../tools/mfcrack32 %08x %08x %08x %08x",
ar_nr_responses[0], // UID
ar_nr_responses[1], //NT
ar_nr_responses[2], //AR1
ar_nr_responses[3], //NR1
ar_nr_responses[6], //AR2
ar_nr_responses[7] //NR2
);
}else
{
Dbprintf("Failed to obtain two AR/NR pairs!");
if(ar_nr_collected >0)
{
Dbprintf("Only got these: UID=%08d, nonce=%08d, AR1=%08d, NR1=%08d",
ar_nr_responses[0], // UID
ar_nr_responses[1], //NT
ar_nr_responses[2], //AR1
ar_nr_responses[3] //NR1
);
}
}
}
if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", tracing, traceLen);
}
//-----------------------------------------------------------------------------
// MIFARE sniffer.
//

View file

@ -137,86 +137,86 @@ int CmdHF14AMfWrBl(const char *Cmd)
PrintAndLog("Command execute timeout");
}
return 0;
}
int CmdHF14AMfUWrBl(const char *Cmd)
{
uint8_t blockNo = 0;
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
UsbCommand resp;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf uwrbl <block number> <block data (8 hex symbols)>");
PrintAndLog(" sample: hf mf uwrbl 0 01020304");
return 0;
}
blockNo = param_get8(Cmd, 0);
if (param_gethex(Cmd, 1, bldata, 8)) {
PrintAndLog("Block data must include 8 HEX symbols");
return 1;
}
switch(blockNo)
{
case 0:
PrintAndLog("Access Denied");
break;
case 1:
PrintAndLog("Access Denied");
break;
case 2:
PrintAndLog("--specialblock no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(c.d.asBytes, bldata, 4);
SendCommand(&c);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
case 3:
PrintAndLog("--specialblock no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(d.d.asBytes,bldata, 4);
SendCommand(&d);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
default:
PrintAndLog("--block no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
//UsbCommand e = {CMD_MIFAREU_WRITEBL_COMPAT, {blockNo}};
//memcpy(e.d.asBytes,bldata, 16);
UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(e.d.asBytes,bldata, 4);
SendCommand(&e);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
}
return 0;
}
int CmdHF14AMfRdBl(const char *Cmd)
{
uint8_t blockNo = 0;
return 0;
}
int CmdHF14AMfUWrBl(const char *Cmd)
{
uint8_t blockNo = 0;
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
UsbCommand resp;
if (strlen(Cmd)<3) {
PrintAndLog("Usage: hf mf uwrbl <block number> <block data (8 hex symbols)>");
PrintAndLog(" sample: hf mf uwrbl 0 01020304");
return 0;
}
blockNo = param_get8(Cmd, 0);
if (param_gethex(Cmd, 1, bldata, 8)) {
PrintAndLog("Block data must include 8 HEX symbols");
return 1;
}
switch(blockNo)
{
case 0:
PrintAndLog("Access Denied");
break;
case 1:
PrintAndLog("Access Denied");
break;
case 2:
PrintAndLog("--specialblock no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(c.d.asBytes, bldata, 4);
SendCommand(&c);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
case 3:
PrintAndLog("--specialblock no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
UsbCommand d = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(d.d.asBytes,bldata, 4);
SendCommand(&d);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
default:
PrintAndLog("--block no:%02x", blockNo);
PrintAndLog("--data: %s", sprint_hex(bldata, 4));
//UsbCommand e = {CMD_MIFAREU_WRITEBL_COMPAT, {blockNo}};
//memcpy(e.d.asBytes,bldata, 16);
UsbCommand e = {CMD_MIFAREU_WRITEBL, {blockNo}};
memcpy(e.d.asBytes,bldata, 4);
SendCommand(&e);
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
break;
}
return 0;
}
int CmdHF14AMfRdBl(const char *Cmd)
{
uint8_t blockNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
@ -259,135 +259,135 @@ int CmdHF14AMfRdBl(const char *Cmd)
PrintAndLog("Command execute timeout");
}
return 0;
}
int CmdHF14AMfURdBl(const char *Cmd)
{
uint8_t blockNo = 0;
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf mf urdbl <block number>");
PrintAndLog(" sample: hf mf urdbl 0");
return 0;
}
blockNo = param_get8(Cmd, 0);
PrintAndLog("--block no:%02x", blockNo);
UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
if (isOK)
PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
else
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
return 0;
}
int CmdHF14AMfURdCard(const char *Cmd)
{
int i;
uint8_t sectorNo = 0;
uint8_t *lockbytes_t=NULL;
uint8_t lockbytes[2]={0,0};
bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t isOK = 0;
uint8_t * data = NULL;
if (sectorNo > 15) {
PrintAndLog("Sector number must be less than 16");
return 1;
}
PrintAndLog("Attempting to Read Ultralight... ");
UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
isOK = resp.arg[0] & 0xff;
data = resp.d.asBytes;
PrintAndLog("isOk:%02x", isOK);
if (isOK)
for (i = 0; i < 16; i++) {
switch(i){
case 2:
//process lock bytes
lockbytes_t=data+(i*4);
lockbytes[0]=lockbytes_t[2];
lockbytes[1]=lockbytes_t[3];
for(int j=0; j<16; j++){
bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8));
}
//PrintAndLog("LB %02x %02x", lockbytes[0],lockbytes[1]);
//PrintAndLog("LB2b %02x %02x %02x %02x %02x %02x %02x %02x",bit[8],bit[9],bit[10],bit[11],bit[12],bit[13],bit[14],bit[15]);
PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
break;
case 3:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]);
break;
case 4:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]);
break;
case 5:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]);
break;
case 6:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]);
break;
case 7:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]);
break;
case 8:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]);
break;
case 9:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]);
break;
case 10:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]);
break;
case 11:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]);
break;
case 12:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]);
break;
case 13:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]);
break;
case 14:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]);
break;
case 15:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]);
break;
default:
PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
break;
}
}
} else {
PrintAndLog("Command1 execute timeout");
}
return 0;
}
int CmdHF14AMfRdSc(const char *Cmd)
{
int i;
return 0;
}
int CmdHF14AMfURdBl(const char *Cmd)
{
uint8_t blockNo = 0;
if (strlen(Cmd)<1) {
PrintAndLog("Usage: hf mf urdbl <block number>");
PrintAndLog(" sample: hf mf urdbl 0");
return 0;
}
blockNo = param_get8(Cmd, 0);
PrintAndLog("--block no:%02x", blockNo);
UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
uint8_t isOK = resp.arg[0] & 0xff;
uint8_t * data = resp.d.asBytes;
if (isOK)
PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 4));
else
PrintAndLog("isOk:%02x", isOK);
} else {
PrintAndLog("Command execute timeout");
}
return 0;
}
int CmdHF14AMfURdCard(const char *Cmd)
{
int i;
uint8_t sectorNo = 0;
uint8_t *lockbytes_t=NULL;
uint8_t lockbytes[2]={0,0};
bool bit[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t isOK = 0;
uint8_t * data = NULL;
if (sectorNo > 15) {
PrintAndLog("Sector number must be less than 16");
return 1;
}
PrintAndLog("Attempting to Read Ultralight... ");
UsbCommand c = {CMD_MIFAREU_READCARD, {sectorNo}};
SendCommand(&c);
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
isOK = resp.arg[0] & 0xff;
data = resp.d.asBytes;
PrintAndLog("isOk:%02x", isOK);
if (isOK)
for (i = 0; i < 16; i++) {
switch(i){
case 2:
//process lock bytes
lockbytes_t=data+(i*4);
lockbytes[0]=lockbytes_t[2];
lockbytes[1]=lockbytes_t[3];
for(int j=0; j<16; j++){
bit[j]=lockbytes[j/8] & ( 1 <<(7-j%8));
}
//PrintAndLog("LB %02x %02x", lockbytes[0],lockbytes[1]);
//PrintAndLog("LB2b %02x %02x %02x %02x %02x %02x %02x %02x",bit[8],bit[9],bit[10],bit[11],bit[12],bit[13],bit[14],bit[15]);
PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
break;
case 3:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[4]);
break;
case 4:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[3]);
break;
case 5:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[2]);
break;
case 6:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[1]);
break;
case 7:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[0]);
break;
case 8:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[15]);
break;
case 9:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[14]);
break;
case 10:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[13]);
break;
case 11:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[12]);
break;
case 12:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[11]);
break;
case 13:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[10]);
break;
case 14:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[9]);
break;
case 15:
PrintAndLog("Block %02x:%s [%d]", i,sprint_hex(data + i * 4, 4),bit[8]);
break;
default:
PrintAndLog("Block %02x:%s ", i,sprint_hex(data + i * 4, 4));
break;
}
}
} else {
PrintAndLog("Command1 execute timeout");
}
return 0;
}
int CmdHF14AMfRdSc(const char *Cmd)
{
int i;
uint8_t sectorNo = 0;
uint8_t keyType = 0;
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
@ -1144,24 +1144,68 @@ int CmdHF14AMfChk(const char *Cmd)
int CmdHF14AMf1kSim(const char *Cmd)
{
uint8_t uid[4] = {0, 0, 0, 0};
uint8_t uid[7] = {0, 0, 0, 0,0,0,0};
uint8_t exitAfterNReads = 0;
uint8_t flags = 0;
if (param_getchar(Cmd, 0) == 'h') {
PrintAndLog("Usage: hf mf sim <uid (8 hex symbols)>");
PrintAndLog("Usage: hf mf sim u <uid (8 hex symbols)> n <numreads> i x");
PrintAndLog(" u (Optional) UID. If not specified, the UID from emulator memory will be used");
PrintAndLog(" n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite");
PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted");
PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)");
PrintAndLog(" sample: hf mf sim 0a0a0a0a ");
return 0;
}
if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) {
PrintAndLog("UID must include 8 HEX symbols");
return 1;
}
PrintAndLog(" uid:%s ", sprint_hex(uid, 4));
UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}};
memcpy(c.d.asBytes, uid, 4);
uint8_t pnr = 0;
if (param_getchar(Cmd, pnr) == 'u') {
if(param_gethex(Cmd, pnr+1, uid, 8) == 0)
{
flags |=FLAG_4B_UID_IN_DATA; // UID from packet
}else if(param_gethex(Cmd,pnr+1,uid,14) == 0)
{
flags |= FLAG_7B_UID_IN_DATA;// UID from packet
}else
{
PrintAndLog("UID, if specified, must include 8 or 14 HEX symbols");
return 1;
}
pnr +=2;
}
if (param_getchar(Cmd, pnr) == 'n') {
exitAfterNReads = param_get8(Cmd,pnr+1);
pnr += 2;
}
if (param_getchar(Cmd, pnr) == 'i' ) {
//Using a flag to signal interactiveness, least significant bit
flags |= FLAG_INTERACTIVE;
pnr++;
}
if (param_getchar(Cmd, pnr) == 'x' ) {
//Using a flag to signal interactiveness, least significant bit
flags |= FLAG_NR_AR_ATTACK;
}
PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) ",
flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4):
flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A"
, exitAfterNReads, flags,flags);
UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}};
memcpy(c.d.asBytes, uid, sizeof(uid));
SendCommand(&c);
if(flags & 1)
{
UsbCommand resp;
PrintAndLog("Press pm3-button to abort simulation");
while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
//We're waiting only 1.5 s at a time, otherwise we get the
// annoying message about "Waiting for a response... "
}
}
return 0;
}
@ -1291,7 +1335,11 @@ int CmdHF14AMfELoad(const char *Cmd)
while(!feof(f)){
memset(buf, 0, sizeof(buf));
if (fgets(buf, sizeof(buf), f) == NULL) {
PrintAndLog("File reading error.");
if(blockNum == 16 * 4)
{
break;
}
PrintAndLog("File reading error.");
return 2;
}
@ -1319,7 +1367,7 @@ int CmdHF14AMfELoad(const char *Cmd)
PrintAndLog("File content error. There must be 64 blocks");
return 4;
}
PrintAndLog("Loaded from file: %s", filename);
PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);
return 0;
}
@ -1864,15 +1912,15 @@ int CmdHF14AMfSniff(const char *Cmd){
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},
{"help", CmdHelp, 1, "This help"},
{"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"},
{"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"},
{"urdbl", CmdHF14AMfURdBl, 0, "Read MIFARE Ultralight block"},
{"urdcard", CmdHF14AMfURdCard, 0,"Read MIFARE Ultralight Card"},
{"uwrbl", CmdHF14AMfUWrBl, 0,"Write MIFARE Ultralight block"},
{"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"},
{"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"},
{"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"},
{"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"},
{"chk", CmdHF14AMfChk, 0, "Test block keys"},
{"mifare", CmdHF14AMifare, 0, "Read parity error messages. param - <used card nonce>"},

View file

@ -151,6 +151,15 @@ typedef struct {
#define CMD_UNKNOWN 0xFFFF
//Mifare simulation flags
#define FLAG_INTERACTIVE 0x01
#define FLAG_4B_UID_IN_DATA 0x02
#define FLAG_7B_UID_IN_DATA 0x04
#define FLAG_NR_AR_ATTACK 0x08
// CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions:
/* Whether a bootloader that understands the common_area is present */
#define DEVICE_INFO_FLAG_BOOTROM_PRESENT (1<<0)