fix little endian vs big endian in the macros... again... but this time correct
[RRG-proxmark3.git] / client / src / cmdhfmf.c
blobb08de964cb11305785443133e6815ebfe3d5eeb4
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2011,2012 Merlok
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // High frequency MIFARE commands
9 //-----------------------------------------------------------------------------
11 #include "cmdhfmf.h"
12 #include <ctype.h>
14 #include "cmdparser.h" // command_t
15 #include "commonutil.h" // ARRAYLEN
16 #include "comms.h" // clearCommandBuffer
17 #include "fileutils.h"
18 #include "cmdtrace.h"
19 #include "mifare/mifaredefault.h" // mifare default key array
20 #include "cliparser.h" // argtable
21 #include "hardnested_bf_core.h" // SetSIMDInstr
22 #include "mifare/mad.h"
23 #include "nfc/ndef.h"
24 #include "protocols.h"
25 #include "util_posix.h" // msclock
26 #include "cmdhfmfhard.h"
27 #include "des.h" // des ecb
28 #include "crapto1/crapto1.h" // prng_successor
29 #include "cmdhf14a.h" // exchange APDU
30 #include "crypto/libpcrypto.h"
32 #define MFBLOCK_SIZE 16
34 #define MIFARE_4K_MAXBLOCK 256
35 #define MIFARE_2K_MAXBLOCK 128
36 #define MIFARE_1K_MAXBLOCK 64
37 #define MIFARE_MINI_MAXBLOCK 20
39 #define MIFARE_MINI_MAXSECTOR 5
40 #define MIFARE_1K_MAXSECTOR 16
41 #define MIFARE_2K_MAXSECTOR 32
42 #define MIFARE_4K_MAXSECTOR 40
44 static int CmdHelp(const char *Cmd);
47 static int usage_hf14_keybrute(void) {
48 PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery");
49 PrintAndLogEx(NORMAL, "You have a known 4 last bytes of a key recovered with mf_nonce_brute tool.");
50 PrintAndLogEx(NORMAL, "First 2 bytes of key will be bruteforced");
51 PrintAndLogEx(NORMAL, "");
52 PrintAndLogEx(NORMAL, " ---[ This attack is obsolete, try hardnested instead ]---");
53 PrintAndLogEx(NORMAL, "Options:");
54 PrintAndLogEx(NORMAL, " h this help");
55 PrintAndLogEx(NORMAL, " <block number> target block number");
56 PrintAndLogEx(NORMAL, " <A|B> target key type");
57 PrintAndLogEx(NORMAL, " <key> candidate key from mf_nonce_brute tool");
58 PrintAndLogEx(NORMAL, "Examples:");
59 PrintAndLogEx(NORMAL, _YELLOW_(" hf mf keybrute --blk 1 -k 000011223344"));
60 return 0;
64 int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) {
66 // ref: MIFARE Classic EV1 Originality Signature Validation
67 #define PUBLIC_MFCEV1_ECDA_KEYLEN 33
68 const ecdsa_publickey_t nxp_mfc_public_keys[] = {
69 {"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
72 uint8_t i;
73 bool is_valid = false;
75 for (i = 0; i < ARRAYLEN(nxp_mfc_public_keys); i++) {
77 int dl = 0;
78 uint8_t key[PUBLIC_MFCEV1_ECDA_KEYLEN];
79 param_gethex_to_eol(nxp_mfc_public_keys[i].value, 0, key, PUBLIC_MFCEV1_ECDA_KEYLEN, &dl);
81 int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, uidlen, signature, signature_len, false);
82 is_valid = (res == 0);
83 if (is_valid)
84 break;
87 PrintAndLogEx(INFO, "");
88 PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
89 if (is_valid == false || i == ARRAYLEN(nxp_mfc_public_keys)) {
90 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
91 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
92 PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed"));
93 return PM3_ESOFT;
96 PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_mfc_public_keys[i].desc);
97 PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfc_public_keys[i].value);
98 PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
99 PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32));
100 PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful"));
101 return PM3_SUCCESS;
104 static int GetHFMF14AUID(uint8_t *uid, int *uidlen) {
105 clearCommandBuffer();
106 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
107 PacketResponseNG resp;
108 if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
109 PrintAndLogEx(WARNING, "iso14443a card select failed");
110 DropField();
111 return 0;
114 iso14a_card_select_t card;
115 memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
116 memcpy(uid, card.uid, card.uidlen * sizeof(uint8_t));
117 *uidlen = card.uidlen;
118 return 1;
121 static char *GenerateFilename(const char *prefix, const char *suffix) {
122 if (! IfPm3Iso14443a()) {
123 return NULL;
125 uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
126 int uidlen = 0;
127 char *fptr = calloc(sizeof(char) * (strlen(prefix) + strlen(suffix)) + sizeof(uid) * 2 + 1, sizeof(uint8_t));
129 GetHFMF14AUID(uid, &uidlen);
130 if (!uidlen) {
131 PrintAndLogEx(WARNING, "No tag found.");
132 free(fptr);
133 return NULL;
136 strcpy(fptr, prefix);
137 FillFileNameByUID(fptr, uid, suffix, uidlen);
138 return fptr;
141 static int32_t initSectorTable(sector_t **src, int32_t items) {
143 (*src) = calloc(items, sizeof(sector_t));
145 if (*src == NULL)
146 return -1;
148 // empty e_sector
149 for (int i = 0; i < items; ++i) {
150 for (int j = 0; j < 2; ++j) {
151 (*src)[i].Key[j] = 0xffffffffffff;
152 (*src)[i].foundKey[j] = false;
155 return items;
158 static void decode_print_st(uint16_t blockno, uint8_t *data) {
159 if (mfIsSectorTrailer(blockno)) {
160 PrintAndLogEx(NORMAL, "");
161 PrintAndLogEx(INFO, "----------------------- " _CYAN_("Sector trailer decoder") " -----------------------");
162 PrintAndLogEx(INFO, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data, 6));
163 PrintAndLogEx(INFO, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data + 6, 3));
164 PrintAndLogEx(INFO, "user / gpb... " _GREEN_("%02x"), data[9]);
165 PrintAndLogEx(INFO, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6));
166 PrintAndLogEx(NORMAL, "");
167 PrintAndLogEx(INFO, " # | Access rights");
168 PrintAndLogEx(INFO, "----+-----------------------------------------------------------------");
170 int bln = mfFirstBlockOfSector(mfSectorNum(blockno));
171 int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1;
172 for (int i = 0; i < 4; i++) {
173 PrintAndLogEx(INFO, "%3d%c| " _YELLOW_("%s"), bln, ((blinc > 1) && (i < 3) ? '+' : ' '), mfGetAccessConditionsDesc(i, &data[6]));
174 bln += blinc;
176 PrintAndLogEx(INFO, "----------------------------------------------------------------------");
177 PrintAndLogEx(NORMAL, "");
181 static uint8_t NumOfSectors(char card) {
182 switch (card) {
183 case '0' :
184 return MIFARE_MINI_MAXSECTOR;
185 case '1' :
186 return MIFARE_1K_MAXSECTOR;
187 case '2' :
188 return MIFARE_2K_MAXSECTOR;
189 case '4' :
190 return MIFARE_4K_MAXSECTOR;
191 default :
192 return 0;
196 static uint8_t FirstBlockOfSector(uint8_t sectorNo) {
197 if (sectorNo < 32) {
198 return sectorNo * 4;
199 } else {
200 return 32 * 4 + (sectorNo - 32) * 16;
204 static uint8_t NumBlocksPerSector(uint8_t sectorNo) {
205 if (sectorNo < 32) {
206 return 4;
207 } else {
208 return 16;
212 static uint8_t GetSectorFromBlockNo(uint8_t blockNo) {
213 if (blockNo < 32 * 4)
214 return blockNo / 4;
215 else
216 return 32 + ((blockNo - (32 * 4)) / 16);
219 static char GetFormatFromSector(uint8_t sectorNo) {
220 switch (sectorNo) {
221 case MIFARE_MINI_MAXSECTOR:
222 return '0';
223 case MIFARE_1K_MAXSECTOR:
224 return '1';
225 case MIFARE_2K_MAXSECTOR:
226 return '2';
227 case MIFARE_4K_MAXSECTOR:
228 return '4';
229 default :
230 return ' ';
234 static void mf_print_block(uint8_t blockno, uint8_t *d) {
235 if (blockno == 0) {
236 PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
237 } else if (mfIsSectorTrailer(blockno)) {
238 PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
239 } else {
240 PrintAndLogEx(INFO, "%3d | %s ", blockno, sprint_hex_ascii(d, MFBLOCK_SIZE));
244 static void mf_print_blocks(uint16_t n, uint8_t *d) {
245 PrintAndLogEx(NORMAL, "");
246 PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
247 PrintAndLogEx(INFO, "blk | data | ascii");
248 PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
249 for (uint16_t i = 0; i < n; i++) {
250 mf_print_block(i, d + (i * MFBLOCK_SIZE));
252 PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
253 PrintAndLogEx(NORMAL, "");
256 static void mf_print_sector_hdr(uint8_t sector) {
257 PrintAndLogEx(NORMAL, "");
258 PrintAndLogEx(INFO, " # | sector " _GREEN_("%02d") " / " _GREEN_("0x%02X") " | ascii", sector, sector);
259 PrintAndLogEx(INFO, "----+-------------------------------------------------+-----------------");
262 static int CmdHF14AMfDarkside(const char *Cmd) {
263 CLIParserContext *ctx;
264 CLIParserInit(&ctx, "hf mf darkside",
265 "Darkside attack",
266 "hf mf darkside\n"
267 "hf mf darkside --blk 16\n"
268 "hf mf darkside --blk 16 -b\n");
270 void *argtable[] = {
271 arg_param_begin,
272 arg_int0(NULL, "blk", "<dec> ", "Target block"),
273 arg_lit0("b", NULL, "Target key B instead of default key A"),
274 arg_param_end
276 CLIExecWithReturn(ctx, Cmd, argtable, true);
278 uint8_t blockno = arg_get_u32_def(ctx, 1, 0);
280 uint8_t key_type = MIFARE_AUTH_KEYA;
282 if (arg_get_lit(ctx, 2)) {
283 PrintAndLogEx(INFO, "Targeting key B");
284 key_type = MIFARE_AUTH_KEYB;
287 CLIParserFree(ctx);
289 uint64_t key = 0;
291 int isOK = mfDarkside(blockno, key_type, &key);
292 PrintAndLogEx(NORMAL, "");
293 switch (isOK) {
294 case -1 :
295 PrintAndLogEx(WARNING, "button pressed. Aborted.");
296 return PM3_ESOFT;
297 case -2 :
298 PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
299 return PM3_ESOFT;
300 case -3 :
301 PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator is not predictable).");
302 return PM3_ESOFT;
303 case -4 :
304 PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
305 PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour.");
306 return PM3_ESOFT;
307 case -5 :
308 PrintAndLogEx(WARNING, "aborted via keyboard.");
309 return PM3_ESOFT;
310 default :
311 PrintAndLogEx(SUCCESS, "found valid key: "_YELLOW_("%012" PRIx64), key);
312 break;
314 PrintAndLogEx(NORMAL, "");
315 return PM3_SUCCESS;
318 static int CmdHF14AMfWrBl(const char *Cmd) {
320 CLIParserContext *ctx;
321 CLIParserInit(&ctx, "hf mf wrbl",
322 "Write MIFARE Classic block",
323 "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f"
325 void *argtable[] = {
326 arg_param_begin,
327 arg_int1(NULL, "blk", "<dec>", "block number"),
328 arg_lit0("a", NULL, "input key type is key A (def)"),
329 arg_lit0("b", NULL, "input key type is key B"),
330 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
331 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
333 arg_param_end
335 CLIExecWithReturn(ctx, Cmd, argtable, false);
337 int b = arg_get_int_def(ctx, 1, 0);
339 uint8_t keytype = MF_KEY_A;
340 if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) {
341 CLIParserFree(ctx);
342 PrintAndLogEx(WARNING, "Input key type must be A or B");
343 return PM3_EINVARG;
344 } else if (arg_get_lit(ctx, 3)) {
345 keytype = MF_KEY_B;;
348 int keylen = 0;
349 uint8_t key[6] = {0};
350 CLIGetHexWithReturn(ctx, 4, key, &keylen);
352 uint8_t block[MFBLOCK_SIZE] = {0x00};
353 int blen = 0;
354 CLIGetHexWithReturn(ctx, 5, block, &blen);
355 CLIParserFree(ctx);
357 if (blen != MFBLOCK_SIZE) {
358 PrintAndLogEx(WARNING, "block data must include 16 HEX bytes. Got %i", blen);
359 return PM3_EINVARG;
362 if (b > 255) {
363 return PM3_EINVARG;
365 uint8_t blockno = (uint8_t)b;
367 PrintAndLogEx(INFO, "--block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
368 PrintAndLogEx(INFO, "--data: %s", sprint_hex(block, sizeof(block)));
370 uint8_t data[26];
371 memcpy(data, key, sizeof(key));
372 memcpy(data + 10, block, sizeof(block));
373 clearCommandBuffer();
374 SendCommandMIX(CMD_HF_MIFARE_WRITEBL, blockno, keytype, 0, data, sizeof(data));
376 PacketResponseNG resp;
377 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
378 PrintAndLogEx(FAILED, "Command execute timeout");
379 return PM3_ETIMEOUT;
382 uint8_t isok = resp.oldarg[0] & 0xff;
383 if (isok) {
384 PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
385 PrintAndLogEx(HINT, "try `" _YELLOW_("hf mf rdbl") "` to verify");
386 } else {
387 PrintAndLogEx(FAILED, "Write ( " _RED_("fail") " )");
388 // suggest the opposite keytype than what was used.
389 PrintAndLogEx(HINT, "Maybe access rights? Try specify keytype " _YELLOW_("%c") " instead", (keytype == MF_KEY_A) ? 'B' : 'A');
391 return PM3_SUCCESS;
394 static int CmdHF14AMfRdBl(const char *Cmd) {
395 CLIParserContext *ctx;
396 CLIParserInit(&ctx, "hf mf rdbl",
397 "Read MIFARE Classic block",
398 "hf mf rdbl --blk 0 -k FFFFFFFFFFFF\n"
399 "hf mf rdbl -b 3 -v -> get block 3, decode sector trailer\n"
401 void *argtable[] = {
402 arg_param_begin,
403 arg_int1(NULL, "blk", "<dec>", "block number"),
404 arg_lit0("a", NULL, "input key type is key A (def)"),
405 arg_lit0("b", NULL, "input key type is key B"),
406 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
407 arg_lit0("v", "verbose", "verbose output"),
408 arg_param_end
410 CLIExecWithReturn(ctx, Cmd, argtable, false);
411 int b = arg_get_int_def(ctx, 1, 0);
413 uint8_t keytype = MF_KEY_A;
414 if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) {
415 CLIParserFree(ctx);
416 PrintAndLogEx(WARNING, "Input key type must be A or B");
417 return PM3_EINVARG;
418 } else if (arg_get_lit(ctx, 3)) {
419 keytype = MF_KEY_B;
422 int keylen = 0;
423 uint8_t key[6] = {0};
424 CLIGetHexWithReturn(ctx, 4, key, &keylen);
425 bool verbose = arg_get_lit(ctx, 5);
426 CLIParserFree(ctx);
428 if (b > 255) {
429 return PM3_EINVARG;
431 uint8_t blockno = (uint8_t)b;
433 uint8_t data[16] = {0};
434 int res = mfReadBlock(blockno, keytype, key, data);
435 if (res == PM3_SUCCESS) {
437 uint8_t sector = GetSectorFromBlockNo(blockno);
438 mf_print_sector_hdr(sector);
439 mf_print_block(blockno, data);
440 if (verbose) {
441 decode_print_st(blockno, data);
444 PrintAndLogEx(NORMAL, "");
445 return res;
448 static int CmdHF14AMfRdSc(const char *Cmd) {
450 CLIParserContext *ctx;
451 CLIParserInit(&ctx, "hf mf rdsc",
452 "Read MIFARE Classic sector",
453 "hf mf rdsc -s 0 -k FFFFFFFFFFFF\n"
455 void *argtable[] = {
456 arg_param_begin,
457 arg_lit0("a", NULL, "input key specified is A key (def)"),
458 arg_lit0("b", NULL, "input key specified is B key"),
459 arg_str0("k", "key", "<hex>", "key specified as 6 hex bytes"),
460 arg_int1("s", "sec", "<dec>", "sector number"),
461 arg_lit0("v", "verbose", "verbose output"),
462 arg_param_end
464 CLIExecWithReturn(ctx, Cmd, argtable, false);
465 uint8_t keytype = MF_KEY_A;
466 if (arg_get_lit(ctx, 1) && arg_get_lit(ctx, 2)) {
467 CLIParserFree(ctx);
468 PrintAndLogEx(WARNING, "Input key type must be A or B");
469 return PM3_EINVARG;
470 } else if (arg_get_lit(ctx, 2)) {
471 keytype = MF_KEY_B;
474 int keylen = 0;
475 uint8_t key[6] = {0};
476 CLIGetHexWithReturn(ctx, 3, key, &keylen);
478 int s = arg_get_int_def(ctx, 4, 0);
479 bool verbose = arg_get_lit(ctx, 5);
480 CLIParserFree(ctx);
482 if (s > MIFARE_4K_MAXSECTOR) {
483 PrintAndLogEx(WARNING, "Sector number must be less then 40");
484 return PM3_EINVARG;
486 uint8_t sector = (uint8_t)s;
487 uint8_t sc_size = mfNumBlocksPerSector(sector) * MFBLOCK_SIZE;
488 uint8_t *data = calloc(sc_size, sizeof(uint8_t));
489 if (data == NULL) {
490 PrintAndLogEx(ERR, "failed to allocate memory");
491 return PM3_EMALLOC;
494 int res = mfReadSector(sector, keytype, key, data);
495 if (res == PM3_SUCCESS) {
497 uint8_t blocks = NumBlocksPerSector(sector);
498 uint8_t start = FirstBlockOfSector(sector);
500 mf_print_sector_hdr(sector);
501 for (int i = 0; i < blocks; i++) {
502 mf_print_block(start + i, data + (i * MFBLOCK_SIZE));
505 if (verbose) {
506 decode_print_st(start + blocks - 1, data + ((blocks - 1) * MFBLOCK_SIZE));
509 free(data);
510 PrintAndLogEx(NORMAL, "");
511 return PM3_SUCCESS;
514 static int FastDumpWithEcFill(uint8_t numsectors) {
515 PacketResponseNG resp;
517 mfc_eload_t payload;
518 payload.sectorcnt = numsectors;
519 payload.keytype = MF_KEY_A;
521 // ecfill key A
522 clearCommandBuffer();
523 SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload));
525 bool res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2500);
526 if (res == false) {
527 PrintAndLogEx(WARNING, "Command execute timeout");
528 return PM3_ETIMEOUT;
531 if (resp.status != PM3_SUCCESS) {
532 PrintAndLogEx(INFO, "fast dump reported back failure w KEY A, swapping to KEY B");
534 // ecfill key B
535 payload.keytype = MF_KEY_B;
537 clearCommandBuffer();
538 SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload));
539 res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2500);
540 if (res == false) {
541 PrintAndLogEx(WARNING, "Command execute timeout");
542 return PM3_ETIMEOUT;
545 if (resp.status != PM3_SUCCESS) {
546 PrintAndLogEx(INFO, "fast dump reported back failure w KEY B");
547 PrintAndLogEx(INFO, "Dump file is " _RED_("PARTIAL") " complete");
550 return PM3_SUCCESS;
553 static int CmdHF14AMfDump(const char *Cmd) {
554 CLIParserContext *ctx;
555 CLIParserInit(&ctx, "hf mf dump",
556 "Dump MIFARE Classic tag to binary file\n"
557 "If no <name> given, UID will be used as filename",
558 "hf mf dump --mini --> MIFARE Mini\n"
559 "hf mf dump --1k --> MIFARE Classic 1k\n"
560 "hf mf dump --2k --> MIFARE 2k\n"
561 "hf mf dump --4k --> MIFARE 4k\n"
562 "hf mf dump --keys hf-mf-066C8B78-key.bin --> MIFARE 1k with keys from specified file\n");
564 void *argtable[] = {
565 arg_param_begin,
566 arg_str0("f", "file", "<fn>", "filename of dump"),
567 arg_str0("k", "keys", "<fn>", "filename of keys"),
568 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
569 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
570 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
571 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
572 arg_param_end
574 CLIExecWithReturn(ctx, Cmd, argtable, true);
576 int datafnlen = 0;
577 char dataFilename[FILE_PATH_SIZE] = {0};
578 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)dataFilename, FILE_PATH_SIZE, &datafnlen);
580 int keyfnlen = 0;
581 char keyFilename[FILE_PATH_SIZE] = {0};
582 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
584 bool m0 = arg_get_lit(ctx, 3);
585 bool m1 = arg_get_lit(ctx, 4);
586 bool m2 = arg_get_lit(ctx, 5);
587 bool m4 = arg_get_lit(ctx, 6);
589 CLIParserFree(ctx);
591 uint64_t t1 = msclock();
593 // validations
594 if ((m0 + m1 + m2 + m4) > 1) {
595 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
596 return PM3_EINVARG;
597 } else if ((m0 + m1 + m2 + m4) == 0) {
598 m1 = true;
601 uint8_t numSectors = MIFARE_1K_MAXSECTOR;
603 if (m0) {
604 numSectors = MIFARE_MINI_MAXSECTOR;
605 } else if (m1) {
606 numSectors = MIFARE_1K_MAXSECTOR;
607 } else if (m2) {
608 numSectors = MIFARE_2K_MAXSECTOR;
609 } else if (m4) {
610 numSectors = MIFARE_4K_MAXSECTOR;
611 } else {
612 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
613 return PM3_EINVARG;
616 uint8_t sectorNo, blockNo;
617 uint8_t keyA[40][6];
618 uint8_t keyB[40][6];
619 uint8_t rights[40][4];
620 uint8_t carddata[256][16];
622 FILE *f;
623 PacketResponseNG resp;
625 char *fptr;
627 if (keyFilename[0] == 0x00) {
628 fptr = GenerateFilename("hf-mf-", "-key.bin");
629 if (fptr == NULL)
630 return PM3_ESOFT;
632 strcpy(keyFilename, fptr);
633 free(fptr);
636 if ((f = fopen(keyFilename, "rb")) == NULL) {
637 PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), keyFilename);
638 return PM3_EFILE;
641 PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename);
643 // Read keys A from file
644 size_t bytes_read;
645 for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
646 bytes_read = fread(keyA[sectorNo], 1, 6, f);
647 if (bytes_read != 6) {
648 PrintAndLogEx(ERR, "File reading error.");
649 fclose(f);
650 return PM3_EFILE;
654 // Read keys B from file
655 for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
656 bytes_read = fread(keyB[sectorNo], 1, 6, f);
657 if (bytes_read != 6) {
658 PrintAndLogEx(ERR, "File reading error.");
659 fclose(f);
660 return PM3_EFILE;
664 fclose(f);
666 PrintAndLogEx(INFO, "Reading sector access bits...");
667 PrintAndLogEx(INFO, "." NOLF);
669 uint8_t tries;
670 mf_readblock_t payload;
671 for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
672 for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) {
673 PrintAndLogEx(NORMAL, "." NOLF);
674 fflush(stdout);
676 payload.blockno = FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1;
677 payload.keytype = MF_KEY_A;
678 memcpy(payload.key, keyA[sectorNo], sizeof(payload.key));
680 clearCommandBuffer();
681 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
683 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) {
685 uint8_t *data = resp.data.asBytes;
686 if (resp.status == PM3_SUCCESS) {
687 rights[sectorNo][0] = ((data[7] & 0x10) >> 2) | ((data[8] & 0x1) << 1) | ((data[8] & 0x10) >> 4); // C1C2C3 for data area 0
688 rights[sectorNo][1] = ((data[7] & 0x20) >> 3) | ((data[8] & 0x2) << 0) | ((data[8] & 0x20) >> 5); // C1C2C3 for data area 1
689 rights[sectorNo][2] = ((data[7] & 0x40) >> 4) | ((data[8] & 0x4) >> 1) | ((data[8] & 0x40) >> 6); // C1C2C3 for data area 2
690 rights[sectorNo][3] = ((data[7] & 0x80) >> 5) | ((data[8] & 0x8) >> 2) | ((data[8] & 0x80) >> 7); // C1C2C3 for sector trailer
691 break;
692 } else if (tries == 2) { // on last try set defaults
693 PrintAndLogEx(FAILED, "\ncould not get access rights for sector %2d. Trying with defaults...", sectorNo);
694 rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00;
695 rights[sectorNo][3] = 0x01;
697 } else {
698 PrintAndLogEx(FAILED, "\ncommand execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo);
699 rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00;
700 rights[sectorNo][3] = 0x01;
704 PrintAndLogEx(NORMAL, "");
705 PrintAndLogEx(SUCCESS, "Finished reading sector access bits");
706 PrintAndLogEx(INFO, "Dumping all blocks from card...");
708 for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
709 for (blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
710 bool received = false;
712 for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) {
713 if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A.
715 payload.blockno = FirstBlockOfSector(sectorNo) + blockNo;
716 payload.keytype = MF_KEY_A;
717 memcpy(payload.key, keyA[sectorNo], sizeof(payload.key));
719 clearCommandBuffer();
720 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
721 received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
722 } else { // data block. Check if it can be read with key A or key B
723 uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5;
724 if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work
726 payload.blockno = FirstBlockOfSector(sectorNo) + blockNo;
727 payload.keytype = 1;
728 memcpy(payload.key, keyB[sectorNo], sizeof(payload.key));
730 clearCommandBuffer();
731 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
732 received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
733 } else if (rights[sectorNo][data_area] == 0x07) { // no key would work
734 PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo);
735 // where do you want to go?? Next sector or block?
736 break;
737 } else { // key A would work
739 payload.blockno = FirstBlockOfSector(sectorNo) + blockNo;
740 payload.keytype = MF_KEY_A;
741 memcpy(payload.key, keyA[sectorNo], sizeof(payload.key));
743 clearCommandBuffer();
744 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
745 received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500);
748 if (received) {
749 if (resp.status == PM3_SUCCESS) {
750 // break the re-try loop
751 break;
756 if (received) {
757 uint8_t *data = resp.data.asBytes;
758 if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys.
759 data[0] = (keyA[sectorNo][0]);
760 data[1] = (keyA[sectorNo][1]);
761 data[2] = (keyA[sectorNo][2]);
762 data[3] = (keyA[sectorNo][3]);
763 data[4] = (keyA[sectorNo][4]);
764 data[5] = (keyA[sectorNo][5]);
765 data[10] = (keyB[sectorNo][0]);
766 data[11] = (keyB[sectorNo][1]);
767 data[12] = (keyB[sectorNo][2]);
768 data[13] = (keyB[sectorNo][3]);
769 data[14] = (keyB[sectorNo][4]);
770 data[15] = (keyB[sectorNo][5]);
772 if (resp.status == PM3_SUCCESS) {
773 memcpy(carddata[FirstBlockOfSector(sectorNo) + blockNo], data, 16);
774 PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo);
775 } else {
776 PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo);
777 break;
779 } else {
780 PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo);
781 break;
786 PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000);
788 PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
790 if (strlen(dataFilename) < 1) {
791 fptr = GenerateFilename("hf-mf-", "-dump");
792 if (fptr == NULL)
793 return PM3_ESOFT;
795 strcpy(dataFilename, fptr);
796 free(fptr);
799 uint16_t bytes = 16 * (FirstBlockOfSector(numSectors - 1) + NumBlocksPerSector(numSectors - 1));
801 saveFile(dataFilename, ".bin", (uint8_t *)carddata, bytes);
802 saveFileEML(dataFilename, (uint8_t *)carddata, bytes, MFBLOCK_SIZE);
803 saveFileJSON(dataFilename, jsfCardMemory, (uint8_t *)carddata, bytes, NULL);
804 return PM3_SUCCESS;
807 static int CmdHF14AMfRestore(const char *Cmd) {
809 CLIParserContext *ctx;
810 CLIParserInit(&ctx, "hf mf restore",
811 "Restore MIFARE Classic binary file to tag.\n"
812 "\n"
813 "The key file and data file will program the card sector trailers.\n"
814 "By default we authenticate to card with key B 0xFFFFFFFFFFFF.\n"
815 "\n"
816 "`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
817 " If not specified, it will read the card uid instead.\n"
818 " `-w` param you can indicate that the key file should be used for authentication instead.\n"
819 " if so we also try both B/A keys",
820 "hf mf restore\n"
821 "hf mf restore --1k --uid 04010203\n"
822 "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n"
823 "hf mf restore --4k"
826 void *argtable[] = {
827 arg_param_begin,
828 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
829 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
830 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
831 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
832 arg_str0("u", "uid", "<hex>", "uid, 6 hex bytes"),
833 arg_str0("f", "file", "<fn>", "data filename"),
834 arg_str0("k", "kfn", "<fn>", "key filename"),
835 arg_lit0(NULL, "ka", "use specified keyfile to authenticate"),
836 arg_param_end
838 CLIExecWithReturn(ctx, Cmd, argtable, true);
840 bool m0 = arg_get_lit(ctx, 1);
841 bool m1 = arg_get_lit(ctx, 2);
842 bool m2 = arg_get_lit(ctx, 3);
843 bool m4 = arg_get_lit(ctx, 4);
845 int uidlen = 0;
846 char uid[14] = {0};
847 CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)uid, sizeof(uid), &uidlen);
849 int datafnlen = 0;
850 char datafilename[FILE_PATH_SIZE] = {0};
851 CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)datafilename, FILE_PATH_SIZE, &datafnlen);
853 int keyfnlen = 0;
854 char keyfilename[FILE_PATH_SIZE] = {0};
855 CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)keyfilename, FILE_PATH_SIZE, &keyfnlen);
857 bool use_keyfile_for_auth = arg_get_lit(ctx, 8);
858 CLIParserFree(ctx);
860 // validations
861 if ((m0 + m1 + m2 + m4) > 1) {
862 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
863 return PM3_EINVARG;
864 } else if ((m0 + m1 + m2 + m4) == 0) {
865 m1 = true;
868 uint8_t sectors = MIFARE_1K_MAXSECTOR;
870 if (m0) {
871 sectors = MIFARE_MINI_MAXSECTOR;
872 } else if (m1) {
873 sectors = MIFARE_1K_MAXSECTOR;
874 } else if (m2) {
875 sectors = MIFARE_2K_MAXSECTOR;
876 } else if (m4) {
877 sectors = MIFARE_4K_MAXSECTOR;
878 } else {
879 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
880 return PM3_EINVARG;
883 // if user specified UID, use it in file templates
884 if (uidlen) {
886 if (keyfnlen == 0) {
887 snprintf(keyfilename, FILE_PATH_SIZE, "hf-mf-%s-key.bin", uid);
888 keyfnlen = strlen(keyfilename);
891 if (datafnlen == 0) {
892 snprintf(datafilename, FILE_PATH_SIZE, "hf-mf-%s-dump.bin", uid);
893 datafnlen = strlen(datafilename);
897 // try reading card uid and create filename
898 if (keyfnlen == 0) {
899 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
900 if (fptr == NULL)
901 return PM3_ESOFT;
903 strcpy(keyfilename, fptr);
904 free(fptr);
907 FILE *f;
908 if ((f = fopen(keyfilename, "rb")) == NULL) {
909 PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), keyfilename);
910 return PM3_EFILE;
913 // key arrays
914 uint8_t keyA[40][6];
915 uint8_t keyB[40][6];
917 // read key file
918 size_t bytes_read;
919 for (uint8_t s = 0; s < sectors; s++) {
920 bytes_read = fread(keyA[s], 1, 6, f);
921 if (bytes_read != 6) {
922 PrintAndLogEx(ERR, "File reading error " _YELLOW_("%s"), keyfilename);
923 fclose(f);
924 return PM3_EFILE;
928 for (uint8_t s = 0; s < sectors; s++) {
929 bytes_read = fread(keyB[s], 1, 6, f);
930 if (bytes_read != 6) {
931 PrintAndLogEx(ERR, "File reading error " _YELLOW_("%s"), keyfilename);
932 fclose(f);
933 return PM3_EFILE;
936 fclose(f);
937 f = NULL;
939 // try reading card uid and create filename
940 if (datafnlen == 0) {
941 char *fptr = GenerateFilename("hf-mf-", "-dump.bin");
942 if (fptr == NULL)
943 return PM3_ESOFT;
945 strcpy(datafilename, fptr);
946 free(fptr);
949 // read dump file
950 if ((f = fopen(datafilename, "rb")) == NULL) {
951 PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), datafilename);
952 return PM3_EINVARG;
955 // default authentication key
956 uint8_t default_key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
958 PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", datafilename);
960 for (uint8_t s = 0; s < sectors; s++) {
961 for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
963 uint8_t data[26];
964 uint8_t bldata[MFBLOCK_SIZE] = {0x00};
966 bytes_read = fread(bldata, 1, MFBLOCK_SIZE, f);
967 if (bytes_read != sizeof(bldata)) {
968 PrintAndLogEx(ERR, "File reading error " _YELLOW_("%s"), datafilename);
969 fclose(f);
970 f = NULL;
971 return PM3_EFILE;
974 if (use_keyfile_for_auth == false) {
976 // sector trailer
977 if (b == NumBlocksPerSector(s) - 1) {
978 bldata[0] = (keyA[s][0]);
979 bldata[1] = (keyA[s][1]);
980 bldata[2] = (keyA[s][2]);
981 bldata[3] = (keyA[s][3]);
982 bldata[4] = (keyA[s][4]);
983 bldata[5] = (keyA[s][5]);
984 bldata[10] = (keyB[s][0]);
985 bldata[11] = (keyB[s][1]);
986 bldata[12] = (keyB[s][2]);
987 bldata[13] = (keyB[s][3]);
988 bldata[14] = (keyB[s][4]);
989 bldata[15] = (keyB[s][5]);
993 memcpy(data + 10, bldata, sizeof(bldata));
995 if (use_keyfile_for_auth) {
996 for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
998 if (kt == MF_KEY_A)
999 memcpy(data, keyA[s], 6);
1000 else
1001 memcpy(data, keyB[s], 6);
1003 PrintAndLogEx(INFO, "block %3d: %s", FirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
1004 clearCommandBuffer();
1005 SendCommandMIX(CMD_HF_MIFARE_WRITEBL, FirstBlockOfSector(s) + b, kt, 0, data, sizeof(data));
1006 PacketResponseNG resp;
1008 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
1009 uint8_t isOK = resp.oldarg[0] & 0xff;
1010 if (isOK == 0) {
1011 if (b == 0) {
1012 PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B');
1013 } else {
1014 PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B');
1016 } else {
1017 // if success, skip to next block
1018 break;
1020 } else {
1021 PrintAndLogEx(WARNING, "Command execute timeout");
1024 } else {
1025 memcpy(data, default_key, 6);
1026 PrintAndLogEx(INFO, "block %3d: %s", FirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
1027 clearCommandBuffer();
1028 SendCommandMIX(CMD_HF_MIFARE_WRITEBL, FirstBlockOfSector(s) + b, MF_KEY_B, 0, data, sizeof(data));
1030 PacketResponseNG resp;
1031 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
1032 uint8_t isOK = resp.oldarg[0] & 0xff;
1033 if (isOK == 0) {
1034 if (b == 0) {
1035 PrintAndLogEx(INFO, "Writing to manufacture block w key B ( " _RED_("fail") " )");
1036 } else {
1037 PrintAndLogEx(FAILED, "Write to block %u w key B ( " _RED_("fail") " )", b);
1040 } else {
1041 PrintAndLogEx(WARNING, "Command execute timeout");
1046 fclose(f);
1047 PrintAndLogEx(INFO, "Done!");
1048 return PM3_SUCCESS;
1051 static int CmdHF14AMfNested(const char *Cmd) {
1052 CLIParserContext *ctx;
1053 CLIParserInit(&ctx, "hf mf nested",
1054 "Execute Nested attack against MIFARE Classic card for key recovery",
1055 "hf mf nested --single --blk 0 -a FFFFFFFFFFFF --tblk 4 --ta --> Single sector key recovery. Use block 0 Key A to find block 4 Key A\n"
1056 "hf mf nested --mini --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
1057 "hf mf nested --1k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
1058 "hf mf nested --2k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
1059 "hf mf nested --4k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k");
1061 void *argtable[] = {
1062 arg_param_begin,
1063 arg_str0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
1064 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
1065 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50"),
1066 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
1067 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
1068 arg_int0(NULL, "blk", "<dec>", "Input block number"),
1069 arg_lit0("a", NULL, "Input key specified is A key (default)"),
1070 arg_lit0("b", NULL, "Input key specified is B key"),
1071 arg_int0(NULL, "tblk", "<dec>", "Target block number"),
1072 arg_lit0(NULL, "ta", "Target A key (default)"),
1073 arg_lit0(NULL, "tb", "Target B key"),
1074 arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
1075 arg_lit0(NULL, "dump", "Dump found keys to file"),
1076 arg_lit0(NULL, "single", "Single sector (defaults to All)"),
1077 arg_param_end
1079 CLIExecWithReturn(ctx, Cmd, argtable, false);
1081 int keylen = 0;
1082 uint8_t key[6] = {0};
1083 CLIGetHexWithReturn(ctx, 1, key, &keylen);
1085 bool m0 = arg_get_lit(ctx, 2);
1086 bool m1 = arg_get_lit(ctx, 3);
1087 bool m2 = arg_get_lit(ctx, 4);
1088 bool m4 = arg_get_lit(ctx, 5);
1090 uint8_t blockNo = arg_get_u32_def(ctx, 6, 0);
1092 uint8_t keyType = MF_KEY_A;
1094 if (arg_get_lit(ctx, 7) && arg_get_lit(ctx, 8)) {
1095 CLIParserFree(ctx);
1096 PrintAndLogEx(WARNING, "Input key type must be A or B");
1097 return PM3_EINVARG;
1098 } else if (arg_get_lit(ctx, 8)) {
1099 keyType = MF_KEY_B;
1102 uint8_t trgBlockNo = arg_get_u32_def(ctx, 9, 0);
1104 uint8_t trgKeyType = MF_KEY_A;
1106 if (arg_get_lit(ctx, 10) && arg_get_lit(ctx, 11)) {
1107 CLIParserFree(ctx);
1108 PrintAndLogEx(WARNING, "Target key type must be A or B");
1109 return PM3_EINVARG;
1110 } else if (arg_get_lit(ctx, 11)) {
1111 trgKeyType = MF_KEY_B;
1114 bool transferToEml = arg_get_lit(ctx, 12);
1115 bool createDumpFile = arg_get_lit(ctx, 13);
1116 bool singleSector = arg_get_lit(ctx, 14);
1118 CLIParserFree(ctx);
1120 //validations
1121 if ((m0 + m1 + m2 + m4) > 1) {
1122 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
1123 return PM3_EINVARG;
1126 uint8_t SectorsCnt = 1;
1127 if (m0) {
1128 SectorsCnt = MIFARE_MINI_MAXSECTOR;
1129 } else if (m1) {
1130 SectorsCnt = MIFARE_1K_MAXSECTOR;
1131 } else if (m2) {
1132 SectorsCnt = MIFARE_2K_MAXSECTOR;
1133 } else if (m4) {
1134 SectorsCnt = MIFARE_4K_MAXSECTOR;
1137 if (singleSector == false) {
1138 if (SectorsCnt == 0) {
1139 PrintAndLogEx(WARNING, "Invalid MIFARE Type");
1140 return PM3_EINVARG;
1144 if (keylen != 6) {
1145 PrintAndLogEx(WARNING, "Input key must include 12 HEX symbols");
1146 return PM3_EINVARG;
1149 sector_t *e_sector = NULL;
1150 uint8_t keyBlock[(ARRAYLEN(g_mifare_default_keys) + 1) * 6];
1151 uint64_t key64 = 0;
1153 // check if tag doesn't have static nonce
1154 if (detect_classic_static_nonce() == NONCE_STATIC) {
1155 PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
1156 PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf staticnested`"));
1157 return PM3_EOPABORTED;
1160 // check if we can authenticate to sector
1161 if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) {
1162 PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A');
1163 return PM3_EOPABORTED;
1166 if (singleSector) {
1167 int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
1168 switch (isOK) {
1169 case PM3_ETIMEOUT:
1170 PrintAndLogEx(ERR, "Command execute timeout\n");
1171 break;
1172 case PM3_EOPABORTED:
1173 PrintAndLogEx(WARNING, "Button pressed. Aborted.\n");
1174 break;
1175 case PM3_EFAILED:
1176 PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
1177 break;
1178 case PM3_ESOFT:
1179 PrintAndLogEx(FAILED, "No valid key found");
1180 break;
1181 case PM3_SUCCESS:
1182 key64 = bytes_to_num(keyBlock, 6);
1184 // transfer key to the emulator
1185 if (transferToEml) {
1186 uint8_t sectortrailer;
1188 if (trgBlockNo < 32 * 4) { // 4 block sector
1189 sectortrailer = trgBlockNo | 0x03;
1190 } else { // 16 block sector
1191 sectortrailer = trgBlockNo | 0x0f;
1193 mfEmlGetMem(keyBlock, sectortrailer, 1);
1195 if (trgKeyType == MF_KEY_A)
1196 num_to_bytes(key64, 6, keyBlock);
1197 else
1198 num_to_bytes(key64, 6, &keyBlock[10]);
1200 mfEmlSetMem(keyBlock, sectortrailer, 1);
1201 PrintAndLogEx(SUCCESS, "Key transferred to emulator memory.");
1203 return PM3_SUCCESS;
1204 default :
1205 PrintAndLogEx(ERR, "Unknown error.\n");
1207 return PM3_SUCCESS;
1208 } else { // ------------------------------------ multiple sectors working
1209 uint64_t t1 = msclock();
1211 e_sector = calloc(SectorsCnt, sizeof(sector_t));
1212 if (e_sector == NULL) return PM3_EMALLOC;
1214 // add our known key
1215 e_sector[GetSectorFromBlockNo(blockNo)].foundKey[keyType] = 1;
1216 e_sector[GetSectorFromBlockNo(blockNo)].Key[keyType] = key64;
1218 //test current key and additional standard keys first
1219 // add parameter key
1220 memcpy(keyBlock + (ARRAYLEN(g_mifare_default_keys) * 6), key, 6);
1222 for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) {
1223 num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6));
1226 PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt);
1227 int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false);
1228 if (res == PM3_SUCCESS) {
1229 PrintAndLogEx(SUCCESS, "Fast check found all keys");
1230 goto jumptoend;
1233 uint64_t t2 = msclock() - t1;
1234 PrintAndLogEx(SUCCESS, "Time to check " _YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0);
1235 PrintAndLogEx(SUCCESS, "enter nested key recovery");
1237 // nested sectors
1238 bool calibrate = true;
1240 for (trgKeyType = MF_KEY_A; trgKeyType <= MF_KEY_B; ++trgKeyType) {
1241 for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) {
1242 for (int i = 0; i < MIFARE_SECTOR_RETRY; i++) {
1244 if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
1246 int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate);
1247 switch (isOK) {
1248 case PM3_ETIMEOUT:
1249 PrintAndLogEx(ERR, "Command execute timeout\n");
1250 break;
1251 case PM3_EOPABORTED:
1252 PrintAndLogEx(WARNING, "button pressed. Aborted.\n");
1253 break;
1254 case PM3_EFAILED :
1255 PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
1256 break;
1257 case PM3_ESOFT:
1258 //key not found
1259 calibrate = false;
1260 continue;
1261 case PM3_SUCCESS:
1262 calibrate = false;
1263 e_sector[sectorNo].foundKey[trgKeyType] = 1;
1264 e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
1266 mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false);
1267 continue;
1268 default :
1269 PrintAndLogEx(ERR, "Unknown error.\n");
1271 free(e_sector);
1272 return PM3_ESOFT;
1277 t1 = msclock() - t1;
1278 PrintAndLogEx(SUCCESS, "time in nested " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
1281 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
1282 PrintAndLogEx(INFO, "trying to read key B...");
1283 for (int i = 0; i < SectorsCnt; i++) {
1284 // KEY A but not KEY B
1285 if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
1287 uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
1289 PrintAndLogEx(SUCCESS, "reading block %d", sectrail);
1291 mf_readblock_t payload;
1292 payload.blockno = sectrail;
1293 payload.keytype = MF_KEY_A;
1295 num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A
1297 clearCommandBuffer();
1298 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
1300 PacketResponseNG resp;
1301 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
1303 if (resp.status != PM3_SUCCESS) continue;
1305 uint8_t *data = resp.data.asBytes;
1306 key64 = bytes_to_num(data + 10, 6);
1307 if (key64) {
1308 PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, 6));
1309 e_sector[i].foundKey[1] = true;
1310 e_sector[i].Key[1] = key64;
1315 jumptoend:
1317 PrintAndLogEx(NORMAL, "");
1318 PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
1320 //print them
1321 printKeyTable(SectorsCnt, e_sector);
1323 // transfer them to the emulator
1324 if (transferToEml) {
1325 // fast push mode
1326 conn.block_after_ACK = true;
1327 for (int i = 0; i < SectorsCnt; i++) {
1328 mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
1330 if (e_sector[i].foundKey[0])
1331 num_to_bytes(e_sector[i].Key[0], 6, keyBlock);
1333 if (e_sector[i].foundKey[1])
1334 num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
1336 if (i == SectorsCnt - 1) {
1337 // Disable fast mode on last packet
1338 conn.block_after_ACK = false;
1340 mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
1342 PrintAndLogEx(SUCCESS, "keys transferred to emulator memory.");
1345 // Create dump file
1346 if (createDumpFile) {
1347 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
1348 if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
1349 PrintAndLogEx(ERR, "Failed to save keys to file");
1350 free(e_sector);
1351 free(fptr);
1352 return PM3_ESOFT;
1354 free(fptr);
1356 free(e_sector);
1358 return PM3_SUCCESS;
1361 static int CmdHF14AMfNestedStatic(const char *Cmd) {
1362 CLIParserContext *ctx;
1363 CLIParserInit(&ctx, "hf mf staticnested",
1364 "Execute Nested attack against MIFARE Classic card with static nonce for key recovery",
1365 "hf mf staticnested --mini --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
1366 "hf mf staticnested --1k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
1367 "hf mf staticnested --2k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
1368 "hf mf staticnested --4k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k\n");
1370 void *argtable[] = {
1371 arg_param_begin,
1372 arg_str0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
1373 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
1374 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50"),
1375 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
1376 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
1377 arg_int0(NULL, "blk", "<dec>", "Input block number"),
1378 arg_lit0("a", NULL, "Input key specified is A key (default)"),
1379 arg_lit0("b", NULL, "Input key specified is B key"),
1380 arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
1381 arg_lit0(NULL, "dumpkeys", "Dump found keys to file"),
1382 arg_param_end
1384 CLIExecWithReturn(ctx, Cmd, argtable, false);
1386 int keylen = 0;
1387 uint8_t key[6] = {0};
1388 CLIGetHexWithReturn(ctx, 1, key, &keylen);
1390 bool m0 = arg_get_lit(ctx, 2);
1391 bool m1 = arg_get_lit(ctx, 3);
1392 bool m2 = arg_get_lit(ctx, 4);
1393 bool m4 = arg_get_lit(ctx, 5);
1395 uint8_t blockNo = arg_get_u32_def(ctx, 6, 0);
1397 uint8_t keyType = MF_KEY_A;
1399 if (arg_get_lit(ctx, 7) && arg_get_lit(ctx, 8)) {
1400 CLIParserFree(ctx);
1401 PrintAndLogEx(WARNING, "Input key type must be A or B");
1402 return PM3_EINVARG;
1403 } else if (arg_get_lit(ctx, 8)) {
1404 keyType = MF_KEY_B;
1407 bool transferToEml = arg_get_lit(ctx, 9);
1408 bool createDumpFile = arg_get_lit(ctx, 10);
1410 CLIParserFree(ctx);
1412 //validations
1413 if ((m0 + m1 + m2 + m4) > 1) {
1414 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
1415 return PM3_EINVARG;
1418 uint8_t SectorsCnt = 1;
1419 if (m0) {
1420 SectorsCnt = MIFARE_MINI_MAXSECTOR;
1421 } else if (m1) {
1422 SectorsCnt = MIFARE_1K_MAXSECTOR;
1423 } else if (m2) {
1424 SectorsCnt = MIFARE_2K_MAXSECTOR;
1425 } else if (m4) {
1426 SectorsCnt = MIFARE_4K_MAXSECTOR;
1427 } else {
1428 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
1429 return PM3_EINVARG;
1432 if (keylen != 6) {
1433 PrintAndLogEx(WARNING, "Input key must include 12 HEX symbols");
1434 return PM3_EINVARG;
1437 sector_t *e_sector = NULL;
1439 uint8_t trgKeyType = MF_KEY_A;
1441 uint8_t keyBlock[(ARRAYLEN(g_mifare_default_keys) + 1) * 6];
1442 uint64_t key64 = 0;
1444 // check if tag have static nonce
1445 if (detect_classic_static_nonce() != NONCE_STATIC) {
1446 PrintAndLogEx(WARNING, "Normal nonce detected, or failed read of card. Quitting...");
1447 PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf nested`"));
1448 return PM3_EOPABORTED;
1451 // check if we can authenticate to sector
1452 if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) {
1453 PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block: %3d key type: %c", blockNo, keyType ? 'B' : 'A');
1454 return PM3_EOPABORTED;
1457 if (IfPm3Flash()) {
1458 PrintAndLogEx(INFO, "RDV4 with flashmemory supported detected.");
1461 uint64_t t1 = msclock();
1463 e_sector = calloc(SectorsCnt, sizeof(sector_t));
1464 if (e_sector == NULL) return PM3_EMALLOC;
1466 // add our known key
1467 e_sector[GetSectorFromBlockNo(blockNo)].foundKey[keyType] = 1;
1468 e_sector[GetSectorFromBlockNo(blockNo)].Key[keyType] = key64;
1470 //test current key and additional standard keys first
1471 // add parameter key
1472 memcpy(keyBlock + (ARRAYLEN(g_mifare_default_keys) * 6), key, 6);
1474 for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) {
1475 num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6));
1478 PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt);
1479 int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false);
1480 if (res == PM3_SUCCESS) {
1481 // all keys found
1482 PrintAndLogEx(SUCCESS, "Fast check found all keys");
1483 goto jumptoend;
1486 uint64_t t2 = msclock() - t1;
1487 PrintAndLogEx(SUCCESS, "Time to check "_YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0);
1488 PrintAndLogEx(SUCCESS, "enter static nested key recovery");
1490 // nested sectors
1491 for (trgKeyType = MF_KEY_A; trgKeyType <= MF_KEY_B; ++trgKeyType) {
1492 for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) {
1494 for (int i = 0; i < 1; i++) {
1496 if (e_sector[sectorNo].foundKey[trgKeyType]) continue;
1498 int16_t isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock);
1499 switch (isOK) {
1500 case PM3_ETIMEOUT :
1501 PrintAndLogEx(ERR, "Command execute timeout");
1502 break;
1503 case PM3_EOPABORTED :
1504 PrintAndLogEx(WARNING, "aborted via keyboard.");
1505 break;
1506 case PM3_ESOFT :
1507 continue;
1508 case PM3_SUCCESS :
1509 e_sector[sectorNo].foundKey[trgKeyType] = 1;
1510 e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6);
1512 mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false);
1513 continue;
1514 default :
1515 PrintAndLogEx(ERR, "unknown error.\n");
1517 free(e_sector);
1518 return PM3_ESOFT;
1523 t1 = msclock() - t1;
1524 PrintAndLogEx(SUCCESS, "time in static nested " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
1527 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
1528 PrintAndLogEx(INFO, "trying to read key B...");
1529 for (int i = 0; i < SectorsCnt; i++) {
1530 // KEY A but not KEY B
1531 if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
1533 uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
1535 PrintAndLogEx(SUCCESS, "reading block %d", sectrail);
1537 mf_readblock_t payload;
1538 payload.blockno = sectrail;
1539 payload.keytype = MF_KEY_A;
1541 num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A
1543 clearCommandBuffer();
1544 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
1546 PacketResponseNG resp;
1547 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
1549 if (resp.status != PM3_SUCCESS) continue;
1551 uint8_t *data = resp.data.asBytes;
1552 key64 = bytes_to_num(data + 10, 6);
1553 if (key64) {
1554 PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, 6));
1555 e_sector[i].foundKey[1] = true;
1556 e_sector[i].Key[1] = key64;
1561 jumptoend:
1563 PrintAndLogEx(NORMAL, "");
1564 PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
1566 //print them
1567 printKeyTable(SectorsCnt, e_sector);
1569 // transfer them to the emulator
1570 if (transferToEml) {
1571 // fast push mode
1572 conn.block_after_ACK = true;
1573 for (int i = 0; i < SectorsCnt; i++) {
1574 mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
1576 if (e_sector[i].foundKey[0])
1577 num_to_bytes(e_sector[i].Key[0], 6, keyBlock);
1579 if (e_sector[i].foundKey[1])
1580 num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
1582 if (i == SectorsCnt - 1) {
1583 // Disable fast mode on last packet
1584 conn.block_after_ACK = false;
1586 mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
1588 PrintAndLogEx(SUCCESS, "keys transferred to emulator memory.");
1591 // Create dump file
1592 if (createDumpFile) {
1593 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
1594 if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
1595 PrintAndLogEx(ERR, "Failed to save keys to file");
1596 free(e_sector);
1597 free(fptr);
1598 return PM3_ESOFT;
1600 free(fptr);
1602 free(e_sector);
1604 return PM3_SUCCESS;
1607 static int CmdHF14AMfNestedHard(const char *Cmd) {
1609 CLIParserContext *ctx;
1610 CLIParserInit(&ctx, "hf mf hardnested",
1611 "Nested attack for hardened MIFARE Classic cards.\n"
1612 "`--i<X>` set type of SIMD instructions. Without this flag programs autodetect it.\n"
1613 " or \n"
1614 " hf mf hardnested -r --tk [known target key]\n"
1615 "Add the known target key to check if it is present in the remaining key space\n"
1616 " hf mf hardnested --blk 0 -a -k A0A1A2A3A4A5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
1618 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta\n"
1619 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -w\n"
1620 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -f nonces.bin -w -s\n"
1621 "hf mf hardnested -r\n"
1622 "hf mf hardnested -r --tk a0a1a2a3a4a5\n"
1623 "hf mf hardnested -t --tk a0a1a2a3a4a5\n"
1624 "hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk FFFFFFFFFFFF"
1627 void *argtable[] = {
1628 arg_param_begin,
1629 arg_str0("k", "key", "<hex>", "Key, 12 hex bytes"), // 1
1630 arg_int0(NULL, "blk", "<dec>", "Input block number"), // 2
1631 arg_lit0("a", NULL, "Input key A (def)"), // 3
1632 arg_lit0("b", NULL, "Input key B"),
1633 arg_int0(NULL, "tblk", "<dec>", "Target block number"),
1634 arg_lit0(NULL, "ta", "Target key A"),
1635 arg_lit0(NULL, "tb", "Target key B"),
1636 arg_str0(NULL, "tk", "<hex>", "Target key, 12 hex bytes"), // 8
1637 arg_str0("u", "uid", "<hex>", "R/W `hf-mf-<UID>-nonces.bin` instead of default name"),
1638 arg_str0("f", "file", "<fn>", "R/W <name> instead of default name"),
1639 arg_lit0("r", "read", "Read `hf-mf-<UID>-nonces.bin` if tag present, otherwise `nonces.bin`, and start attack"),
1640 arg_lit0("s", "slow", "Slower acquisition (required by some non standard cards)"),
1641 arg_lit0("t", "tests", "Run tests"),
1642 arg_lit0("w", "wr", "Acquire nonces and UID, and write them to file `hf-mf-<UID>-nonces.bin`"),
1644 arg_lit0(NULL, "in", "None (use CPU regular instruction set)"),
1645 #if defined(COMPILER_HAS_SIMD)
1646 arg_lit0(NULL, "im", "MMX"),
1647 arg_lit0(NULL, "is", "SSE2"),
1648 arg_lit0(NULL, "ia", "AVX"),
1649 arg_lit0(NULL, "i2", "AVX2"),
1650 #endif
1651 #if defined(COMPILER_HAS_SIMD_AVX512)
1652 arg_lit0(NULL, "i5", "AVX512"),
1653 #endif
1654 arg_param_end
1656 CLIExecWithReturn(ctx, Cmd, argtable, false);
1658 int keylen = 0;
1659 uint8_t key[6] = {0};
1660 CLIGetHexWithReturn(ctx, 1, key, &keylen);
1662 uint8_t blockno = arg_get_u32_def(ctx, 2, 0);
1664 uint8_t keytype = MF_KEY_A;
1665 if (arg_get_lit(ctx, 3) && arg_get_lit(ctx, 4)) {
1666 CLIParserFree(ctx);
1667 PrintAndLogEx(WARNING, "Input key type must be A or B");
1668 return PM3_EINVARG;
1669 } else if (arg_get_lit(ctx, 4)) {
1670 keytype = MF_KEY_B;
1673 uint8_t trg_blockno = arg_get_u32_def(ctx, 5, 0);
1675 uint8_t trg_keytype = MF_KEY_A;
1676 if (arg_get_lit(ctx, 6) && arg_get_lit(ctx, 7)) {
1677 CLIParserFree(ctx);
1678 PrintAndLogEx(WARNING, "Input key type must be A or B");
1679 return PM3_EINVARG;
1680 } else if (arg_get_lit(ctx, 7)) {
1681 trg_keytype = MF_KEY_B;
1684 int trg_keylen = 0;
1685 uint8_t trg_key[6] = {0};
1686 CLIGetHexWithReturn(ctx, 8, trg_key, &trg_keylen);
1688 int uidlen = 0;
1689 char uid[14] = {0};
1690 CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)uid, sizeof(uid), &uidlen);
1692 int fnlen = 0;
1693 char filename[FILE_PATH_SIZE] = {0};
1694 CLIParamStrToBuf(arg_get_str(ctx, 10), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1696 bool nonce_file_read = arg_get_lit(ctx, 11);
1697 bool slow = arg_get_lit(ctx, 12);
1698 bool tests = arg_get_lit(ctx, 13);
1699 bool nonce_file_write = arg_get_lit(ctx, 14);
1701 bool in = arg_get_lit(ctx, 15);
1702 #if defined(COMPILER_HAS_SIMD)
1703 bool im = arg_get_lit(ctx, 16);
1704 bool is = arg_get_lit(ctx, 17);
1705 bool ia = arg_get_lit(ctx, 18);
1706 bool i2 = arg_get_lit(ctx, 19);
1707 #endif
1708 #if defined(COMPILER_HAS_SIMD_AVX512)
1709 bool i5 = arg_get_lit(ctx, 20);
1710 #endif
1711 CLIParserFree(ctx);
1713 // set SIM instructions
1714 SetSIMDInstr(SIMD_AUTO);
1716 #if defined(COMPILER_HAS_SIMD_AVX512)
1717 if (i5)
1718 SetSIMDInstr(SIMD_AVX512);
1719 #endif
1721 #if defined(COMPILER_HAS_SIMD)
1722 if (i2)
1723 SetSIMDInstr(SIMD_AVX2);
1724 if (ia)
1725 SetSIMDInstr(SIMD_AVX);
1726 if (is)
1727 SetSIMDInstr(SIMD_SSE2);
1728 if (im)
1729 SetSIMDInstr(SIMD_MMX);
1730 #endif
1731 if (in)
1732 SetSIMDInstr(SIMD_NONE);
1735 bool know_target_key = (trg_keylen);
1737 if (nonce_file_read) {
1738 char *fptr = GenerateFilename("hf-mf-", "-nonces.bin");
1739 if (fptr == NULL)
1740 strncpy(filename, "nonces.bin", FILE_PATH_SIZE - 1);
1741 else
1742 strncpy(filename, fptr, FILE_PATH_SIZE - 1);
1743 free(fptr);
1746 if (nonce_file_write) {
1747 char *fptr = GenerateFilename("hf-mf-", "-nonces.bin");
1748 if (fptr == NULL)
1749 return 1;
1750 strncpy(filename, fptr, FILE_PATH_SIZE - 1);
1751 free(fptr);
1754 if (uidlen) {
1755 snprintf(filename, FILE_PATH_SIZE, "hf-mf-%s-nonces.bin", uid);
1758 if (know_target_key == false && nonce_file_read == false) {
1760 // check if tag doesn't have static nonce
1761 if (detect_classic_static_nonce() == NONCE_STATIC) {
1762 PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
1763 PrintAndLogEx(HINT, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
1764 return PM3_EOPABORTED;
1767 uint64_t key64 = 0;
1768 // check if we can authenticate to sector
1769 if (mfCheckKeys(blockno, keytype, true, 1, key, &key64) != PM3_SUCCESS) {
1770 PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block: %3d key type: %c", blockno, (keytype == MF_KEY_B) ? 'B' : 'A');
1771 return PM3_EWRONGANSWER;
1775 PrintAndLogEx(INFO, "Target block no " _YELLOW_("%3d") ", target key type: " _YELLOW_("%c") ", known target key: " _YELLOW_("%02x%02x%02x%02x%02x%02x%s"),
1776 trg_blockno,
1777 (trg_keytype == MF_KEY_B) ? 'B' : 'A',
1778 trg_key[0], trg_key[1], trg_key[2], trg_key[3], trg_key[4], trg_key[5],
1779 know_target_key ? "" : " (not set)"
1781 PrintAndLogEx(INFO, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"),
1782 nonce_file_write ? "write" : nonce_file_read ? "read" : "none",
1783 slow ? "Yes" : "No",
1784 tests);
1786 uint64_t foundkey = 0;
1787 int16_t isOK = mfnestedhard(blockno, keytype, key, trg_blockno, trg_keytype, know_target_key ? trg_key : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename);
1789 if ((tests == 0) && IfPm3Iso14443a()) {
1790 DropField();
1793 if (isOK) {
1794 switch (isOK) {
1795 case 1 :
1796 PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n");
1797 break;
1798 case 2 :
1799 PrintAndLogEx(NORMAL, "Button pressed. Aborted.\n");
1800 break;
1801 default :
1802 break;
1804 return 2;
1806 return 0;
1809 static int CmdHF14AMfAutoPWN(const char *Cmd) {
1811 CLIParserContext *ctx;
1812 CLIParserInit(&ctx, "hf mf autopwn",
1813 "This command automates the key recovery process on MIFARE Classic cards.\n"
1814 "It uses the fchk, chk, darkside, nested, hardnested and staticnested to recover keys.\n"
1815 "If all keys are found, it try dumping card content both to file and emulator memory.",
1816 "hf mf autopwn\n"
1817 "hf mf autopwn -s 0 -a -k FFFFFFFFFFFF --> target MFC 1K card, Sector 0 with known key A 'FFFFFFFFFFFF'\n"
1818 "hf mf autopwn --1k -f mfc_default_keys --> target MFC 1K card, default dictionary\n"
1819 "hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -f mfc_default_keys --> combo of the two above samples"
1822 void *argtable[] = {
1823 arg_param_begin,
1824 arg_str0("k", "key", "<hex>", "Known key, 12 hex bytes"),
1825 arg_int0("s", "sector", "<dec>", "Input sector number"),
1826 arg_lit0("a", NULL, "Input key A (def)"),
1827 arg_lit0("b", NULL, "Input key B"),
1828 arg_str0("f", "file", "<fn>", "filename of dictionary"),
1829 arg_lit0("s", "slow", "Slower acquisition (required by some non standard cards)"),
1830 arg_lit0("l", "legacy", "legacy mode (use the slow `hf mf chk`)"),
1831 arg_lit0("v", "verbose", "verbose output (statistics)"),
1833 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
1834 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"),
1835 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
1836 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
1838 arg_lit0(NULL, "in", "None (use CPU regular instruction set)"),
1839 #if defined(COMPILER_HAS_SIMD)
1840 arg_lit0(NULL, "im", "MMX"),
1841 arg_lit0(NULL, "is", "SSE2"),
1842 arg_lit0(NULL, "ia", "AVX"),
1843 arg_lit0(NULL, "i2", "AVX2"),
1844 #endif
1845 #if defined(COMPILER_HAS_SIMD_AVX512)
1846 arg_lit0(NULL, "i5", "AVX512"),
1847 #endif
1848 arg_param_end
1850 CLIExecWithReturn(ctx, Cmd, argtable, true);
1852 int keylen = 0;
1853 uint8_t key[6] = {0};
1854 int32_t res = CLIParamHexToBuf(arg_get_str(ctx, 1), key, sizeof(key), &keylen);
1855 if (res) {
1856 CLIParserFree(ctx);
1857 PrintAndLogEx(FAILED, "Error parsing key bytes");
1858 return PM3_EINVARG;
1861 bool know_target_key = (keylen == 6);
1863 uint8_t sectorno = arg_get_u32_def(ctx, 2, 0);
1865 uint8_t keytype = MF_KEY_A;
1866 if (arg_get_lit(ctx, 3) && arg_get_lit(ctx, 4)) {
1867 CLIParserFree(ctx);
1868 PrintAndLogEx(WARNING, "Input key type must be A or B");
1869 return PM3_EINVARG;
1870 } else if (arg_get_lit(ctx, 4)) {
1871 keytype = MF_KEY_B;
1874 int fnlen = 0;
1875 char filename[FILE_PATH_SIZE] = {0};
1876 CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
1877 bool has_filename = (fnlen > 0);
1879 bool slow = arg_get_lit(ctx, 6);
1880 bool legacy_mfchk = arg_get_lit(ctx, 7);
1881 bool verbose = arg_get_lit(ctx, 8);
1883 bool m0 = arg_get_lit(ctx, 9);
1884 bool m1 = arg_get_lit(ctx, 10);
1885 bool m2 = arg_get_lit(ctx, 11);
1886 bool m4 = arg_get_lit(ctx, 12);
1888 bool in = arg_get_lit(ctx, 13);
1889 #if defined(COMPILER_HAS_SIMD)
1890 bool im = arg_get_lit(ctx, 14);
1891 bool is = arg_get_lit(ctx, 15);
1892 bool ia = arg_get_lit(ctx, 16);
1893 bool i2 = arg_get_lit(ctx, 17);
1894 #endif
1895 #if defined(COMPILER_HAS_SIMD_AVX512)
1896 bool i5 = arg_get_lit(ctx, 18);
1897 #endif
1898 CLIParserFree(ctx);
1900 //validations
1901 if ((m0 + m1 + m2 + m4) > 1) {
1902 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
1903 return PM3_EINVARG;
1904 } else if ((m0 + m1 + m2 + m4) == 0) {
1905 m1 = true;
1908 uint8_t sector_cnt = MIFARE_1K_MAXSECTOR;
1909 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
1911 if (m0) {
1912 sector_cnt = MIFARE_MINI_MAXSECTOR;
1913 block_cnt = MIFARE_MINI_MAXBLOCK;
1914 } else if (m1) {
1915 sector_cnt = MIFARE_1K_MAXSECTOR;
1916 block_cnt = MIFARE_1K_MAXBLOCK;
1917 } else if (m2) {
1918 sector_cnt = MIFARE_2K_MAXSECTOR;
1919 block_cnt = MIFARE_2K_MAXBLOCK;
1920 } else if (m4) {
1921 sector_cnt = MIFARE_4K_MAXSECTOR;
1922 block_cnt = MIFARE_4K_MAXBLOCK;
1923 } else {
1924 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
1925 return PM3_EINVARG;
1929 // set SIM instructions
1930 SetSIMDInstr(SIMD_AUTO);
1932 #if defined(COMPILER_HAS_SIMD_AVX512)
1933 if (i5)
1934 SetSIMDInstr(SIMD_AVX512);
1935 #endif
1937 #if defined(COMPILER_HAS_SIMD)
1938 if (i2)
1939 SetSIMDInstr(SIMD_AVX2);
1940 if (ia)
1941 SetSIMDInstr(SIMD_AVX);
1942 if (is)
1943 SetSIMDInstr(SIMD_SSE2);
1944 if (im)
1945 SetSIMDInstr(SIMD_MMX);
1946 #endif
1947 if (in)
1948 SetSIMDInstr(SIMD_NONE);
1951 // Nested and Hardnested parameter
1952 uint64_t key64 = 0;
1953 bool calibrate = true;
1954 // Attack key storage variables
1955 uint8_t *keyBlock = NULL;
1956 uint32_t key_cnt = 0;
1957 sector_t *e_sector;
1958 uint8_t tmp_key[6] = {0};
1960 // Nested and Hardnested returned status
1961 uint64_t foundkey = 0;
1962 int isOK = 0;
1963 int current_sector_i = 0, current_key_type_i = 0;
1964 // Dumping and transfere to simulater memory
1965 uint8_t block[16] = {0x00};
1966 int bytes;
1967 // Settings
1968 int prng_type = PM3_EUNDEF;
1969 int has_staticnonce;
1970 uint8_t num_found_keys = 0;
1972 // ------------------------------
1974 // create/initialize key storage structure
1975 uint32_t e_sector_size = sector_cnt > sectorno ? sector_cnt : sectorno + 1;
1976 res = initSectorTable(&e_sector, e_sector_size);
1977 if (res != e_sector_size) {
1978 free(e_sector);
1979 return PM3_EMALLOC;
1982 // read uid to generate a filename for the key file
1983 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
1985 // check if tag doesn't have static nonce
1986 has_staticnonce = detect_classic_static_nonce();
1988 // card prng type (weak=1 / hard=0 / select/card comm error = negative value)
1989 if (has_staticnonce == NONCE_NORMAL) {
1990 prng_type = detect_classic_prng();
1991 if (prng_type < 0) {
1992 PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error");
1993 free(e_sector);
1994 free(fptr);
1995 return prng_type;
1999 // print parameters
2000 if (verbose) {
2001 PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " =======================");
2002 PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sector_cnt);
2003 PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), know_target_key ? "True" : "False");
2004 PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno);
2005 PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A');
2006 PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key)));
2008 if (has_staticnonce == NONCE_STATIC)
2009 PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC"));
2010 else if (has_staticnonce == NONCE_NORMAL)
2011 PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD");
2012 else
2013 PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("Could not determine PRNG,") " " _RED_("read failed."));
2015 PrintAndLogEx(INFO, " dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "NONE");
2016 PrintAndLogEx(INFO, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk ? "True" : "False");
2018 PrintAndLogEx(INFO, "========================================================================");
2021 // Start the timer
2022 uint64_t t1 = msclock();
2024 // check the user supplied key
2025 if (know_target_key == false) {
2026 PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail");
2027 } else {
2028 if (verbose) {
2029 PrintAndLogEx(INFO, "======================= " _YELLOW_("START KNOWN KEY ATTACK") " =======================");
2032 if (mfCheckKeys(FirstBlockOfSector(sectorno), keytype, true, 1, key, &key64) == PM3_SUCCESS) {
2033 PrintAndLogEx(INFO, "target sector %3u key type %c -- using valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
2034 sectorno,
2035 (keytype == MF_KEY_B) ? 'B' : 'A',
2036 sprint_hex(key, sizeof(key))
2039 // Store the key for the nested / hardnested attack (if supplied by the user)
2040 e_sector[sectorno].Key[keytype] = key64;
2041 e_sector[sectorno].foundKey[keytype] = 'U';
2043 ++num_found_keys;
2044 } else {
2045 know_target_key = false;
2046 PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector"_RED_("%3d") " key type "_RED_("%c") " key " _RED_("%s"),
2047 sectorno,
2048 (keytype == MF_KEY_B) ? 'B' : 'A',
2049 sprint_hex(key, sizeof(key))
2051 PrintAndLogEx(WARNING, "falling back to dictionary");
2054 // Check if the user supplied key is used by other sectors
2055 for (int i = 0; i < sector_cnt; i++) {
2056 for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
2057 if (e_sector[i].foundKey[j] == 0) {
2058 if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, key, &key64) == PM3_SUCCESS) {
2059 e_sector[i].Key[j] = bytes_to_num(key, 6);
2060 e_sector[i].foundKey[j] = 'U';
2062 // If the user supplied secctor / keytype was wrong --> just be nice and correct it ;)
2063 if (know_target_key == false) {
2064 num_to_bytes(e_sector[i].Key[j], 6, key);
2065 know_target_key = true;
2066 sectorno = i;
2067 keytype = j;
2068 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
2070 (j == MF_KEY_B) ? 'B' : 'A',
2071 sprint_hex_inrow(key, sizeof(key))
2073 } else {
2074 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2076 (j == MF_KEY_B) ? 'B' : 'A',
2077 sprint_hex_inrow(key, sizeof(key))
2080 ++num_found_keys;
2086 if (num_found_keys == sector_cnt * 2) {
2087 goto all_found;
2091 bool load_success = true;
2092 // Load the dictionary
2093 if (has_filename) {
2094 res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 6, &key_cnt);
2095 if (res != PM3_SUCCESS || key_cnt == 0 || keyBlock == NULL) {
2096 PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)");
2097 if (keyBlock != NULL) {
2098 free(keyBlock);
2100 load_success = false;
2104 if (has_filename == false || load_success == false) {
2105 keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
2106 if (keyBlock == NULL) {
2107 free(e_sector);
2108 free(fptr);
2109 return PM3_EMALLOC;
2112 for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) {
2113 num_to_bytes(g_mifare_default_keys[cnt], 6, keyBlock + cnt * 6);
2115 key_cnt = ARRAYLEN(g_mifare_default_keys);
2116 PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") " keys from hardcoded default array", key_cnt);
2119 // Use the dictionary to find sector keys on the card
2120 if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("START DICTIONARY ATTACK") " =======================");
2122 if (legacy_mfchk) {
2123 PrintAndLogEx(INFO, "." NOLF);
2124 // Check all the sectors
2125 for (int i = 0; i < sector_cnt; i++) {
2126 for (int j = 0; j < 2; j++) {
2127 // Check if the key is known
2128 if (e_sector[i].foundKey[j] == 0) {
2129 for (uint32_t k = 0; k < key_cnt; k++) {
2130 PrintAndLogEx(NORMAL, "." NOLF);
2131 fflush(stdout);
2133 if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, (keyBlock + (6 * k)), &key64) == PM3_SUCCESS) {
2134 e_sector[i].Key[j] = bytes_to_num((keyBlock + (6 * k)), 6);
2135 e_sector[i].foundKey[j] = 'D';
2136 ++num_found_keys;
2137 break;
2143 PrintAndLogEx(NORMAL, "");
2144 } else {
2146 uint32_t chunksize = key_cnt > (PM3_CMD_DATA_SIZE / 6) ? (PM3_CMD_DATA_SIZE / 6) : key_cnt;
2147 bool firstChunk = true, lastChunk = false;
2149 for (uint8_t strategy = 1; strategy < 3; strategy++) {
2150 PrintAndLogEx(INFO, "running strategy %u", strategy);
2151 // main keychunk loop
2152 for (uint32_t i = 0; i < key_cnt; i += chunksize) {
2154 if (kbd_enter_pressed()) {
2155 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
2156 i = key_cnt;
2157 strategy = 3;
2158 break; // Exit the loop
2160 uint32_t size = ((key_cnt - i) > chunksize) ? chunksize : key_cnt - i;
2161 // last chunk?
2162 if (size == key_cnt - i)
2163 lastChunk = true;
2165 res = mfCheckKeys_fast(sector_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false);
2166 if (firstChunk)
2167 firstChunk = false;
2168 // all keys, aborted
2169 if (res == PM3_SUCCESS) {
2170 i = key_cnt;
2171 strategy = 3;
2172 break; // Exit the loop
2174 } // end chunks of keys
2175 firstChunk = true;
2176 lastChunk = false;
2177 } // end strategy
2180 // Analyse the dictionary attack
2181 for (int i = 0; i < sector_cnt; i++) {
2182 for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
2183 if (e_sector[i].foundKey[j] == 1) {
2184 e_sector[i].foundKey[j] = 'D';
2185 num_to_bytes(e_sector[i].Key[j], 6, tmp_key);
2187 // Store valid credentials for the nested / hardnested attack if none exist
2188 if (know_target_key == false) {
2189 num_to_bytes(e_sector[i].Key[j], 6, key);
2190 know_target_key = true;
2191 sectorno = i;
2192 keytype = j;
2193 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
2195 (j == MF_KEY_B) ? 'B' : 'A',
2196 sprint_hex_inrow(tmp_key, sizeof(tmp_key))
2198 } else {
2199 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2201 (j == MF_KEY_B) ? 'B' : 'A',
2202 sprint_hex_inrow(tmp_key, sizeof(tmp_key))
2209 // Check if at least one sector key was found
2210 if (know_target_key == false) {
2211 // Check if the darkside attack can be used
2212 if (prng_type && has_staticnonce != NONCE_STATIC) {
2213 if (verbose) {
2214 PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
2216 isOK = mfDarkside(FirstBlockOfSector(sectorno), keytype + 0x60, &key64);
2218 switch (isOK) {
2219 case -1 :
2220 PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
2221 goto noValidKeyFound;
2222 case -2 :
2223 PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
2224 goto noValidKeyFound;
2225 case -3 :
2226 PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (its random number generator is not predictable).");
2227 goto noValidKeyFound;
2228 case -4 :
2229 PrintAndLogEx(FAILED, "\nCard is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown");
2230 PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour.");
2231 goto noValidKeyFound;
2232 case -5 :
2233 PrintAndLogEx(WARNING, "\naborted via keyboard.");
2234 goto noValidKeyFound;
2235 default :
2236 PrintAndLogEx(SUCCESS, "\nFound valid key [ " _GREEN_("%012" PRIx64) " ]\n", key64);
2237 break;
2240 // Store the keys
2241 num_to_bytes(key64, 6, key);
2242 e_sector[sectorno].Key[keytype] = key64;
2243 e_sector[sectorno].foundKey[keytype] = 'S';
2244 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)",
2245 sectorno,
2246 (keytype == MF_KEY_B) ? 'B' : 'A',
2247 key64
2249 } else {
2250 noValidKeyFound:
2251 PrintAndLogEx(FAILED, "No usable key was found!");
2252 free(keyBlock);
2253 free(e_sector);
2254 free(fptr);
2255 return PM3_ESOFT;
2259 free(keyBlock);
2260 // Clear the needed variables
2261 num_to_bytes(0, 6, tmp_key);
2262 bool nested_failed = false;
2264 // Iterate over each sector and key(A/B)
2265 for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) {
2266 for (current_key_type_i = 0; current_key_type_i < 2; current_key_type_i++) {
2268 // If the key is already known, just skip it
2269 if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) {
2271 // Try the found keys are reused
2272 if (bytes_to_num(tmp_key, 6) != 0) {
2273 // <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false);
2274 // <!> Returns false keys, so we just stick to the slower mfchk.
2275 for (int i = 0; i < sector_cnt; i++) {
2276 for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
2277 // Check if the sector key is already broken
2278 if (e_sector[i].foundKey[j])
2279 continue;
2281 // Check if the key works
2282 if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) {
2283 e_sector[i].Key[j] = bytes_to_num(tmp_key, 6);
2284 e_sector[i].foundKey[j] = 'R';
2285 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2287 (j == MF_KEY_B) ? 'B' : 'A',
2288 sprint_hex_inrow(tmp_key, sizeof(tmp_key))
2294 // Clear the last found key
2295 num_to_bytes(0, 6, tmp_key);
2297 if (current_key_type_i == MF_KEY_B) {
2298 if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) {
2299 if (verbose) {
2300 PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " =======================");
2301 PrintAndLogEx(INFO, "reading B key of sector %3d with key type %c",
2302 current_sector_i,
2303 (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
2305 uint8_t sectrail = (FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1);
2307 mf_readblock_t payload;
2308 payload.blockno = sectrail;
2309 payload.keytype = MF_KEY_A;
2311 num_to_bytes(e_sector[current_sector_i].Key[0], 6, payload.key); // KEY A
2313 clearCommandBuffer();
2314 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
2316 PacketResponseNG resp;
2317 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) goto skipReadBKey;
2319 if (resp.status != PM3_SUCCESS) goto skipReadBKey;
2321 uint8_t *data = resp.data.asBytes;
2322 key64 = bytes_to_num(data + 10, 6);
2323 if (key64) {
2324 e_sector[current_sector_i].foundKey[current_key_type_i] = 'A';
2325 e_sector[current_sector_i].Key[current_key_type_i] = key64;
2326 num_to_bytes(key64, 6, tmp_key);
2327 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2328 current_sector_i,
2329 (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
2330 sprint_hex_inrow(tmp_key, sizeof(tmp_key))
2332 } else {
2333 if (verbose) {
2334 PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c",
2335 current_sector_i,
2336 (current_key_type_i == MF_KEY_B) ? 'B' : 'A'
2338 PrintAndLogEx(INFO, " -- reading the B key was not possible, maybe due to access rights?");
2346 // Use the nested / hardnested attack
2347 skipReadBKey:
2348 if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) {
2350 if (has_staticnonce == NONCE_STATIC)
2351 goto tryStaticnested;
2353 if (prng_type && (nested_failed == false)) {
2354 uint8_t retries = 0;
2355 if (verbose) {
2356 PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " =======================");
2357 PrintAndLogEx(INFO, "sector no %3d, target key type %c",
2358 current_sector_i,
2359 (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
2361 tryNested:
2362 isOK = mfnested(FirstBlockOfSector(sectorno), keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, calibrate);
2364 switch (isOK) {
2365 case PM3_ETIMEOUT: {
2366 PrintAndLogEx(ERR, "\nError: No response from Proxmark3.");
2367 free(e_sector);
2368 free(fptr);
2369 return PM3_ESOFT;
2371 case PM3_EOPABORTED: {
2372 PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
2373 free(e_sector);
2374 free(fptr);
2375 return PM3_EOPABORTED;
2377 case PM3_EFAILED: {
2378 PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable).");
2379 PrintAndLogEx(FAILED, "Nested attack failed --> try hardnested");
2380 goto tryHardnested;
2382 case PM3_ESOFT: {
2383 // key not found
2384 calibrate = false;
2385 // this can happen on some old cards, it's worth trying some more before switching to slower hardnested
2386 if (retries++ < MIFARE_SECTOR_RETRY) {
2387 PrintAndLogEx(FAILED, "Nested attack failed, trying again (%i/%i)", retries, MIFARE_SECTOR_RETRY);
2388 goto tryNested;
2389 } else {
2390 PrintAndLogEx(FAILED, "Nested attack failed, moving to hardnested");
2391 nested_failed = true;
2392 goto tryHardnested;
2394 break;
2396 case PM3_SUCCESS: {
2397 calibrate = false;
2398 e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6);
2399 e_sector[current_sector_i].foundKey[current_key_type_i] = 'N';
2400 break;
2402 default: {
2403 PrintAndLogEx(ERR, "unknown Error.\n");
2404 free(e_sector);
2405 free(fptr);
2406 return PM3_ESOFT;
2410 } else {
2411 tryHardnested: // If the nested attack fails then we try the hardnested attack
2412 if (verbose) {
2413 PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " =======================");
2414 PrintAndLogEx(INFO, "sector no %3d, target key type %c, Slow %s",
2415 current_sector_i,
2416 (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
2417 slow ? "Yes" : "No");
2420 isOK = mfnestedhard(FirstBlockOfSector(sectorno), keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
2421 DropField();
2422 if (isOK) {
2423 switch (isOK) {
2424 case 1: {
2425 PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
2426 break;
2428 case 2: {
2429 PrintAndLogEx(NORMAL, "\nButton pressed, user aborted");
2430 break;
2432 default: {
2433 break;
2436 free(e_sector);
2437 free(fptr);
2438 return PM3_ESOFT;
2441 // Copy the found key to the tmp_key variale (for the following print statement, and the mfCheckKeys above)
2442 num_to_bytes(foundkey, 6, tmp_key);
2443 e_sector[current_sector_i].Key[current_key_type_i] = foundkey;
2444 e_sector[current_sector_i].foundKey[current_key_type_i] = 'H';
2447 if (has_staticnonce == NONCE_STATIC) {
2448 tryStaticnested:
2449 if (verbose) {
2450 PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
2451 PrintAndLogEx(INFO, "sector no %3d, target key type %c",
2452 current_sector_i,
2453 (current_key_type_i == MF_KEY_B) ? 'B' : 'A');
2456 isOK = mfStaticNested(sectorno, keytype, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key);
2457 DropField();
2458 switch (isOK) {
2459 case PM3_ETIMEOUT: {
2460 PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
2461 free(e_sector);
2462 free(fptr);
2463 return PM3_ESOFT;
2465 case PM3_EOPABORTED: {
2466 PrintAndLogEx(WARNING, "\nButton pressed, user aborted");
2467 free(e_sector);
2468 free(fptr);
2469 return PM3_EOPABORTED;
2471 case PM3_SUCCESS: {
2472 e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6);
2473 e_sector[current_sector_i].foundKey[current_key_type_i] = 'C';
2474 break;
2476 default: {
2477 break;
2482 // Check if the key was found
2483 if (e_sector[current_sector_i].foundKey[current_key_type_i]) {
2484 PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2485 current_sector_i,
2486 (current_key_type_i == MF_KEY_B) ? 'B' : 'A',
2487 sprint_hex_inrow(tmp_key, sizeof(tmp_key))
2495 all_found:
2497 // Show the results to the user
2498 PrintAndLogEx(NORMAL, "");
2499 PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
2501 printKeyTable(sector_cnt, e_sector);
2503 // Dump the keys
2504 PrintAndLogEx(NORMAL, "");
2506 if (createMfcKeyDump(fptr, sector_cnt, e_sector) != PM3_SUCCESS) {
2507 PrintAndLogEx(ERR, "Failed to save keys to file");
2510 // clear emulator mem
2511 clearCommandBuffer();
2512 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR, NULL, 0);
2514 PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)");
2516 for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) {
2517 mfEmlGetMem(block, current_sector_i, 1);
2518 if (e_sector[current_sector_i].foundKey[0])
2519 num_to_bytes(e_sector[current_sector_i].Key[0], 6, block);
2520 if (e_sector[current_sector_i].foundKey[1])
2521 num_to_bytes(e_sector[current_sector_i].Key[1], 6, block + 10);
2523 mfEmlSetMem(block, FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1, 1);
2526 // use ecfill trick
2527 FastDumpWithEcFill(sector_cnt);
2529 bytes = block_cnt * MFBLOCK_SIZE;
2530 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
2531 if (dump == NULL) {
2532 PrintAndLogEx(ERR, "Fail, cannot allocate memory");
2533 free(e_sector);
2534 free(fptr);
2535 return PM3_EMALLOC;
2538 PrintAndLogEx(INFO, "downloading the card content from emulator memory");
2539 if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
2540 PrintAndLogEx(ERR, "Fail, transfer from device time-out");
2541 free(e_sector);
2542 free(dump);
2543 free(fptr);
2544 return PM3_ETIMEOUT;
2547 free(fptr);
2548 fptr = GenerateFilename("hf-mf-", "-dump");
2549 if (fptr == NULL) {
2550 free(dump);
2551 free(e_sector);
2552 free(fptr);
2553 return PM3_ESOFT;
2555 strcpy(filename, fptr);
2556 free(fptr);
2558 saveFile(filename, ".bin", dump, bytes);
2559 saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
2560 saveFileJSON(filename, jsfCardMemory, dump, bytes, NULL);
2562 // Generate and show statistics
2563 t1 = msclock() - t1;
2564 PrintAndLogEx(INFO, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0);
2566 free(dump);
2567 free(e_sector);
2568 return PM3_SUCCESS;
2571 static int CmdHF14AMfChk_fast(const char *Cmd) {
2572 CLIParserContext *ctx;
2573 CLIParserInit(&ctx, "hf mf fchk",
2574 "This is a improved checkkeys method speedwise. It checks MIFARE Classic tags sector keys against a dictionary file with keys",
2575 "hf mf fchk --mini -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
2576 "hf mf fchk --1k -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
2577 "hf mf fchk --2k -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
2578 "hf mf fchk --4k -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k\n"
2579 "hf mf fchk --1k -f mfc_default_keys.dic --> Target 1K using default dictionary file\n"
2580 "hf mf fchk --1k --emu --> Target 1K, write keys to emulator memory\n"
2581 "hf mf fchk --1k --dump --> Target 1K, write keys to file\n"
2582 "hf mf fchk --1k --mem --> Target 1K, use dictionary from flash memory");
2584 void *argtable[] = {
2585 arg_param_begin,
2586 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
2587 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
2588 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"),
2589 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
2590 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
2591 arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
2592 arg_lit0(NULL, "dump", "Dump found keys to binary file"),
2593 arg_lit0(NULL, "mem", "Use dictionary from flashmemory"),
2594 arg_str0("f", "file", "<fn>", "filename of dictionary"),
2595 arg_param_end
2597 CLIExecWithReturn(ctx, Cmd, argtable, true);
2599 int keylen = 0;
2600 uint8_t key[255 * 6] = {0};
2601 CLIGetHexWithReturn(ctx, 1, key, &keylen);
2603 bool m0 = arg_get_lit(ctx, 2);
2604 bool m1 = arg_get_lit(ctx, 3);
2605 bool m2 = arg_get_lit(ctx, 4);
2606 bool m4 = arg_get_lit(ctx, 5);
2608 bool transferToEml = arg_get_lit(ctx, 6);
2609 bool createDumpFile = arg_get_lit(ctx, 7);
2610 bool use_flashmemory = arg_get_lit(ctx, 8);
2612 int fnlen = 0;
2613 char filename[FILE_PATH_SIZE] = {0};
2614 CLIParamStrToBuf(arg_get_str(ctx, 9), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
2616 CLIParserFree(ctx);
2618 //validations
2620 if ((m0 + m1 + m2 + m4) > 1) {
2621 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
2622 return PM3_EINVARG;
2623 } else if ((m0 + m1 + m2 + m4) == 0) {
2624 m1 = true;
2627 uint8_t sectorsCnt = 1;
2628 if (m0) {
2629 sectorsCnt = MIFARE_MINI_MAXSECTOR;
2630 } else if (m1) {
2631 sectorsCnt = MIFARE_1K_MAXSECTOR;
2632 } else if (m2) {
2633 sectorsCnt = MIFARE_2K_MAXSECTOR;
2634 } else if (m4) {
2635 sectorsCnt = MIFARE_4K_MAXSECTOR;
2636 } else {
2637 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
2638 return PM3_EINVARG;
2641 // Handle Keys
2642 int keycnt = 0;
2643 uint32_t keyitems = ARRAYLEN(g_mifare_default_keys);
2644 uint8_t *keyBlock, *p;
2645 // Allocate memory for keys to be tested
2646 keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
2647 if (keyBlock == NULL) return PM3_EMALLOC;
2649 // Copy default keys to list
2650 for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++)
2651 num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6));
2653 // Handle user supplied key
2654 if (keylen >= 6) {
2655 int numKeys = keylen / 6;
2657 p = realloc(keyBlock, 6 * (keyitems + numKeys));
2658 if (!p) {
2659 PrintAndLogEx(FAILED, "cannot allocate memory for Keys");
2660 free(keyBlock);
2661 return PM3_EMALLOC;
2663 keyBlock = p;
2665 memcpy(keyBlock + 6 * keycnt, key, 6 * numKeys);
2667 for (int i = 0; i < numKeys; i++) {
2668 PrintAndLogEx(NORMAL, "[%2d] key %s", keycnt, sprint_hex((keyBlock + 6 * keycnt), 6));
2669 keycnt++;
2674 // Handle user supplied dictionary file
2675 FILE *f;
2676 char buf[13];
2677 if (fnlen > 0) {
2678 char *dict_path;
2679 int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false);
2680 if (res != PM3_SUCCESS) {
2681 free(keyBlock);
2682 return PM3_EFILE;
2684 f = fopen(dict_path, "r");
2685 if (!f) {
2686 PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path);
2687 free(dict_path);
2688 free(keyBlock);
2689 return PM3_EFILE;
2691 free(dict_path);
2692 // load keys from dictionary file
2693 while (fgets(buf, sizeof(buf), f)) {
2694 if (strlen(buf) < 12 || buf[11] == '\n')
2695 continue;
2697 while (fgetc(f) != '\n' && !feof(f)) ; //goto next line
2699 if (buf[0] == '#') continue; //The line start with # is comment, skip
2701 // codesmell, only checks first char?
2702 if (!isxdigit(buf[0])) {
2703 PrintAndLogEx(FAILED, "File content error. '" _YELLOW_("%s")"' must include 12 HEX symbols", buf);
2704 continue;
2707 buf[12] = 0;
2709 if (keyitems - keycnt < 2) {
2710 p = realloc(keyBlock, 6 * (keyitems += 64));
2711 if (!p) {
2712 PrintAndLogEx(FAILED, "Cannot allocate memory for defKeys");
2713 free(keyBlock);
2714 fclose(f);
2715 return PM3_EMALLOC;
2717 keyBlock = p;
2719 memset(keyBlock + 6 * keycnt, 0, 6);
2720 num_to_bytes(strtoll(buf, NULL, 16), 6, keyBlock + 6 * keycnt);
2721 //PrintAndLogEx(NORMAL, "check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6));
2722 keycnt++;
2723 memset(buf, 0, sizeof(buf));
2725 fclose(f);
2726 PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename);
2729 if (keycnt == 0 && !use_flashmemory) {
2730 PrintAndLogEx(SUCCESS, "No key specified, trying default keys");
2731 for (; keycnt < ARRAYLEN(g_mifare_default_keys); keycnt++)
2732 PrintAndLogEx(NORMAL, "[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
2733 (keyBlock + 6 * keycnt)[0], (keyBlock + 6 * keycnt)[1], (keyBlock + 6 * keycnt)[2],
2734 (keyBlock + 6 * keycnt)[3], (keyBlock + 6 * keycnt)[4], (keyBlock + 6 * keycnt)[5]);
2737 // create/initialize key storage structure
2738 sector_t *e_sector = NULL;
2739 int32_t res = initSectorTable(&e_sector, sectorsCnt);
2740 if (res != sectorsCnt) {
2741 free(keyBlock);
2742 return PM3_EMALLOC;
2746 uint32_t chunksize = keycnt > (PM3_CMD_DATA_SIZE / 6) ? (PM3_CMD_DATA_SIZE / 6) : keycnt;
2747 bool firstChunk = true, lastChunk = false;
2749 int i = 0;
2750 // time
2751 uint64_t t1 = msclock();
2753 if (use_flashmemory) {
2754 PrintAndLogEx(SUCCESS, "Using dictionary in flash memory");
2755 mfCheckKeys_fast(sectorsCnt, true, true, 1, 0, keyBlock, e_sector, use_flashmemory);
2756 } else {
2758 // strategys. 1= deep first on sector 0 AB, 2= width first on all sectors
2759 for (uint8_t strategy = 1; strategy < 3; strategy++) {
2760 PrintAndLogEx(INFO, "Running strategy %u", strategy);
2762 // main keychunk loop
2763 for (i = 0; i < keycnt; i += chunksize) {
2765 if (kbd_enter_pressed()) {
2766 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
2767 goto out;
2770 uint32_t size = ((keycnt - i) > chunksize) ? chunksize : keycnt - i;
2772 // last chunk?
2773 if (size == keycnt - i)
2774 lastChunk = true;
2776 res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false);
2778 if (firstChunk)
2779 firstChunk = false;
2781 // all keys, aborted
2782 if (res == PM3_SUCCESS || res == 2)
2783 goto out;
2784 } // end chunks of keys
2785 firstChunk = true;
2786 lastChunk = false;
2787 } // end strategy
2789 out:
2790 t1 = msclock() - t1;
2791 PrintAndLogEx(INFO, "time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1 / 1000.0));
2793 // check..
2794 uint8_t found_keys = 0;
2795 for (i = 0; i < sectorsCnt; ++i) {
2797 if (e_sector[i].foundKey[0])
2798 found_keys++;
2800 if (e_sector[i].foundKey[1])
2801 found_keys++;
2804 if (found_keys == 0) {
2805 PrintAndLogEx(WARNING, "No keys found");
2806 } else {
2808 PrintAndLogEx(NORMAL, "");
2809 PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
2811 printKeyTable(sectorsCnt, e_sector);
2813 if (use_flashmemory && found_keys == (sectorsCnt << 1)) {
2814 PrintAndLogEx(SUCCESS, "Card dumped as well. run " _YELLOW_("`%s %c`"),
2815 "hf mf esave",
2816 GetFormatFromSector(sectorsCnt)
2820 if (transferToEml) {
2821 // fast push mode
2822 conn.block_after_ACK = true;
2823 uint8_t block[16] = {0x00};
2824 for (i = 0; i < sectorsCnt; ++i) {
2825 uint8_t b = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1;
2826 mfEmlGetMem(block, b, 1);
2828 if (e_sector[i].foundKey[0])
2829 num_to_bytes(e_sector[i].Key[0], 6, block);
2831 if (e_sector[i].foundKey[1])
2832 num_to_bytes(e_sector[i].Key[1], 6, block + 10);
2834 if (i == sectorsCnt - 1) {
2835 // Disable fast mode on last packet
2836 conn.block_after_ACK = false;
2838 mfEmlSetMem(block, b, 1);
2840 PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory");
2842 if (found_keys == (sectorsCnt << 1)) {
2843 FastDumpWithEcFill(sectorsCnt);
2847 if (createDumpFile) {
2849 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
2850 if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) {
2851 PrintAndLogEx(ERR, "Failed to save keys to file");
2853 free(fptr);
2857 free(keyBlock);
2858 free(e_sector);
2859 PrintAndLogEx(NORMAL, "");
2860 return PM3_SUCCESS;
2863 static int CmdHF14AMfChk(const char *Cmd) {
2864 CLIParserContext *ctx;
2865 CLIParserInit(&ctx, "hf mf chk",
2866 "Check keys on MIFARE Classic card",
2867 "hf mf chk --mini -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Mini\n"
2868 "hf mf chk --1k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Classic 1k\n"
2869 "hf mf chk --2k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 2k\n"
2870 "hf mf chk --4k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 4k\n"
2871 "hf mf chk --1k --emu --> Check all sectors, all keys, 1K, and write to emulator memory\n"
2872 "hf mf chk --1k --dump --> Check all sectors, all keys, 1K, and write to file\n"
2873 "hf mf chk -a --blk 0 -f mfc_default_keys.dic --> Check dictionary against block 0, key A");
2875 void *argtable[] = {
2876 arg_param_begin,
2877 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
2878 arg_int0(NULL, "blk", "<dec>", "Input block number"),
2879 arg_lit0("a", NULL, "Target Key A, if found also check Key B for duplicate"),
2880 arg_lit0("b", NULL, "Target Key B"),
2881 arg_lit0("*", "all", "Target both key A & B (default)"),
2882 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
2883 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (default)"),
2884 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
2885 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
2886 arg_lit0(NULL, "emu", "Fill simulator keys from found keys"),
2887 arg_lit0(NULL, "dump", "Dump found keys to binary file"),
2888 arg_str0("f", "file", "<filename>", "filename of dictionary"),
2889 arg_param_end
2891 CLIExecWithReturn(ctx, Cmd, argtable, true);
2893 int keylen = 0;
2894 uint8_t key[255 * 6] = {0};
2895 CLIGetHexWithReturn(ctx, 1, key, &keylen);
2897 int blockNo = arg_get_int_def(ctx, 2, -1);
2899 uint8_t keyType = 2;
2901 if ((arg_get_lit(ctx, 3) && arg_get_lit(ctx, 4)) || arg_get_lit(ctx, 5)) {
2902 keyType = 2;
2903 } else if (arg_get_lit(ctx, 3)) {
2904 keyType = MF_KEY_A;
2905 } else if (arg_get_lit(ctx, 4)) {
2906 keyType = MF_KEY_B;
2909 bool m0 = arg_get_lit(ctx, 6);
2910 bool m1 = arg_get_lit(ctx, 7);
2911 bool m2 = arg_get_lit(ctx, 8);
2912 bool m4 = arg_get_lit(ctx, 9);
2914 bool transferToEml = arg_get_lit(ctx, 10);
2915 bool createDumpFile = arg_get_lit(ctx, 11);
2917 int fnlen = 0;
2918 char filename[FILE_PATH_SIZE] = {0};
2919 CLIParamStrToBuf(arg_get_str(ctx, 12), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
2921 CLIParserFree(ctx);
2923 //validations
2924 if ((m0 + m1 + m2 + m4) > 1) {
2925 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
2926 return PM3_EINVARG;
2929 uint8_t SectorsCnt = 1;
2930 if (m0) {
2931 SectorsCnt = MIFARE_MINI_MAXSECTOR;
2932 } else if (m1) {
2933 SectorsCnt = MIFARE_1K_MAXSECTOR;
2934 } else if (m2) {
2935 SectorsCnt = MIFARE_2K_MAXSECTOR;
2936 } else if (m4) {
2937 SectorsCnt = MIFARE_4K_MAXSECTOR;
2940 if ((blockNo == -1) && (SectorsCnt == 1)) {
2941 // Default to 1K if block number not specified
2942 SectorsCnt = MIFARE_1K_MAXSECTOR;
2945 if (blockNo > -1) {
2946 if (SectorsCnt == 0) {
2947 PrintAndLogEx(WARNING, "Invalid MIFARE Type");
2948 return PM3_EINVARG;
2950 } else {
2951 blockNo = 3;
2954 // Handle Keys
2955 int keycnt = 0;
2956 uint32_t keyitems = ARRAYLEN(g_mifare_default_keys);
2957 uint8_t *keyBlock, *p;
2958 // Allocate memory for keys to be tested
2959 keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
2960 if (keyBlock == NULL) return PM3_EMALLOC;
2962 // Copy default keys to list
2963 for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++)
2964 num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6));
2966 // Handle user supplied key
2967 if (keylen >= 6) {
2968 int numKeys = keylen / 6;
2970 p = realloc(keyBlock, 6 * (keyitems + numKeys));
2971 if (!p) {
2972 PrintAndLogEx(FAILED, "cannot allocate memory for Keys");
2973 free(keyBlock);
2974 return PM3_EMALLOC;
2976 keyBlock = p;
2978 memcpy(keyBlock + 6 * keycnt, key, 6 * numKeys);
2980 for (int i = 0; i < numKeys; i++) {
2981 PrintAndLogEx(NORMAL, "[%2d] key %s", keycnt, sprint_hex((keyBlock + 6 * keycnt), 6));
2982 keycnt++;
2987 // Handle user supplied dictionary file
2988 FILE *f;
2989 char buf[13];
2990 if (fnlen > 0) {
2991 char *dict_path;
2992 int res = searchFile(&dict_path, DICTIONARIES_SUBDIR, filename, ".dic", false);
2993 if (res != PM3_SUCCESS) {
2994 free(keyBlock);
2995 return PM3_EFILE;
2997 f = fopen(dict_path, "r");
2998 if (!f) {
2999 PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", dict_path);
3000 free(dict_path);
3001 free(keyBlock);
3002 return PM3_EFILE;
3004 free(dict_path);
3005 // load keys from dictionary file
3006 while (fgets(buf, sizeof(buf), f)) {
3007 if (strlen(buf) < 12 || buf[11] == '\n')
3008 continue;
3010 while (fgetc(f) != '\n' && !feof(f)) ; //goto next line
3012 if (buf[0] == '#') continue; //The line start with # is comment, skip
3014 // codesmell, only checks first char?
3015 if (!isxdigit(buf[0])) {
3016 PrintAndLogEx(FAILED, "File content error. '" _YELLOW_("%s")"' must include 12 HEX symbols", buf);
3017 continue;
3020 buf[12] = 0;
3022 if (keyitems - keycnt < 2) {
3023 p = realloc(keyBlock, 6 * (keyitems += 64));
3024 if (!p) {
3025 PrintAndLogEx(FAILED, "Cannot allocate memory for defKeys");
3026 free(keyBlock);
3027 fclose(f);
3028 return PM3_EMALLOC;
3030 keyBlock = p;
3032 memset(keyBlock + 6 * keycnt, 0, 6);
3033 num_to_bytes(strtoll(buf, NULL, 16), 6, keyBlock + 6 * keycnt);
3034 //PrintAndLogEx(NORMAL, "check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6));
3035 keycnt++;
3036 memset(buf, 0, sizeof(buf));
3038 fclose(f);
3039 PrintAndLogEx(SUCCESS, "Loaded %2d keys from " _YELLOW_("%s"), keycnt, filename);
3042 uint64_t key64 = 0;
3044 if (keycnt == 0) {
3045 PrintAndLogEx(INFO, "No key specified, trying default keys");
3046 for (; keycnt < ARRAYLEN(g_mifare_default_keys); keycnt++)
3047 PrintAndLogEx(NORMAL, "[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
3048 (keyBlock + 6 * keycnt)[0],
3049 (keyBlock + 6 * keycnt)[1],
3050 (keyBlock + 6 * keycnt)[2],
3051 (keyBlock + 6 * keycnt)[3],
3052 (keyBlock + 6 * keycnt)[4],
3053 (keyBlock + 6 * keycnt)[5]
3057 // create/initialize key storage structure
3058 sector_t *e_sector = NULL;
3059 int32_t res = initSectorTable(&e_sector, SectorsCnt);
3060 if (res != SectorsCnt) {
3061 free(keyBlock);
3062 return PM3_EMALLOC;
3065 uint8_t trgKeyType = MF_KEY_A;
3066 uint16_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
3068 PrintAndLogEx(INFO, "Start check for keys...");
3069 PrintAndLogEx(INFO, "." NOLF);
3071 // fast push mode
3072 conn.block_after_ACK = true;
3074 // clear trace log by first check keys call only
3075 bool clearLog = true;
3077 // time
3078 uint64_t t1 = msclock();
3080 // check keys.
3081 for (trgKeyType = (keyType == 2) ? 0 : keyType; trgKeyType < 2; (keyType == 2) ? (++trgKeyType) : (trgKeyType = 2)) {
3083 // loop sectors but block is used as to keep track of from which blocks to test
3084 int b = blockNo;
3085 for (int i = 0; i < SectorsCnt; ++i) {
3087 // skip already found keys.
3088 if (e_sector[i].foundKey[trgKeyType]) continue;
3090 for (uint16_t c = 0; c < keycnt; c += max_keys) {
3092 PrintAndLogEx(NORMAL, "." NOLF);
3093 fflush(stdout);
3095 if (kbd_enter_pressed()) {
3096 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
3097 goto out;
3100 uint16_t size = keycnt - c > max_keys ? max_keys : keycnt - c;
3102 if (mfCheckKeys(b, trgKeyType, clearLog, size, &keyBlock[6 * c], &key64) == PM3_SUCCESS) {
3103 e_sector[i].Key[trgKeyType] = key64;
3104 e_sector[i].foundKey[trgKeyType] = true;
3105 clearLog = false;
3106 break;
3108 clearLog = false;
3110 b < 127 ? (b += 4) : (b += 16);
3113 t1 = msclock() - t1;
3114 PrintAndLogEx(INFO, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
3116 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
3117 if (keyType != MF_KEY_B) {
3118 PrintAndLogEx(INFO, "testing to read key B...");
3120 // loop sectors but block is used as to keep track of from which blocks to test
3121 int b = blockNo;
3122 for (int i = 0; i < SectorsCnt; i++) {
3124 // KEY A but not KEY B
3125 if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) {
3127 uint8_t s = GetSectorFromBlockNo(b);
3128 uint8_t sectrail = (FirstBlockOfSector(s) + NumBlocksPerSector(s) - 1);
3129 PrintAndLogEx(INFO, "Sector: %u, First block: %u, Last block: %u, Num of blocks: %u", s, FirstBlockOfSector(s), sectrail, NumBlocksPerSector(s));
3130 PrintAndLogEx(INFO, "Reading sector trailer");
3132 mf_readblock_t payload;
3133 payload.blockno = sectrail;
3134 payload.keytype = MF_KEY_A;
3136 // Use key A
3137 num_to_bytes(e_sector[i].Key[0], 6, payload.key);
3139 clearCommandBuffer();
3140 SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
3142 PacketResponseNG resp;
3143 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
3145 if (resp.status != PM3_SUCCESS) continue;
3147 uint8_t *data = resp.data.asBytes;
3148 key64 = bytes_to_num(data + 10, 6);
3149 if (key64) {
3150 PrintAndLogEx(NORMAL, "Data:%s", sprint_hex(data + 10, 6));
3151 e_sector[i].foundKey[1] = 1;
3152 e_sector[i].Key[1] = key64;
3155 b < 127 ? (b += 4) : (b += 16);
3159 out:
3160 PrintAndLogEx(NORMAL, "");
3161 PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
3163 //print keys
3164 if (SectorsCnt == 1)
3165 printKeyTableEx(SectorsCnt, e_sector, GetSectorFromBlockNo(blockNo));
3166 else
3167 printKeyTable(SectorsCnt, e_sector);
3169 if (transferToEml) {
3170 // fast push mode
3171 conn.block_after_ACK = true;
3172 uint8_t block[16] = {0x00};
3173 for (int i = 0; i < SectorsCnt; ++i) {
3174 uint8_t blockno = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1;
3175 mfEmlGetMem(block, blockno, 1);
3177 if (e_sector[i].foundKey[0])
3178 num_to_bytes(e_sector[i].Key[0], 6, block);
3180 if (e_sector[i].foundKey[1])
3181 num_to_bytes(e_sector[i].Key[1], 6, block + 10);
3183 if (i == SectorsCnt - 1) {
3184 // Disable fast mode on last packet
3185 conn.block_after_ACK = false;
3187 mfEmlSetMem(block, blockno, 1);
3189 PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory");
3192 if (createDumpFile) {
3193 char *fptr = GenerateFilename("hf-mf-", "-key.bin");
3194 if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
3195 PrintAndLogEx(ERR, "Failed to save keys to file");
3197 free(fptr);
3200 free(keyBlock);
3201 free(e_sector);
3203 // Disable fast mode and send a dummy command to make it effective
3204 conn.block_after_ACK = false;
3205 SendCommandNG(CMD_PING, NULL, 0);
3206 if (!WaitForResponseTimeout(CMD_PING, NULL, 1000)) {
3207 PrintAndLogEx(WARNING, "command execution time out");
3208 return PM3_ETIMEOUT;
3211 PrintAndLogEx(NORMAL, "");
3212 return PM3_SUCCESS;
3215 void showSectorTable(sector_t *k_sector, uint8_t k_sectorsCount) {
3216 if (k_sector != NULL) {
3217 printKeyTable(k_sectorsCount, k_sector);
3218 free(k_sector);
3222 void readerAttack(sector_t *k_sector, uint8_t k_sectorsCount, nonces_t data, bool setEmulatorMem, bool verbose) {
3224 uint64_t key = 0;
3225 bool success = false;
3227 if (k_sector == NULL) {
3228 int32_t res = initSectorTable(&k_sector, k_sectorsCount);
3229 if (res != k_sectorsCount) {
3230 free(k_sector);
3231 return;
3235 success = mfkey32_moebius(&data, &key);
3236 if (success) {
3237 uint8_t sector = data.sector;
3238 uint8_t keytype = data.keytype;
3240 PrintAndLogEx(INFO, "Reader is trying authenticate with: Key %s, sector %02d: [%012" PRIx64 "]"
3241 , (keytype == MF_KEY_B) ? "B" : "A"
3242 , sector
3243 , key
3246 k_sector[sector].Key[keytype] = key;
3247 k_sector[sector].foundKey[keytype] = true;
3249 //set emulator memory for keys
3250 if (setEmulatorMem) {
3251 uint8_t memBlock[16] = {0, 0, 0, 0, 0, 0, 0xff, 0x0F, 0x80, 0x69, 0, 0, 0, 0, 0, 0};
3252 num_to_bytes(k_sector[sector].Key[0], 6, memBlock);
3253 num_to_bytes(k_sector[sector].Key[1], 6, memBlock + 10);
3254 //iceman, guessing this will not work so well for 4K tags.
3255 PrintAndLogEx(INFO, "Setting Emulator Memory Block %02d: [%s]"
3256 , (sector * 4) + 3
3257 , sprint_hex(memBlock, sizeof(memBlock))
3259 mfEmlSetMem(memBlock, (sector * 4) + 3, 1);
3263 free(k_sector);
3266 static int CmdHF14AMfSim(const char *Cmd) {
3267 CLIParserContext *ctx;
3268 CLIParserInit(&ctx, "hf mf sim",
3269 "Simulate MIFARE Classic card",
3270 "hf mf sim --mini --> MIFARE Mini\n"
3271 "hf mf sim --1k --> MIFARE Classic 1k (default)\n"
3272 "hf mf sim --1k -u 0a0a0a0a --> MIFARE Classic 1k with 4b UID\n"
3273 "hf mf sim --1k -u 11223344556677 --> MIFARE Classic 1k with 7b UID\n"
3274 "hf mf sim --1k -u 11223344 -i --crack --> Perform reader attack in interactive mode\n"
3275 "hf mf sim --2k --> MIFARE 2k\n"
3276 "hf mf sim --4k --> MIFARE 4k");
3278 void *argtable[] = {
3279 arg_param_begin,
3280 arg_str0("u", "uid", "<hex>", "UID 4,7 or 10bytes. If not specified, the UID 4b/7b from emulator memory will be used"),
3281 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
3282 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50"),
3283 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
3284 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
3285 arg_str0(NULL, "atqa", "<hex>", "Provide explicit ATQA (2 bytes, overrides option t)"),
3286 arg_str0(NULL, "sak", "<hex>", "Provide explicit SAK (1 bytes, overrides option t)"),
3287 arg_int0("n", "num", "<dec> ", "Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite"),
3288 arg_lit0("i", "interactive", "Console will not be returned until simulation finishes or is aborted"),
3289 arg_lit0("x", NULL, "Performs the 'reader attack', nr/ar attack against a reader"),
3290 arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
3291 arg_lit0("v", "verbose", "verbose output"),
3292 arg_lit0(NULL, "cve", "trigger CVE 2021_0430"),
3293 arg_param_end
3295 CLIExecWithReturn(ctx, Cmd, argtable, true);
3297 uint16_t flags = 0;
3299 int uidlen = 0;
3300 uint8_t uid[10] = {0};
3301 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
3303 char uidsize[8] = {0};
3304 if (uidlen > 0) {
3305 switch (uidlen) {
3306 case 10:
3307 flags |= FLAG_10B_UID_IN_DATA;
3308 snprintf(uidsize, sizeof(uidsize), "10 byte");
3309 break;
3310 case 7:
3311 flags |= FLAG_7B_UID_IN_DATA;
3312 snprintf(uidsize, sizeof(uidsize), "7 byte");
3313 break;
3314 case 4:
3315 flags |= FLAG_4B_UID_IN_DATA;
3316 snprintf(uidsize, sizeof(uidsize), "4 byte");
3317 break;
3318 default:
3319 PrintAndLogEx(WARNING, "Invalid parameter for UID");
3320 CLIParserFree(ctx);
3321 return PM3_EINVARG;
3325 bool m0 = arg_get_lit(ctx, 2);
3326 bool m1 = arg_get_lit(ctx, 3);
3327 bool m2 = arg_get_lit(ctx, 4);
3328 bool m4 = arg_get_lit(ctx, 5);
3330 int atqalen = 0;
3331 uint8_t atqa[2] = {0};
3332 CLIGetHexWithReturn(ctx, 6, atqa, &atqalen);
3334 int saklen = 0;
3335 uint8_t sak[1] = {0};
3336 CLIGetHexWithReturn(ctx, 7, sak, &saklen);
3338 uint8_t exitAfterNReads = arg_get_u32_def(ctx, 8, 0);
3340 if (arg_get_lit(ctx, 9)) {
3341 flags |= FLAG_INTERACTIVE;
3344 if (arg_get_lit(ctx, 10)) {
3345 flags |= FLAG_NR_AR_ATTACK;
3348 bool setEmulatorMem = arg_get_lit(ctx, 11);
3349 bool verbose = arg_get_lit(ctx, 12);
3351 if (arg_get_lit(ctx, 13)) {
3352 flags |= FLAG_CVE21_0430;
3354 CLIParserFree(ctx);
3356 nonces_t data[1];
3358 sector_t *k_sector = NULL;
3360 //Validations
3361 if (atqalen > 0) {
3362 if (atqalen != 2) {
3363 PrintAndLogEx(WARNING, "Wrong ATQA length");
3364 return PM3_EINVARG;
3367 flags |= FLAG_FORCED_ATQA;
3369 if (saklen > 0) {
3370 if (saklen != 1) {
3371 PrintAndLogEx(WARNING, "Wrong SAK length");
3372 return PM3_EINVARG;
3375 flags |= FLAG_FORCED_SAK;
3378 // Use UID, SAK, ATQA from EMUL, if uid not defined
3379 if ((flags & (FLAG_4B_UID_IN_DATA | FLAG_7B_UID_IN_DATA | FLAG_10B_UID_IN_DATA)) == 0) {
3380 flags |= FLAG_UID_IN_EMUL;
3383 uint8_t k_sectorsCount = 40;
3384 char csize[13] = { 0 };
3386 if ((m0 + m1 + m2 + m4) > 1) {
3387 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
3388 return PM3_EINVARG;
3391 if (m0) {
3392 flags |= FLAG_MF_MINI;
3393 snprintf(csize, sizeof(csize), "MINI");
3394 k_sectorsCount = MIFARE_MINI_MAXSECTOR;
3395 } else if (m1) {
3396 flags |= FLAG_MF_1K;
3397 snprintf(csize, sizeof(csize), "1K");
3398 k_sectorsCount = MIFARE_1K_MAXSECTOR;
3399 } else if (m2) {
3400 flags |= FLAG_MF_2K;
3401 snprintf(csize, sizeof(csize), "2K with RATS");
3402 k_sectorsCount = MIFARE_2K_MAXSECTOR;
3403 } else if (m4) {
3404 flags |= FLAG_MF_4K;
3405 snprintf(csize, sizeof(csize), "4K");
3406 k_sectorsCount = MIFARE_4K_MAXSECTOR;
3407 } else {
3408 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
3409 return PM3_EINVARG;
3412 PrintAndLogEx(INFO, _YELLOW_("MIFARE %s") " | %s UID " _YELLOW_("%s") ""
3413 , csize
3414 , uidsize
3415 , (uidlen == 0) ? "N/A" : sprint_hex(uid, uidlen)
3418 PrintAndLogEx(INFO, "Options [ numreads: %d, flags: %d (0x%02x) ]"
3419 , exitAfterNReads
3420 , flags
3421 , flags);
3423 struct {
3424 uint16_t flags;
3425 uint8_t exitAfter;
3426 uint8_t uid[10];
3427 uint16_t atqa;
3428 uint8_t sak;
3429 } PACKED payload;
3431 payload.flags = flags;
3432 payload.exitAfter = exitAfterNReads;
3433 memcpy(payload.uid, uid, uidlen);
3434 payload.atqa = (atqa[1] << 8) | atqa[0];
3435 payload.sak = sak[0];
3437 clearCommandBuffer();
3438 SendCommandNG(CMD_HF_MIFARE_SIMULATE, (uint8_t *)&payload, sizeof(payload));
3439 PacketResponseNG resp;
3441 if (flags & FLAG_INTERACTIVE) {
3442 PrintAndLogEx(INFO, "Press pm3-button or send another cmd to abort simulation");
3444 while (!kbd_enter_pressed()) {
3445 if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) continue;
3446 if (!(flags & FLAG_NR_AR_ATTACK)) break;
3447 if ((resp.oldarg[0] & 0xffff) != CMD_HF_MIFARE_SIMULATE) break;
3449 memcpy(data, resp.data.asBytes, sizeof(data));
3450 readerAttack(k_sector, k_sectorsCount, data[0], setEmulatorMem, verbose);
3452 showSectorTable(k_sector, k_sectorsCount);
3454 return PM3_SUCCESS;
3458 static int CmdHF14AMfKeyBrute(const char *Cmd) {
3460 uint8_t blockNo = 0, keytype = MF_KEY_A;
3461 uint8_t key[6] = {0, 0, 0, 0, 0, 0};
3462 uint64_t foundkey = 0;
3464 char cmdp = tolower(param_getchar(Cmd, 0));
3465 if (cmdp == 'h') return usage_hf14_keybrute();
3467 // block number
3468 blockNo = param_get8(Cmd, 0);
3470 // keytype
3471 cmdp = tolower(param_getchar(Cmd, 1));
3472 if (cmdp == 'b') keytype = MF_KEY_B;
3474 // key
3475 if (param_gethex(Cmd, 2, key, 12)) return usage_hf14_keybrute();
3477 uint64_t t1 = msclock();
3479 if (mfKeyBrute(blockNo, keytype, key, &foundkey))
3480 PrintAndLogEx(SUCCESS, "found valid key: %012" PRIx64 " \n", foundkey);
3481 else
3482 PrintAndLogEx(FAILED, "key not found");
3484 t1 = msclock() - t1;
3485 PrintAndLogEx(SUCCESS, "\ntime in keybrute " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
3486 return PM3_SUCCESS;
3490 void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) {
3491 return printKeyTableEx(sectorscnt, e_sector, 0);
3493 void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector) {
3494 char strA[12 + 1] = {0};
3495 char strB[12 + 1] = {0};
3496 PrintAndLogEx(NORMAL, "");
3497 PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
3498 PrintAndLogEx(SUCCESS, "| Sec | key A |res| key B |res|");
3499 PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
3500 for (uint8_t i = 0; i < sectorscnt; i++) {
3502 snprintf(strA, sizeof(strA), "------------");
3503 snprintf(strB, sizeof(strB), "------------");
3505 if (e_sector[i].foundKey[0])
3506 snprintf(strA, sizeof(strA), "%012" PRIx64, e_sector[i].Key[0]);
3508 if (e_sector[i].foundKey[1])
3509 snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]);
3511 if (e_sector[i].foundKey[0] > 1) {
3512 PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")" | " _GREEN_("%s")" | " _YELLOW_("%c")" | " _GREEN_("%s")" | " _YELLOW_("%c")" |"
3514 , strA, e_sector[i].foundKey[0]
3515 , strB, e_sector[i].foundKey[1]
3517 } else {
3519 // keep track if we use start_sector or i...
3520 uint8_t s = start_sector;
3521 if (start_sector == 0)
3522 s = i;
3524 PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")" | " _GREEN_("%s")" | " _YELLOW_("%d")" | " _GREEN_("%s")" | " _YELLOW_("%d")" |"
3526 , strA, e_sector[i].foundKey[0]
3527 , strB, e_sector[i].foundKey[1]
3531 PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
3533 if (e_sector[0].foundKey[0] > 1) {
3534 PrintAndLogEx(INFO, "( "
3535 _YELLOW_("D") ":Dictionary / "
3536 _YELLOW_("S") ":darkSide / "
3537 _YELLOW_("U") ":User / "
3538 _YELLOW_("R") ":Reused / "
3539 _YELLOW_("N") ":Nested / "
3540 _YELLOW_("H") ":Hardnested / "
3541 _YELLOW_("C") ":statiCnested / "
3542 _YELLOW_("A") ":keyA "
3543 " )"
3545 } else {
3546 PrintAndLogEx(SUCCESS, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success )");
3548 PrintAndLogEx(NORMAL, "");
3552 // EMULATOR COMMANDS
3553 static int CmdHF14AMfEGetBlk(const char *Cmd) {
3554 CLIParserContext *ctx;
3555 CLIParserInit(&ctx, "hf mf egetblk",
3556 "Get emulator memory block",
3557 "hf mf egetblk --blk 0 -> get block 0 (manufacturer)\n"
3558 "hf mf egetblk --blk 3 -v -> get block 3, decode sector trailer\n"
3560 void *argtable[] = {
3561 arg_param_begin,
3562 arg_int1("b", "blk", "<dec>", "block number"),
3563 arg_lit0("v", "verbose", "verbose output"),
3564 arg_param_end
3566 CLIExecWithReturn(ctx, Cmd, argtable, false);
3567 int b = arg_get_int_def(ctx, 1, 0);
3568 bool verbose = arg_get_lit(ctx, 2);
3569 CLIParserFree(ctx);
3571 if (b > 255) {
3572 return PM3_EINVARG;
3574 uint8_t blockno = (uint8_t)b;
3576 uint8_t data[16] = {0x00};
3577 if (mfEmlGetMem(data, blockno, 1) == PM3_SUCCESS) {
3579 uint8_t sector = GetSectorFromBlockNo(blockno);
3580 mf_print_sector_hdr(sector);
3581 mf_print_block(blockno, data);
3583 if (verbose) {
3584 decode_print_st(blockno, data);
3585 } else {
3586 PrintAndLogEx(NORMAL, "");
3588 return PM3_SUCCESS;
3591 static int CmdHF14AMfEGetSc(const char *Cmd) {
3592 CLIParserContext *ctx;
3593 CLIParserInit(&ctx, "hf mf egetsc",
3594 "Get emulator memory sector",
3595 "hf mf egetsc -s 0"
3597 void *argtable[] = {
3598 arg_param_begin,
3599 arg_int1("s", "sec", "<dec>", "sector number"),
3600 arg_lit0("v", "verbose", "verbose output"),
3601 arg_param_end
3603 CLIExecWithReturn(ctx, Cmd, argtable, false);
3604 int s = arg_get_int_def(ctx, 1, 0);
3605 bool verbose = arg_get_lit(ctx, 2);
3606 CLIParserFree(ctx);
3608 if (s > 39) {
3609 PrintAndLogEx(WARNING, "Sector number must be less then 40");
3610 return PM3_EINVARG;
3613 uint8_t sector = (uint8_t)s;
3614 mf_print_sector_hdr(sector);
3616 uint8_t blocks = NumBlocksPerSector(sector);
3617 uint8_t start = FirstBlockOfSector(sector);
3619 uint8_t data[16] = {0};
3620 for (int i = 0; i < blocks; i++) {
3621 int res = mfEmlGetMem(data, start + i, 1);
3622 if (res == PM3_SUCCESS) {
3623 mf_print_block(start + i, data);
3626 if (verbose) {
3627 decode_print_st(start + blocks - 1, data);
3628 } else {
3629 PrintAndLogEx(NORMAL, "");
3631 return PM3_SUCCESS;
3634 static int CmdHF14AMfEClear(const char *Cmd) {
3635 CLIParserContext *ctx;
3636 CLIParserInit(&ctx, "hf mf eclr",
3637 "It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF",
3638 "hf mf eclr"
3640 void *argtable[] = {
3641 arg_param_begin,
3642 arg_param_end
3644 CLIExecWithReturn(ctx, Cmd, argtable, true);
3645 CLIParserFree(ctx);
3646 clearCommandBuffer();
3647 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR, NULL, 0);
3648 return PM3_SUCCESS;
3651 static int CmdHF14AMfESet(const char *Cmd) {
3653 CLIParserContext *ctx;
3654 CLIParserInit(&ctx, "hf mf esetblk",
3655 "Set emulator memory block",
3656 "hf mf esetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
3658 void *argtable[] = {
3659 arg_param_begin,
3660 arg_int1("b", "blk", "<dec>", "block number"),
3661 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
3662 arg_param_end
3664 CLIExecWithReturn(ctx, Cmd, argtable, false);
3666 int b = arg_get_int_def(ctx, 1, 0);
3668 uint8_t data[16] = {0x00};
3669 int datalen = 0;
3670 int res = CLIParamHexToBuf(arg_get_str(ctx, 2), data, sizeof(data), &datalen);
3671 CLIParserFree(ctx);
3672 if (res) {
3673 PrintAndLogEx(FAILED, "Error parsing bytes");
3674 return PM3_EINVARG;
3677 if (b > 255) {
3678 return PM3_EINVARG;
3681 if (datalen != sizeof(data)) {
3682 PrintAndLogEx(WARNING, "block data must include 16 HEX bytes. Got %i", datalen);
3683 return PM3_EINVARG;
3686 // 1 - blocks count
3687 return mfEmlSetMem(data, b, 1);
3690 int CmdHF14AMfELoad(const char *Cmd) {
3692 CLIParserContext *ctx;
3693 CLIParserInit(&ctx, "hf mf eload",
3694 "Load emulator memory with data from (bin/eml/json) dump file",
3695 "hf mf eload -f hf-mf-01020304.bin\n"
3696 "hf mf eload --4k -f hf-mf-01020304.eml\n"
3698 void *argtable[] = {
3699 arg_param_begin,
3700 arg_str1("f", "file", "<fn>", "filename of dump"),
3701 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
3702 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
3703 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
3704 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
3705 arg_lit0(NULL, "ul", "MIFARE Ultralight family"),
3706 arg_int0("q", "qty", "<dec>", "manually set number of blocks (overrides)"),
3707 arg_param_end
3709 CLIExecWithReturn(ctx, Cmd, argtable, false);
3711 int fnlen = 0;
3712 char filename[FILE_PATH_SIZE];
3713 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3715 bool m0 = arg_get_lit(ctx, 2);
3716 bool m1 = arg_get_lit(ctx, 3);
3717 bool m2 = arg_get_lit(ctx, 4);
3718 bool m4 = arg_get_lit(ctx, 5);
3719 bool mu = arg_get_lit(ctx, 6);
3721 int numblks = arg_get_int_def(ctx, 7, -1);
3723 CLIParserFree(ctx);
3725 // validations
3726 if ((m0 + m1 + m2 + m4 + mu) > 1) {
3727 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
3728 return PM3_EINVARG;
3729 } else if ((m0 + m1 + m2 + m4 + mu) == 0) {
3730 m1 = true;
3733 uint8_t block_width = 16;
3734 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
3736 if (m0) {
3737 block_cnt = MIFARE_MINI_MAXBLOCK;
3738 } else if (m1) {
3739 block_cnt = MIFARE_1K_MAXBLOCK;
3740 } else if (m2) {
3741 block_cnt = MIFARE_2K_MAXBLOCK;
3742 } else if (m4) {
3743 block_cnt = MIFARE_4K_MAXBLOCK;
3744 } else if (mu) {
3745 block_cnt = 255;
3746 block_width = 4;
3747 } else {
3748 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
3749 return PM3_EINVARG;
3752 PrintAndLogEx(INFO, "%d blocks ( %u bytes ) to upload", block_cnt, block_cnt * block_width);
3754 if (numblks > 0) {
3755 block_cnt = MIN(numblks, block_cnt);
3756 PrintAndLogEx(INFO, "overriding number of blocks, will use %d blocks ( %u bytes )", block_cnt, block_cnt * block_width);
3759 uint8_t *data = NULL;
3760 size_t datalen = 0;
3761 int res = PM3_SUCCESS;
3762 DumpFileType_t dftype = getfiletype(filename);
3763 switch (dftype) {
3764 case BIN: {
3765 res = loadFile_safe(filename, ".bin", (void **)&data, &datalen);
3766 break;
3768 case EML: {
3769 res = loadFileEML_safe(filename, (void **)&data, &datalen);
3770 break;
3772 case JSON: {
3773 data = calloc(MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK, sizeof(uint8_t));
3774 if (data == NULL) {
3775 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
3776 return PM3_EMALLOC;
3778 res = loadFileJSON(filename, (void *)data, MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, &datalen, NULL);
3779 break;
3781 case DICTIONARY: {
3782 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
3783 free(data);
3784 return PM3_EINVARG;
3788 if (res != PM3_SUCCESS) {
3789 free(data);
3790 return PM3_EFILE;
3793 // 64 or 256 blocks.
3794 if ((datalen % block_width) != 0) {
3795 PrintAndLogEx(FAILED, "File content error. Size doesn't match blockwidth ");
3796 free(data);
3797 return PM3_ESOFT;
3800 // convert plain or old mfu format to new format
3801 if (block_width == 4) {
3802 res = convert_mfu_dump_format(&data, &datalen, true);
3803 if (res != PM3_SUCCESS) {
3804 PrintAndLogEx(FAILED, "Failed convert on load to new Ultralight/NTAG format");
3805 free(data);
3806 return res;
3809 mfu_dump_t *mfu_dump = (mfu_dump_t *)data;
3810 printMFUdumpEx(mfu_dump, mfu_dump->pages + 1, 0);
3812 // update expected blocks to match converted data.
3813 block_cnt = datalen / 4;
3814 PrintAndLogEx(INFO, "MIFARE Ultralight override, will use %d blocks ( %u bytes )", block_cnt, block_cnt * block_width);
3817 PrintAndLogEx(INFO, "Uploading to emulator memory");
3818 PrintAndLogEx(INFO, "." NOLF);
3820 // fast push mode
3821 conn.block_after_ACK = true;
3823 size_t offset = 0;
3824 int cnt = 0;
3826 while (datalen && cnt < block_cnt) {
3827 if (datalen == block_width) {
3828 // Disable fast mode on last packet
3829 conn.block_after_ACK = false;
3832 if (mfEmlSetMem_xt(data + offset, cnt, 1, block_width) != PM3_SUCCESS) {
3833 PrintAndLogEx(FAILED, "Can't set emulator mem at block: %3d", cnt);
3834 free(data);
3835 return PM3_ESOFT;
3837 PrintAndLogEx(NORMAL, "." NOLF);
3838 fflush(stdout);
3840 cnt++;
3841 offset += block_width;
3842 datalen -= block_width;
3844 free(data);
3845 PrintAndLogEx(NORMAL, "");
3847 if (block_width == 4) {
3848 PrintAndLogEx(HINT, "You are ready to simulate. See " _YELLOW_("`hf mfu sim -h`"));
3849 // MFU / NTAG
3850 if ((cnt != block_cnt)) {
3851 PrintAndLogEx(WARNING, "Warning, Ultralight/Ntag file content, Loaded %d blocks of expected %d blocks into emulator memory", cnt, block_cnt);
3852 return PM3_SUCCESS;
3854 } else {
3855 PrintAndLogEx(HINT, "You are ready to simulate. See " _YELLOW_("`hf mf sim -h`"));
3856 // MFC
3857 if ((cnt != block_cnt)) {
3858 PrintAndLogEx(WARNING, "Error, file content, Only loaded %d blocks, must be %d blocks into emulator memory", cnt, block_cnt);
3859 return PM3_SUCCESS;
3862 PrintAndLogEx(INFO, "Done!");
3863 return PM3_SUCCESS;
3866 static int CmdHF14AMfESave(const char *Cmd) {
3868 CLIParserContext *ctx;
3869 CLIParserInit(&ctx, "hf mf esave",
3870 "Save emulator memory into three files (BIN/EML/JSON) ",
3871 "hf mf esave\n"
3872 "hf mf esave --4k\n"
3873 "hf mf esave --4k -f hf-mf-01020304.eml"
3875 void *argtable[] = {
3876 arg_param_begin,
3877 arg_str0("f", "file", "<fn>", "filename of dump"),
3878 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
3879 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
3880 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
3881 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
3882 arg_param_end
3884 CLIExecWithReturn(ctx, Cmd, argtable, true);
3886 int fnlen = 0;
3887 char filename[FILE_PATH_SIZE];
3888 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
3890 bool m0 = arg_get_lit(ctx, 2);
3891 bool m1 = arg_get_lit(ctx, 3);
3892 bool m2 = arg_get_lit(ctx, 4);
3893 bool m4 = arg_get_lit(ctx, 5);
3894 CLIParserFree(ctx);
3896 // validations
3897 if ((m0 + m1 + m2 + m4) > 1) {
3898 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
3899 return PM3_EINVARG;
3900 } else if ((m0 + m1 + m2 + m4) == 0) {
3901 m1 = true;
3904 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
3906 if (m0) {
3907 block_cnt = MIFARE_MINI_MAXBLOCK;
3908 } else if (m1) {
3909 block_cnt = MIFARE_1K_MAXBLOCK;
3910 } else if (m2) {
3911 block_cnt = MIFARE_2K_MAXBLOCK;
3912 } else if (m4) {
3913 block_cnt = MIFARE_4K_MAXBLOCK;
3916 int bytes = block_cnt * MFBLOCK_SIZE;
3918 // reserv memory
3919 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
3920 if (dump == NULL) {
3921 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
3922 return PM3_EMALLOC;
3924 memset(dump, 0, bytes);
3926 PrintAndLogEx(INFO, "downloading %u bytes from emulator memory", bytes);
3927 if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
3928 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
3929 free(dump);
3930 return PM3_ETIMEOUT;
3933 // user supplied filename?
3934 if (fnlen < 1) {
3935 char *fptr = filename;
3936 fptr += snprintf(fptr, sizeof(filename), "hf-mf-");
3937 FillFileNameByUID(fptr, dump, "-dump", 4);
3940 saveFile(filename, ".bin", dump, bytes);
3941 saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
3942 saveFileJSON(filename, jsfCardMemory, dump, bytes, NULL);
3943 free(dump);
3944 return PM3_SUCCESS;
3947 static int CmdHF14AMfEView(const char *Cmd) {
3949 CLIParserContext *ctx;
3950 CLIParserInit(&ctx, "hf mf eview",
3951 "It displays emulator memory",
3952 "hf mf eview\n"
3953 "hf mf eview --4k"
3955 void *argtable[] = {
3956 arg_param_begin,
3957 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
3958 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
3959 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
3960 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
3961 arg_param_end
3963 CLIExecWithReturn(ctx, Cmd, argtable, true);
3964 bool m0 = arg_get_lit(ctx, 1);
3965 bool m1 = arg_get_lit(ctx, 2);
3966 bool m2 = arg_get_lit(ctx, 3);
3967 bool m4 = arg_get_lit(ctx, 4);
3968 CLIParserFree(ctx);
3970 // validations
3971 if ((m0 + m1 + m2 + m4) > 1) {
3972 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
3973 return PM3_EINVARG;
3974 } else if ((m0 + m1 + m2 + m4) == 0) {
3975 m1 = true;
3978 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
3980 if (m0) {
3981 block_cnt = MIFARE_MINI_MAXBLOCK;
3982 } else if (m1) {
3983 block_cnt = MIFARE_1K_MAXBLOCK;
3984 } else if (m2) {
3985 block_cnt = MIFARE_2K_MAXBLOCK;
3986 } else if (m4) {
3987 block_cnt = MIFARE_4K_MAXBLOCK;
3988 } else {
3989 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
3990 return PM3_EINVARG;
3993 int bytes = block_cnt * MFBLOCK_SIZE;
3995 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
3996 if (dump == NULL) {
3997 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
3998 return PM3_EMALLOC;
4000 memset(dump, 0, bytes);
4002 PrintAndLogEx(INFO, "downloading emulator memory");
4003 if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) {
4004 PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
4005 free(dump);
4006 return PM3_ETIMEOUT;
4009 mf_print_blocks(block_cnt, dump);
4010 free(dump);
4011 return PM3_SUCCESS;
4014 static int CmdHF14AMfECFill(const char *Cmd) {
4016 CLIParserContext *ctx;
4017 CLIParserInit(&ctx, "hf mf ecfill",
4018 "Dump card and transfer the data to emulator memory.\n"
4019 "Keys must be laid in the emulator memory",
4020 "hf mf ecfill --> use key type A\n"
4021 "hf mf ecfill --4k -b --> target 4K card with key type B"
4023 void *argtable[] = {
4024 arg_param_begin,
4025 arg_lit0("a", NULL, "input key type is key A(def)"),
4026 arg_lit0("b", NULL, "input key type is key B"),
4027 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
4028 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
4029 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
4030 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
4031 arg_param_end
4033 CLIExecWithReturn(ctx, Cmd, argtable, true);
4034 uint8_t keytype = MF_KEY_A;
4035 if (arg_get_lit(ctx, 1) && arg_get_lit(ctx, 2)) {
4036 CLIParserFree(ctx);
4037 PrintAndLogEx(WARNING, "Input key type must be A or B");
4038 return PM3_EINVARG;
4039 } else if (arg_get_lit(ctx, 2)) {
4040 keytype = MF_KEY_B;
4043 bool m0 = arg_get_lit(ctx, 3);
4044 bool m1 = arg_get_lit(ctx, 4);
4045 bool m2 = arg_get_lit(ctx, 5);
4046 bool m4 = arg_get_lit(ctx, 6);
4047 CLIParserFree(ctx);
4049 // validations
4050 if ((m0 + m1 + m2 + m4) > 1) {
4051 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
4052 return PM3_EINVARG;
4053 } else if ((m0 + m1 + m2 + m4) == 0) {
4054 m1 = true;
4057 uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
4059 if (m0) {
4060 sectors_cnt = MIFARE_MINI_MAXSECTOR;
4061 } else if (m1) {
4062 sectors_cnt = MIFARE_1K_MAXSECTOR;
4063 } else if (m2) {
4064 sectors_cnt = MIFARE_2K_MAXSECTOR;
4065 } else if (m4) {
4066 sectors_cnt = MIFARE_4K_MAXSECTOR;
4067 } else {
4068 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
4069 return PM3_EINVARG;
4072 mfc_eload_t payload = {
4073 .sectorcnt = sectors_cnt,
4074 .keytype = keytype
4077 clearCommandBuffer();
4078 SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload));
4080 // 2021, iceman: should get a response from device when its done.
4081 return PM3_SUCCESS;
4084 static int CmdHF14AMfEKeyPrn(const char *Cmd) {
4086 CLIParserContext *ctx;
4087 CLIParserInit(&ctx, "hf mf ekeyprn",
4088 "Download and print the keys from emulator memory",
4089 "hf mf ekeyprn --1k --> print MFC 1K keyset\n"
4090 "hf mf ekeyprn -w --> write keys to binary file"
4092 void *argtable[] = {
4093 arg_param_begin,
4094 arg_lit0("w", "write", "write keys to binary file `hf-mf-<UID>-key.bin`"),
4095 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
4096 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
4097 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
4098 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
4099 arg_param_end
4101 CLIExecWithReturn(ctx, Cmd, argtable, true);
4103 bool create_dumpfile = arg_get_lit(ctx, 1);
4104 bool m0 = arg_get_lit(ctx, 2);
4105 bool m1 = arg_get_lit(ctx, 3);
4106 bool m2 = arg_get_lit(ctx, 4);
4107 bool m4 = arg_get_lit(ctx, 5);
4108 CLIParserFree(ctx);
4110 // validations
4111 if ((m0 + m1 + m2 + m4) > 1) {
4112 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
4113 return PM3_EINVARG;
4114 } else if ((m0 + m1 + m2 + m4) == 0) {
4115 m1 = true;
4118 uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
4120 if (m0) {
4121 sectors_cnt = MIFARE_MINI_MAXSECTOR;
4122 } else if (m1) {
4123 sectors_cnt = MIFARE_1K_MAXSECTOR;
4124 } else if (m2) {
4125 sectors_cnt = MIFARE_2K_MAXSECTOR;
4126 } else if (m4) {
4127 sectors_cnt = MIFARE_4K_MAXSECTOR;
4128 } else {
4129 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
4130 return PM3_EINVARG;
4133 sector_t *e_sector = NULL;
4135 // create/initialize key storage structure
4136 int32_t res = initSectorTable(&e_sector, sectors_cnt);
4137 if (res != sectors_cnt) {
4138 free(e_sector);
4139 return PM3_EMALLOC;
4142 // read UID from EMUL
4143 uint8_t data[16];
4144 if (mfEmlGetMem(data, 0, 1) != PM3_SUCCESS) {
4145 PrintAndLogEx(WARNING, "error get block 0");
4146 free(e_sector);
4147 return PM3_ESOFT;
4150 // assuming 4byte UID.
4151 uint8_t uid[4];
4152 memcpy(uid, data, sizeof(uid));
4154 // download keys from EMUL
4155 for (int i = 0; i < sectors_cnt; i++) {
4157 if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1) != PM3_SUCCESS) {
4158 PrintAndLogEx(WARNING, "error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
4159 e_sector[i].foundKey[0] = false;
4160 e_sector[i].foundKey[1] = false;
4161 } else {
4162 e_sector[i].foundKey[0] = true;
4163 e_sector[i].Key[0] = bytes_to_num(data, 6);
4164 e_sector[i].foundKey[1] = true;
4165 e_sector[i].Key[1] = bytes_to_num(data + 10, 6);
4169 // print keys
4170 printKeyTable(sectors_cnt, e_sector);
4172 // dump the keys
4173 if (create_dumpfile) {
4175 char filename[FILE_PATH_SIZE] = {0};
4176 char *fptr = filename;
4177 fptr += snprintf(fptr, sizeof(filename), "hf-mf-");
4178 FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid));
4179 createMfcKeyDump(filename, sectors_cnt, e_sector);
4182 free(e_sector);
4183 return PM3_SUCCESS;
4186 // CHINESE MAGIC COMMANDS
4187 static int CmdHF14AMfCSetUID(const char *Cmd) {
4189 CLIParserContext *ctx;
4190 CLIParserInit(&ctx, "hf mf csetuid",
4191 "Set UID, ATQA, and SAK for magic gen1a card",
4192 "hf mf csetuid -u 01020304\n"
4193 "hf mf csetuid -w -u 01020304 --atqa 0004 --sak 08"
4195 void *argtable[] = {
4196 arg_param_begin,
4197 arg_lit0("w", "wipe", "wipes card with backdoor cmd`"),
4198 arg_str0("u", "uid", "<hex>", "UID, 4/7 hex bytes"),
4199 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
4200 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
4201 arg_param_end
4203 CLIExecWithReturn(ctx, Cmd, argtable, true);
4205 uint8_t wipe_card = arg_get_lit(ctx, 1);
4207 int uidlen = 0;
4208 uint8_t uid[7] = {0x00};
4209 CLIGetHexWithReturn(ctx, 2, uid, &uidlen);
4211 int alen = 0;
4212 uint8_t atqa[2] = {0x00};
4213 CLIGetHexWithReturn(ctx, 3, atqa, &alen);
4215 int slen = 0;
4216 uint8_t sak[1] = {0x00};
4217 CLIGetHexWithReturn(ctx, 4, sak, &slen);
4218 CLIParserFree(ctx);
4220 // sanity checks
4221 if (uidlen != 4 && uidlen != 7) {
4222 PrintAndLogEx(FAILED, "UID must be 4 or 7 hex bytes. Got %d", uidlen);
4223 return PM3_EINVARG;
4225 if (alen && alen != 2) {
4226 PrintAndLogEx(FAILED, "ATQA must be 2 hex bytes. Got %d", alen);
4227 return PM3_EINVARG;
4229 if (slen && slen != 1) {
4230 PrintAndLogEx(FAILED, "SAK must be 1 hex byte. Got %d", slen);
4231 return PM3_EINVARG;
4234 uint8_t old_uid[7] = {0};
4235 uint8_t verify_uid[7] = {0};
4237 int res = mfCSetUID(
4238 uid,
4239 uidlen,
4240 (alen) ? atqa : NULL,
4241 (slen) ? sak : NULL,
4242 old_uid,
4243 verify_uid,
4244 wipe_card
4247 if (res) {
4248 PrintAndLogEx(ERR, "Can't set UID. error %d", res);
4249 return PM3_ESOFT;
4252 res = memcmp(uid, verify_uid, uidlen);
4254 PrintAndLogEx(SUCCESS, "Old UID... %s", sprint_hex(old_uid, uidlen));
4255 PrintAndLogEx(SUCCESS, "New UID... %s ( %s )",
4256 sprint_hex(verify_uid, uidlen),
4257 (res == 0) ? _GREEN_("verified") : _RED_("fail")
4259 return PM3_SUCCESS;
4262 static int CmdHF14AMfCWipe(const char *cmd) {
4263 CLIParserContext *ctx;
4264 CLIParserInit(&ctx, "hf mf cwipe",
4265 "Wipe gen1 magic chinese card.\n"
4266 "Set UID / ATQA / SAK / Data / Keys / Access to default values",
4267 "hf mf cwipe\n"
4268 "hf mf cwipe -u 09080706 -a 0004 -s 18 --> set UID, ATQA and SAK and wipe card");
4270 void *argtable[] = {
4271 arg_param_begin,
4272 arg_str0("u", "uid", "<hex>", "UID, 4 hex bytes"),
4273 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
4274 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
4275 arg_param_end
4277 CLIExecWithReturn(ctx, cmd, argtable, true);
4279 int uidlen = 0;
4280 uint8_t uid[8] = {0x00};
4281 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
4283 int alen = 0;
4284 uint8_t atqa[2] = {0x00};
4285 CLIGetHexWithReturn(ctx, 2, atqa, &alen);
4287 int slen = 0;
4288 uint8_t sak[1] = {0x00};
4289 CLIGetHexWithReturn(ctx, 3, sak, &slen);
4290 CLIParserFree(ctx);
4292 if (uidlen && uidlen != 4) {
4293 PrintAndLogEx(ERR, "UID length must be 4 bytes, got %d", uidlen);
4294 return PM3_EINVARG;
4296 if (alen && alen != 2) {
4297 PrintAndLogEx(ERR, "ATQA length must be 2 bytes, got %d", alen);
4298 return PM3_EINVARG;
4300 if (slen && slen != 1) {
4301 PrintAndLogEx(ERR, "SAK length must be 1 byte, got %d", slen);
4302 return PM3_EINVARG;
4305 int res = mfCWipe((uidlen) ? uid : NULL, (alen) ? atqa : NULL, (slen) ? sak : NULL);
4306 if (res) {
4307 PrintAndLogEx(ERR, "Can't wipe card. error %d", res);
4308 return PM3_ESOFT;
4311 PrintAndLogEx(SUCCESS, "Card wiped successfully");
4312 return PM3_SUCCESS;
4315 static int CmdHF14AMfCSetBlk(const char *Cmd) {
4317 CLIParserContext *ctx;
4318 CLIParserInit(&ctx, "hf mf csetblk",
4319 "Set block data on a magic gen1a card",
4320 "hf mf csetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
4322 void *argtable[] = {
4323 arg_param_begin,
4324 arg_int1("b", "blk", "<dec>", "block number"),
4325 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
4326 arg_lit0("w", "wipe", "wipes card with backdoor cmd before writing"),
4327 arg_param_end
4329 CLIExecWithReturn(ctx, Cmd, argtable, false);
4331 int b = arg_get_int_def(ctx, 1, -1);
4333 uint8_t data[MFBLOCK_SIZE] = {0x00};
4334 int datalen = 0;
4335 CLIGetHexWithReturn(ctx, 2, data, &datalen);
4337 uint8_t wipe_card = arg_get_lit(ctx, 3);
4338 CLIParserFree(ctx);
4340 if (b < 0 || b >= MIFARE_1K_MAXBLOCK) {
4341 PrintAndLogEx(FAILED, "target block number out-of-range, got %i", b);
4342 return PM3_EINVARG;
4345 if (datalen != MFBLOCK_SIZE) {
4346 PrintAndLogEx(FAILED, "expected 16 bytes data, got %i", datalen);
4347 return PM3_EINVARG;
4350 uint8_t params = MAGIC_SINGLE;
4351 if (wipe_card) {
4352 params |= MAGIC_WIPE;
4355 PrintAndLogEx(INFO, "Writing block number:%2d data:%s", b, sprint_hex_inrow(data, sizeof(data)));
4357 int res = mfCSetBlock(b, data, NULL, params);
4358 if (res) {
4359 PrintAndLogEx(ERR, "Can't write block. error=%d", res);
4360 return PM3_ESOFT;
4362 return PM3_SUCCESS;
4365 static int CmdHF14AMfCLoad(const char *Cmd) {
4367 CLIParserContext *ctx;
4368 CLIParserInit(&ctx, "hf mf cload",
4369 "Load magic gen1a card with data from (bin/eml/json) dump file\n"
4370 "or from emulator memory.",
4371 "hf mf cload --emu\n"
4372 "hf mf cload -f hf-mf-01020304.eml\n"
4374 void *argtable[] = {
4375 arg_param_begin,
4376 arg_str1("f", "file", "<fn>", "filename of dump"),
4377 arg_lit0(NULL, "emu", "from emulator memory"),
4378 arg_param_end
4380 CLIExecWithReturn(ctx, Cmd, argtable, false);
4382 int fnlen = 0;
4383 char filename[FILE_PATH_SIZE];
4384 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
4386 bool fill_from_emulator = arg_get_lit(ctx, 2);
4387 CLIParserFree(ctx);
4389 if (fill_from_emulator) {
4391 PrintAndLogEx(INFO, "Start upload to emulator memory");
4392 PrintAndLogEx(INFO, "." NOLF);
4394 for (int b = 0; b < MIFARE_1K_MAXBLOCK; b++) {
4395 int flags = 0;
4396 uint8_t buf8[MFBLOCK_SIZE] = {0x00};
4398 // read from emul memory
4399 if (mfEmlGetMem(buf8, b, 1)) {
4400 PrintAndLogEx(WARNING, "Can't read from emul block: %d", b);
4401 return PM3_ESOFT;
4404 // switch on field and send magic sequence
4405 if (b == 0) {
4406 flags = MAGIC_INIT + MAGIC_WUPC;
4409 // just write
4410 if (b == 1) {
4411 flags = 0;
4414 // Done. Magic Halt and switch off field.
4415 if (b == ((MFBLOCK_SIZE * 4) - 1)) {
4416 flags = MAGIC_HALT + MAGIC_OFF;
4419 // write to card
4420 if (mfCSetBlock(b, buf8, NULL, flags)) {
4421 PrintAndLogEx(WARNING, "Can't set magic card block: %d", b);
4422 return PM3_ESOFT;
4424 PrintAndLogEx(NORMAL, "." NOLF);
4425 fflush(stdout);
4427 PrintAndLogEx(NORMAL, "");
4428 return PM3_SUCCESS;
4431 uint8_t *data = NULL;
4432 size_t bytes_read = 0;
4433 int res = 0;
4434 DumpFileType_t dftype = getfiletype(filename);
4435 switch (dftype) {
4436 case BIN: {
4437 res = loadFile_safe(filename, ".bin", (void **)&data, &bytes_read);
4438 break;
4440 case EML: {
4441 res = loadFileEML_safe(filename, (void **)&data, &bytes_read);
4442 break;
4444 case JSON: {
4445 data = calloc(MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK, sizeof(uint8_t));
4446 if (data == NULL) {
4447 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
4448 return PM3_EMALLOC;
4450 res = loadFileJSON(filename, (void *)data, MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, &bytes_read, NULL);
4451 break;
4453 case DICTIONARY: {
4454 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
4455 free(data);
4456 return PM3_EINVARG;
4460 if (res != PM3_SUCCESS) {
4461 free(data);
4462 return PM3_EFILE;
4465 // 64 or 256blocks.
4466 if (bytes_read != (MIFARE_1K_MAXBLOCK * MFBLOCK_SIZE) &&
4467 bytes_read != (MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE)) {
4468 PrintAndLogEx(ERR, "File content error. Read %zu bytes", bytes_read);
4469 free(data);
4470 return PM3_EFILE;
4473 PrintAndLogEx(INFO, "Copying to magic gen1a card");
4474 PrintAndLogEx(INFO, "." NOLF);
4476 int blockno = 0;
4477 int flags = 0;
4478 while (bytes_read) {
4480 // switch on field and send magic sequence
4481 if (blockno == 0) {
4482 flags = MAGIC_INIT + MAGIC_WUPC;
4485 // write
4486 if (blockno == 1) {
4487 flags = 0;
4490 // switch off field
4491 if (blockno == MFBLOCK_SIZE * 4 - 1) {
4492 flags = MAGIC_HALT + MAGIC_OFF;
4495 if (mfCSetBlock(blockno, data + (MFBLOCK_SIZE * blockno), NULL, flags)) {
4496 PrintAndLogEx(WARNING, "Can't set magic card block: %d", blockno);
4497 free(data);
4498 return PM3_ESOFT;
4501 bytes_read -= MFBLOCK_SIZE;
4503 PrintAndLogEx(NORMAL, "." NOLF);
4504 fflush(stdout);
4506 blockno++;
4508 // magic card type - mifare 1K
4509 if (blockno >= MIFARE_1K_MAXBLOCK) break;
4511 PrintAndLogEx(NORMAL, "\n");
4513 free(data);
4515 // confirm number written blocks. Must be 64 or 256 blocks
4516 if (blockno != MIFARE_1K_MAXBLOCK) {
4517 if (blockno != MIFARE_4K_MAXBLOCK) {
4518 PrintAndLogEx(ERR, "File content error. There must be %u blocks", MIFARE_4K_MAXBLOCK);
4519 return PM3_EFILE;
4521 PrintAndLogEx(ERR, "File content error. There must be %d blocks", MIFARE_1K_MAXBLOCK);
4522 return PM3_EFILE;
4525 PrintAndLogEx(SUCCESS, "Card loaded %d blocks from file", blockno);
4526 PrintAndLogEx(INFO, "Done!");
4527 return PM3_SUCCESS;
4530 static int CmdHF14AMfCGetBlk(const char *Cmd) {
4531 CLIParserContext *ctx;
4532 CLIParserInit(&ctx, "hf mf cgetblk",
4533 "Get block data from magic Chinese card.\n"
4534 "Only works with magic gen1a cards",
4535 "hf mf cgetblk --blk 0 --> get block 0 (manufacturer)\n"
4536 "hf mf cgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
4538 void *argtable[] = {
4539 arg_param_begin,
4540 arg_int1("b", "blk", "<dec>", "block number"),
4541 arg_lit0("v", "verbose", "verbose output"),
4542 arg_param_end
4544 CLIExecWithReturn(ctx, Cmd, argtable, false);
4545 int b = arg_get_int_def(ctx, 1, 0);
4546 bool verbose = arg_get_lit(ctx, 2);
4547 CLIParserFree(ctx);
4549 if (b > 255) {
4550 return PM3_EINVARG;
4553 uint8_t blockno = (uint8_t)b;
4554 uint8_t data[16] = {0};
4555 int res = mfCGetBlock(blockno, data, MAGIC_SINGLE);
4556 if (res) {
4557 PrintAndLogEx(ERR, "Can't read block. error=%d", res);
4558 return PM3_ESOFT;
4561 uint8_t sector = GetSectorFromBlockNo(blockno);
4562 mf_print_sector_hdr(sector);
4563 mf_print_block(blockno, data);
4565 if (verbose) {
4566 decode_print_st(blockno, data);
4567 } else {
4568 PrintAndLogEx(NORMAL, "");
4570 return PM3_SUCCESS;
4573 static int CmdHF14AMfCGetSc(const char *Cmd) {
4574 CLIParserContext *ctx;
4575 CLIParserInit(&ctx, "hf mf cgetsc",
4576 "Get sector data from magic Chinese card.\n"
4577 "Only works with magic gen1a cards",
4578 "hf mf cgetsc -s 0"
4580 void *argtable[] = {
4581 arg_param_begin,
4582 arg_int1("s", "sec", "<dec>", "sector number"),
4583 arg_lit0("v", "verbose", "verbose output"),
4584 arg_param_end
4586 CLIExecWithReturn(ctx, Cmd, argtable, false);
4587 int s = arg_get_int_def(ctx, 1, 0);
4588 bool verbose = arg_get_lit(ctx, 2);
4589 CLIParserFree(ctx);
4590 if (s > 39) {
4591 PrintAndLogEx(WARNING, "Sector number must be less then 40");
4592 return PM3_EINVARG;
4595 uint8_t sector = (uint8_t)s;
4596 mf_print_sector_hdr(sector);
4598 uint8_t blocks = 4;
4599 uint8_t start = sector * 4;
4600 if (sector >= 32) {
4601 blocks = 16;
4602 start = 128 + (sector - 32) * 16;
4605 int flags = MAGIC_INIT + MAGIC_WUPC;
4606 uint8_t data[16] = {0};
4607 for (int i = 0; i < blocks; i++) {
4608 if (i == 1) flags = 0;
4609 if (i == blocks - 1) flags = MAGIC_HALT + MAGIC_OFF;
4611 int res = mfCGetBlock(start + i, data, flags);
4612 if (res) {
4613 PrintAndLogEx(ERR, "Can't read block. %d error=%d", start + i, res);
4614 return PM3_ESOFT;
4616 mf_print_block(start + i, data);
4618 if (verbose) {
4619 decode_print_st(start + blocks - 1, data);
4620 } else {
4621 PrintAndLogEx(NORMAL, "");
4623 return PM3_SUCCESS;
4626 static int CmdHF14AMfCSave(const char *Cmd) {
4627 CLIParserContext *ctx;
4628 CLIParserInit(&ctx, "hf mf csave",
4629 "Save magic gen1a card memory into three files (BIN/EML/JSON)"
4630 "or into emulator memory",
4631 "hf mf csave\n"
4632 "hf mf csave --4k"
4634 void *argtable[] = {
4635 arg_param_begin,
4636 arg_str0("f", "file", "<fn>", "filename of dump"),
4637 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
4638 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
4639 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
4640 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
4641 arg_lit0(NULL, "emu", "from emulator memory"),
4642 arg_param_end
4644 CLIExecWithReturn(ctx, Cmd, argtable, true);
4646 int fnlen = 0;
4647 char filename[FILE_PATH_SIZE];
4648 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
4650 bool m0 = arg_get_lit(ctx, 2);
4651 bool m1 = arg_get_lit(ctx, 3);
4652 bool m2 = arg_get_lit(ctx, 4);
4653 bool m4 = arg_get_lit(ctx, 5);
4654 bool fill_emulator = arg_get_lit(ctx, 6);
4655 CLIParserFree(ctx);
4657 // validations
4658 if ((m0 + m1 + m2 + m4) > 1) {
4659 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
4660 return PM3_EINVARG;
4661 } else if ((m0 + m1 + m2 + m4) == 0) {
4662 m1 = true;
4665 char s[6];
4666 memset(s, 0, sizeof(s));
4667 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
4668 if (m0) {
4669 block_cnt = MIFARE_MINI_MAXBLOCK;
4670 strncpy(s, "Mini", 5);
4671 } else if (m1) {
4672 block_cnt = MIFARE_1K_MAXBLOCK;
4673 strncpy(s, "1K", 3);
4674 } else if (m2) {
4675 block_cnt = MIFARE_2K_MAXBLOCK;
4676 strncpy(s, "2K", 3);
4677 } else if (m4) {
4678 block_cnt = MIFARE_4K_MAXBLOCK;
4679 strncpy(s, "4K", 3);
4680 } else {
4681 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
4682 return PM3_EINVARG;
4685 PrintAndLogEx(SUCCESS, "Dumping magic Gen1a MIFARE Classic " _GREEN_("%s") " card memory", s);
4686 PrintAndLogEx(INFO, "." NOLF);
4688 // Select card to get UID/UIDLEN information
4689 clearCommandBuffer();
4690 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
4691 PacketResponseNG resp;
4692 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
4693 PrintAndLogEx(WARNING, "iso14443a card select timeout");
4694 return PM3_ETIMEOUT;
4698 0: couldn't read
4699 1: OK, with ATS
4700 2: OK, no ATS
4701 3: proprietary Anticollision
4703 uint64_t select_status = resp.oldarg[0];
4704 if (select_status == 0) {
4705 PrintAndLogEx(WARNING, "iso14443a card select failed");
4706 return select_status;
4709 // store card info
4710 iso14a_card_select_t card;
4711 memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
4713 // reserve memory
4714 uint16_t bytes = block_cnt * MFBLOCK_SIZE;
4715 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
4716 if (dump == NULL) {
4717 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
4718 return PM3_EMALLOC;
4721 // switch on field and send magic sequence
4722 uint8_t flags = MAGIC_INIT + MAGIC_WUPC;
4723 for (uint16_t i = 0; i < block_cnt; i++) {
4725 // read
4726 if (i == 1) {
4727 flags = 0;
4729 // switch off field
4730 if (i == block_cnt - 1) {
4731 flags = MAGIC_HALT + MAGIC_OFF;
4734 if (mfCGetBlock(i, dump + (i * MFBLOCK_SIZE), flags)) {
4735 PrintAndLogEx(WARNING, "Can't get magic card block: %d", i);
4736 PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
4737 free(dump);
4738 return PM3_ESOFT;
4740 PrintAndLogEx(NORMAL, "." NOLF);
4741 fflush(stdout);
4743 PrintAndLogEx(NORMAL, "");
4745 if (fill_emulator) {
4746 PrintAndLogEx(INFO, "uploading to emulator memory");
4747 PrintAndLogEx(INFO, "." NOLF);
4748 // fast push mode
4749 conn.block_after_ACK = true;
4750 for (int i = 0; i < block_cnt; i += 5) {
4751 if (i == block_cnt - 1) {
4752 // Disable fast mode on last packet
4753 conn.block_after_ACK = false;
4755 if (mfEmlSetMem(dump + (i * MFBLOCK_SIZE), i, 5) != PM3_SUCCESS) {
4756 PrintAndLogEx(WARNING, "Can't set emul block: %d", i);
4758 PrintAndLogEx(NORMAL, "." NOLF);
4759 fflush(stdout);
4761 PrintAndLogEx(NORMAL, "");
4762 PrintAndLogEx(SUCCESS, "uploaded %d bytes to emulator memory", bytes);
4765 // user supplied filename?
4766 if (fnlen < 1) {
4767 char *fptr = filename;
4768 fptr += snprintf(fptr, sizeof(filename), "hf-mf-");
4769 FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
4772 saveFile(filename, ".bin", dump, bytes);
4773 saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
4774 saveFileJSON(filename, jsfCardMemory, dump, bytes, NULL);
4775 free(dump);
4776 return PM3_SUCCESS;
4779 static int CmdHF14AMfCView(const char *Cmd) {
4781 CLIParserContext *ctx;
4782 CLIParserInit(&ctx, "hf mf cview",
4783 "View `magic gen1a` card memory",
4784 "hf mf cview\n"
4785 "hf mf cview --4k"
4787 void *argtable[] = {
4788 arg_param_begin,
4789 arg_lit0(NULL, "mini", "MIFARE Classic Mini / S20"),
4790 arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"),
4791 arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
4792 arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
4793 arg_param_end
4795 CLIExecWithReturn(ctx, Cmd, argtable, true);
4796 bool m0 = arg_get_lit(ctx, 1);
4797 bool m1 = arg_get_lit(ctx, 2);
4798 bool m2 = arg_get_lit(ctx, 3);
4799 bool m4 = arg_get_lit(ctx, 4);
4800 CLIParserFree(ctx);
4802 // validations
4803 if ((m0 + m1 + m2 + m4) > 1) {
4804 PrintAndLogEx(WARNING, "Only specify one MIFARE Type");
4805 return PM3_EINVARG;
4806 } else if ((m0 + m1 + m2 + m4) == 0) {
4807 m1 = true;
4810 char s[6];
4811 memset(s, 0, sizeof(s));
4812 uint16_t block_cnt = MIFARE_1K_MAXBLOCK;
4813 if (m0) {
4814 block_cnt = MIFARE_MINI_MAXBLOCK;
4815 strncpy(s, "Mini", 5);
4816 } else if (m1) {
4817 block_cnt = MIFARE_1K_MAXBLOCK;
4818 strncpy(s, "1K", 3);
4819 } else if (m2) {
4820 block_cnt = MIFARE_2K_MAXBLOCK;
4821 strncpy(s, "2K", 3);
4822 } else if (m4) {
4823 block_cnt = MIFARE_4K_MAXBLOCK;
4824 strncpy(s, "4K", 3);
4825 } else {
4826 PrintAndLogEx(WARNING, "Please specify a MIFARE Type");
4827 return PM3_EINVARG;
4829 PrintAndLogEx(SUCCESS, "View magic Gen1a MIFARE Classic " _GREEN_("%s"), s);
4830 PrintAndLogEx(INFO, "." NOLF);
4832 // Select card to get UID/UIDLEN information
4833 clearCommandBuffer();
4834 SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
4835 PacketResponseNG resp;
4836 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
4837 PrintAndLogEx(WARNING, "iso14443a card select timeout");
4838 return PM3_ETIMEOUT;
4842 0: couldn't read
4843 1: OK, with ATS
4844 2: OK, no ATS
4845 3: proprietary Anticollision
4847 uint64_t select_status = resp.oldarg[0];
4849 if (select_status == 0) {
4850 PrintAndLogEx(WARNING, "iso14443a card select failed");
4851 return select_status;
4854 iso14a_card_select_t card;
4855 memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
4857 // reserve memory
4858 uint16_t bytes = block_cnt * MFBLOCK_SIZE;
4859 uint8_t *dump = calloc(bytes, sizeof(uint8_t));
4860 if (dump == NULL) {
4861 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
4862 return PM3_EMALLOC;
4865 // switch on field and send magic sequence
4866 uint8_t flags = MAGIC_INIT + MAGIC_WUPC;
4867 for (uint16_t i = 0; i < block_cnt; i++) {
4868 // read
4869 if (i == 1) {
4870 flags = 0;
4872 // switch off field
4873 if (i == block_cnt - 1) {
4874 flags = MAGIC_HALT + MAGIC_OFF;
4877 if (mfCGetBlock(i, dump + (i * MFBLOCK_SIZE), flags)) {
4878 PrintAndLogEx(WARNING, "Can't get magic card block: %u", i);
4879 PrintAndLogEx(HINT, "Verify your card size, and try again or try another tag position");
4880 free(dump);
4881 return PM3_ESOFT;
4883 PrintAndLogEx(NORMAL, "." NOLF);
4884 fflush(stdout);
4887 PrintAndLogEx(NORMAL, "");
4888 mf_print_blocks(block_cnt, dump);
4889 free(dump);
4890 return PM3_SUCCESS;
4893 //needs nt, ar, at, Data to decrypt
4894 static int CmdHf14AMfDecryptBytes(const char *Cmd) {
4895 CLIParserContext *ctx;
4896 CLIParserInit(&ctx, "hf mf decrypt",
4897 "Decrypt Crypto-1 encrypted bytes given some known state of crypto. See tracelog to gather needed values",
4898 "hf mf decrypt --nt b830049b --ar 9248314a --at 9280e203 -d 41e586f9\n"
4899 " -> 41e586f9 becomes 3003999a\n"
4900 " -> which annotates 30 03 [99 9a] read block 3 [crc]"
4902 void *argtable[] = {
4903 arg_param_begin,
4904 arg_str1(NULL, "nt", "<hex>", "tag nonce"),
4905 arg_str1(NULL, "ar", "<hex>", "ar_enc, encrypted reader response"),
4906 arg_str1(NULL, "at", "<hex>", "at_enc, encrypted tag response"),
4907 arg_str1("d", "data", "<hex>", "encrypted data, taken directly after at_enc and forward"),
4908 arg_param_end
4910 CLIExecWithReturn(ctx, Cmd, argtable, false);
4912 uint32_t nt = 0;
4913 int res = arg_get_u32_hexstr_def(ctx, 1, 0, &nt);
4914 if (res != 1) {
4915 CLIParserFree(ctx);
4916 PrintAndLogEx(WARNING, "check `nt` parameter");
4917 return PM3_EINVARG;
4920 uint32_t ar_enc = 0;
4921 res = arg_get_u32_hexstr_def(ctx, 2, 0, &ar_enc);
4922 if (res != 1) {
4923 CLIParserFree(ctx);
4924 PrintAndLogEx(WARNING, "check `ar` parameter");
4925 return PM3_EINVARG;
4928 uint32_t at_enc = 0;
4929 res = arg_get_u32_hexstr_def(ctx, 3, 0, &at_enc);
4930 if (res != 1) {
4931 CLIParserFree(ctx);
4932 PrintAndLogEx(WARNING, "check `at` parameter");
4933 return PM3_EINVARG;
4936 int datalen = 0;
4937 uint8_t data[512] = {0x00};
4938 CLIGetHexWithReturn(ctx, 4, data, &datalen);
4939 CLIParserFree(ctx);
4941 PrintAndLogEx(INFO, "nt....... %08X", nt);
4942 PrintAndLogEx(INFO, "ar enc... %08X", ar_enc);
4943 PrintAndLogEx(INFO, "at enc... %08X", at_enc);
4945 return tryDecryptWord(nt, ar_enc, at_enc, data, datalen);
4948 static int CmdHf14AMfSetMod(const char *Cmd) {
4950 CLIParserContext *ctx;
4951 CLIParserInit(&ctx, "hf mf setmod",
4952 "Sets the load modulation strength of a MIFARE Classic EV1 card",
4953 "hf mf setmod -k ffffffffffff -0"
4955 void *argtable[] = {
4956 arg_param_begin,
4957 arg_lit0("0", NULL, "normal modulation"),
4958 arg_lit0("1", NULL, "strong modulation (def)"),
4959 arg_str0("k", "key", "<hex>", "key A, Sector 0, 6 hex bytes"),
4960 arg_param_end
4962 CLIExecWithReturn(ctx, Cmd, argtable, true);
4963 bool m0 = arg_get_lit(ctx, 1);
4964 bool m1 = arg_get_lit(ctx, 2);
4966 int keylen = 0;
4967 uint8_t key[6] = {0};
4968 CLIGetHexWithReturn(ctx, 3, key, &keylen);
4969 CLIParserFree(ctx);
4971 if (m0 + m1 > 1) {
4972 PrintAndLogEx(WARNING, "please select one modulation");
4973 return PM3_EINVARG;
4976 uint8_t data[7] = {0};
4977 memcpy(data + 1, key, 6);
4979 if (m1) {
4980 data[0] = 1;
4981 } else {
4982 data[0] = 0;
4985 clearCommandBuffer();
4986 SendCommandNG(CMD_HF_MIFARE_SETMOD, data, sizeof(data));
4987 PacketResponseNG resp;
4988 if (WaitForResponseTimeout(CMD_HF_MIFARE_SETMOD, &resp, 1500) == false) {
4989 PrintAndLogEx(WARNING, "Command execute timeout");
4990 return PM3_ETIMEOUT;
4993 if (resp.status == PM3_SUCCESS)
4994 PrintAndLogEx(SUCCESS, "Change ( " _GREEN_("ok") " )");
4995 else
4996 PrintAndLogEx(FAILED, "Change (" _GREEN_("fail") " )");
4998 return resp.status;
5001 // MIFARE NACK bug detection
5002 static int CmdHf14AMfNack(const char *Cmd) {
5003 CLIParserContext *ctx;
5004 CLIParserInit(&ctx, "hf mf nack",
5005 "Test a MIFARE Classic based card for the NACK bug",
5006 "hf mf nack"
5008 void *argtable[] = {
5009 arg_param_begin,
5010 arg_lit0("v", "verbose", "verbose output`"),
5011 arg_param_end
5013 CLIExecWithReturn(ctx, Cmd, argtable, true);
5014 bool verbose = arg_get_lit(ctx, 1);
5015 CLIParserFree(ctx);
5017 if (verbose)
5018 PrintAndLogEx(INFO, "Started testing card for NACK bug. Press Enter to abort");
5020 detect_classic_nackbug(verbose);
5021 return PM3_SUCCESS;
5025 static int CmdHF14AMfice(const char *Cmd) {
5026 CLIParserContext *ctx;
5027 CLIParserInit(&ctx, "hf mf ice",
5028 "Collect MIFARE Classic nonces to file",
5029 "hf mf ice\n"
5030 "hf mf ice -f nonces.bin");
5032 void *argtable[] = {
5033 arg_param_begin,
5034 arg_str0("f", "file", "<filename>", "filename of nonce dump"),
5035 arg_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
5036 arg_param_end
5038 CLIExecWithReturn(ctx, Cmd, argtable, true);
5040 int fnlen = 0;
5041 char filename[FILE_PATH_SIZE] = {0};
5042 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
5044 uint32_t limit = arg_get_u32_def(ctx, 2, 50000);
5046 CLIParserFree(ctx);
5048 // Validations
5049 char *fptr;
5051 if (filename[0] == '\0') {
5052 fptr = GenerateFilename("hf-mf-", "-nonces.bin");
5053 if (fptr == NULL)
5054 return PM3_EFILE;
5055 strcpy(filename, fptr);
5056 free(fptr);
5059 uint8_t blockNo = 0;
5060 uint8_t keyType = MF_KEY_A;
5061 uint8_t trgBlockNo = 0;
5062 uint8_t trgKeyType = MF_KEY_B;
5063 bool slow = false;
5064 bool initialize = true;
5065 bool acquisition_completed = false;
5066 uint32_t total_num_nonces = 0;
5067 PacketResponseNG resp;
5069 uint32_t part_limit = 3000;
5071 PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit);
5073 FILE *fnonces = NULL;
5074 if ((fnonces = fopen(filename, "wb")) == NULL) {
5075 PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), filename);
5076 return PM3_EFILE;
5079 clearCommandBuffer();
5081 uint64_t t1 = msclock();
5083 do {
5084 if (kbd_enter_pressed()) {
5085 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
5086 break;
5089 uint32_t flags = 0;
5090 flags |= initialize ? 0x0001 : 0;
5091 flags |= slow ? 0x0002 : 0;
5092 clearCommandBuffer();
5093 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0);
5095 if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out;
5096 if (resp.oldarg[0]) goto out;
5098 uint32_t items = resp.oldarg[2];
5099 fwrite(resp.data.asBytes, 1, items * 4, fnonces);
5100 fflush(fnonces);
5102 total_num_nonces += items;
5103 if (total_num_nonces > part_limit) {
5104 PrintAndLogEx(INFO, "Total nonces %u\n", total_num_nonces);
5105 part_limit += 3000;
5108 acquisition_completed = (total_num_nonces > limit);
5110 initialize = false;
5112 } while (!acquisition_completed);
5114 out:
5115 PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000);
5117 if (fnonces) {
5118 fflush(fnonces);
5119 fclose(fnonces);
5122 clearCommandBuffer();
5123 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, NULL, 0);
5124 return PM3_SUCCESS;
5128 static int CmdHF14AMfAuth4(const char *Cmd) {
5129 uint8_t keyn[20] = {0};
5130 int keynlen = 0;
5131 uint8_t key[16] = {0};
5132 int keylen = 0;
5134 CLIParserContext *ctx;
5135 CLIParserInit(&ctx, "hf mf auth4",
5136 "Executes AES authentication command in ISO14443-4",
5137 "hf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
5138 "hf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n");
5140 void *argtable[] = {
5141 arg_param_begin,
5142 arg_str1(NULL, NULL, "<Key Num (HEX 2 bytes)>", NULL),
5143 arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
5144 arg_param_end
5146 CLIExecWithReturn(ctx, Cmd, argtable, true);
5148 CLIGetHexWithReturn(ctx, 1, keyn, &keynlen);
5149 CLIGetHexWithReturn(ctx, 2, key, &keylen);
5150 CLIParserFree(ctx);
5152 if (keynlen != 2) {
5153 PrintAndLogEx(ERR, "<Key Num> must be 2 bytes long instead of: %d", keynlen);
5154 return PM3_ESOFT;
5157 if (keylen != 16) {
5158 PrintAndLogEx(ERR, "<Key Value> must be 16 bytes long instead of: %d", keylen);
5159 return PM3_ESOFT;
5162 return MifareAuth4(NULL, keyn, key, true, false, true, true, false);
5165 // https://www.nxp.com/docs/en/application-note/AN10787.pdf
5166 static int CmdHF14AMfMAD(const char *Cmd) {
5168 CLIParserContext *ctx;
5169 CLIParserInit(&ctx, "hf mf mad",
5170 "Checks and prints MIFARE Application Directory (MAD)",
5171 "hf mf mad -> shows MAD if exists\n"
5172 "hf mf mad --aid e103 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"
5173 "hf mf mad --dch -k ffffffffffff -> decode CardHolder information\n");
5175 void *argtable[] = {
5176 arg_param_begin,
5177 arg_lit0("v", "verbose", "show technical data"),
5178 arg_str0(NULL, "aid", "<aid>", "print all sectors with specified aid"),
5179 arg_str0("k", "key", "<key>", "key for printing sectors"),
5180 arg_lit0("b", "keyb", "use key B for access printing sectors (by default: key A)"),
5181 arg_lit0(NULL, "be", "(optional, BigEndian)"),
5182 arg_lit0(NULL, "dch", "decode Card Holder information"),
5183 arg_param_end
5185 CLIExecWithReturn(ctx, Cmd, argtable, true);
5186 bool verbose = arg_get_lit(ctx, 1);
5187 uint8_t aid[2] = {0};
5188 int aidlen = 0;
5189 CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
5190 uint8_t userkey[6] = {0};
5191 int keylen = 0;
5192 CLIGetHexWithReturn(ctx, 3, userkey, &keylen);
5193 bool keyB = arg_get_lit(ctx, 4);
5194 bool swapmad = arg_get_lit(ctx, 5);
5195 bool decodeholder = arg_get_lit(ctx, 6);
5197 CLIParserFree(ctx);
5199 uint8_t sector0[16 * 4] = {0};
5200 uint8_t sector10[16 * 4] = {0};
5202 bool got_first = true;
5203 if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0) != PM3_SUCCESS) {
5204 PrintAndLogEx(WARNING, "error, read sector 0. card don't have MAD or don't have MAD on default keys");
5205 got_first = false;
5206 } else {
5207 PrintAndLogEx(INFO, "Authentication ( " _GREEN_("OK") " )");
5210 // User supplied key
5211 if (got_first == false && keylen == 6) {
5212 PrintAndLogEx(INFO, "Trying user specified key...");
5213 if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, userkey, sector0) != PM3_SUCCESS) {
5214 PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't the custom key is wrong");
5215 } else {
5216 PrintAndLogEx(INFO, "Authentication ( " _GREEN_("OK") " )");
5217 got_first = true;
5221 // Both default and user supplied key failed
5222 if (got_first == false) {
5223 return PM3_ESOFT;
5226 PrintAndLogEx(NORMAL, "");
5227 PrintAndLogEx(INFO, "--- " _CYAN_("MIFARE App Directory Information") " ----------------");
5228 PrintAndLogEx(INFO, "-----------------------------------------------------");
5230 bool haveMAD2 = false;
5231 MAD1DecodeAndPrint(sector0, swapmad, verbose, &haveMAD2);
5233 if (haveMAD2) {
5234 if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
5235 PrintAndLogEx(ERR, "error, read sector 0x10. card don't have MAD or don't have MAD on default keys");
5236 return PM3_ESOFT;
5239 MAD2DecodeAndPrint(sector10, swapmad, verbose);
5242 if (aidlen == 2 || decodeholder) {
5243 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
5244 size_t madlen = 0;
5245 if (MADDecode(sector0, sector10, mad, &madlen, swapmad)) {
5246 PrintAndLogEx(ERR, "can't decode MAD");
5247 return PM3_ESOFT;
5250 // copy default NDEF key
5251 uint8_t akey[6] = {0};
5252 memcpy(akey, g_mifare_ndef_key, 6);
5254 // user specified key
5255 if (keylen == 6) {
5256 memcpy(akey, userkey, 6);
5259 uint16_t aaid = 0x0004;
5260 if (aidlen == 2) {
5262 aaid = (aid[0] << 8) + aid[1];
5264 PrintAndLogEx(NORMAL, "");
5265 PrintAndLogEx(INFO, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid);
5267 for (int i = 0; i < madlen; i++) {
5268 if (aaid == mad[i]) {
5269 uint8_t vsector[16 * 4] = {0};
5270 if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) {
5271 PrintAndLogEx(NORMAL, "");
5272 PrintAndLogEx(ERR, "error, read sector %d", i + 1);
5273 return PM3_ESOFT;
5276 for (int j = 0; j < (verbose ? 4 : 3); j ++)
5277 PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16));
5282 if (decodeholder) {
5284 PrintAndLogEx(NORMAL, "");
5285 PrintAndLogEx(INFO, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid);
5287 uint8_t data[4096] = {0};
5288 int datalen = 0;
5290 for (int i = 0; i < madlen; i++) {
5291 if (aaid == mad[i]) {
5293 uint8_t vsector[16 * 4] = {0};
5294 if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) {
5295 PrintAndLogEx(NORMAL, "");
5296 PrintAndLogEx(ERR, "error, read sector %d", i + 1);
5297 return PM3_ESOFT;
5300 memcpy(&data[datalen], vsector, 16 * 3);
5301 datalen += 16 * 3;
5305 if (!datalen) {
5306 PrintAndLogEx(WARNING, "no Card Holder Info data");
5307 return PM3_SUCCESS;
5309 MADCardHolderInfoDecode(data, datalen, verbose);
5313 if (verbose) {
5314 PrintAndLogEx(NORMAL, "");
5315 PrintAndLogEx(INFO, "------------ " _CYAN_("MAD sector raw") " -------------");
5316 for (int i = 0; i < 4; i ++)
5317 PrintAndLogEx(INFO, "[%d] %s", i, sprint_hex(&sector0[i * 16], 16));
5320 return PM3_SUCCESS;
5323 int CmdHFMFNDEFRead(const char *Cmd) {
5325 CLIParserContext *ctx;
5326 CLIParserInit(&ctx, "hf mf ndefread",
5327 "Prints NFC Data Exchange Format (NDEF)",
5328 "hf mf ndefread -> shows NDEF parsed data\n"
5329 "hf mf ndefread -vv -> shows NDEF parsed and raw data\n"
5330 "hf mf ndefread --aid e103 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n");
5332 void *argtable[] = {
5333 arg_param_begin,
5334 arg_litn("v", "verbose", 0, 2, "show technical data"),
5335 arg_str0(NULL, "aid", "<aid>", "replace default aid for NDEF"),
5336 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
5337 arg_lit0("b", "keyb", "use key B for access sectors (by default: key A)"),
5338 arg_param_end
5340 CLIExecWithReturn(ctx, Cmd, argtable, true);
5342 bool verbose = arg_get_lit(ctx, 1);
5343 bool verbose2 = arg_get_lit(ctx, 1) > 1;
5344 uint8_t aid[2] = {0};
5345 int aidlen;
5346 CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
5347 uint8_t key[6] = {0};
5348 int keylen;
5349 CLIGetHexWithReturn(ctx, 3, key, &keylen);
5350 bool keyB = arg_get_lit(ctx, 4);
5352 CLIParserFree(ctx);
5354 uint16_t ndefAID = 0xe103;
5355 if (aidlen == 2)
5356 ndefAID = (aid[0] << 8) + aid[1];
5358 uint8_t ndefkey[6] = {0};
5359 memcpy(ndefkey, g_mifare_ndef_key, 6);
5360 if (keylen == 6) {
5361 memcpy(ndefkey, key, 6);
5364 uint8_t sector0[16 * 4] = {0};
5365 uint8_t sector10[16 * 4] = {0};
5366 uint8_t data[4096] = {0};
5367 int datalen = 0;
5369 if (verbose)
5370 PrintAndLogEx(INFO, "reading MAD v1 sector");
5372 if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) {
5373 PrintAndLogEx(ERR, "error, read sector 0. card don't have MAD or don't have MAD on default keys");
5374 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
5375 return PM3_ESOFT;
5378 bool haveMAD2 = false;
5379 int res = MADCheck(sector0, NULL, verbose, &haveMAD2);
5380 if (res != PM3_SUCCESS) {
5381 PrintAndLogEx(ERR, "MAD error %d", res);
5382 return res;
5385 if (haveMAD2) {
5386 if (verbose)
5387 PrintAndLogEx(INFO, "reading MAD v2 sector");
5389 if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) {
5390 PrintAndLogEx(ERR, "error, read sector 0x10. card don't have MAD or don't have MAD on default keys");
5391 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
5392 return PM3_ESOFT;
5396 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0};
5397 size_t madlen = 0;
5398 res = MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen, false);
5399 if (res != PM3_SUCCESS) {
5400 PrintAndLogEx(ERR, "can't decode MAD");
5401 return res;
5404 PrintAndLogEx(INFO, "reading data from tag");
5405 for (int i = 0; i < madlen; i++) {
5406 if (ndefAID == mad[i]) {
5407 uint8_t vsector[16 * 4] = {0};
5408 if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) {
5409 PrintAndLogEx(ERR, "error, reading sector %d ", i + 1);
5410 return PM3_ESOFT;
5413 memcpy(&data[datalen], vsector, 16 * 3);
5414 datalen += 16 * 3;
5416 PrintAndLogEx(INPLACE, "%d", i);
5419 PrintAndLogEx(NORMAL, "");
5421 if (!datalen) {
5422 PrintAndLogEx(WARNING, "no NDEF data");
5423 return PM3_SUCCESS;
5426 if (verbose2) {
5427 PrintAndLogEx(NORMAL, "");
5428 PrintAndLogEx(INFO, "--- " _CYAN_("MFC NDEF raw") " ----------------");
5429 print_buffer(data, datalen, 1);
5432 NDEFDecodeAndPrint(data, datalen, verbose);
5434 PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -vv`") " for more details");
5435 return PM3_SUCCESS;
5438 static int CmdHFMFPersonalize(const char *cmd) {
5439 CLIParserContext *ctx;
5440 CLIParserInit(&ctx, "hf mf personalize",
5441 "Personalize the UID of a MIFARE Classic EV1 card. This is only possible \n"
5442 "if it is a 7Byte UID card and if it is not already personalized.",
5443 "hf mf personalize --f0 -> double size UID\n"
5444 "hf mf personalize --f1 -> double size UID, optional usage of selection process shortcut\n"
5445 "hf mf personalize --f2 -> single size random ID\n"
5446 "hf mf personalize --f3 -> single size NUID\n"
5447 "hf mf personalize -b -k B0B1B2B3B4B5 --f3 -> use key B = 0xB0B1B2B3B4B5"
5450 void *argtable[] = {
5451 arg_param_begin,
5452 arg_lit0("a", NULL, "use key A to authenticate sector 0 (def)"),
5453 arg_lit0("b", NULL, "use key B to authenticate sector 0"),
5454 arg_str0("k", "key", "<hex>", "key (def FFFFFFFFFFFF)"),
5455 arg_lit0(NULL, "f0", "UIDFO, double size UID"),
5456 arg_lit0(NULL, "f1", "UIDF1, double size UID, optional usage of selection process shortcut"),
5457 arg_lit0(NULL, "f2", "UIDF2, single size random ID"),
5458 arg_lit0(NULL, "f3", "UIDF3, single size NUID"),
5459 arg_param_end
5461 CLIExecWithReturn(ctx, cmd, argtable, true);
5463 bool use_a = arg_get_lit(ctx, 1);
5464 bool use_b = arg_get_lit(ctx, 2);
5466 if (use_a + use_b > 1) {
5467 PrintAndLogEx(ERR, "error, use only one key type");
5468 CLIParserFree(ctx);
5469 return PM3_EINVARG;
5472 uint8_t keytype = 0;
5473 if (use_b) {
5474 keytype = 1;
5477 uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
5478 int key_len;
5479 int res = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 6, &key_len);
5480 if (res || (!res && key_len && key_len != 6)) {
5481 PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits");
5482 CLIParserFree(ctx);
5483 return PM3_EINVARG;
5486 bool f0 = arg_get_lit(ctx, 4);
5487 bool f1 = arg_get_lit(ctx, 5);
5488 bool f2 = arg_get_lit(ctx, 6);
5489 bool f3 = arg_get_lit(ctx, 7);
5490 CLIParserFree(ctx);
5492 uint8_t tmp = f0 + f1 + f2 + f3;
5493 if (tmp > 1) {
5494 PrintAndLogEx(WARNING, "select only one key type");
5495 return PM3_EINVARG;
5497 if (tmp == 0) {
5498 PrintAndLogEx(WARNING, "select one key type");
5499 return PM3_EINVARG;
5502 uint8_t pers_option = MIFARE_EV1_UIDF3;
5503 if (f0) {
5504 pers_option = MIFARE_EV1_UIDF0;
5505 } else if (f1) {
5506 pers_option = MIFARE_EV1_UIDF1;
5507 } else if (f2) {
5508 pers_option = MIFARE_EV1_UIDF2;
5511 CLIParserFree(ctx);
5513 struct {
5514 uint8_t keytype;
5515 uint8_t pers_option;
5516 uint8_t key[6];
5517 } PACKED payload;
5518 payload.keytype = keytype;
5519 payload.pers_option = pers_option;
5520 memcpy(payload.key, key, sizeof(payload.key));
5522 clearCommandBuffer();
5523 SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload));
5524 PacketResponseNG resp;
5525 if (WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500) == false) {
5526 return PM3_ETIMEOUT;
5529 if (resp.status == PM3_SUCCESS) {
5530 PrintAndLogEx(SUCCESS, "Personalization ( %s )", _GREEN_("ok"));
5531 } else {
5532 PrintAndLogEx(FAILED, "Personalization ( %s )", _RED_("fail"));
5534 return PM3_SUCCESS;
5537 static int CmdHF14AMfList(const char *Cmd) {
5538 return CmdTraceListAlias(Cmd, "hf mf", "mf");
5541 static int CmdHf14AGen3UID(const char *Cmd) {
5542 CLIParserContext *ctx;
5543 CLIParserInit(&ctx, "hf mf gen3uid",
5544 "Set UID for magic Gen3 card _without_ changes to manufacturer block 0",
5545 "hf mf gen3uid --uid 01020304 --> set 4 byte uid\n"
5546 "hf mf gen3uid --uid 01020304050607 --> set 7 byte uid"
5548 void *argtable[] = {
5549 arg_param_begin,
5550 arg_str0("u", "uid", "<hex>", "UID 4/7 hex bytes"),
5551 arg_param_end
5553 CLIExecWithReturn(ctx, Cmd, argtable, true);
5555 uint8_t uid[7] = {0};
5556 int uidlen = 0;
5557 CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
5558 CLIParserFree(ctx);
5560 // sanity checks
5561 if (uidlen != 4 && uidlen != 7) {
5562 PrintAndLogEx(FAILED, "UID must be 4 or 7 hex bytes. Got %d", uidlen);
5563 return PM3_EINVARG;
5566 uint8_t old_uid[10] = {0};
5568 int res = mfGen3UID(uid, uidlen, old_uid);
5569 if (res != PM3_SUCCESS) {
5570 PrintAndLogEx(ERR, "Can't set UID");
5571 PrintAndLogEx(HINT, "Are you sure your card is a Gen3 ?");
5572 return PM3_ESOFT;
5575 PrintAndLogEx(SUCCESS, "Old UID... %s", sprint_hex(old_uid, uidlen));
5576 PrintAndLogEx(SUCCESS, "New UID... %s", sprint_hex(uid, uidlen));
5577 return PM3_SUCCESS;
5580 static int CmdHf14AGen3Block(const char *Cmd) {
5581 CLIParserContext *ctx;
5582 CLIParserInit(&ctx, "hf mf gen3blk",
5583 "Overwrite full manufacturer block for magic Gen3 card\n"
5584 " - You can specify part of manufacturer block as\n"
5585 " 4/7-bytes for UID change only\n"
5586 "\n"
5587 "NOTE: BCC, SAK, ATQA will be calculated automatically"
5589 "hf mf gen3blk --> print current data\n"
5590 "hf mf gen3blk -d 01020304 --> set 4 byte uid\n"
5591 "hf mf gen3blk -d 01020304050607 --> set 7 byte uid \n"
5592 "hf mf gen3blk -d 01020304FFFFFFFF0102030405060708"
5595 void *argtable[] = {
5596 arg_param_begin,
5597 arg_str0("d", "data", "<hex>", "manufacturer block data up to 16 hex bytes"),
5598 arg_param_end
5600 CLIExecWithReturn(ctx, Cmd, argtable, true);
5602 uint8_t data[MFBLOCK_SIZE] = {0x00};
5603 int datalen = 0;
5604 CLIGetHexWithReturn(ctx, 1, data, &datalen);
5605 CLIParserFree(ctx);
5607 uint8_t new_block[MFBLOCK_SIZE] = {0x00};
5608 int res = mfGen3Block(data, datalen, new_block);
5609 if (res) {
5610 PrintAndLogEx(ERR, "Can't change manufacturer block data. error %d", res);
5611 return PM3_ESOFT;
5614 PrintAndLogEx(SUCCESS, "Current block... %s", sprint_hex_inrow(new_block, sizeof(new_block)));
5615 return PM3_SUCCESS;
5618 static int CmdHf14AGen3Freeze(const char *Cmd) {
5619 CLIParserContext *ctx;
5620 CLIParserInit(&ctx, "hf mf gen3freeze",
5621 "Perma lock further UID changes. No more UID changes available after operation completed\n"
5622 "\nNote: operation is " _RED_("! irreversible !"),
5624 "hf mf gen3freeze -y"
5626 void *argtable[] = {
5627 arg_param_begin,
5628 arg_lit1("y", "yes", "confirm UID lock operation"),
5629 arg_param_end
5631 CLIExecWithReturn(ctx, Cmd, argtable, false);
5632 bool confirm = arg_get_lit(ctx, 1);
5633 CLIParserFree(ctx);
5634 if (confirm == false) {
5635 PrintAndLogEx(INFO, "please confirm that you want to perma lock the card");
5636 return PM3_SUCCESS;
5639 int res = mfGen3Freeze();
5640 if (res != PM3_SUCCESS) {
5641 PrintAndLogEx(ERR, "Can't lock UID changes. error %d", res);
5642 } else {
5643 PrintAndLogEx(SUCCESS, "MFC Gen3 UID card is now perma-locked");
5645 return res;
5648 static void des_decrypt(void *out, const void *in, const void *key) {
5649 mbedtls_des_context ctx;
5650 mbedtls_des_setkey_dec(&ctx, key);
5651 mbedtls_des_crypt_ecb(&ctx, in, out);
5654 static int CmdHf14AMfSuperCard(const char *Cmd) {
5656 CLIParserContext *ctx;
5657 CLIParserInit(&ctx, "hf mf supercard",
5658 "Extract info from a `super card`",
5659 "hf mf supercard");
5661 void *argtable[] = {
5662 arg_param_begin,
5663 arg_lit0("r", "reset", "reset card"),
5664 arg_param_end
5666 CLIExecWithReturn(ctx, Cmd, argtable, true);
5667 bool reset_card = arg_get_lit(ctx, 1);
5668 CLIParserFree(ctx);
5670 bool activate_field = true;
5671 bool keep_field_on = true;
5672 int res = 0;
5674 if (reset_card) {
5676 keep_field_on = false;
5677 uint8_t response[6];
5678 int resplen = 0;
5680 // --------------- RESET CARD ----------------
5681 uint8_t aRESET[] = { 0x00, 0xa6, 0xc0, 0x00 };
5682 res = ExchangeAPDU14a(aRESET, sizeof(aRESET), activate_field, keep_field_on, response, sizeof(response), &resplen);
5683 if (res != PM3_SUCCESS) {
5684 PrintAndLogEx(FAILED, "Super card reset [ " _RED_("fail") " ]");
5685 DropField();
5686 return res;
5688 PrintAndLogEx(SUCCESS, "Super card reset [ " _GREEN_("ok") " ]");
5689 return PM3_SUCCESS;
5693 uint8_t responseA[22];
5694 uint8_t responseB[22];
5695 int respAlen = 0;
5696 int respBlen = 0;
5698 // --------------- First ----------------
5699 uint8_t aFIRST[] = { 0x00, 0xa6, 0xb0, 0x00, 0x10 };
5700 res = ExchangeAPDU14a(aFIRST, sizeof(aFIRST), activate_field, keep_field_on, responseA, sizeof(responseA), &respAlen);
5701 if (res != PM3_SUCCESS) {
5702 DropField();
5703 return res;
5706 // --------------- Second ----------------
5707 activate_field = false;
5708 keep_field_on = false;
5710 uint8_t aSECOND[] = { 0x00, 0xa6, 0xb0, 0x01, 0x10 };
5711 res = ExchangeAPDU14a(aSECOND, sizeof(aSECOND), activate_field, keep_field_on, responseB, sizeof(responseB), &respBlen);
5712 if (res != PM3_SUCCESS) {
5713 DropField();
5714 return res;
5717 // uint8_t inA[] = { 0x72, 0xD7, 0xF4, 0x3E, 0xFD, 0xAB, 0xF2, 0x35, 0xFD, 0x49, 0xEE, 0xDC, 0x44, 0x95, 0x43, 0xC4};
5718 // uint8_t inB[] = { 0xF0, 0xA2, 0x67, 0x6A, 0x04, 0x6A, 0x72, 0x12, 0x76, 0xA4, 0x1D, 0x02, 0x1F, 0xEA, 0x20, 0x85};
5720 uint8_t outA[16] = {0};
5721 uint8_t outB[16] = {0};
5723 uint8_t key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
5724 for (uint8_t i = 0; i < 16; i += 8) {
5725 des_decrypt(outA + i, responseA + i, key);
5726 des_decrypt(outB + i, responseB + i, key);
5729 PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseA, respAlen));
5730 PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outA, sizeof(outA)));
5731 PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseB, respAlen));
5732 PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outB, sizeof(outB)));
5734 if (memcmp(outA, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
5735 PrintAndLogEx(INFO, "No trace recorded");
5736 return PM3_SUCCESS;
5739 // second trace?
5740 if (memcmp(outB, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
5741 PrintAndLogEx(INFO, "Only one trace recorded");
5742 return PM3_SUCCESS;
5745 nonces_t data;
5747 // first
5748 uint16_t NT0 = (outA[6] << 8) | outA[7];
5749 data.cuid = bytes_to_num(outA, 4);
5750 data.nonce = prng_successor(NT0, 31);
5751 data.nr = bytes_to_num(outA + 8, 4);
5752 data.ar = bytes_to_num(outA + 12, 4);
5753 data.at = 0;
5755 // second
5756 NT0 = (outB[6] << 8) | outB[7];
5757 data.nonce2 = prng_successor(NT0, 31);;
5758 data.nr2 = bytes_to_num(outB + 8, 4);
5759 data.ar2 = bytes_to_num(outB + 12, 4);
5760 data.sector = GetSectorFromBlockNo(outA[5]);
5761 data.keytype = outA[4];
5762 data.state = FIRST;
5764 PrintAndLogEx(DEBUG, "A Sector %02x", data.sector);
5765 PrintAndLogEx(DEBUG, "A NT %08x", data.nonce);
5766 PrintAndLogEx(DEBUG, "A NR %08x", data.nr);
5767 PrintAndLogEx(DEBUG, "A AR %08x", data.ar);
5768 PrintAndLogEx(DEBUG, "");
5769 PrintAndLogEx(DEBUG, "B NT %08x", data.nonce2);
5770 PrintAndLogEx(DEBUG, "B NR %08x", data.nr2);
5771 PrintAndLogEx(DEBUG, "B AR %08x", data.ar2);
5773 uint64_t key64 = -1;
5774 res = mfkey32_moebius(&data, &key64);
5776 if (res) {
5777 PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ " _GREEN_("%12" PRIX64) " ]"
5778 , sprint_hex_inrow(outA, 4)
5779 , data.sector
5780 , (data.keytype == 0x60) ? 'A' : 'B'
5781 , key64);
5782 } else {
5783 PrintAndLogEx(FAILED, "failed to recover any key");
5785 return PM3_SUCCESS;
5788 static int CmdHF14AMfWipe(const char *Cmd) {
5789 CLIParserContext *ctx;
5790 CLIParserInit(&ctx, "hf mf wipe",
5791 "Wipe card to zeros and default keys/acc. This command takes a key file to wipe card\n"
5792 "Will use UID from card to generate keyfile name if not specified.\n"
5793 "New A/B keys..... FF FF FF FF FF FF\n"
5794 "New acc rights... FF 07 80\n"
5795 "New GPB.......... 69",
5796 "hf mf wipe --> reads card uid to generate file name\n"
5797 "hf mf wipe --gen2 --> force write to S0, B0 manufacture block\n"
5798 "hf mf wipe -f mykey.bin --> use mykey.bin\n"
5800 void *argtable[] = {
5801 arg_param_begin,
5802 arg_str0("f", "file", "<fn>", "key filename"),
5803 arg_lit0(NULL, "gen2", "force write to Sector 0, block 0 (GEN2)"),
5804 arg_param_end
5806 CLIExecWithReturn(ctx, Cmd, argtable, true);
5808 int keyfnlen = 0;
5809 char keyFilename[FILE_PATH_SIZE] = {0};
5810 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
5812 bool gen2 = arg_get_lit(ctx, 2);
5813 CLIParserFree(ctx);
5815 char *fptr;
5816 if (keyfnlen == 0) {
5817 fptr = GenerateFilename("hf-mf-", "-key.bin");
5818 if (fptr == NULL)
5819 return PM3_ESOFT;
5821 strcpy(keyFilename, fptr);
5822 free(fptr);
5825 uint8_t *keys;
5826 size_t keyslen = 0;
5827 if (loadFile_safeEx(keyFilename, ".bin", (void **)&keys, (size_t *)&keyslen, false) != PM3_SUCCESS) {
5828 PrintAndLogEx(FAILED, "failed to load key file");
5829 return PM3_ESOFT;
5832 uint8_t keyA[MIFARE_4K_MAXSECTOR * 6];
5833 uint8_t keyB[MIFARE_4K_MAXSECTOR * 6];
5834 uint8_t num_sectors = 0;
5836 uint8_t mf[MFBLOCK_SIZE];
5837 switch (keyslen) {
5838 case (MIFARE_MINI_MAXSECTOR * 2 * 6): {
5839 PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic Mini 320b");
5840 memcpy(keyA, keys, (MIFARE_MINI_MAXSECTOR * 6));
5841 memcpy(keyB, keys + (MIFARE_MINI_MAXSECTOR * 6), (MIFARE_MINI_MAXSECTOR * 6));
5842 num_sectors = NumOfSectors('0');
5843 memcpy(mf, "\x11\x22\x33\x44\x44\x09\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE);
5844 break;
5846 case (MIFARE_1K_MAXSECTOR * 2 * 6): {
5847 PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic 1K");
5848 memcpy(keyA, keys, (MIFARE_1K_MAXSECTOR * 6));
5849 memcpy(keyB, keys + (MIFARE_1K_MAXSECTOR * 6), (MIFARE_1K_MAXSECTOR * 6));
5850 num_sectors = NumOfSectors('1');
5852 memcpy(mf, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE);
5853 break;
5855 case (MIFARE_4K_MAXSECTOR * 2 * 6): {
5856 PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic 4K");
5857 memcpy(keyA, keys, (MIFARE_4K_MAXSECTOR * 6));
5858 memcpy(keyB, keys + (MIFARE_4K_MAXSECTOR * 6), (MIFARE_4K_MAXSECTOR * 6));
5859 num_sectors = NumOfSectors('4');
5860 memcpy(mf, "\x11\x22\x33\x44\x44\x18\x02\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE);
5861 break;
5863 default: {
5864 PrintAndLogEx(INFO, "wrong key file size");
5865 goto out;
5869 if (gen2)
5870 PrintAndLogEx(INFO, "Forcing overwrite of sector 0 / block 0 ");
5871 else
5872 PrintAndLogEx(INFO, "Skipping sector 0 / block 0");
5873 PrintAndLogEx(NORMAL, "");
5875 uint8_t zeros[MFBLOCK_SIZE] = {0};
5876 memset(zeros, 0x00, sizeof(zeros));
5877 uint8_t st[MFBLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
5879 // time to wipe card
5880 for (uint8_t s = 0; s < num_sectors; s++) {
5882 for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
5884 // Skipp write to manufacture block if not enforced
5885 if (s == 0 && b == 0 && gen2 == false) {
5886 continue;
5889 uint8_t data[26];
5890 memset(data, 0, sizeof(data));
5891 if (mfIsSectorTrailer(b)) {
5892 memcpy(data + 10, st, sizeof(st));
5893 } else {
5894 memcpy(data + 10, zeros, sizeof(zeros));
5897 // add correct manufacture block if UID Gen2
5898 if (s == 0 && b == 0 && gen2) {
5899 memcpy(data + 10, mf, sizeof(mf));
5902 // try both A/B keys, start with B key first
5903 for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
5905 if (kt == MF_KEY_A)
5906 memcpy(data, keyA + (s * 6), 6);
5907 else
5908 memcpy(data, keyB + (s * 6), 6);
5910 PrintAndLogEx(INFO, "block %3d: %s" NOLF, FirstBlockOfSector(s) + b, sprint_hex(data + 10, MFBLOCK_SIZE));
5911 clearCommandBuffer();
5912 SendCommandMIX(CMD_HF_MIFARE_WRITEBL, FirstBlockOfSector(s) + b, kt, 0, data, sizeof(data));
5913 PacketResponseNG resp;
5914 if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
5915 uint8_t isOK = resp.oldarg[0] & 0xff;
5916 if (isOK == 0) {
5917 PrintAndLogEx(NORMAL, "( " _RED_("fail") " )");
5918 } else {
5919 PrintAndLogEx(NORMAL, "( " _GREEN_("ok") " )");
5920 break;
5922 } else {
5923 PrintAndLogEx(WARNING, "Command execute timeout");
5929 PrintAndLogEx(NORMAL, "");
5930 PrintAndLogEx(INFO, "Done!");
5931 out:
5932 free(keys);
5933 return PM3_SUCCESS;
5936 static int CmdHF14AMfView(const char *Cmd) {
5938 CLIParserContext *ctx;
5939 CLIParserInit(&ctx, "hf mf view",
5940 "Print a MIFARE Classic dump file (bin/eml/json)",
5941 "hf mf view -f hf-mf-01020304-dump.bin"
5943 void *argtable[] = {
5944 arg_param_begin,
5945 arg_str1("f", "file", "<fn>", "filename of dump"),
5946 arg_lit0("v", "verbose", "verbose output"),
5947 arg_param_end
5949 CLIExecWithReturn(ctx, Cmd, argtable, false);
5950 int fnlen = 0;
5951 char filename[FILE_PATH_SIZE];
5952 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
5953 bool verbose = arg_get_lit(ctx, 2);
5954 CLIParserFree(ctx);
5956 // reserve memory
5957 uint8_t *dump = NULL;
5958 size_t bytes_read = 0;
5959 int res = 0;
5960 DumpFileType_t dftype = getfiletype(filename);
5961 switch (dftype) {
5962 case BIN: {
5963 res = loadFile_safe(filename, ".bin", (void **)&dump, &bytes_read);
5964 break;
5966 case EML: {
5967 res = loadFileEML_safe(filename, (void **)&dump, &bytes_read);
5968 break;
5970 case JSON: {
5971 dump = calloc(MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK, sizeof(uint8_t));
5972 if (dump == NULL) {
5973 PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
5974 return PM3_EMALLOC;
5976 res = loadFileJSON(filename, (void *)dump, MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, &bytes_read, NULL);
5977 break;
5979 case DICTIONARY: {
5980 PrintAndLogEx(ERR, "Error: Only BIN/JSON/EML formats allowed");
5981 free(dump);
5982 return PM3_EINVARG;
5986 if (res != PM3_SUCCESS) {
5987 PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", filename);
5988 free(dump);
5989 return PM3_EFILE;
5992 uint16_t block_cnt = MIN(MIFARE_1K_MAXBLOCK, (bytes_read / MFBLOCK_SIZE));
5993 if (bytes_read == 320)
5994 block_cnt = MIFARE_MINI_MAXBLOCK;
5995 else if (bytes_read == 2048)
5996 block_cnt = MIFARE_2K_MAXBLOCK;
5997 else if (bytes_read == 4096)
5998 block_cnt = MIFARE_4K_MAXBLOCK;
6000 if (verbose) {
6001 PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename);
6002 PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt);
6005 mf_print_blocks(block_cnt, dump);
6006 free(dump);
6007 return PM3_SUCCESS;
6010 static command_t CommandTable[] = {
6011 {"help", CmdHelp, AlwaysAvailable, "This help"},
6012 {"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"},
6013 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("recovery") " -----------------------"},
6014 {"darkside", CmdHF14AMfDarkside, IfPm3Iso14443a, "Darkside attack"},
6015 {"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"},
6016 {"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"},
6017 {"staticnested", CmdHF14AMfNestedStatic, IfPm3Iso14443a, "Nested attack against static nonce MIFARE Classic cards"},
6018 {"autopwn", CmdHF14AMfAutoPWN, IfPm3Iso14443a, "Automatic key recovery tool for MIFARE Classic"},
6019 // {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
6020 {"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"},
6021 {"chk", CmdHF14AMfChk, IfPm3Iso14443a, "Check keys"},
6022 {"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"},
6023 {"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"},
6024 {"supercard", CmdHf14AMfSuperCard, IfPm3Iso14443a, "Extract info from a `super card`"},
6025 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"},
6026 {"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
6027 {"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"},
6028 {"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
6029 {"ndefread", CmdHFMFNDEFRead, IfPm3Iso14443a, "Prints NDEF records from card"},
6030 {"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (MIFARE Classic EV1 only)"},
6031 {"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE Classic block"},
6032 {"rdsc", CmdHF14AMfRdSc, IfPm3Iso14443a, "Read MIFARE Classic sector"},
6033 {"restore", CmdHF14AMfRestore, IfPm3Iso14443a, "Restore MIFARE Classic binary file to BLANK tag"},
6034 {"setmod", CmdHf14AMfSetMod, IfPm3Iso14443a, "Set MIFARE Classic EV1 load modulation strength"},
6035 {"view", CmdHF14AMfView, AlwaysAvailable, "Display content from tag dump file"},
6036 {"wipe", CmdHF14AMfWipe, IfPm3Iso14443a, "Wipe card to zeros and default keys/acc"},
6037 {"wrbl", CmdHF14AMfWrBl, IfPm3Iso14443a, "Write MIFARE Classic block"},
6038 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"},
6039 {"sim", CmdHF14AMfSim, IfPm3Iso14443a, "Simulate MIFARE card"},
6040 {"ecfill", CmdHF14AMfECFill, IfPm3Iso14443a, "Fill emulator memory with help of keys from emulator"},
6041 {"eclr", CmdHF14AMfEClear, IfPm3Iso14443a, "Clear emulator memory"},
6042 {"egetblk", CmdHF14AMfEGetBlk, IfPm3Iso14443a, "Get emulator memory block"},
6043 {"egetsc", CmdHF14AMfEGetSc, IfPm3Iso14443a, "Get emulator memory sector"},
6044 {"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from emulator memory"},
6045 {"eload", CmdHF14AMfELoad, IfPm3Iso14443a, "Load from file emul dump"},
6046 {"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"},
6047 {"esetblk", CmdHF14AMfESet, IfPm3Iso14443a, "Set emulator memory block"},
6048 {"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emulator memory"},
6049 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen1") " -----------------------"},
6050 {"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block from card"},
6051 {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector from card"},
6052 {"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump to card"},
6053 {"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from card into file or emulator"},
6054 {"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block to card"},
6055 {"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID on card"},
6056 {"cview", CmdHF14AMfCView, IfPm3Iso14443a, "View card"},
6057 {"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"},
6058 {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
6059 {"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without changing manufacturer block"},
6060 {"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite manufacturer block"},
6061 {"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock UID changes. irreversible"},
6063 // {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
6064 // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
6065 {NULL, NULL, NULL, NULL}
6068 static int CmdHelp(const char *Cmd) {
6069 (void)Cmd; // Cmd is not used so far
6070 CmdsHelp(CommandTable);
6071 return PM3_SUCCESS;
6074 int CmdHFMF(const char *Cmd) {
6075 clearCommandBuffer();
6076 return CmdsParse(CommandTable, Cmd);