X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/bbd118760ba7c244d64b8380de0072c6f95a6113..eabbb166f06996c5f8a04166f9a9e934195e85af:/client/cmdhfmf.c diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 05202ac5..4cb9577b 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,86 +9,48 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" -#include "./nonce2key/nonce2key.h" + +#include +#include +#include +#include +#include +#include "proxmark3.h" +#include "cmdmain.h" +#include "cmdhfmfhard.h" +#include "util.h" +#include "util_posix.h" +#include "usb_cmd.h" +#include "ui.h" +#include "mifarehost.h" +#include "mifare.h" +#include "mfkey.h" + +#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up + static int CmdHelp(const char *Cmd); int CmdHF14AMifare(const char *Cmd) { - uint32_t uid = 0; - uint32_t nt = 0, nr = 0; - uint64_t par_list = 0, ks_list = 0, r_key = 0; - int16_t isOK = 0; - - UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; - - // message - printf("-------------------------------------------------------------------------\n"); - printf("Executing command. Expected execution time: 25sec on average :-)\n"); - printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); - printf("-------------------------------------------------------------------------\n"); - - - start: - clearCommandBuffer(); - SendCommand(&c); - - //flush queue - while (ukbhit()) getchar(); - - // wait cycle - while (true) { - printf("."); - fflush(stdout); - if (ukbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { - isOK = resp.arg[0]; - uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); - nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); - par_list = bytes_to_num(resp.d.asBytes + 8, 8); - ks_list = bytes_to_num(resp.d.asBytes + 16, 8); - nr = bytes_to_num(resp.d.asBytes + 24, 4); - printf("\n\n"); - switch (isOK) { - case -1 : PrintAndLog("Button pressed. Aborted.\n"); break; - case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break; - case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break; - case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown"); - PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour.\n"); break; - default: ; - } - break; - } - } - - printf("\n"); - - // error - if (isOK != 1) return 1; - - // execute original function from util nonce2key - if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { - isOK = 2; - PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); - PrintAndLog("Failing is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); - c.arg[0] = false; - goto start; - } else { - isOK = 0; - printf("------------------------------------------------------------------\n"); - PrintAndLog("Found valid key:%012"llx" \n", r_key); + int isOK = 0; + uint64_t key = 0; + isOK = mfDarkside(&key); + switch (isOK) { + case -1 : PrintAndLog("Button pressed. Aborted."); return 1; + case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)."); return 1; + case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable)."); return 1; + case -4 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown"); + PrintAndLog("generating polynomial with 16 effective bits only, but shows unexpected behaviour."); return 1; + case -5 : PrintAndLog("Aborted via keyboard."); return 1; + default : PrintAndLog("Found valid key:%012" PRIx64 "\n", key); } PrintAndLog(""); return 0; } + int CmdHF14AMfWrBl(const char *Cmd) { uint8_t blockNo = 0; @@ -302,7 +264,8 @@ int CmdHF14AMfDump(const char *Cmd) // Read keys A from file for (sectorNo=0; sectorNo>2) | ((data[8] & 0x1)<<1) | ((data[8] & 0x10)>>4); // C1C2C3 for data area 0 - rights[sectorNo][1] = ((data[7] & 0x20)>>3) | ((data[8] & 0x2)<<0) | ((data[8] & 0x20)>>5); // C1C2C3 for data area 1 - rights[sectorNo][2] = ((data[7] & 0x40)>>4) | ((data[8] & 0x4)>>1) | ((data[8] & 0x40)>>6); // C1C2C3 for data area 2 - rights[sectorNo][3] = ((data[7] & 0x80)>>5) | ((data[8] & 0x8)>>2) | ((data[8] & 0x80)>>7); // C1C2C3 for sector trailer + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + uint8_t *data = resp.d.asBytes; + if (isOK){ + rights[sectorNo][0] = ((data[7] & 0x10)>>2) | ((data[8] & 0x1)<<1) | ((data[8] & 0x10)>>4); // C1C2C3 for data area 0 + rights[sectorNo][1] = ((data[7] & 0x20)>>3) | ((data[8] & 0x2)<<0) | ((data[8] & 0x20)>>5); // C1C2C3 for data area 1 + rights[sectorNo][2] = ((data[7] & 0x40)>>4) | ((data[8] & 0x4)>>1) | ((data[8] & 0x40)>>6); // C1C2C3 for data area 2 + rights[sectorNo][3] = ((data[7] & 0x80)>>5) | ((data[8] & 0x8)>>2) | ((data[8] & 0x80)>>7); // C1C2C3 for sector trailer + break; + } else if (tries == 2) { // on last try set defaults + PrintAndLog("Could not get access rights for sector %2d. Trying with defaults...", sectorNo); + rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; + rights[sectorNo][3] = 0x01; + } } else { - PrintAndLog("Could not get access rights for sector %2d. Trying with defaults...", sectorNo); + PrintAndLog("Command execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; rights[sectorNo][3] = 0x01; } - } else { - PrintAndLog("Command execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); - rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; - rights[sectorNo][3] = 0x01; } } @@ -357,27 +324,33 @@ int CmdHF14AMfDump(const char *Cmd) for (sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { bool received = false; - - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. - UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; - memcpy(c.d.asBytes, keyA[sectorNo], 6); - SendCommand(&c); - received = WaitForResponseTimeout(CMD_ACK,&resp,1500); - } else { // data block. Check if it can be read with key A or key B - uint8_t data_area = sectorNo<32?blockNo:blockNo/5; - if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work - UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}}; - memcpy(c.d.asBytes, keyB[sectorNo], 6); - SendCommand(&c); - received = WaitForResponseTimeout(CMD_ACK,&resp,1500); - } else if (rights[sectorNo][data_area] == 0x07) { // no key would work - isOK = false; - PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); - } else { // key A would work + for (tries = 0; tries < 3; tries++) { + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keyA[sectorNo], 6); SendCommand(&c); received = WaitForResponseTimeout(CMD_ACK,&resp,1500); + } else { // data block. Check if it can be read with key A or key B + uint8_t data_area = sectorNo<32?blockNo:blockNo/5; + if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work + UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}}; + memcpy(c.d.asBytes, keyB[sectorNo], 6); + SendCommand(&c); + received = WaitForResponseTimeout(CMD_ACK,&resp,1500); + } else if (rights[sectorNo][data_area] == 0x07) { // no key would work + isOK = false; + PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); + tries = 2; + } else { // key A would work + UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; + memcpy(c.d.asBytes, keyA[sectorNo], 6); + SendCommand(&c); + received = WaitForResponseTimeout(CMD_ACK,&resp,1500); + } + } + if (received) { + isOK = resp.arg[0] & 0xff; + if (isOK) break; } } @@ -466,16 +439,17 @@ int CmdHF14AMfRestore(const char *Cmd) } for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) { + size_t bytes_read = fread(keyA[sectorNo], 1, 6, fkeys); + if (bytes_read != 6) { PrintAndLog("File reading error (dumpkeys.bin)."); - fclose(fkeys); return 2; } } for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) { + size_t bytes_read = fread(keyB[sectorNo], 1, 6, fkeys); + if (bytes_read != 6) { PrintAndLog("File reading error (dumpkeys.bin)."); fclose(fkeys); return 2; @@ -495,7 +469,8 @@ int CmdHF14AMfRestore(const char *Cmd) UsbCommand c = {CMD_MIFARE_WRITEBL, {FirstBlockOfSector(sectorNo) + blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); - if (fread(bldata, 1, 16, fdump) == 0) { + size_t bytes_read = fread(bldata, 1, 16, fdump); + if (bytes_read != 16) { PrintAndLog("File reading error (dumpdata.bin)."); fclose(fdump); return 2; @@ -535,10 +510,17 @@ int CmdHF14AMfRestore(const char *Cmd) return 0; } + +typedef struct { + uint64_t Key[2]; + int foundKey[2]; +} sector_t; + + int CmdHF14AMfNested(const char *Cmd) { int i, j, res, iterations; - sector *e_sector = NULL; + sector_t *e_sector = NULL; uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t trgBlockNo = 0; @@ -632,7 +614,7 @@ int CmdHF14AMfNested(const char *Cmd) } key64 = bytes_to_num(keyBlock, 6); if (key64) { - PrintAndLog("Found valid key:%012"llx, key64); + PrintAndLog("Found valid key:%012" PRIx64, key64); // transfer key to the emulator if (transferToEml) { @@ -655,10 +637,10 @@ int CmdHF14AMfNested(const char *Cmd) } } else { // ------------------------------------ multiple sectors working - clock_t time1; - time1 = clock(); + uint64_t msclock1; + msclock1 = msclock(); - e_sector = calloc(SectorsCnt, sizeof(sector)); + e_sector = calloc(SectorsCnt, sizeof(sector_t)); if (e_sector == NULL) return 1; //test current key and additional standard keys first @@ -718,7 +700,7 @@ int CmdHF14AMfNested(const char *Cmd) key64 = bytes_to_num(keyBlock, 6); if (key64) { - PrintAndLog("Found valid key:%012"llx, key64); + PrintAndLog("Found valid key:%012" PRIx64, key64); e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = key64; } @@ -726,7 +708,7 @@ int CmdHF14AMfNested(const char *Cmd) } } - printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)clock() - time1)/CLOCKS_PER_SEC, ((float)clock() - time1)/iterations/CLOCKS_PER_SEC); + printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0); PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations); //print them @@ -734,7 +716,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("|sec|key A |res|key B |res|"); PrintAndLog("|---|----------------|---|----------------|---|"); for (i = 0; i < SectorsCnt; i++) { - PrintAndLog("|%03d| %012"llx" | %d | %012"llx" | %d |", i, + PrintAndLog("|%03d| %012" PRIx64 " | %d | %012" PRIx64 " | %d |", i, e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); } PrintAndLog("|---|----------------|---|----------------|---|"); @@ -785,6 +767,127 @@ int CmdHF14AMfNested(const char *Cmd) return 0; } + +int CmdHF14AMfNestedHard(const char *Cmd) +{ + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t trgBlockNo = 0; + uint8_t trgKeyType = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint8_t trgkey[6] = {0, 0, 0, 0, 0, 0}; + + char ctmp; + ctmp = param_getchar(Cmd, 0); + + if (ctmp != 'R' && ctmp != 'r' && ctmp != 'T' && ctmp != 't' && strlen(Cmd) < 20) { + PrintAndLog("Usage:"); + PrintAndLog(" hf mf hardnested "); + PrintAndLog(" [known target key (12 hex symbols)] [w] [s]"); + PrintAndLog(" or hf mf hardnested r [known target key]"); + PrintAndLog(" "); + PrintAndLog("Options: "); + PrintAndLog(" w: Acquire nonces and write them to binary file nonces.bin"); + PrintAndLog(" s: Slower acquisition (required by some non standard cards)"); + PrintAndLog(" r: Read nonces.bin and start attack"); + PrintAndLog(" "); + PrintAndLog(" sample1: hf mf hardnested 0 A FFFFFFFFFFFF 4 A"); + PrintAndLog(" sample2: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w"); + PrintAndLog(" sample3: hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s"); + PrintAndLog(" sample4: hf mf hardnested r"); + PrintAndLog(" "); + PrintAndLog("Add the known target key to check if it is present in the remaining key space:"); + PrintAndLog(" sample5: hf mf hardnested 0 A A0A1A2A3A4A5 4 A FFFFFFFFFFFF"); + return 0; + } + + bool know_target_key = false; + bool nonce_file_read = false; + bool nonce_file_write = false; + bool slow = false; + int tests = 0; + + + if (ctmp == 'R' || ctmp == 'r') { + nonce_file_read = true; + if (!param_gethex(Cmd, 1, trgkey, 12)) { + know_target_key = true; + } + } else if (ctmp == 'T' || ctmp == 't') { + tests = param_get32ex(Cmd, 1, 100, 10); + if (!param_gethex(Cmd, 2, trgkey, 12)) { + know_target_key = true; + } + } else { + blockNo = param_get8(Cmd, 0); + ctmp = param_getchar(Cmd, 1); + if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') { + keyType = 1; + } + + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + + trgBlockNo = param_get8(Cmd, 3); + ctmp = param_getchar(Cmd, 4); + if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { + PrintAndLog("Target key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') { + trgKeyType = 1; + } + + uint16_t i = 5; + + if (!param_gethex(Cmd, 5, trgkey, 12)) { + know_target_key = true; + i++; + } + + while ((ctmp = param_getchar(Cmd, i))) { + if (ctmp == 's' || ctmp == 'S') { + slow = true; + } else if (ctmp == 'w' || ctmp == 'W') { + nonce_file_write = true; + } else { + PrintAndLog("Possible options are w and/or s"); + return 1; + } + i++; + } + } + + PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d ", + trgBlockNo, + trgKeyType?'B':'A', + trgkey[0], trgkey[1], trgkey[2], trgkey[3], trgkey[4], trgkey[5], + know_target_key?"":" (not set)", + nonce_file_write?"write":nonce_file_read?"read":"none", + slow?"Yes":"No", + tests); + + int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, know_target_key?trgkey:NULL, nonce_file_read, nonce_file_write, slow, tests); + + if (isOK) { + switch (isOK) { + case 1 : PrintAndLog("Error: No response from Proxmark.\n"); break; + case 2 : PrintAndLog("Button pressed. Aborted.\n"); break; + default : break; + } + return 2; + } + + return 0; +} + + int CmdHF14AMfChk(const char *Cmd) { if (strlen(Cmd)<3) { @@ -868,6 +971,7 @@ int CmdHF14AMfChk(const char *Cmd) break; default: PrintAndLog("Key type must be A , B or ?"); + free(keyBlock); return 1; }; @@ -919,13 +1023,14 @@ int CmdHF14AMfChk(const char *Cmd) if (!p) { PrintAndLog("Cannot allocate memory for defKeys"); free(keyBlock); + fclose(f); return 2; } keyBlock = p; } memset(keyBlock + 6 * keycnt, 0, 6); num_to_bytes(strtoll(buf, NULL, 16), 6, keyBlock + 6*keycnt); - PrintAndLog("chk custom key[%2d] %012"llx, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6)); + PrintAndLog("chk custom key[%2d] %012" PRIx64 , keycnt, bytes_to_num(keyBlock + 6*keycnt, 6)); keycnt++; memset(buf, 0, sizeof(buf)); } @@ -969,7 +1074,7 @@ int CmdHF14AMfChk(const char *Cmd) res = mfCheckKeys(b, t, true, size, &keyBlock[6*c], &key64); if (res != 1) { if (!res) { - PrintAndLog("Found valid key:[%012"llx"]",key64); + PrintAndLog("Found valid key:[%012" PRIx64 "]",key64); num_to_bytes(key64, 6, foundKey[t][i]); validKey[t][i] = true; } @@ -1016,12 +1121,12 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } -void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { - #define ATTACK_KEY_COUNT 8 +void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { + #define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim() + // cannot be more than 7 or it will overrun c.d.asBytes(512) uint64_t key = 0; typedef struct { uint64_t keyA; - uint32_t security; uint64_t keyB; } st_t; st_t sector_trailer[ATTACK_KEY_COUNT]; @@ -1034,9 +1139,9 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { for (uint8_t i = 0; i 0) { - //PrintAndLog("Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); - if (mfkey32(ar_resp[i], &key)) { - PrintAndLog("Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); + //PrintAndLog("DEBUG: Trying sector %d, cuid %08x, nt %08x, ar %08x, nr %08x, ar2 %08x, nr2 %08x",ar_resp[i].sector, ar_resp[i].cuid,ar_resp[i].nonce,ar_resp[i].ar,ar_resp[i].nr,ar_resp[i].ar2,ar_resp[i].nr2); + if (doStandardAttack && mfkey32(ar_resp[i], &key)) { + PrintAndLog(" Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); for (uint8_t ii = 0; ii0) { - //PrintAndLog ("block %d, keyA:%04x%08x, keyb:%04x%08x",stSector[i]*4+3, (uint32_t) (sector_trailer[i].keyA>>32), (uint32_t) (sector_trailer[i].keyA &0xFFFFFFFF),(uint32_t) (sector_trailer[i].keyB>>32), (uint32_t) (sector_trailer[i].keyB &0xFFFFFFFF)); uint8_t memBlock[16]; memset(memBlock, 0x00, sizeof(memBlock)); char cmd1[36]; @@ -1081,34 +1213,40 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem) { } } } - //moebius attack + /* + //un-comment to use as well moebius attack for (uint8_t i = ATTACK_KEY_COUNT; i 0) { if (tryMfk32_moebius(ar_resp[i], &key)) { PrintAndLog("M-Found Key%s for sector %02d: [%04x%08x]", (ar_resp[i].keytype) ? "B" : "A", ar_resp[i].sector, (uint32_t) (key>>32), (uint32_t) (key &0xFFFFFFFF)); } } - } + }*/ } int usage_hf14_mf1ksim(void) { - PrintAndLog("Usage: hf mf sim [h] u n i x"); + PrintAndLog("Usage: hf mf sim h u n i x"); PrintAndLog("options:"); PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID 4,7 bytes. If not specified, the UID 4b from emulator memory will be used"); + PrintAndLog(" u (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used"); PrintAndLog(" n (Optional) Automatically exit simulation after 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(" e (Optional) set keys found from 'reader attack' to emulator memory"); - PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f '"); + PrintAndLog(" e (Optional) set keys found from 'reader attack' to emulator memory (implies x and i)"); + PrintAndLog(" f (Optional) get UIDs to use for 'reader attack' from file 'f ' (implies x and i)"); + PrintAndLog(" r (Optional) Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works."); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); PrintAndLog(" hf mf sim u 11223344556677"); - PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim u 112233445566778899AA"); + PrintAndLog(" hf mf sim f uids.txt"); + PrintAndLog(" hf mf sim u 0a0a0a0a e"); + return 0; } int CmdHF14AMf1kSim(const char *Cmd) { + UsbCommand resp; uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; @@ -1121,7 +1259,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { memset(filename, 0x00, sizeof(filename)); int len = 0; char buf[64]; - uint8_t uidBuffer[64]; uint8_t cmdp = 0; bool errors = false; @@ -1131,6 +1268,9 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 'e': case 'E': setEmulatorMem = true; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; cmdp++; break; case 'f': @@ -1141,7 +1281,10 @@ int CmdHF14AMf1kSim(const char *Cmd) { return 0; } attackFromFile = true; - cmdp+=2; + //implies x and i + flags |= FLAG_INTERACTIVE; + flags |= FLAG_NR_AR_ATTACK; + cmdp += 2; break; case 'h': case 'H': @@ -1156,6 +1299,11 @@ int CmdHF14AMf1kSim(const char *Cmd) { exitAfterNReads = param_get8(Cmd, pnr+1); cmdp += 2; break; + case 'r': + case 'R': + flags |= FLAG_RANDOM_NONCE; + cmdp++; + break; case 'u': case 'U': param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); @@ -1165,7 +1313,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 8: flags = FLAG_4B_UID_IN_DATA; break; default: return usage_hf14_mf1ksim(); } - cmdp +=2; + cmdp += 2; break; case 'x': case 'X': @@ -1182,12 +1330,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { //Validations if(errors) return usage_hf14_mf1ksim(); - // attack from file implies nr ar attack... - if (!(flags & FLAG_NR_AR_ATTACK) && attackFromFile) flags |= FLAG_NR_AR_ATTACK; - - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; - UsbCommand resp; - //get uid from file if (attackFromFile) { int count = 0; @@ -1197,9 +1339,10 @@ int CmdHF14AMf1kSim(const char *Cmd) { PrintAndLog("File %s not found or locked", filename); return 1; } - while(!feof(f)){ + PrintAndLog("Loading file and simulating. Press keyboard to abort"); + while(!feof(f) && !ukbhit()){ memset(buf, 0, sizeof(buf)); - memset(uidBuffer, 0, sizeof(uidBuffer)); + memset(uid, 0, sizeof(uid)); if (fgets(buf, sizeof(buf), f) == NULL) { if (count > 0) break; @@ -1208,47 +1351,52 @@ int CmdHF14AMf1kSim(const char *Cmd) { fclose(f); return 2; } - - if (strlen(buf) < uidlen) { - if(strlen(buf) && feof(f)) - break; - PrintAndLog("File content error. Block data must include %d HEX symbols", uidlen); - fclose(f); - return 2; + if(!strlen(buf) && feof(f)) break; + + uidlen = strlen(buf)-1; + switch(uidlen) { + case 20: flags |= FLAG_10B_UID_IN_DATA; break; //not complete + case 14: flags |= FLAG_7B_UID_IN_DATA; break; + case 8: flags |= FLAG_4B_UID_IN_DATA; break; + default: + PrintAndLog("uid in file wrong length at %d (length: %d) [%s]",count, uidlen, buf); + fclose(f); + return 2; } - + for (uint8_t i = 0; i < uidlen; i += 2) { - sscanf(&buf[i], "%02x", (unsigned int *)&uidBuffer[i / 2]); + sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]); } - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", + PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" , exitAfterNReads, flags, flags); + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); - if(flags & FLAG_INTERACTIVE) { - 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... " - } - //got a response - if (flags & FLAG_NR_AR_ATTACK) { - nonces_t ar_resp[ATTACK_KEY_COUNT*2]; - memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); - readerAttack(ar_resp, setEmulatorMem); - } + 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... " + } + //got a response + nonces_t ar_resp[ATTACK_KEY_COUNT*2]; + memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); + // We can skip the standard attack if we have RANDOM_NONCE set. + readerAttack(ar_resp, setEmulatorMem, !(flags & FLAG_RANDOM_NONCE)); + if ((bool)resp.arg[1]) { + PrintAndLog("Device button pressed - quitting"); + fclose(f); + return 4; } - count++; } fclose(f); - } else { + } else { //not from file PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): @@ -1256,6 +1404,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" , exitAfterNReads, flags, flags); + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); @@ -1270,7 +1419,8 @@ int CmdHF14AMf1kSim(const char *Cmd) { if (flags & FLAG_NR_AR_ATTACK) { nonces_t ar_resp[ATTACK_KEY_COUNT*2]; memcpy(ar_resp, resp.d.asBytes, sizeof(ar_resp)); - readerAttack(ar_resp, setEmulatorMem); + // We can skip the standard attack if we have RANDOM_NONCE set. + readerAttack(ar_resp, setEmulatorMem, !(flags & FLAG_RANDOM_NONCE)); } } } @@ -1403,7 +1553,7 @@ int CmdHF14AMfELoad(const char *Cmd) len = param_getstr(Cmd,nameParamNo,filename); - if (len > FILE_PATH_SIZE - 4) len = FILE_PATH_SIZE - 4; + if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; fnameptr += len; @@ -1502,7 +1652,7 @@ int CmdHF14AMfESave(const char *Cmd) len = param_getstr(Cmd,nameParamNo,filename); - if (len > FILE_PATH_SIZE - 4) len = FILE_PATH_SIZE - 4; + if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; // user supplied filename? if (len < 1) { @@ -1626,7 +1776,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) } keyA = bytes_to_num(data, 6); keyB = bytes_to_num(data + 10, 6); - PrintAndLog("|%03d| %012"llx" | %012"llx" |", i, keyA, keyB); + PrintAndLog("|%03d| %012" PRIx64 " | %012" PRIx64 " |", i, keyA, keyB); } PrintAndLog("|---|----------------|----------------|"); @@ -1707,7 +1857,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) { uint8_t memBlock[16] = {0x00}; uint8_t blockNo = 0; - bool wipeCard = FALSE; + bool wipeCard = false; int res; if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { @@ -1778,7 +1928,7 @@ int CmdHF14AMfCLoad(const char *Cmd) return 0; } else { len = strlen(Cmd); - if (len > FILE_PATH_SIZE - 4) len = FILE_PATH_SIZE - 4; + if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; memcpy(filename, Cmd, len); fnameptr += len; @@ -1819,6 +1969,7 @@ int CmdHF14AMfCLoad(const char *Cmd) if (mfCSetBlock(blockNum, buf8, NULL, 0, flags)) { PrintAndLog("Can't set magic card block: %d", blockNum); + fclose(f); return 3; } blockNum++; @@ -1947,7 +2098,7 @@ int CmdHF14AMfCSave(const char *Cmd) { return 0; } else { len = strlen(Cmd); - if (len > FILE_PATH_SIZE - 4) len = FILE_PATH_SIZE - 4; + if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; if (len < 1) { // get filename @@ -2067,11 +2218,14 @@ int CmdHF14AMfSniff(const char *Cmd){ uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; - if (res == 0) return 0; // we are done + if (res == 0) { // we are done + free(buf); + return 0; + } if (res == 1) { // there is (more) data to be transferred if (pckNum == 0) { // first packet, (re)allocate necessary buffer - if (traceLen > bufsize) { + if (traceLen > bufsize || buf == NULL) { uint8_t *p; if (buf == NULL) { // not yet allocated p = malloc(traceLen); @@ -2155,33 +2309,34 @@ int CmdDecryptTraceCmds(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"}, - {"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."}, - {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, - {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, - {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, - {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, - {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, - {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, - {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, - {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, - {"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, - {"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, - {"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"}, - {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"}, - {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"}, - {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, - {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, - {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, - {"decrypt", CmdDecryptTraceCmds,1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, + {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic 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."}, + {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, + {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, + {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, + {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, + {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, + {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, + {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, + {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, + {"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, + {"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, + {"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"}, + {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"}, + {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"}, + {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, + {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, + {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, + {"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, + {NULL, NULL, 0, NULL} }; int CmdHFMF(const char *Cmd)