X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/e683ecb6a56d5aaea9b3d6428dc8c8acdb64bc9f..a9eeb576983f932ee622554ccd4e08be10e695b5:/client/cmdhfmf.c?ds=inline diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index e5592efa..ede88cb7 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,70 +9,228 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" -#include "cmdhfmfhard.h" -#include "nonce2key/nonce2key.h" static int CmdHelp(const char *Cmd); +int usage_hf14_mifare(void){ + PrintAndLog("Usage: hf mf mifare [h] "); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" (Optional) target other block"); + PrintAndLog(" (optional) target key type"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf mifare"); + PrintAndLog(" hf mf mifare 16"); + PrintAndLog(" hf mf mifare 16 B"); + return 0; +} +int usage_hf14_mf1ksim(void){ + PrintAndLog("Usage: hf mf sim [h] u n [i] [x] [e] [v]"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" u (Optional) UID 4,7 or 10bytes. 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 reader"); + PrintAndLog(" e (Optional) Fill simulator keys from found keys"); + PrintAndLog(" v (Optional) Verbose"); + 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 11223344 i x"); + return 0; +} +int usage_hf14_dbg(void){ + PrintAndLog("Usage: hf mf dbg [h] "); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" (Optional) see list for valid levels"); + PrintAndLog(" 0 - no debug messages"); + PrintAndLog(" 1 - error messages"); + PrintAndLog(" 2 - plus information messages"); + PrintAndLog(" 3 - plus debug messages"); + PrintAndLog(" 4 - print even debug messages in timing critical functions"); + PrintAndLog(" Note: this option therefore may cause malfunction itself"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf dbg 3"); + return 0; +} +int usage_hf14_sniff(void){ + PrintAndLog("It continuously gets data from the field and saves it to: log, emulator, emulator file."); + PrintAndLog("Usage: hf mf sniff [h] [l] [d] [f]"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" l save encrypted sequence to logfile `uid.log`"); + PrintAndLog(" d decrypt sequence and put it to log file `uid.log`"); +// PrintAndLog(" n/a e decrypt sequence, collect read and write commands and save the result of the sequence to emulator memory"); + PrintAndLog(" f decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml`"); + PrintAndLog("sample:"); + PrintAndLog(" hf mf sniff l d f"); + return 0; +} +int usage_hf14_nested(void){ + PrintAndLog("Usage:"); + PrintAndLog(" all sectors: hf mf nested [t,d]"); + PrintAndLog(" one sector: hf mf nested o "); + PrintAndLog(" [t]"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog(" t transfer keys into emulator memory"); + PrintAndLog(" d write keys to binary file"); + PrintAndLog(" "); + PrintAndLog("samples:"); + PrintAndLog(" hf mf nested 1 0 A FFFFFFFFFFFF "); + PrintAndLog(" hf mf nested 1 0 A FFFFFFFFFFFF t "); + PrintAndLog(" hf mf nested 1 0 A FFFFFFFFFFFF d "); + PrintAndLog(" hf mf nested o 0 A FFFFFFFFFFFF 4 A"); + return 0; +} +int usage_hf14_hardnested(void){ + 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(" h this help"); + 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(" t tests?"); + PrintAndLog(" "); + PrintAndLog("samples:"); + PrintAndLog(" hf mf hardnested 0 A FFFFFFFFFFFF 4 A"); + PrintAndLog(" hf mf hardnested 0 A FFFFFFFFFFFF 4 A w"); + PrintAndLog(" hf mf hardnested 0 A FFFFFFFFFFFF 4 A w s"); + PrintAndLog(" hf mf hardnested r"); + PrintAndLog(" hf mf hardnested r a0a1a2a3a4a5"); + 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; +} +int usage_hf14_chk(void){ + PrintAndLog("Usage: hf mf chk |<*card memory> [t|d] [] []"); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" * all sectors based on card memory, other values then below defaults to 1k"); + PrintAndLog(" 0 - MINI(320 bytes)"); + PrintAndLog(" 1 - 1K"); + PrintAndLog(" 2 - 2K"); + PrintAndLog(" 4 - 4K"); + PrintAndLog(" d write keys to binary file"); + PrintAndLog(" t write keys to emulator memory\n"); + PrintAndLog(" "); + PrintAndLog("samples:"); + PrintAndLog(" hf mf chk 0 A 1234567890ab keys.dic -- target block 0, Key A"); + PrintAndLog(" hf mf chk *1 ? t -- target all blocks, all keys, 1K, write to emul"); + PrintAndLog(" hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file"); + return 0; +} +int usage_hf14_keybrute(void){ + PrintAndLog("J_Run's 2nd phase of multiple sector nested authentication key recovery"); + PrintAndLog("You have a known 4 last bytes of a key recovered with mf_nonce_brute tool."); + PrintAndLog("First 2 bytes of key will be bruteforced"); + PrintAndLog(""); + PrintAndLog("Usage: hf mf keybrute [h] "); + PrintAndLog("options:"); + PrintAndLog(" h this help"); + PrintAndLog(" target block number"); + PrintAndLog(" target key type"); + PrintAndLog(" candidate key from mf_nonce_brute tool"); + PrintAndLog("samples:"); + PrintAndLog(" hf mf keybrute 1 A 000011223344"); + return 0; +} -int CmdHF14AMifare(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}}; + int tmpchar; + uint8_t blockNo = 0, keytype = MIFARE_AUTH_KEYA; + + char cmdp = param_getchar(Cmd, 0); + if ( cmdp == 'H' || cmdp == 'h') return usage_hf14_mifare(); + + blockNo = param_get8(Cmd, 0); + + cmdp = param_getchar(Cmd, 1); + if (cmdp == 'B' || cmdp == 'b') + keytype = MIFARE_AUTH_KEYB; + + UsbCommand c = {CMD_READER_MIFARE, {true, blockNo, keytype}}; // message printf("-------------------------------------------------------------------------\n"); - printf("Executing command. Expected execution time: 25sec on average :-)\n"); + printf("Executing darkside attack. Expected execution time: 25sec on average :-)\n"); printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); printf("-------------------------------------------------------------------------\n"); - + clock_t t1 = clock(); + time_t start, end; + time(&start); start: clearCommandBuffer(); SendCommand(&c); //flush queue - while (ukbhit()) getchar(); + while (ukbhit()) { + tmpchar = getchar(); + (void)tmpchar; + } // wait cycle while (true) { printf("."); fflush(stdout); if (ukbhit()) { - getchar(); + tmpchar = getchar(); + (void)tmpchar; printf("\naborted via keyboard!\n"); break; } UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { isOK = resp.arg[0]; + printf("\n"); 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"); + case -2 : PrintAndLog("Card isn't vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break; + case -3 : PrintAndLog("Card isn't vulnerable to Darkside attack (its random number generator is not predictable).\n"); break; + case -4 : PrintAndLog("Card isn't 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; + if (par_list == 0 && ks_list != 0) { + // this special attack when parities is zero, uses checkkeys. Which now with block/keytype option also needs. + // but it uses 0|1 instead of 0x60|0x61... + if (nonce2key_ex(blockNo, keytype - 0x60 , uid, nt, nr, ks_list, &r_key) ){ + PrintAndLog("Trying again with a different reader nonce..."); + c.arg[0] = false; + goto start; + } else { + PrintAndLog("Found valid key: %012" PRIx64 " \n", r_key); + goto END; + } + } + // execute original function from util nonce2key if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) { isOK = 2; @@ -81,17 +239,28 @@ start: c.arg[0] = false; goto start; } else { - isOK = 0; - printf("------------------------------------------------------------------\n"); - PrintAndLog("Found valid key: %012"llx" \n", r_key); - } - - PrintAndLog(""); + + // nonce2key found a candidate key. Lets verify it. + uint8_t keyblock[] = {0,0,0,0,0,0}; + num_to_bytes(r_key, 6, keyblock); + uint64_t key64 = 0; + int res = mfCheckKeys(blockNo, keytype - 0x60 , false, 1, keyblock, &key64); + if ( res > 0 ) { + PrintAndLog("Candidate Key found (%012" PRIx64 ") - Test authentication failed. [%d] Restarting darkside attack", r_key, res); + goto start; + } + PrintAndLog("Found valid key: %012" PRIx64 " \n", r_key); + } +END: + t1 = clock() - t1; + time(&end); + unsigned long elapsed_time = difftime(end, start); + if ( t1 > 0 ) + PrintAndLog("Time in darkside: %.0f ticks %u seconds\n", (float)t1, elapsed_time); return 0; } -int CmdHF14AMfWrBl(const char *Cmd) -{ +int CmdHF14AMfWrBl(const char *Cmd) { uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; @@ -140,14 +309,11 @@ int CmdHF14AMfWrBl(const char *Cmd) return 0; } -int CmdHF14AMfRdBl(const char *Cmd) -{ +int CmdHF14AMfRdBl(const char *Cmd) { uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - - char cmdp = 0x00; - + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf rdbl "); @@ -189,8 +355,7 @@ int CmdHF14AMfRdBl(const char *Cmd) return 0; } -int CmdHF14AMfRdSc(const char *Cmd) -{ +int CmdHF14AMfRdSc(const char *Cmd) { int i; uint8_t sectorNo = 0; uint8_t keyType = 0; @@ -247,8 +412,7 @@ int CmdHF14AMfRdSc(const char *Cmd) return 0; } -uint8_t FirstBlockOfSector(uint8_t sectorNo) -{ +uint8_t FirstBlockOfSector(uint8_t sectorNo) { if (sectorNo < 32) { return sectorNo * 4; } else { @@ -256,8 +420,7 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) } } -uint8_t NumBlocksPerSector(uint8_t sectorNo) -{ +uint8_t NumBlocksPerSector(uint8_t sectorNo) { if (sectorNo < 32) { return 4; } else { @@ -265,8 +428,7 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo) } } -int CmdHF14AMfDump(const char *Cmd) -{ +int CmdHF14AMfDump(const char *Cmd) { uint8_t sectorNo, blockNo; uint8_t keyA[40][6]; @@ -305,8 +467,10 @@ int CmdHF14AMfDump(const char *Cmd) } // Read keys A from file + size_t bytes_read; for (sectorNo=0; sectorNo>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 - } else { + 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; @@ -353,6 +520,7 @@ int CmdHF14AMfDump(const char *Cmd) rights[sectorNo][3] = 0x01; } } + } PrintAndLog("|-----------------------------------------|"); PrintAndLog("|----- Dumping all blocks to file... -----|"); @@ -362,7 +530,7 @@ int CmdHF14AMfDump(const char *Cmd) for (sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { bool received = false; - + 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); @@ -379,12 +547,18 @@ int CmdHF14AMfDump(const char *Cmd) } 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); clearCommandBuffer(); SendCommand(&c); received = WaitForResponseTimeout(CMD_ACK,&resp,1500); + } + } + if (received) { + isOK = resp.arg[0] & 0xff; + if (isOK) break; } } @@ -435,8 +609,7 @@ int CmdHF14AMfDump(const char *Cmd) return 0; } -int CmdHF14AMfRestore(const char *Cmd) -{ +int CmdHF14AMfRestore(const char *Cmd) { uint8_t sectorNo,blockNo; uint8_t keyType = 0; uint8_t key[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; @@ -472,8 +645,10 @@ int CmdHF14AMfRestore(const char *Cmd) return 1; } + size_t bytes_read; for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) { + bytes_read = fread( keyA[sectorNo], 1, 6, fkeys ); + if ( bytes_read != 6) { PrintAndLog("File reading error (dumpkeys.bin)."); fclose(fkeys); return 2; @@ -481,7 +656,8 @@ int CmdHF14AMfRestore(const char *Cmd) } for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) { + bytes_read = fread( keyB[sectorNo], 1, 6, fkeys ); + if ( bytes_read != 6) { PrintAndLog("File reading error (dumpkeys.bin)."); fclose(fkeys); return 2; @@ -499,11 +675,12 @@ int CmdHF14AMfRestore(const char *Cmd) for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { for(blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { UsbCommand c = {CMD_MIFARE_WRITEBL, {FirstBlockOfSector(sectorNo) + blockNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - - if (fread(bldata, 1, 16, fdump) == 0) { + memcpy(c.d.asBytes, key, 6); + bytes_read = fread(bldata, 1, 16, fdump); + if ( bytes_read != 16) { PrintAndLog("File reading error (dumpdata.bin)."); fclose(fdump); + fdump = NULL; return 2; } @@ -542,8 +719,7 @@ int CmdHF14AMfRestore(const char *Cmd) return 0; } -int CmdHF14AMfNested(const char *Cmd) -{ +int CmdHF14AMfNested(const char *Cmd) { int i, j, res, iterations; sector *e_sector = NULL; uint8_t blockNo = 0; @@ -552,7 +728,7 @@ int CmdHF14AMfNested(const char *Cmd) uint8_t trgKeyType = 0; uint8_t SectorsCnt = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - uint8_t keyBlock[14*6]; + uint8_t keyBlock[6*6]; uint64_t key64 = 0; bool transferToEml = false; @@ -560,29 +736,14 @@ int CmdHF14AMfNested(const char *Cmd) FILE *fkeys; uint8_t standart[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t tempkey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - char cmdp, ctmp; - if (strlen(Cmd)<3) { - PrintAndLog("Usage:"); - PrintAndLog(" all sectors: hf mf nested [t,d]"); - PrintAndLog(" one sector: hf mf nested o "); - PrintAndLog(" [t]"); - PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog("t - transfer keys into emulator memory"); - PrintAndLog("d - write keys to binary file"); - PrintAndLog(" "); - PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF "); - PrintAndLog(" sample2: hf mf nested 1 0 A FFFFFFFFFFFF t "); - PrintAndLog(" sample3: hf mf nested 1 0 A FFFFFFFFFFFF d "); - PrintAndLog(" sample4: hf mf nested o 0 A FFFFFFFFFFFF 4 A"); - return 0; - } + if (strlen(Cmd)<3) return usage_hf14_nested(); + char cmdp, ctmp; cmdp = param_getchar(Cmd, 0); blockNo = param_get8(Cmd, 1); ctmp = param_getchar(Cmd, 2); - + if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { PrintAndLog("Key type must be A or B"); return 1; @@ -626,45 +787,42 @@ int CmdHF14AMfNested(const char *Cmd) transferToEml |= (ctmp == 'd' || ctmp == 'D'); if (cmdp == 'o') { - PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A'); int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true); - if (isOK) { - switch (isOK) { - case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break; - case -2 : PrintAndLog("Button pressed. Aborted.\n"); break; - case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break; - default : PrintAndLog("Unknown Error.\n"); - } - return 2; - } - key64 = bytes_to_num(keyBlock, 6); - if (key64) { - PrintAndLog("Found valid key:%012"llx, key64); - - // transfer key to the emulator - if (transferToEml) { - uint8_t sectortrailer; - if (trgBlockNo < 32*4) { // 4 block sector - sectortrailer = (trgBlockNo & 0x03) + 3; - } else { // 16 block sector - sectortrailer = (trgBlockNo & 0x0f) + 15; + switch (isOK) { + case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break; + case -2 : PrintAndLog("Button pressed. Aborted.\n"); break; + case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random number generator is not predictable).\n"); break; + case -4 : PrintAndLog("No valid key found"); break; + case -5 : + key64 = bytes_to_num(keyBlock, 6); + + // transfer key to the emulator + if (transferToEml) { + uint8_t sectortrailer; + if (trgBlockNo < 32*4) { // 4 block sector + sectortrailer = (trgBlockNo & 0x03) + 3; + } else { // 16 block sector + sectortrailer = (trgBlockNo & 0x0f) + 15; + } + mfEmlGetMem(keyBlock, sectortrailer, 1); + + if (!trgKeyType) + num_to_bytes(key64, 6, keyBlock); + else + num_to_bytes(key64, 6, &keyBlock[10]); + mfEmlSetMem(keyBlock, sectortrailer, 1); } - mfEmlGetMem(keyBlock, sectortrailer, 1); - - if (!trgKeyType) - num_to_bytes(key64, 6, keyBlock); - else - num_to_bytes(key64, 6, &keyBlock[10]); - mfEmlSetMem(keyBlock, sectortrailer, 1); - } - } else { - PrintAndLog("No valid key found"); + return 0; + default : PrintAndLog("Unknown Error.\n"); } + return 2; } else { // ------------------------------------ multiple sectors working - clock_t time1; - time1 = clock(); - + clock_t t1 = clock(); + unsigned long elapsed_time; + time_t start, end; + time(&start); + e_sector = calloc(SectorsCnt, sizeof(sector)); if (e_sector == NULL) return 1; @@ -675,14 +833,6 @@ int CmdHF14AMfNested(const char *Cmd) num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 3 * 6)); num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 4 * 6)); num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); - num_to_bytes(0x4d3a99c351dd, 6, (uint8_t*)(keyBlock + 6 * 6)); - num_to_bytes(0x1a982c7e459a, 6, (uint8_t*)(keyBlock + 7 * 6)); - num_to_bytes(0xd3f7d3f7d3f7, 6, (uint8_t*)(keyBlock + 8 * 6)); - num_to_bytes(0x714c5c886e97, 6, (uint8_t*)(keyBlock + 9 * 6)); - num_to_bytes(0x587ee5f9350f, 6, (uint8_t*)(keyBlock + 10 * 6)); - num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6)); - num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6)); - num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6)); PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); for (i = 0; i < SectorsCnt; i++) { @@ -693,58 +843,93 @@ int CmdHF14AMfNested(const char *Cmd) if (!res) { e_sector[i].Key[j] = key64; - e_sector[i].foundKey[j] = 1; + e_sector[i].foundKey[j] = TRUE; } } } + clock_t t2 = clock() - t1; + time(&end); + elapsed_time = difftime(end, start); + if ( t2 > 0 ) + PrintAndLog("Time to check 6 known keys: %.0f ticks %u seconds\n", (float)t2 , elapsed_time); + + PrintAndLog("enter nested..."); // nested sectors iterations = 0; - PrintAndLog("nested..."); bool calibrate = true; + for (i = 0; i < NESTED_SECTOR_RETRY; i++) { - for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { - for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { + for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) { + for (trgKeyType = 0; trgKeyType < 2; ++trgKeyType) { + if (e_sector[sectorNo].foundKey[trgKeyType]) continue; - PrintAndLog("-----------------------------------------------"); + int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate); - if(isOK) { - switch (isOK) { - case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break; - case -2 : PrintAndLog("Button pressed. Aborted.\n"); break; - case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (random numbers are not predictable).\n"); break; - default : PrintAndLog("Unknown Error.\n"); - } - free(e_sector); - return 2; - } else { - calibrate = false; + switch (isOK) { + case -1 : PrintAndLog("Error: No response from Proxmark.\n"); break; + case -2 : PrintAndLog("Button pressed. Aborted.\n"); break; + case -3 : PrintAndLog("Tag isn't vulnerable to Nested Attack (its random number generator is not predictable).\n"); break; + case -4 : //key not found + calibrate = false; + iterations++; + continue; + case -5 : + calibrate = false; + iterations++; + e_sector[sectorNo].foundKey[trgKeyType] = 1; + e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); + continue; + + default : PrintAndLog("Unknown Error.\n"); } - - iterations++; + free(e_sector); + return 2; + } + } + } + + t1 = clock() - t1; + time(&end); + elapsed_time = difftime(end, start); + if ( t1 > 0 ) + PrintAndLog("Time in nested: %.0f ticks %u seconds\n", (float)t1, elapsed_time); - key64 = bytes_to_num(keyBlock, 6); - if (key64) { - PrintAndLog("Found valid key:%012"llx, key64); - e_sector[sectorNo].foundKey[trgKeyType] = 1; - e_sector[sectorNo].Key[trgKeyType] = key64; - } + + // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? + PrintAndLog("trying to read key B..."); + for (i = 0; i < SectorsCnt; i++) { + // KEY A but not KEY B + if ( e_sector[i].foundKey[0] && !e_sector[i].foundKey[1] ) { + + uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + + PrintAndLog("Reading block %d", sectrail); + + UsbCommand c = {CMD_MIFARE_READBL, {sectrail, 0, 0}}; + num_to_bytes(e_sector[i].Key[0], 6, c.d.asBytes); // KEY A + clearCommandBuffer(); + SendCommand(&c); + + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500)) continue; + + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK) continue; + + uint8_t *data = resp.d.asBytes; + key64 = bytes_to_num(data+10, 6); + if (key64) { + PrintAndLog("Data:%s", sprint_hex(data+10, 6)); + e_sector[i].foundKey[1] = TRUE; + e_sector[i].Key[1] = key64; } } } - 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); - PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations); //print them - PrintAndLog("|---|----------------|---|----------------|---|"); - PrintAndLog("|sec|key A |res|key B |res|"); - PrintAndLog("|---|----------------|---|----------------|---|"); - for (i = 0; i < SectorsCnt; i++) { - PrintAndLog("|%03d| %012"llx" | %d | %012"llx" | %d |", i, - e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); - } - PrintAndLog("|---|----------------|---|----------------|---|"); + printKeyTable( SectorsCnt, e_sector ); // transfer them to the emulator if (transferToEml) { @@ -792,8 +977,7 @@ int CmdHF14AMfNested(const char *Cmd) return 0; } -int CmdHF14AMfNestedHard(const char *Cmd) -{ +int CmdHF14AMfNestedHard(const char *Cmd) { uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t trgBlockNo = 0; @@ -803,41 +987,23 @@ int CmdHF14AMfNestedHard(const char *Cmd) char ctmp; ctmp = param_getchar(Cmd, 0); - - if (ctmp != 'R' && ctmp != 'r' && 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; - } + if (ctmp == 'H' || ctmp == 'h' ) return usage_hf14_hardnested(); + if (ctmp != 'R' && ctmp != 'r' && ctmp != 'T' && ctmp != 't' && strlen(Cmd) < 20) return usage_hf14_hardnested(); 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); } else { - blockNo = param_get8(Cmd, 0); ctmp = param_getchar(Cmd, 1); if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') { @@ -883,15 +1049,17 @@ int CmdHF14AMfNestedHard(const char *Cmd) } } - 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 ", + 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"); + 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); + uint64_t foundkey = 0; + int16_t isOK = mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType, know_target_key ? trgkey : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey); if (isOK) { switch (isOK) { @@ -905,19 +1073,9 @@ int CmdHF14AMfNestedHard(const char *Cmd) return 0; } -int CmdHF14AMfChk(const char *Cmd) -{ - if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf mf chk |<*card memory> [t|d] [] []"); - PrintAndLog(" * - all sectors"); - PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog("d - write keys to binary file"); - PrintAndLog("t - write keys to emulator memory\n"); - PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); - PrintAndLog(" hf mf chk *1 ? t"); - PrintAndLog(" hf mf chk *1 ? d"); - return 0; - } +int CmdHF14AMfChk(const char *Cmd) { + + if (strlen(Cmd)<3) return usage_hf14_chk(); FILE * f; char filename[FILE_PATH_SIZE]={0}; @@ -925,6 +1083,8 @@ int CmdHF14AMfChk(const char *Cmd) uint8_t *keyBlock = NULL, *p; uint8_t stKeyBlock = 20; + sector *e_sector = NULL; + int i, res; int keycnt = 0; char ctmp = 0x00; @@ -933,14 +1093,15 @@ int CmdHF14AMfChk(const char *Cmd) uint8_t keyType = 0; uint64_t key64 = 0; + uint8_t tempkey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + int transferToEml = 0; int createDumpFile = 0; keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; - uint64_t defaultKeys[] = - { + uint64_t defaultKeys[] = { 0xffffffffffff, // Default key (first key used by program if no user defined key) 0x000000000000, // Blank key 0xa0a1a2a3a4a5, // NFCForum MAD key @@ -958,9 +1119,8 @@ int CmdHF14AMfChk(const char *Cmd) int defaultKeysSize = sizeof(defaultKeys) / sizeof(uint64_t); for (int defaultKeyCounter = 0; defaultKeyCounter < defaultKeysSize; defaultKeyCounter++) - { num_to_bytes(defaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6)); - } + if (param_getchar(Cmd, 0)=='*') { blockNo = 3; @@ -971,9 +1131,9 @@ int CmdHF14AMfChk(const char *Cmd) case '4': SectorsCnt = 40; break; default: SectorsCnt = 16; } - } - else + } else { blockNo = param_get8(Cmd, 0); + } ctmp = param_getchar(Cmd, 1); switch (ctmp) { @@ -1007,7 +1167,7 @@ int CmdHF14AMfChk(const char *Cmd) } keyBlock = p; } - PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, + PrintAndLog("key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); keycnt++; @@ -1040,13 +1200,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("check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6)); keycnt++; memset(buf, 0, sizeof(buf)); } @@ -1063,205 +1224,516 @@ int CmdHF14AMfChk(const char *Cmd) if (keycnt == 0) { PrintAndLog("No key specified, trying default keys"); for (;keycnt < defaultKeysSize; keycnt++) - PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, + PrintAndLog("key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } // initialize storage for found keys - bool validKey[2][40]; - uint8_t foundKey[2][40][6]; - for (uint16_t t = 0; t < 2; t++) { - for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { - validKey[t][sectorNo] = false; - for (uint16_t i = 0; i < 6; i++) { - foundKey[t][sectorNo][i] = 0xff; - } - } + e_sector = calloc(SectorsCnt, sizeof(sector)); + if (e_sector == NULL) { + free(keyBlock); + return 1; + } + + // empty e_sector + for(int i = 0; i < SectorsCnt; ++i){ + e_sector[i].Key[0] = 0xffffffffffff; + e_sector[i].Key[1] = 0xffffffffffff; + e_sector[i].foundKey[0] = FALSE; + e_sector[i].foundKey[1] = FALSE; } + - for ( int t = !keyType; t < 2; keyType==2?(t++):(t=2) ) { - int b=blockNo; + uint8_t trgKeyType = 0; + uint32_t max_keys = keycnt > (USB_CMD_DATA_SIZE/6) ? (USB_CMD_DATA_SIZE/6) : keycnt; + + // time + clock_t t1 = clock(); + time_t start, end; + time(&start); + + // check keys. + for (trgKeyType = !keyType; trgKeyType < 2; (keyType==2) ? (++trgKeyType) : (trgKeyType=2) ) { + + int b = blockNo; for (int i = 0; i < SectorsCnt; ++i) { - PrintAndLog("--sector:%2d, block:%3d, key type:%C, key count:%2d ", i, b, t?'B':'A', keycnt); - uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt; - for (uint32_t c = 0; c < keycnt; c+=max_keys) { - uint32_t size = keycnt-c>max_keys?max_keys:keycnt-c; - res = mfCheckKeys(b, t, true, size, &keyBlock[6*c], &key64); - if (res != 1) { - if (!res) { - PrintAndLog("Found valid key:[%012"llx"]",key64); - num_to_bytes(key64, 6, foundKey[t][i]); - validKey[t][i] = true; - } - } else { - PrintAndLog("Command execute timeout"); + + // skip already found keys. + if (e_sector[i].foundKey[trgKeyType]) continue; + + for (uint32_t c = 0; c < keycnt; c += max_keys) { + printf("."); + fflush(stdout); + uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; + + res = mfCheckKeys(b, trgKeyType, true, size, &keyBlock[6*c], &key64); + if (!res) { + e_sector[i].Key[trgKeyType] = key64; + e_sector[i].foundKey[trgKeyType] = TRUE; + break; } } - b<127?(b+=4):(b+=16); + b < 127 ? ( b +=4 ) : ( b += 16 ); } } + t1 = clock() - t1; + time(&end); + unsigned long elapsed_time = difftime(end, start); + if ( t1 > 0 ) + PrintAndLog("\nTime in checkkeys: %.0f ticks %u seconds\n", (float)t1, elapsed_time); - if (transferToEml) { - uint8_t block[16]; - for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { - if (validKey[0][sectorNo] || validKey[1][sectorNo]) { - mfEmlGetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); - for (uint16_t t = 0; t < 2; t++) { - if (validKey[t][sectorNo]) { - memcpy(block + t*10, foundKey[t][sectorNo], 6); - } + + // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? + if ( keyType != 1 ) { + PrintAndLog("testing to read key B..."); + for (i = 0; i < SectorsCnt; i++) { + // KEY A but not KEY B + if ( e_sector[i].foundKey[0] && !e_sector[i].foundKey[1] ) { + + uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + + PrintAndLog("Reading block %d", sectrail); + + UsbCommand c = {CMD_MIFARE_READBL, {sectrail, 0, 0}}; + num_to_bytes(e_sector[i].Key[0], 6, c.d.asBytes); // KEY A + clearCommandBuffer(); + SendCommand(&c); + + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK,&resp,1500)) continue; + + uint8_t isOK = resp.arg[0] & 0xff; + if (!isOK) continue; + + uint8_t *data = resp.d.asBytes; + key64 = bytes_to_num(data+10, 6); + if (key64) { + PrintAndLog("Data:%s", sprint_hex(data+10, 6)); + e_sector[i].foundKey[1] = 1; + e_sector[i].Key[1] = key64; } - mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); } } - PrintAndLog("Found keys have been transferred to the emulator memory"); } + + //print them + printKeyTable( SectorsCnt, e_sector ); + + if (transferToEml) { + uint8_t block[16] = {0x00}; + for (uint8_t i = 0; i < SectorsCnt; ++i ) { + mfEmlGetMem(block, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); + if (e_sector[i].foundKey[0]) + num_to_bytes(e_sector[i].Key[0], 6, block); + if (e_sector[i].foundKey[1]) + num_to_bytes(e_sector[i].Key[1], 6, block+10); + mfEmlSetMem(block, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); + } + PrintAndLog("Found keys have been transferred to the emulator memory"); + } + if (createDumpFile) { FILE *fkeys = fopen("dumpkeys.bin","wb"); if (fkeys == NULL) { PrintAndLog("Could not create file dumpkeys.bin"); free(keyBlock); + free(e_sector); return 1; } - for (uint16_t t = 0; t < 2; t++) { - fwrite(foundKey[t], 1, 6*SectorsCnt, fkeys); + PrintAndLog("Printing keys to binary file dumpkeys.bin..."); + + for( i=0; i n i x"); - PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID. If not specified, the UID 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(""); - PrintAndLog(" sample: hf mf sim u 0a0a0a0a "); - return 0; - } - 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; + // initialize storage for found keys + if (k_sector == NULL) + k_sector = calloc(k_sectorsCount, sizeof(sector)); + if (k_sector == NULL) + return; + + // empty e_sector + for(int i = 0; i < k_sectorsCount; ++i){ + k_sector[i].Key[0] = 0xffffffffffff; + k_sector[i].Key[1] = 0xffffffffffff; + k_sector[i].foundKey[0] = FALSE; + k_sector[i].foundKey[1] = FALSE; } - if (param_getchar(Cmd, pnr) == 'n') { - exitAfterNReads = param_get8(Cmd,pnr+1); - pnr += 2; +} +void showSectorTable(){ + if (k_sector != NULL) { + printKeyTable(k_sectorsCount, k_sector); + free(k_sector); + k_sector = NULL; } - if (param_getchar(Cmd, pnr) == 'i' ) { - //Using a flag to signal interactiveness, least significant bit - flags |= FLAG_INTERACTIVE; - pnr++; +} +void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose) { + + uint64_t key = 0; + bool success = FALSE; + + if (k_sector == NULL) + emptySectorTable(); + + success = tryMfk32_moebius(data, &key, verbose); + if (success) { + uint8_t sector = data.sector; + uint8_t keytype = data.keytype; + + PrintAndLog("Reader is trying authenticate with: Key %s, sector %02d: [%012" PRIx64 "]" + , keytype ? "B" : "A" + , sector + , key + ); + + k_sector[sector].Key[keytype] = key; + k_sector[sector].foundKey[keytype] = TRUE; + + //set emulator memory for keys + if (setEmulatorMem) { + uint8_t memBlock[16] = {0,0,0,0,0,0, 0xff, 0x0F, 0x80, 0x69, 0,0,0,0,0,0}; + num_to_bytes( k_sector[sector].Key[0], 6, memBlock); + num_to_bytes( k_sector[sector].Key[1], 6, memBlock+10); + //iceman, guessing this will not work so well for 4K tags. + PrintAndLog("Setting Emulator Memory Block %02d: [%s]" + , (sector*4) + 3 + , sprint_hex( memBlock, sizeof(memBlock)) + ); + mfEmlSetMem( memBlock, (sector*4) + 3, 1); + } } +} - 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); +int CmdHF14AMf1kSim(const char *Cmd) { + uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t exitAfterNReads = 0; + uint8_t flags = (FLAG_UID_IN_EMUL | FLAG_4B_UID_IN_DATA); + int uidlen = 0; + uint8_t cmdp = 0; + bool errors = FALSE; + bool verbose = FALSE; + bool setEmulatorMem = FALSE; + nonces_t data[1]; + + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { + case 'e': + case 'E': + setEmulatorMem = TRUE; + cmdp++; + break; + case 'h': + case 'H': + return usage_hf14_mf1ksim(); + case 'i': + case 'I': + flags |= FLAG_INTERACTIVE; + cmdp++; + break; + case 'n': + case 'N': + exitAfterNReads = param_get8(Cmd, cmdp+1); + cmdp += 2; + break; + case 'u': + case 'U': + param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); + switch(uidlen) { + case 20: flags = FLAG_10B_UID_IN_DATA; break; + case 14: flags = FLAG_7B_UID_IN_DATA; break; + case 8: flags = FLAG_4B_UID_IN_DATA; break; + default: return usage_hf14_mf1ksim(); + } + cmdp += 2; + break; + case 'v': + case 'V': + verbose = TRUE; + cmdp++; + break; + case 'x': + case 'X': + flags |= FLAG_NR_AR_ATTACK; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = TRUE; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_hf14_mf1ksim(); + + PrintAndLog(" uid:%s, numreads:%d, flags:%d (0x%02x) " + , (uidlen == 0 ) ? "N/A" : sprint_hex(uid, uidlen>>1) + , exitAfterNReads + , flags + , flags); - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads, 0}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); + UsbCommand resp; - if(flags & FLAG_INTERACTIVE) - { - uint8_t data[40]; - uint8_t key[6]; - - UsbCommand resp; + if(flags & FLAG_INTERACTIVE) { PrintAndLog("Press pm3-button or send another cmd 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... " - //} - while(!ukbhit() ){ - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) continue; + while( !ukbhit() ){ + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) continue; if ( !(flags & FLAG_NR_AR_ATTACK) ) break; if ( (resp.arg[0] & 0xffff) != CMD_SIMULATE_MIFARE_CARD ) break; - memset(data, 0x00, sizeof(data)); - memset(key, 0x00, sizeof(key)); - int len = (resp.arg[1] > sizeof(data)) ? sizeof(data) : resp.arg[1]; - - memcpy(data, resp.d.asBytes, len); - - uint64_t corr_uid = 0; - if ( memcmp(data, "\x00\x00\x00\x00", 4) == 0 ) { - corr_uid = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]; - tryMfk32(corr_uid, data, key); - } else { - corr_uid |= (uint64_t)data[2] << 48; - corr_uid |= (uint64_t)data[1] << 40; - corr_uid |= (uint64_t)data[0] << 32; - corr_uid |= data[7] << 24; - corr_uid |= data[6] << 16; - corr_uid |= data[5] << 8; - corr_uid |= data[4]; - tryMfk64(corr_uid, data, key); + memcpy(data, resp.d.asBytes, sizeof(data)); + readerAttack(data[0], setEmulatorMem, verbose); + } + showSectorTable(); + } + return 0; +} + +int CmdHF14AMfSniff(const char *Cmd){ + bool wantLogToFile = FALSE; + bool wantDecrypt = FALSE; + //bool wantSaveToEml = FALSE; TODO + bool wantSaveToEmlFile = FALSE; + + //var + int tmpchar; + int res = 0; + int len = 0; + int blockLen = 0; + int pckNum = 0; + int num = 0; + uint8_t uid[10]; + uint8_t uid_len = 0; + uint8_t atqa[2] = {0x00, 0x00}; + uint8_t sak = 0; + bool isTag = FALSE; + uint8_t *buf = NULL; + uint16_t bufsize = 0; + uint8_t *bufPtr = NULL; + uint16_t traceLen = 0; + + memset(uid, 0x00, sizeof(uid)); + + char ctmp = param_getchar(Cmd, 0); + if ( ctmp == 'h' || ctmp == 'H' ) return usage_hf14_sniff(); + + for (int i = 0; i < 4; i++) { + ctmp = param_getchar(Cmd, i); + if (ctmp == 'l' || ctmp == 'L') wantLogToFile = true; + if (ctmp == 'd' || ctmp == 'D') wantDecrypt = true; + //if (ctmp == 'e' || ctmp == 'E') wantSaveToEml = true; TODO + if (ctmp == 'f' || ctmp == 'F') wantSaveToEmlFile = true; + } + + printf("-------------------------------------------------------------------------\n"); + printf("Executing mifare sniffing command. \n"); + printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n"); + printf("Press the key on pc keyboard to abort the client.\n"); + printf("-------------------------------------------------------------------------\n"); + + UsbCommand c = {CMD_MIFARE_SNIFFER, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + + // wait cycle + while (true) { + printf("."); + fflush(stdout); + if (ukbhit()) { + tmpchar = getchar(); + (void)tmpchar; + printf("\naborted via keyboard!\n"); + break; + } + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + res = resp.arg[0] & 0xff; + traceLen = resp.arg[1]; + len = resp.arg[2]; + + // we are done? + if (res == 0) { + 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 || buf == NULL) { + uint8_t *p; + if (buf == NULL) // not yet allocated + p = malloc(traceLen); + else // need more memory + p = realloc(buf, traceLen); + + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(buf); + return 2; + } + buf = p; } - PrintAndLog("--"); + bufPtr = buf; + bufsize = traceLen; + memset(buf, 0x00, traceLen); + } + if (bufPtr == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(buf); + return 2; } + // what happens if LEN is bigger then TRACELEN --iceman + memcpy(bufPtr, resp.d.asBytes, len); + bufPtr += len; + pckNum++; } - + + if (res == 2) { // received all data, start displaying + blockLen = bufPtr - buf; + bufPtr = buf; + printf(">\n"); + PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); + while (bufPtr - buf < blockLen) { + bufPtr += 6; // skip (void) timing information + len = *((uint16_t *)bufPtr); + if(len & 0x8000) { + isTag = true; + len &= 0x7fff; + } else { + isTag = false; + } + bufPtr += 2; + if ((len == 17) && (bufPtr[0] == 0xff) && (bufPtr[1] == 0xff) && (bufPtr[15] == 0xff) && (bufPtr[16] == 0xff)) { + memcpy(uid, bufPtr + 2, 10); + memcpy(atqa, bufPtr + 2 + 10, 2); + switch (atqa[0] & 0xC0) { + case 0x80: uid_len = 10; break; + case 0x40: uid_len = 7; break; + default: uid_len = 4; break; + } + sak = bufPtr[14]; + PrintAndLog("tag select uid| %s atqa:0x%02x%02x sak:0x%02x", + sprint_hex(uid, uid_len), + atqa[1], + atqa[0], + sak); + if (wantLogToFile || wantDecrypt) { + FillFileNameByUID(logHexFileName, uid, ".log", uid_len); + AddLogCurrentDT(logHexFileName); + } + if (wantDecrypt) + mfTraceInit(uid, uid_len, atqa, sak, wantSaveToEmlFile); + } else { + PrintAndLog("%03d| %s |%s", num, isTag ? "TAG" : "RDR", sprint_hex(bufPtr, len)); + if (wantLogToFile) + AddLogHex(logHexFileName, isTag ? "TAG| ":"RDR| ", bufPtr, len); + if (wantDecrypt) + mfTraceDecode(bufPtr, len, wantSaveToEmlFile); + num++; + } + bufPtr += len; + bufPtr += ((len-1)/8+1); // ignore parity + } + pckNum = 0; + } + } // resp not NULL + } // while (true) + + free(buf); return 0; } -int CmdHF14AMfDbg(const char *Cmd) -{ - int dbgMode = param_get32ex(Cmd, 0, 0, 10); - if (dbgMode > 4) { - PrintAndLog("Max debug mode parameter is 4 \n"); - } - - if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) { - PrintAndLog("Usage: hf mf dbg "); - PrintAndLog(" 0 - no debug messages"); - PrintAndLog(" 1 - error messages"); - PrintAndLog(" 2 - plus information messages"); - PrintAndLog(" 3 - plus debug messages"); - PrintAndLog(" 4 - print even debug messages in timing critical functions"); - PrintAndLog(" Note: this option therefore may cause malfunction itself"); - return 0; - } +int CmdHF14AMfDbg(const char *Cmd) { + + char ctmp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_hf14_dbg(); + + uint8_t dbgMode = param_get8ex(Cmd, 0, 0, 10); + if (dbgMode > 4) return usage_hf14_dbg(); UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; SendCommand(&c); - return 0; } +int CmdHF14AMfKeyBrute(const char *Cmd) { + + uint8_t blockNo = 0, keytype = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint64_t foundkey = 0; + + char cmdp = param_getchar(Cmd, 0); + if ( cmdp == 'H' || cmdp == 'h') return usage_hf14_keybrute(); + + // block number + blockNo = param_get8(Cmd, 0); + + // keytype + cmdp = param_getchar(Cmd, 1); + if (cmdp == 'B' || cmdp == 'b') keytype = 1; + + // key + if (param_gethex(Cmd, 2, key, 12)) return usage_hf14_keybrute(); + + clock_t t1 = clock(); + time_t start, end; + time(&start); + + if (mfKeyBrute( blockNo, keytype, key, &foundkey)) + PrintAndLog("Found valid key: %012" PRIx64 " \n", foundkey); + else + PrintAndLog("Key not found"); + + t1 = clock() - t1; + time(&end); + unsigned long elapsed_time = difftime(end, start); + if ( t1 > 0 ) + PrintAndLog("\nTime in keybrute: %.0f ticks %u seconds\n", (float)t1, elapsed_time); + + return 0; +} + +void printKeyTable( uint8_t sectorscnt, sector *e_sector ){ + PrintAndLog("|---|----------------|---|----------------|---|"); + PrintAndLog("|sec|key A |res|key B |res|"); + PrintAndLog("|---|----------------|---|----------------|---|"); + for (uint8_t i = 0; i < sectorscnt; ++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("|---|----------------|---|----------------|---|"); +} + +// EMULATOR COMMANDS int CmdHF14AMfEGet(const char *Cmd) { uint8_t blockNo = 0; @@ -1275,7 +1747,7 @@ int CmdHF14AMfEGet(const char *Cmd) blockNo = param_get8(Cmd, 0); - PrintAndLog(" "); + PrintAndLog(""); if (!mfEmlGetMem(data, blockNo, 1)) { PrintAndLog("data[%3d]:%s", blockNo, sprint_hex(data, 16)); } else { @@ -1302,7 +1774,6 @@ int CmdHF14AMfESet(const char *Cmd) { uint8_t memBlock[16]; uint8_t blockNo = 0; - memset(memBlock, 0x00, sizeof(memBlock)); if (strlen(Cmd) < 3 || param_getchar(Cmd, 0) == 'h') { @@ -1584,15 +2055,16 @@ 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("|---|----------------|----------------|"); return 0; } -int CmdHF14AMfCSetUID(const char *Cmd) -{ +// CHINESE MAGIC COMMANDS + +int CmdHF14AMfCSetUID(const char *Cmd) { uint8_t wipeCard = 0; uint8_t uid[8] = {0x00}; uint8_t oldUid[8] = {0x00}; @@ -1604,11 +2076,13 @@ int CmdHF14AMfCSetUID(const char *Cmd) int argi=0; if (strlen(Cmd) < 1 || param_getchar(Cmd, argi) == 'h') { - PrintAndLog("Usage: hf mf csetuid [ATQA 4 hex symbols SAK 2 hex symbols] [w]"); - PrintAndLog("sample: hf mf csetuid 01020304"); - PrintAndLog("sample: hf mf csetuid 01020304 0004 08 w"); PrintAndLog("Set UID, ATQA, and SAK for magic Chinese card (only works with such cards)"); PrintAndLog("If you also want to wipe the card then add 'w' at the end of the command line."); + PrintAndLog(""); + PrintAndLog("Usage: hf mf csetuid [ATQA 4 hex symbols SAK 2 hex symbols] [w]"); + PrintAndLog(""); + PrintAndLog("sample: hf mf csetuid 01020304"); + PrintAndLog(" hf mf csetuid 01020304 0004 08 w"); return 0; } @@ -1649,7 +2123,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) PrintAndLog("--wipe card:%s uid:%s", (wipeCard)?"YES":"NO", sprint_hex(uid, 4)); - res = mfCSetUID(uid, (atqaPresent)?atqa:NULL, (atqaPresent)?sak:NULL, oldUid, wipeCard); + res = mfCSetUID(uid, (atqaPresent) ? atqa : NULL, (atqaPresent) ? sak : NULL, oldUid, wipeCard); if (res) { PrintAndLog("Can't set UID. error=%d", res); return 1; @@ -1660,8 +2134,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) return 0; } -int CmdHF14AMfCSetBlk(const char *Cmd) -{ +int CmdHF14AMfCSetBlk(const char *Cmd) { uint8_t block[16] = {0x00}; uint8_t blockNo = 0; uint8_t params = MAGIC_SINGLE; @@ -1696,8 +2169,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) return 0; } -int CmdHF14AMfCLoad(const char *Cmd) -{ +int CmdHF14AMfCLoad(const char *Cmd) { FILE * f; char filename[FILE_PATH_SIZE]; char * fnameptr = filename; @@ -1780,6 +2252,7 @@ int CmdHF14AMfCLoad(const char *Cmd) if (mfCSetBlock(blockNum, buf8, NULL, flags)) { PrintAndLog("Can't set magic card block: %d", blockNum); + fclose(f); return 3; } blockNum++; @@ -1959,165 +2432,9 @@ int CmdHF14AMfCSave(const char *Cmd) { } } -int CmdHF14AMfSniff(const char *Cmd){ - - bool wantLogToFile = 0; - bool wantDecrypt = 0; - //bool wantSaveToEml = 0; TODO - bool wantSaveToEmlFile = 0; - - //var - int res = 0; - int len = 0; - int blockLen = 0; - int pckNum = 0; - int num = 0; - uint8_t uid[7]; - uint8_t uid_len; - uint8_t atqa[2] = {0x00}; - uint8_t sak; - bool isTag; - uint8_t *buf = NULL; - uint16_t bufsize = 0; - uint8_t *bufPtr = NULL; - - char ctmp = param_getchar(Cmd, 0); - if ( ctmp == 'h' || ctmp == 'H' ) { - PrintAndLog("It continuously gets data from the field and saves it to: log, emulator, emulator file."); - PrintAndLog("You can specify:"); - PrintAndLog(" l - save encrypted sequence to logfile `uid.log`"); - PrintAndLog(" d - decrypt sequence and put it to log file `uid.log`"); - PrintAndLog(" n/a e - decrypt sequence, collect read and write commands and save the result of the sequence to emulator memory"); - PrintAndLog(" f - decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml`"); - PrintAndLog("Usage: hf mf sniff [l][d][e][f]"); - PrintAndLog(" sample: hf mf sniff l d e"); - return 0; - } - - for (int i = 0; i < 4; i++) { - ctmp = param_getchar(Cmd, i); - if (ctmp == 'l' || ctmp == 'L') wantLogToFile = true; - if (ctmp == 'd' || ctmp == 'D') wantDecrypt = true; - //if (ctmp == 'e' || ctmp == 'E') wantSaveToEml = true; TODO - if (ctmp == 'f' || ctmp == 'F') wantSaveToEmlFile = true; - } - - printf("-------------------------------------------------------------------------\n"); - printf("Executing command. \n"); - printf("Press the key on the proxmark3 device to abort both proxmark3 and client.\n"); - printf("Press the key on pc keyboard to abort the client.\n"); - printf("-------------------------------------------------------------------------\n"); - - UsbCommand c = {CMD_MIFARE_SNIFFER, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - - // wait cycle - while (true) { - printf("."); - fflush(stdout); - if (ukbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,2000)) { - res = resp.arg[0] & 0xff; - uint16_t traceLen = resp.arg[1]; - len = resp.arg[2]; - - if (res == 0) { - free(buf); - return 0; // we are done - } - - if (res == 1) { // there is (more) data to be transferred - if (pckNum == 0) { // first packet, (re)allocate necessary buffer - if (traceLen > bufsize) { - uint8_t *p; - if (buf == NULL) { // not yet allocated - p = malloc(traceLen); - } else { // need more memory - p = realloc(buf, traceLen); - } - if (p == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(buf); - return 2; - } - buf = p; - } - bufPtr = buf; - bufsize = traceLen; - memset(buf, 0x00, traceLen); - } - if (bufPtr == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(buf); - return 2; - } - memcpy(bufPtr, resp.d.asBytes, len); - bufPtr += len; - pckNum++; - } - - if (res == 2) { // received all data, start displaying - blockLen = bufPtr - buf; - bufPtr = buf; - printf(">\n"); - PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); - while (bufPtr - buf < blockLen) { - bufPtr += 6; // skip (void) timing information - len = *((uint16_t *)bufPtr); - if(len & 0x8000) { - isTag = true; - len &= 0x7fff; - } else { - isTag = false; - } - bufPtr += 2; - if ((len == 14) && (bufPtr[0] == 0xff) && (bufPtr[1] == 0xff) && (bufPtr[12] == 0xff) && (bufPtr[13] == 0xff)) { - memcpy(uid, bufPtr + 2, 7); - memcpy(atqa, bufPtr + 2 + 7, 2); - uid_len = (atqa[0] & 0xC0) == 0x40 ? 7 : 4; - sak = bufPtr[11]; - PrintAndLog("tag select uid:%s atqa:0x%02x%02x sak:0x%02x", - sprint_hex(uid + (7 - uid_len), uid_len), - atqa[1], - atqa[0], - sak); - if (wantLogToFile || wantDecrypt) { - FillFileNameByUID(logHexFileName, uid + (7 - uid_len), ".log", uid_len); - AddLogCurrentDT(logHexFileName); - } - if (wantDecrypt) - mfTraceInit(uid, atqa, sak, wantSaveToEmlFile); - } else { - PrintAndLog("%s(%d):%s", isTag ? "TAG":"RDR", num, sprint_hex(bufPtr, len)); - if (wantLogToFile) - AddLogHex(logHexFileName, isTag ? "TAG: ":"RDR: ", bufPtr, len); - if (wantDecrypt) - mfTraceDecode(bufPtr, len, wantSaveToEmlFile); - num++; - } - bufPtr += len; - bufPtr += ((len-1)/8+1); // ignore parity - } - pckNum = 0; - } - } // resp not NULL - } // while (true) - - free(buf); - return 0; -} - //needs nt, ar, at, Data to decrypt int CmdHf14MfDecryptBytes(const char *Cmd){ uint8_t data[50]; - uint32_t nt = param_get32ex(Cmd,0,0,16); uint32_t ar_enc = param_get32ex(Cmd,1,0,16); uint32_t at_enc = param_get32ex(Cmd,2,0,16); @@ -2142,10 +2459,11 @@ static command_t CommandTable[] = { {"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"}, + {"chk", CmdHF14AMfChk, 0, "Check keys"}, + {"mifare", CmdHF14AMifare, 0, "Darkside attack. read parity error messages."}, + {"nested", CmdHF14AMfNested, 0, "Nested attack. Test nested authentication"}, {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, + {"keybrute", CmdHF14AMfKeyBrute, 0, "J_Run's 2nd phase of multiple sector nested authentication key recovery"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, @@ -2166,9 +2484,7 @@ static command_t CommandTable[] = { }; int CmdHFMF(const char *Cmd) { - // flush clearCommandBuffer(); - //WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; }