1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2011,2012 Merlok
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
7 //-----------------------------------------------------------------------------
8 // High frequency MIFARE commands
9 //-----------------------------------------------------------------------------
14 #include "cmdparser.h" // command_t
15 #include "commonutil.h" // ARRAYLEN
16 #include "comms.h" // clearCommandBuffer
17 #include "fileutils.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"
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"));
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"},
73 bool is_valid
= false;
75 for (i
= 0; i
< ARRAYLEN(nxp_mfc_public_keys
); i
++) {
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);
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"));
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"));
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");
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
;
121 static char *GenerateFilename(const char *prefix
, const char *suffix
) {
122 if (! IfPm3Iso14443a()) {
125 uint8_t uid
[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
127 char *fptr
= calloc(sizeof(char) * (strlen(prefix
) + strlen(suffix
)) + sizeof(uid
) * 2 + 1, sizeof(uint8_t));
129 GetHFMF14AUID(uid
, &uidlen
);
131 PrintAndLogEx(WARNING
, "No tag found.");
136 strcpy(fptr
, prefix
);
137 FillFileNameByUID(fptr
, uid
, suffix
, uidlen
);
141 static int32_t initSectorTable(sector_t
**src
, int32_t items
) {
143 (*src
) = calloc(items
, sizeof(sector_t
));
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;
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]));
176 PrintAndLogEx(INFO
, "----------------------------------------------------------------------");
177 PrintAndLogEx(NORMAL
, "");
181 static uint8_t NumOfSectors(char card
) {
184 return MIFARE_MINI_MAXSECTOR
;
186 return MIFARE_1K_MAXSECTOR
;
188 return MIFARE_2K_MAXSECTOR
;
190 return MIFARE_4K_MAXSECTOR
;
196 static uint8_t FirstBlockOfSector(uint8_t sectorNo
) {
200 return 32 * 4 + (sectorNo
- 32) * 16;
204 static uint8_t NumBlocksPerSector(uint8_t sectorNo
) {
212 static uint8_t GetSectorFromBlockNo(uint8_t blockNo
) {
213 if (blockNo
< 32 * 4)
216 return 32 + ((blockNo
- (32 * 4)) / 16);
219 static char GetFormatFromSector(uint8_t sectorNo
) {
221 case MIFARE_MINI_MAXSECTOR
:
223 case MIFARE_1K_MAXSECTOR
:
225 case MIFARE_2K_MAXSECTOR
:
227 case MIFARE_4K_MAXSECTOR
:
234 static void mf_print_block(uint8_t blockno
, uint8_t *d
) {
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
));
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",
267 "hf mf darkside --blk 16\n"
268 "hf mf darkside --blk 16 -b\n");
272 arg_int0(NULL
, "blk", "<dec> ", "Target block"),
273 arg_lit0("b", NULL
, "Target key B instead of default key A"),
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
;
291 int isOK
= mfDarkside(blockno
, key_type
, &key
);
292 PrintAndLogEx(NORMAL
, "");
295 PrintAndLogEx(WARNING
, "button pressed. Aborted.");
298 PrintAndLogEx(FAILED
, "card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
301 PrintAndLogEx(FAILED
, "card is not vulnerable to Darkside attack (its random number generator is not predictable).");
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.");
308 PrintAndLogEx(WARNING
, "aborted via keyboard.");
311 PrintAndLogEx(SUCCESS
, "found valid key: "_YELLOW_("%012" PRIx64
), key
);
314 PrintAndLogEx(NORMAL
, "");
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"
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"),
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)) {
342 PrintAndLogEx(WARNING
, "Input key type must be A or B");
344 } else if (arg_get_lit(ctx
, 3)) {
349 uint8_t key
[6] = {0};
350 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
352 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
354 CLIGetHexWithReturn(ctx
, 5, block
, &blen
);
357 if (blen
!= MFBLOCK_SIZE
) {
358 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", blen
);
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
)));
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");
382 uint8_t isok
= resp
.oldarg
[0] & 0xff;
384 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
385 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf rdbl") "` to verify");
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');
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"
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"),
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)) {
416 PrintAndLogEx(WARNING
, "Input key type must be A or B");
418 } else if (arg_get_lit(ctx
, 3)) {
423 uint8_t key
[6] = {0};
424 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
425 bool verbose
= arg_get_lit(ctx
, 5);
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
);
441 decode_print_st(blockno
, data
);
444 PrintAndLogEx(NORMAL
, "");
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"
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"),
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)) {
468 PrintAndLogEx(WARNING
, "Input key type must be A or B");
470 } else if (arg_get_lit(ctx
, 2)) {
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);
482 if (s
> MIFARE_4K_MAXSECTOR
) {
483 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
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));
490 PrintAndLogEx(ERR
, "failed to allocate memory");
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
));
506 decode_print_st(start
+ blocks
- 1, data
+ ((blocks
- 1) * MFBLOCK_SIZE
));
510 PrintAndLogEx(NORMAL
, "");
514 static int FastDumpWithEcFill(uint8_t numsectors
) {
515 PacketResponseNG resp
;
518 payload
.sectorcnt
= numsectors
;
519 payload
.keytype
= MF_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);
527 PrintAndLogEx(WARNING
, "Command execute timeout");
531 if (resp
.status
!= PM3_SUCCESS
) {
532 PrintAndLogEx(INFO
, "fast dump reported back failure w KEY A, swapping to 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);
541 PrintAndLogEx(WARNING
, "Command execute timeout");
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");
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");
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"),
574 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
577 char dataFilename
[FILE_PATH_SIZE
] = {0};
578 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)dataFilename
, FILE_PATH_SIZE
, &datafnlen
);
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);
591 uint64_t t1
= msclock();
594 if ((m0
+ m1
+ m2
+ m4
) > 1) {
595 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
597 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
601 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
604 numSectors
= MIFARE_MINI_MAXSECTOR
;
606 numSectors
= MIFARE_1K_MAXSECTOR
;
608 numSectors
= MIFARE_2K_MAXSECTOR
;
610 numSectors
= MIFARE_4K_MAXSECTOR
;
612 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
616 uint8_t sectorNo
, blockNo
;
619 uint8_t rights
[40][4];
620 uint8_t carddata
[256][16];
623 PacketResponseNG resp
;
627 if (keyFilename
[0] == 0x00) {
628 fptr
= GenerateFilename("hf-mf-", "-key.bin");
632 strcpy(keyFilename
, fptr
);
636 if ((f
= fopen(keyFilename
, "rb")) == NULL
) {
637 PrintAndLogEx(WARNING
, "Could not find file " _YELLOW_("%s"), keyFilename
);
641 PrintAndLogEx(INFO
, "Using `" _YELLOW_("%s") "`", keyFilename
);
643 // Read keys A from file
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.");
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.");
666 PrintAndLogEx(INFO
, "Reading sector access bits...");
667 PrintAndLogEx(INFO
, "." NOLF
);
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
);
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
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;
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
;
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?
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);
749 if (resp
.status
== PM3_SUCCESS
) {
750 // break the re-try loop
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
);
776 PrintAndLogEx(FAILED
, "could not read block %2d of sector %2d", blockNo
, sectorNo
);
780 PrintAndLogEx(WARNING
, "command execute timeout when trying to read block %2d of sector %2d.", blockNo
, sectorNo
);
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");
795 strcpy(dataFilename
, 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
);
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"
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"
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",
821 "hf mf restore --1k --uid 04010203\n"
822 "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n"
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"),
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);
847 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
850 char datafilename
[FILE_PATH_SIZE
] = {0};
851 CLIParamStrToBuf(arg_get_str(ctx
, 6), (uint8_t *)datafilename
, FILE_PATH_SIZE
, &datafnlen
);
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);
861 if ((m0
+ m1
+ m2
+ m4
) > 1) {
862 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
864 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
868 uint8_t sectors
= MIFARE_1K_MAXSECTOR
;
871 sectors
= MIFARE_MINI_MAXSECTOR
;
873 sectors
= MIFARE_1K_MAXSECTOR
;
875 sectors
= MIFARE_2K_MAXSECTOR
;
877 sectors
= MIFARE_4K_MAXSECTOR
;
879 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
883 // if user specified UID, use it in file templates
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
899 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
903 strcpy(keyfilename
, fptr
);
908 if ((f
= fopen(keyfilename
, "rb")) == NULL
) {
909 PrintAndLogEx(WARNING
, "Could not find file " _YELLOW_("%s"), keyfilename
);
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
);
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
);
939 // try reading card uid and create filename
940 if (datafnlen
== 0) {
941 char *fptr
= GenerateFilename("hf-mf-", "-dump.bin");
945 strcpy(datafilename
, fptr
);
950 if ((f
= fopen(datafilename
, "rb")) == NULL
) {
951 PrintAndLogEx(WARNING
, "Could not find file " _YELLOW_("%s"), datafilename
);
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
++) {
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
);
974 if (use_keyfile_for_auth
== false) {
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
--) {
999 memcpy(data
, keyA
[s
], 6);
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;
1012 PrintAndLogEx(INFO
, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt
== MF_KEY_A
) ? 'A' : 'B');
1014 PrintAndLogEx(FAILED
, "Write to block %u w key %c ( " _RED_("fail") " ) ", b
, (kt
== MF_KEY_A
) ? 'A' : 'B');
1017 // if success, skip to next block
1021 PrintAndLogEx(WARNING
, "Command execute timeout");
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;
1035 PrintAndLogEx(INFO
, "Writing to manufacture block w key B ( " _RED_("fail") " )");
1037 PrintAndLogEx(FAILED
, "Write to block %u w key B ( " _RED_("fail") " )", b
);
1041 PrintAndLogEx(WARNING
, "Command execute timeout");
1047 PrintAndLogEx(INFO
, "Done!");
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
[] = {
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)"),
1079 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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)) {
1096 PrintAndLogEx(WARNING
, "Input key type must be A or B");
1098 } else if (arg_get_lit(ctx
, 8)) {
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)) {
1108 PrintAndLogEx(WARNING
, "Target key type must be A or B");
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);
1121 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1122 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1126 uint8_t SectorsCnt
= 1;
1128 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1130 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1132 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
1134 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
1137 if (singleSector
== false) {
1138 if (SectorsCnt
== 0) {
1139 PrintAndLogEx(WARNING
, "Invalid MIFARE Type");
1145 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
1149 sector_t
*e_sector
= NULL
;
1150 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
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
;
1167 int16_t isOK
= mfnested(blockNo
, keyType
, key
, trgBlockNo
, trgKeyType
, keyBlock
, true);
1170 PrintAndLogEx(ERR
, "Command execute timeout\n");
1172 case PM3_EOPABORTED
:
1173 PrintAndLogEx(WARNING
, "Button pressed. Aborted.\n");
1176 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
1179 PrintAndLogEx(FAILED
, "No valid key found");
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
);
1198 num_to_bytes(key64
, 6, &keyBlock
[10]);
1200 mfEmlSetMem(keyBlock
, sectortrailer
, 1);
1201 PrintAndLogEx(SUCCESS
, "Key transferred to emulator memory.");
1205 PrintAndLogEx(ERR
, "Unknown error.\n");
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");
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");
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
);
1249 PrintAndLogEx(ERR
, "Command execute timeout\n");
1251 case PM3_EOPABORTED
:
1252 PrintAndLogEx(WARNING
, "button pressed. Aborted.\n");
1255 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
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);
1269 PrintAndLogEx(ERR
, "Unknown error.\n");
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);
1308 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
1309 e_sector
[i
].foundKey
[1] = true;
1310 e_sector
[i
].Key
[1] = key64
;
1317 PrintAndLogEx(NORMAL
, "");
1318 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
1321 printKeyTable(SectorsCnt
, e_sector
);
1323 // transfer them to the emulator
1324 if (transferToEml
) {
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.");
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");
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
[] = {
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"),
1384 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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)) {
1401 PrintAndLogEx(WARNING
, "Input key type must be A or B");
1403 } else if (arg_get_lit(ctx
, 8)) {
1407 bool transferToEml
= arg_get_lit(ctx
, 9);
1408 bool createDumpFile
= arg_get_lit(ctx
, 10);
1413 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1414 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1418 uint8_t SectorsCnt
= 1;
1420 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1422 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1424 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
1426 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
1428 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1433 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
1437 sector_t
*e_sector
= NULL
;
1439 uint8_t trgKeyType
= MF_KEY_A
;
1441 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
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
;
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
) {
1482 PrintAndLogEx(SUCCESS
, "Fast check found all keys");
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");
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
);
1501 PrintAndLogEx(ERR
, "Command execute timeout");
1503 case PM3_EOPABORTED
:
1504 PrintAndLogEx(WARNING
, "aborted via keyboard.");
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);
1515 PrintAndLogEx(ERR
, "unknown error.\n");
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);
1554 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
1555 e_sector
[i
].foundKey
[1] = true;
1556 e_sector
[i
].Key
[1] = key64
;
1563 PrintAndLogEx(NORMAL
, "");
1564 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
1567 printKeyTable(SectorsCnt
, e_sector
);
1569 // transfer them to the emulator
1570 if (transferToEml
) {
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.");
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");
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"
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
[] = {
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"),
1651 #if defined(COMPILER_HAS_SIMD_AVX512)
1652 arg_lit0(NULL
, "i5", "AVX512"),
1656 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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)) {
1667 PrintAndLogEx(WARNING
, "Input key type must be A or B");
1669 } else if (arg_get_lit(ctx
, 4)) {
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)) {
1678 PrintAndLogEx(WARNING
, "Input key type must be A or B");
1680 } else if (arg_get_lit(ctx
, 7)) {
1681 trg_keytype
= MF_KEY_B
;
1685 uint8_t trg_key
[6] = {0};
1686 CLIGetHexWithReturn(ctx
, 8, trg_key
, &trg_keylen
);
1690 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
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);
1708 #if defined(COMPILER_HAS_SIMD_AVX512)
1709 bool i5
= arg_get_lit(ctx
, 20);
1713 // set SIM instructions
1714 SetSIMDInstr(SIMD_AUTO
);
1716 #if defined(COMPILER_HAS_SIMD_AVX512)
1718 SetSIMDInstr(SIMD_AVX512
);
1721 #if defined(COMPILER_HAS_SIMD)
1723 SetSIMDInstr(SIMD_AVX2
);
1725 SetSIMDInstr(SIMD_AVX
);
1727 SetSIMDInstr(SIMD_SSE2
);
1729 SetSIMDInstr(SIMD_MMX
);
1732 SetSIMDInstr(SIMD_NONE
);
1735 bool know_target_key
= (trg_keylen
);
1737 if (nonce_file_read
) {
1738 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
1740 strncpy(filename
, "nonces.bin", FILE_PATH_SIZE
- 1);
1742 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
1746 if (nonce_file_write
) {
1747 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
1750 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
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
;
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"),
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",
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()) {
1796 PrintAndLogEx(ERR
, "Error: No response from Proxmark3.\n");
1799 PrintAndLogEx(NORMAL
, "Button pressed. Aborted.\n");
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.",
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
[] = {
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"),
1845 #if defined(COMPILER_HAS_SIMD_AVX512)
1846 arg_lit0(NULL
, "i5", "AVX512"),
1850 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1853 uint8_t key
[6] = {0};
1854 int32_t res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), key
, sizeof(key
), &keylen
);
1857 PrintAndLogEx(FAILED
, "Error parsing key bytes");
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)) {
1868 PrintAndLogEx(WARNING
, "Input key type must be A or B");
1870 } else if (arg_get_lit(ctx
, 4)) {
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);
1895 #if defined(COMPILER_HAS_SIMD_AVX512)
1896 bool i5
= arg_get_lit(ctx
, 18);
1901 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1902 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1904 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
1908 uint8_t sector_cnt
= MIFARE_1K_MAXSECTOR
;
1909 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
1912 sector_cnt
= MIFARE_MINI_MAXSECTOR
;
1913 block_cnt
= MIFARE_MINI_MAXBLOCK
;
1915 sector_cnt
= MIFARE_1K_MAXSECTOR
;
1916 block_cnt
= MIFARE_1K_MAXBLOCK
;
1918 sector_cnt
= MIFARE_2K_MAXSECTOR
;
1919 block_cnt
= MIFARE_2K_MAXBLOCK
;
1921 sector_cnt
= MIFARE_4K_MAXSECTOR
;
1922 block_cnt
= MIFARE_4K_MAXBLOCK
;
1924 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1929 // set SIM instructions
1930 SetSIMDInstr(SIMD_AUTO
);
1932 #if defined(COMPILER_HAS_SIMD_AVX512)
1934 SetSIMDInstr(SIMD_AVX512
);
1937 #if defined(COMPILER_HAS_SIMD)
1939 SetSIMDInstr(SIMD_AVX2
);
1941 SetSIMDInstr(SIMD_AVX
);
1943 SetSIMDInstr(SIMD_SSE2
);
1945 SetSIMDInstr(SIMD_MMX
);
1948 SetSIMDInstr(SIMD_NONE
);
1951 // Nested and Hardnested parameter
1953 bool calibrate
= true;
1954 // Attack key storage variables
1955 uint8_t *keyBlock
= NULL
;
1956 uint32_t key_cnt
= 0;
1958 uint8_t tmp_key
[6] = {0};
1960 // Nested and Hardnested returned status
1961 uint64_t foundkey
= 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};
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
) {
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");
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");
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
, "========================================================================");
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");
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)",
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';
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"),
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;
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
))
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
))
2086 if (num_found_keys
== sector_cnt
* 2) {
2091 bool load_success
= true;
2092 // Load the dictionary
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
) {
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
) {
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") " =======================");
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
);
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';
2143 PrintAndLogEx(NORMAL
, "");
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");
2158 break; // Exit the loop
2160 uint32_t size
= ((key_cnt
- i
) > chunksize
) ? chunksize
: key_cnt
- i
;
2162 if (size
== key_cnt
- i
)
2165 res
= mfCheckKeys_fast(sector_cnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* 6), e_sector
, false);
2168 // all keys, aborted
2169 if (res
== PM3_SUCCESS
) {
2172 break; // Exit the loop
2174 } // end chunks of keys
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;
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
))
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
) {
2214 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
2216 isOK
= mfDarkside(FirstBlockOfSector(sectorno
), keytype
+ 0x60, &key64
);
2220 PrintAndLogEx(WARNING
, "\nButton pressed. Aborted.");
2221 goto noValidKeyFound
;
2223 PrintAndLogEx(FAILED
, "\nCard is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).");
2224 goto noValidKeyFound
;
2226 PrintAndLogEx(FAILED
, "\nCard is not vulnerable to Darkside attack (its random number generator is not predictable).");
2227 goto noValidKeyFound
;
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
;
2233 PrintAndLogEx(WARNING
, "\naborted via keyboard.");
2234 goto noValidKeyFound
;
2236 PrintAndLogEx(SUCCESS
, "\nFound valid key [ " _GREEN_("%012" PRIx64
) " ]\n", key64
);
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)",
2246 (keytype
== MF_KEY_B
) ? 'B' : 'A',
2251 PrintAndLogEx(FAILED
, "No usable key was found!");
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
])
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]) {
2300 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START READ B KEY ATTACK") " =======================");
2301 PrintAndLogEx(INFO
, "reading B key of sector %3d with key type %c",
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);
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") " ]",
2329 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
2330 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2334 PrintAndLogEx(WARNING
, "unknown B key: sector: %3d key type: %c",
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
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;
2356 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START NESTED ATTACK") " =======================");
2357 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
2359 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
2362 isOK
= mfnested(FirstBlockOfSector(sectorno
), keytype
, key
, FirstBlockOfSector(current_sector_i
), current_key_type_i
, tmp_key
, calibrate
);
2365 case PM3_ETIMEOUT
: {
2366 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3.");
2371 case PM3_EOPABORTED
: {
2372 PrintAndLogEx(WARNING
, "\nButton pressed. Aborted.");
2375 return PM3_EOPABORTED
;
2378 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable).");
2379 PrintAndLogEx(FAILED
, "Nested attack failed --> try hardnested");
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
);
2390 PrintAndLogEx(FAILED
, "Nested attack failed, moving to hardnested");
2391 nested_failed
= true;
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';
2403 PrintAndLogEx(ERR
, "unknown Error.\n");
2411 tryHardnested
: // If the nested attack fails then we try the hardnested attack
2413 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START HARDNESTED ATTACK") " =======================");
2414 PrintAndLogEx(INFO
, "sector no %3d, target key type %c, Slow %s",
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
);
2425 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
2429 PrintAndLogEx(NORMAL
, "\nButton pressed, user aborted");
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
) {
2450 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
2451 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
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
);
2459 case PM3_ETIMEOUT
: {
2460 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
2465 case PM3_EOPABORTED
: {
2466 PrintAndLogEx(WARNING
, "\nButton pressed, user aborted");
2469 return PM3_EOPABORTED
;
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';
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") " ]",
2486 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
2487 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2497 // Show the results to the user
2498 PrintAndLogEx(NORMAL
, "");
2499 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
2501 printKeyTable(sector_cnt
, e_sector
);
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);
2527 FastDumpWithEcFill(sector_cnt
);
2529 bytes
= block_cnt
* MFBLOCK_SIZE
;
2530 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
2532 PrintAndLogEx(ERR
, "Fail, cannot allocate memory");
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");
2544 return PM3_ETIMEOUT
;
2548 fptr
= GenerateFilename("hf-mf-", "-dump");
2555 strcpy(filename
, 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);
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
[] = {
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"),
2597 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
2613 char filename
[FILE_PATH_SIZE
] = {0};
2614 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2620 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2621 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2623 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
2627 uint8_t sectorsCnt
= 1;
2629 sectorsCnt
= MIFARE_MINI_MAXSECTOR
;
2631 sectorsCnt
= MIFARE_1K_MAXSECTOR
;
2633 sectorsCnt
= MIFARE_2K_MAXSECTOR
;
2635 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
2637 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
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
2655 int numKeys
= keylen
/ 6;
2657 p
= realloc(keyBlock
, 6 * (keyitems
+ numKeys
));
2659 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
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));
2674 // Handle user supplied dictionary file
2679 int res
= searchFile(&dict_path
, DICTIONARIES_SUBDIR
, filename
, ".dic", false);
2680 if (res
!= PM3_SUCCESS
) {
2684 f
= fopen(dict_path
, "r");
2686 PrintAndLogEx(FAILED
, "File: " _YELLOW_("%s") ": not found or locked.", dict_path
);
2692 // load keys from dictionary file
2693 while (fgets(buf
, sizeof(buf
), f
)) {
2694 if (strlen(buf
) < 12 || buf
[11] == '\n')
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
);
2709 if (keyitems
- keycnt
< 2) {
2710 p
= realloc(keyBlock
, 6 * (keyitems
+= 64));
2712 PrintAndLogEx(FAILED
, "Cannot allocate memory for defKeys");
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));
2723 memset(buf
, 0, sizeof(buf
));
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
) {
2746 uint32_t chunksize
= keycnt
> (PM3_CMD_DATA_SIZE
/ 6) ? (PM3_CMD_DATA_SIZE
/ 6) : keycnt
;
2747 bool firstChunk
= true, lastChunk
= false;
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
);
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");
2770 uint32_t size
= ((keycnt
- i
) > chunksize
) ? chunksize
: keycnt
- i
;
2773 if (size
== keycnt
- i
)
2776 res
= mfCheckKeys_fast(sectorsCnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* 6), e_sector
, false);
2781 // all keys, aborted
2782 if (res
== PM3_SUCCESS
|| res
== 2)
2784 } // end chunks of keys
2790 t1
= msclock() - t1
;
2791 PrintAndLogEx(INFO
, "time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1
/ 1000.0));
2794 uint8_t found_keys
= 0;
2795 for (i
= 0; i
< sectorsCnt
; ++i
) {
2797 if (e_sector
[i
].foundKey
[0])
2800 if (e_sector
[i
].foundKey
[1])
2804 if (found_keys
== 0) {
2805 PrintAndLogEx(WARNING
, "No keys found");
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`"),
2816 GetFormatFromSector(sectorsCnt
)
2820 if (transferToEml
) {
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");
2859 PrintAndLogEx(NORMAL
, "");
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
[] = {
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"),
2891 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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)) {
2903 } else if (arg_get_lit(ctx
, 3)) {
2905 } else if (arg_get_lit(ctx
, 4)) {
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);
2918 char filename
[FILE_PATH_SIZE
] = {0};
2919 CLIParamStrToBuf(arg_get_str(ctx
, 12), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2924 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2925 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2929 uint8_t SectorsCnt
= 1;
2931 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
2933 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
2935 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
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
;
2946 if (SectorsCnt
== 0) {
2947 PrintAndLogEx(WARNING
, "Invalid MIFARE Type");
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
2968 int numKeys
= keylen
/ 6;
2970 p
= realloc(keyBlock
, 6 * (keyitems
+ numKeys
));
2972 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
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));
2987 // Handle user supplied dictionary file
2992 int res
= searchFile(&dict_path
, DICTIONARIES_SUBDIR
, filename
, ".dic", false);
2993 if (res
!= PM3_SUCCESS
) {
2997 f
= fopen(dict_path
, "r");
2999 PrintAndLogEx(FAILED
, "File: " _YELLOW_("%s") ": not found or locked.", dict_path
);
3005 // load keys from dictionary file
3006 while (fgets(buf
, sizeof(buf
), f
)) {
3007 if (strlen(buf
) < 12 || buf
[11] == '\n')
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
);
3022 if (keyitems
- keycnt
< 2) {
3023 p
= realloc(keyBlock
, 6 * (keyitems
+= 64));
3025 PrintAndLogEx(FAILED
, "Cannot allocate memory for defKeys");
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));
3036 memset(buf
, 0, sizeof(buf
));
3039 PrintAndLogEx(SUCCESS
, "Loaded %2d keys from " _YELLOW_("%s"), keycnt
, filename
);
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
) {
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
);
3072 conn
.block_after_ACK
= true;
3074 // clear trace log by first check keys call only
3075 bool clearLog
= true;
3078 uint64_t t1
= msclock();
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
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
);
3095 if (kbd_enter_pressed()) {
3096 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
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;
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
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
;
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);
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);
3160 PrintAndLogEx(NORMAL
, "");
3161 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3164 if (SectorsCnt
== 1)
3165 printKeyTableEx(SectorsCnt
, e_sector
, GetSectorFromBlockNo(blockNo
));
3167 printKeyTable(SectorsCnt
, e_sector
);
3169 if (transferToEml
) {
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");
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
, "");
3215 void showSectorTable(sector_t
*k_sector
, uint8_t k_sectorsCount
) {
3216 if (k_sector
!= NULL
) {
3217 printKeyTable(k_sectorsCount
, k_sector
);
3222 void readerAttack(sector_t
*k_sector
, uint8_t k_sectorsCount
, nonces_t data
, bool setEmulatorMem
, bool verbose
) {
3225 bool success
= false;
3227 if (k_sector
== NULL
) {
3228 int32_t res
= initSectorTable(&k_sector
, k_sectorsCount
);
3229 if (res
!= k_sectorsCount
) {
3235 success
= mfkey32_moebius(&data
, &key
);
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"
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]"
3257 , sprint_hex(memBlock
, sizeof(memBlock
))
3259 mfEmlSetMem(memBlock
, (sector
* 4) + 3, 1);
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
[] = {
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"),
3295 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3300 uint8_t uid
[10] = {0};
3301 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
3303 char uidsize
[8] = {0};
3307 flags
|= FLAG_10B_UID_IN_DATA
;
3308 snprintf(uidsize
, sizeof(uidsize
), "10 byte");
3311 flags
|= FLAG_7B_UID_IN_DATA
;
3312 snprintf(uidsize
, sizeof(uidsize
), "7 byte");
3315 flags
|= FLAG_4B_UID_IN_DATA
;
3316 snprintf(uidsize
, sizeof(uidsize
), "4 byte");
3319 PrintAndLogEx(WARNING
, "Invalid parameter for UID");
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);
3331 uint8_t atqa
[2] = {0};
3332 CLIGetHexWithReturn(ctx
, 6, atqa
, &atqalen
);
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
;
3358 sector_t
*k_sector
= NULL
;
3363 PrintAndLogEx(WARNING
, "Wrong ATQA length");
3367 flags
|= FLAG_FORCED_ATQA
;
3371 PrintAndLogEx(WARNING
, "Wrong SAK length");
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");
3392 flags
|= FLAG_MF_MINI
;
3393 snprintf(csize
, sizeof(csize
), "MINI");
3394 k_sectorsCount
= MIFARE_MINI_MAXSECTOR
;
3396 flags
|= FLAG_MF_1K
;
3397 snprintf(csize
, sizeof(csize
), "1K");
3398 k_sectorsCount
= MIFARE_1K_MAXSECTOR
;
3400 flags
|= FLAG_MF_2K
;
3401 snprintf(csize
, sizeof(csize
), "2K with RATS");
3402 k_sectorsCount
= MIFARE_2K_MAXSECTOR
;
3404 flags
|= FLAG_MF_4K
;
3405 snprintf(csize
, sizeof(csize
), "4K");
3406 k_sectorsCount
= MIFARE_4K_MAXSECTOR
;
3408 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3412 PrintAndLogEx(INFO
, _YELLOW_("MIFARE %s") " | %s UID " _YELLOW_("%s") ""
3415 , (uidlen
== 0) ? "N/A" : sprint_hex(uid
, uidlen
)
3418 PrintAndLogEx(INFO
, "Options [ numreads: %d, flags: %d (0x%02x) ]"
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
);
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();
3468 blockNo = param_get8(Cmd, 0);
3471 cmdp = tolower(param_getchar(Cmd, 1));
3472 if (cmdp == 'b') keytype = MF_KEY_B;
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);
3482 PrintAndLogEx(FAILED, "key not found");
3484 t1 = msclock() - t1;
3485 PrintAndLogEx(SUCCESS, "\ntime in keybrute " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
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]
3519 // keep track if we use start_sector or i...
3520 uint8_t s
= start_sector
;
3521 if (start_sector
== 0)
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 "
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
[] = {
3562 arg_int1("b", "blk", "<dec>", "block number"),
3563 arg_lit0("v", "verbose", "verbose output"),
3566 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3567 int b
= arg_get_int_def(ctx
, 1, 0);
3568 bool verbose
= arg_get_lit(ctx
, 2);
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
);
3584 decode_print_st(blockno
, data
);
3586 PrintAndLogEx(NORMAL
, "");
3591 static int CmdHF14AMfEGetSc(const char *Cmd
) {
3592 CLIParserContext
*ctx
;
3593 CLIParserInit(&ctx
, "hf mf egetsc",
3594 "Get emulator memory sector",
3597 void *argtable
[] = {
3599 arg_int1("s", "sec", "<dec>", "sector number"),
3600 arg_lit0("v", "verbose", "verbose output"),
3603 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3604 int s
= arg_get_int_def(ctx
, 1, 0);
3605 bool verbose
= arg_get_lit(ctx
, 2);
3609 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
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
);
3627 decode_print_st(start
+ blocks
- 1, data
);
3629 PrintAndLogEx(NORMAL
, "");
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",
3640 void *argtable
[] = {
3644 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3646 clearCommandBuffer();
3647 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR
, NULL
, 0);
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
[] = {
3660 arg_int1("b", "blk", "<dec>", "block number"),
3661 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
3664 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
3666 int b
= arg_get_int_def(ctx
, 1, 0);
3668 uint8_t data
[16] = {0x00};
3670 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), data
, sizeof(data
), &datalen
);
3673 PrintAndLogEx(FAILED
, "Error parsing bytes");
3681 if (datalen
!= sizeof(data
)) {
3682 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", datalen
);
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
[] = {
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)"),
3709 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
3726 if ((m0
+ m1
+ m2
+ m4
+ mu
) > 1) {
3727 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3729 } else if ((m0
+ m1
+ m2
+ m4
+ mu
) == 0) {
3733 uint8_t block_width
= 16;
3734 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
3737 block_cnt
= MIFARE_MINI_MAXBLOCK
;
3739 block_cnt
= MIFARE_1K_MAXBLOCK
;
3741 block_cnt
= MIFARE_2K_MAXBLOCK
;
3743 block_cnt
= MIFARE_4K_MAXBLOCK
;
3748 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3752 PrintAndLogEx(INFO
, "%d blocks ( %u bytes ) to upload", block_cnt
, block_cnt
* block_width
);
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
;
3761 int res
= PM3_SUCCESS
;
3762 DumpFileType_t dftype
= getfiletype(filename
);
3765 res
= loadFile_safe(filename
, ".bin", (void **)&data
, &datalen
);
3769 res
= loadFileEML_safe(filename
, (void **)&data
, &datalen
);
3773 data
= calloc(MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
, sizeof(uint8_t));
3775 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
3778 res
= loadFileJSON(filename
, (void *)data
, MIFARE_4K_MAXBLOCK
* MFBLOCK_SIZE
, &datalen
, NULL
);
3782 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
3788 if (res
!= PM3_SUCCESS
) {
3793 // 64 or 256 blocks.
3794 if ((datalen
% block_width
) != 0) {
3795 PrintAndLogEx(FAILED
, "File content error. Size doesn't match blockwidth ");
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");
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
);
3821 conn
.block_after_ACK
= true;
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
);
3837 PrintAndLogEx(NORMAL
, "." NOLF
);
3841 offset
+= block_width
;
3842 datalen
-= block_width
;
3845 PrintAndLogEx(NORMAL
, "");
3847 if (block_width
== 4) {
3848 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mfu sim -h`"));
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
);
3855 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mf sim -h`"));
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
);
3862 PrintAndLogEx(INFO
, "Done!");
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) ",
3872 "hf mf esave --4k\n"
3873 "hf mf esave --4k -f hf-mf-01020304.eml"
3875 void *argtable
[] = {
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"),
3884 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
3897 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3898 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3900 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3904 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
3907 block_cnt
= MIFARE_MINI_MAXBLOCK
;
3909 block_cnt
= MIFARE_1K_MAXBLOCK
;
3911 block_cnt
= MIFARE_2K_MAXBLOCK
;
3913 block_cnt
= MIFARE_4K_MAXBLOCK
;
3916 int bytes
= block_cnt
* MFBLOCK_SIZE
;
3919 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
3921 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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");
3930 return PM3_ETIMEOUT
;
3933 // user supplied filename?
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
);
3947 static int CmdHF14AMfEView(const char *Cmd
) {
3949 CLIParserContext
*ctx
;
3950 CLIParserInit(&ctx
, "hf mf eview",
3951 "It displays emulator memory",
3955 void *argtable
[] = {
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"),
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);
3971 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3972 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3974 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3978 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
3981 block_cnt
= MIFARE_MINI_MAXBLOCK
;
3983 block_cnt
= MIFARE_1K_MAXBLOCK
;
3985 block_cnt
= MIFARE_2K_MAXBLOCK
;
3987 block_cnt
= MIFARE_4K_MAXBLOCK
;
3989 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3993 int bytes
= block_cnt
* MFBLOCK_SIZE
;
3995 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
3997 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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");
4006 return PM3_ETIMEOUT
;
4009 mf_print_blocks(block_cnt
, dump
);
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
[] = {
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"),
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)) {
4037 PrintAndLogEx(WARNING
, "Input key type must be A or B");
4039 } else if (arg_get_lit(ctx
, 2)) {
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);
4050 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4051 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4053 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4057 uint8_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4060 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
4062 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4064 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
4066 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4068 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4072 mfc_eload_t payload
= {
4073 .sectorcnt
= sectors_cnt
,
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.
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
[] = {
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"),
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);
4111 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4112 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4114 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4118 uint8_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4121 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
4123 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4125 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
4127 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4129 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
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
) {
4142 // read UID from EMUL
4144 if (mfEmlGetMem(data
, 0, 1) != PM3_SUCCESS
) {
4145 PrintAndLogEx(WARNING
, "error get block 0");
4150 // assuming 4byte UID.
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;
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);
4170 printKeyTable(sectors_cnt
, e_sector
);
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
);
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
[] = {
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"),
4203 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4205 uint8_t wipe_card
= arg_get_lit(ctx
, 1);
4208 uint8_t uid
[7] = {0x00};
4209 CLIGetHexWithReturn(ctx
, 2, uid
, &uidlen
);
4212 uint8_t atqa
[2] = {0x00};
4213 CLIGetHexWithReturn(ctx
, 3, atqa
, &alen
);
4216 uint8_t sak
[1] = {0x00};
4217 CLIGetHexWithReturn(ctx
, 4, sak
, &slen
);
4221 if (uidlen
!= 4 && uidlen
!= 7) {
4222 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
4225 if (alen
&& alen
!= 2) {
4226 PrintAndLogEx(FAILED
, "ATQA must be 2 hex bytes. Got %d", alen
);
4229 if (slen
&& slen
!= 1) {
4230 PrintAndLogEx(FAILED
, "SAK must be 1 hex byte. Got %d", slen
);
4234 uint8_t old_uid
[7] = {0};
4235 uint8_t verify_uid
[7] = {0};
4237 int res
= mfCSetUID(
4240 (alen
) ? atqa
: NULL
,
4241 (slen
) ? sak
: NULL
,
4248 PrintAndLogEx(ERR
, "Can't set UID. error %d", res
);
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")
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",
4268 "hf mf cwipe -u 09080706 -a 0004 -s 18 --> set UID, ATQA and SAK and wipe card");
4270 void *argtable
[] = {
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"),
4277 CLIExecWithReturn(ctx
, cmd
, argtable
, true);
4280 uint8_t uid
[8] = {0x00};
4281 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
4284 uint8_t atqa
[2] = {0x00};
4285 CLIGetHexWithReturn(ctx
, 2, atqa
, &alen
);
4288 uint8_t sak
[1] = {0x00};
4289 CLIGetHexWithReturn(ctx
, 3, sak
, &slen
);
4292 if (uidlen
&& uidlen
!= 4) {
4293 PrintAndLogEx(ERR
, "UID length must be 4 bytes, got %d", uidlen
);
4296 if (alen
&& alen
!= 2) {
4297 PrintAndLogEx(ERR
, "ATQA length must be 2 bytes, got %d", alen
);
4300 if (slen
&& slen
!= 1) {
4301 PrintAndLogEx(ERR
, "SAK length must be 1 byte, got %d", slen
);
4305 int res
= mfCWipe((uidlen
) ? uid
: NULL
, (alen
) ? atqa
: NULL
, (slen
) ? sak
: NULL
);
4307 PrintAndLogEx(ERR
, "Can't wipe card. error %d", res
);
4311 PrintAndLogEx(SUCCESS
, "Card wiped successfully");
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
[] = {
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"),
4329 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4331 int b
= arg_get_int_def(ctx
, 1, -1);
4333 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
4335 CLIGetHexWithReturn(ctx
, 2, data
, &datalen
);
4337 uint8_t wipe_card
= arg_get_lit(ctx
, 3);
4340 if (b
< 0 || b
>= MIFARE_1K_MAXBLOCK
) {
4341 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
4345 if (datalen
!= MFBLOCK_SIZE
) {
4346 PrintAndLogEx(FAILED
, "expected 16 bytes data, got %i", datalen
);
4350 uint8_t params
= MAGIC_SINGLE
;
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
);
4359 PrintAndLogEx(ERR
, "Can't write block. error=%d", res
);
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
[] = {
4376 arg_str1("f", "file", "<fn>", "filename of dump"),
4377 arg_lit0(NULL
, "emu", "from emulator memory"),
4380 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
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
++) {
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
);
4404 // switch on field and send magic sequence
4406 flags
= MAGIC_INIT
+ MAGIC_WUPC
;
4414 // Done. Magic Halt and switch off field.
4415 if (b
== ((MFBLOCK_SIZE
* 4) - 1)) {
4416 flags
= MAGIC_HALT
+ MAGIC_OFF
;
4420 if (mfCSetBlock(b
, buf8
, NULL
, flags
)) {
4421 PrintAndLogEx(WARNING
, "Can't set magic card block: %d", b
);
4424 PrintAndLogEx(NORMAL
, "." NOLF
);
4427 PrintAndLogEx(NORMAL
, "");
4431 uint8_t *data
= NULL
;
4432 size_t bytes_read
= 0;
4434 DumpFileType_t dftype
= getfiletype(filename
);
4437 res
= loadFile_safe(filename
, ".bin", (void **)&data
, &bytes_read
);
4441 res
= loadFileEML_safe(filename
, (void **)&data
, &bytes_read
);
4445 data
= calloc(MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
, sizeof(uint8_t));
4447 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
4450 res
= loadFileJSON(filename
, (void *)data
, MIFARE_4K_MAXBLOCK
* MFBLOCK_SIZE
, &bytes_read
, NULL
);
4454 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
4460 if (res
!= PM3_SUCCESS
) {
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
);
4473 PrintAndLogEx(INFO
, "Copying to magic gen1a card");
4474 PrintAndLogEx(INFO
, "." NOLF
);
4478 while (bytes_read
) {
4480 // switch on field and send magic sequence
4482 flags
= MAGIC_INIT
+ MAGIC_WUPC
;
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
);
4501 bytes_read
-= MFBLOCK_SIZE
;
4503 PrintAndLogEx(NORMAL
, "." NOLF
);
4508 // magic card type - mifare 1K
4509 if (blockno
>= MIFARE_1K_MAXBLOCK
) break;
4511 PrintAndLogEx(NORMAL
, "\n");
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
);
4521 PrintAndLogEx(ERR
, "File content error. There must be %d blocks", MIFARE_1K_MAXBLOCK
);
4525 PrintAndLogEx(SUCCESS
, "Card loaded %d blocks from file", blockno
);
4526 PrintAndLogEx(INFO
, "Done!");
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
[] = {
4540 arg_int1("b", "blk", "<dec>", "block number"),
4541 arg_lit0("v", "verbose", "verbose output"),
4544 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4545 int b
= arg_get_int_def(ctx
, 1, 0);
4546 bool verbose
= arg_get_lit(ctx
, 2);
4553 uint8_t blockno
= (uint8_t)b
;
4554 uint8_t data
[16] = {0};
4555 int res
= mfCGetBlock(blockno
, data
, MAGIC_SINGLE
);
4557 PrintAndLogEx(ERR
, "Can't read block. error=%d", res
);
4561 uint8_t sector
= GetSectorFromBlockNo(blockno
);
4562 mf_print_sector_hdr(sector
);
4563 mf_print_block(blockno
, data
);
4566 decode_print_st(blockno
, data
);
4568 PrintAndLogEx(NORMAL
, "");
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",
4580 void *argtable
[] = {
4582 arg_int1("s", "sec", "<dec>", "sector number"),
4583 arg_lit0("v", "verbose", "verbose output"),
4586 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4587 int s
= arg_get_int_def(ctx
, 1, 0);
4588 bool verbose
= arg_get_lit(ctx
, 2);
4591 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
4595 uint8_t sector
= (uint8_t)s
;
4596 mf_print_sector_hdr(sector
);
4599 uint8_t start
= sector
* 4;
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
);
4613 PrintAndLogEx(ERR
, "Can't read block. %d error=%d", start
+ i
, res
);
4616 mf_print_block(start
+ i
, data
);
4619 decode_print_st(start
+ blocks
- 1, data
);
4621 PrintAndLogEx(NORMAL
, "");
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",
4634 void *argtable
[] = {
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"),
4644 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
4658 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4659 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4661 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4666 memset(s
, 0, sizeof(s
));
4667 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4669 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4670 strncpy(s
, "Mini", 5);
4672 block_cnt
= MIFARE_1K_MAXBLOCK
;
4673 strncpy(s
, "1K", 3);
4675 block_cnt
= MIFARE_2K_MAXBLOCK
;
4676 strncpy(s
, "2K", 3);
4678 block_cnt
= MIFARE_4K_MAXBLOCK
;
4679 strncpy(s
, "4K", 3);
4681 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
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
;
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
;
4710 iso14a_card_select_t card
;
4711 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
4714 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
4715 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4717 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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
++) {
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");
4740 PrintAndLogEx(NORMAL
, "." NOLF
);
4743 PrintAndLogEx(NORMAL
, "");
4745 if (fill_emulator
) {
4746 PrintAndLogEx(INFO
, "uploading to emulator memory");
4747 PrintAndLogEx(INFO
, "." NOLF
);
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
);
4761 PrintAndLogEx(NORMAL
, "");
4762 PrintAndLogEx(SUCCESS
, "uploaded %d bytes to emulator memory", bytes
);
4765 // user supplied filename?
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
);
4779 static int CmdHF14AMfCView(const char *Cmd
) {
4781 CLIParserContext
*ctx
;
4782 CLIParserInit(&ctx
, "hf mf cview",
4783 "View `magic gen1a` card memory",
4787 void *argtable
[] = {
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"),
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);
4803 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4804 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4806 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4811 memset(s
, 0, sizeof(s
));
4812 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4814 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4815 strncpy(s
, "Mini", 5);
4817 block_cnt
= MIFARE_1K_MAXBLOCK
;
4818 strncpy(s
, "1K", 3);
4820 block_cnt
= MIFARE_2K_MAXBLOCK
;
4821 strncpy(s
, "2K", 3);
4823 block_cnt
= MIFARE_4K_MAXBLOCK
;
4824 strncpy(s
, "4K", 3);
4826 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
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
;
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
));
4858 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
4859 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4861 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
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
++) {
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");
4883 PrintAndLogEx(NORMAL
, "." NOLF
);
4887 PrintAndLogEx(NORMAL
, "");
4888 mf_print_blocks(block_cnt
, dump
);
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
[] = {
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"),
4910 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4913 int res
= arg_get_u32_hexstr_def(ctx
, 1, 0, &nt
);
4916 PrintAndLogEx(WARNING
, "check `nt` parameter");
4920 uint32_t ar_enc
= 0;
4921 res
= arg_get_u32_hexstr_def(ctx
, 2, 0, &ar_enc
);
4924 PrintAndLogEx(WARNING
, "check `ar` parameter");
4928 uint32_t at_enc
= 0;
4929 res
= arg_get_u32_hexstr_def(ctx
, 3, 0, &at_enc
);
4932 PrintAndLogEx(WARNING
, "check `at` parameter");
4937 uint8_t data
[512] = {0x00};
4938 CLIGetHexWithReturn(ctx
, 4, data
, &datalen
);
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
[] = {
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"),
4962 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4963 bool m0
= arg_get_lit(ctx
, 1);
4964 bool m1
= arg_get_lit(ctx
, 2);
4967 uint8_t key
[6] = {0};
4968 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
4972 PrintAndLogEx(WARNING
, "please select one modulation");
4976 uint8_t data
[7] = {0};
4977 memcpy(data
+ 1, key
, 6);
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") " )");
4996 PrintAndLogEx(FAILED
, "Change (" _GREEN_("fail") " )");
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",
5008 void *argtable
[] = {
5010 arg_lit0("v", "verbose", "verbose output`"),
5013 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5014 bool verbose
= arg_get_lit(ctx
, 1);
5018 PrintAndLogEx(INFO
, "Started testing card for NACK bug. Press Enter to abort");
5020 detect_classic_nackbug(verbose
);
5025 static int CmdHF14AMfice(const char *Cmd) {
5026 CLIParserContext *ctx;
5027 CLIParserInit(&ctx, "hf mf ice",
5028 "Collect MIFARE Classic nonces to file",
5030 "hf mf ice -f nonces.bin");
5032 void *argtable[] = {
5034 arg_str0("f", "file", "<filename>", "filename of nonce dump"),
5035 arg_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
5038 CLIExecWithReturn(ctx, Cmd, argtable, true);
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);
5051 if (filename[0] == '\0') {
5052 fptr = GenerateFilename("hf-mf-", "-nonces.bin");
5055 strcpy(filename, 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;
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);
5079 clearCommandBuffer();
5081 uint64_t t1 = msclock();
5084 if (kbd_enter_pressed()) {
5085 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
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);
5102 total_num_nonces += items;
5103 if (total_num_nonces > part_limit) {
5104 PrintAndLogEx(INFO, "Total nonces %u\n", total_num_nonces);
5108 acquisition_completed = (total_num_nonces > limit);
5112 } while (!acquisition_completed);
5115 PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000);
5122 clearCommandBuffer();
5123 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, NULL, 0);
5128 static int CmdHF14AMfAuth4(const char *Cmd
) {
5129 uint8_t keyn
[20] = {0};
5131 uint8_t key
[16] = {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
[] = {
5142 arg_str1(NULL
, NULL
, "<Key Num (HEX 2 bytes)>", NULL
),
5143 arg_str1(NULL
, NULL
, "<Key Value (HEX 16 bytes)>", NULL
),
5146 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5148 CLIGetHexWithReturn(ctx
, 1, keyn
, &keynlen
);
5149 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
5153 PrintAndLogEx(ERR
, "<Key Num> must be 2 bytes long instead of: %d", keynlen
);
5158 PrintAndLogEx(ERR
, "<Key Value> must be 16 bytes long instead of: %d", keylen
);
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
[] = {
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"),
5185 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5186 bool verbose
= arg_get_lit(ctx
, 1);
5187 uint8_t aid
[2] = {0};
5189 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
5190 uint8_t userkey
[6] = {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);
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");
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");
5216 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("OK") " )");
5221 // Both default and user supplied key failed
5222 if (got_first
== false) {
5226 PrintAndLogEx(NORMAL
, "");
5227 PrintAndLogEx(INFO
, "--- " _CYAN_("MIFARE App Directory Information") " ----------------");
5228 PrintAndLogEx(INFO
, "-----------------------------------------------------");
5230 bool haveMAD2
= false;
5231 MAD1DecodeAndPrint(sector0
, swapmad
, verbose
, &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");
5239 MAD2DecodeAndPrint(sector10
, swapmad
, verbose
);
5242 if (aidlen
== 2 || decodeholder
) {
5243 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
5245 if (MADDecode(sector0
, sector10
, mad
, &madlen
, swapmad
)) {
5246 PrintAndLogEx(ERR
, "can't decode MAD");
5250 // copy default NDEF key
5251 uint8_t akey
[6] = {0};
5252 memcpy(akey
, g_mifare_ndef_key
, 6);
5254 // user specified key
5256 memcpy(akey
, userkey
, 6);
5259 uint16_t aaid
= 0x0004;
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);
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));
5284 PrintAndLogEx(NORMAL
, "");
5285 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
5287 uint8_t data
[4096] = {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);
5300 memcpy(&data
[datalen
], vsector
, 16 * 3);
5306 PrintAndLogEx(WARNING
, "no Card Holder Info data");
5309 MADCardHolderInfoDecode(data
, datalen
, 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(§or0
[i
* 16], 16));
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
[] = {
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)"),
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};
5346 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
5347 uint8_t key
[6] = {0};
5349 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
5350 bool keyB
= arg_get_lit(ctx
, 4);
5354 uint16_t ndefAID
= 0xe103;
5356 ndefAID
= (aid
[0] << 8) + aid
[1];
5358 uint8_t ndefkey
[6] = {0};
5359 memcpy(ndefkey
, g_mifare_ndef_key
, 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};
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");
5378 bool haveMAD2
= false;
5379 int res
= MADCheck(sector0
, NULL
, verbose
, &haveMAD2
);
5380 if (res
!= PM3_SUCCESS
) {
5381 PrintAndLogEx(ERR
, "MAD error %d", res
);
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");
5396 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
5398 res
= MADDecode(sector0
, (haveMAD2
? sector10
: NULL
), mad
, &madlen
, false);
5399 if (res
!= PM3_SUCCESS
) {
5400 PrintAndLogEx(ERR
, "can't decode MAD");
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);
5413 memcpy(&data
[datalen
], vsector
, 16 * 3);
5416 PrintAndLogEx(INPLACE
, "%d", i
);
5419 PrintAndLogEx(NORMAL
, "");
5422 PrintAndLogEx(WARNING
, "no NDEF data");
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");
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
[] = {
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"),
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");
5472 uint8_t keytype
= 0;
5477 uint8_t key
[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
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");
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);
5492 uint8_t tmp
= f0
+ f1
+ f2
+ f3
;
5494 PrintAndLogEx(WARNING
, "select only one key type");
5498 PrintAndLogEx(WARNING
, "select one key type");
5502 uint8_t pers_option
= MIFARE_EV1_UIDF3
;
5504 pers_option
= MIFARE_EV1_UIDF0
;
5506 pers_option
= MIFARE_EV1_UIDF1
;
5508 pers_option
= MIFARE_EV1_UIDF2
;
5515 uint8_t pers_option
;
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"));
5532 PrintAndLogEx(FAILED
, "Personalization ( %s )", _RED_("fail"));
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
[] = {
5550 arg_str0("u", "uid", "<hex>", "UID 4/7 hex bytes"),
5553 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5555 uint8_t uid
[7] = {0};
5557 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
5561 if (uidlen
!= 4 && uidlen
!= 7) {
5562 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
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 ?");
5575 PrintAndLogEx(SUCCESS
, "Old UID... %s", sprint_hex(old_uid
, uidlen
));
5576 PrintAndLogEx(SUCCESS
, "New UID... %s", sprint_hex(uid
, uidlen
));
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"
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
[] = {
5597 arg_str0("d", "data", "<hex>", "manufacturer block data up to 16 hex bytes"),
5600 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5602 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
5604 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
5607 uint8_t new_block
[MFBLOCK_SIZE
] = {0x00};
5608 int res
= mfGen3Block(data
, datalen
, new_block
);
5610 PrintAndLogEx(ERR
, "Can't change manufacturer block data. error %d", res
);
5614 PrintAndLogEx(SUCCESS
, "Current block... %s", sprint_hex_inrow(new_block
, sizeof(new_block
)));
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
[] = {
5628 arg_lit1("y", "yes", "confirm UID lock operation"),
5631 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5632 bool confirm
= arg_get_lit(ctx
, 1);
5634 if (confirm
== false) {
5635 PrintAndLogEx(INFO
, "please confirm that you want to perma lock the card");
5639 int res
= mfGen3Freeze();
5640 if (res
!= PM3_SUCCESS
) {
5641 PrintAndLogEx(ERR
, "Can't lock UID changes. error %d", res
);
5643 PrintAndLogEx(SUCCESS
, "MFC Gen3 UID card is now perma-locked");
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`",
5661 void *argtable
[] = {
5663 arg_lit0("r", "reset", "reset card"),
5666 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5667 bool reset_card
= arg_get_lit(ctx
, 1);
5670 bool activate_field
= true;
5671 bool keep_field_on
= true;
5676 keep_field_on
= false;
5677 uint8_t response
[6];
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") " ]");
5688 PrintAndLogEx(SUCCESS
, "Super card reset [ " _GREEN_("ok") " ]");
5693 uint8_t responseA
[22];
5694 uint8_t responseB
[22];
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
) {
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
) {
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");
5740 if (memcmp(outB
, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
5741 PrintAndLogEx(INFO
, "Only one trace recorded");
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);
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];
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
);
5777 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ " _GREEN_("%12" PRIX64
) " ]"
5778 , sprint_hex_inrow(outA
, 4)
5780 , (data
.keytype
== 0x60) ? 'A' : 'B'
5783 PrintAndLogEx(FAILED
, "failed to recover any key");
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
[] = {
5802 arg_str0("f", "file", "<fn>", "key filename"),
5803 arg_lit0(NULL
, "gen2", "force write to Sector 0, block 0 (GEN2)"),
5806 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
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);
5816 if (keyfnlen
== 0) {
5817 fptr
= GenerateFilename("hf-mf-", "-key.bin");
5821 strcpy(keyFilename
, fptr
);
5827 if (loadFile_safeEx(keyFilename
, ".bin", (void **)&keys
, (size_t *)&keyslen
, false) != PM3_SUCCESS
) {
5828 PrintAndLogEx(FAILED
, "failed to load key file");
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
];
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
);
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
);
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
);
5864 PrintAndLogEx(INFO
, "wrong key file size");
5870 PrintAndLogEx(INFO
, "Forcing overwrite of sector 0 / block 0 ");
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) {
5890 memset(data
, 0, sizeof(data
));
5891 if (mfIsSectorTrailer(b
)) {
5892 memcpy(data
+ 10, st
, sizeof(st
));
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
--) {
5906 memcpy(data
, keyA
+ (s
* 6), 6);
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;
5917 PrintAndLogEx(NORMAL
, "( " _RED_("fail") " )");
5919 PrintAndLogEx(NORMAL
, "( " _GREEN_("ok") " )");
5923 PrintAndLogEx(WARNING
, "Command execute timeout");
5929 PrintAndLogEx(NORMAL
, "");
5930 PrintAndLogEx(INFO
, "Done!");
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
[] = {
5945 arg_str1("f", "file", "<fn>", "filename of dump"),
5946 arg_lit0("v", "verbose", "verbose output"),
5949 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
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);
5957 uint8_t *dump
= NULL
;
5958 size_t bytes_read
= 0;
5960 DumpFileType_t dftype
= getfiletype(filename
);
5963 res
= loadFile_safe(filename
, ".bin", (void **)&dump
, &bytes_read
);
5967 res
= loadFileEML_safe(filename
, (void **)&dump
, &bytes_read
);
5971 dump
= calloc(MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
, sizeof(uint8_t));
5973 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5976 res
= loadFileJSON(filename
, (void *)dump
, MIFARE_4K_MAXBLOCK
* MFBLOCK_SIZE
, &bytes_read
, NULL
);
5980 PrintAndLogEx(ERR
, "Error: Only BIN/JSON/EML formats allowed");
5986 if (res
!= PM3_SUCCESS
) {
5987 PrintAndLogEx(FAILED
, "File: " _YELLOW_("%s") ": not found or locked.", filename
);
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
;
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
);
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
);
6074 int CmdHFMF(const char *Cmd
) {
6075 clearCommandBuffer();
6076 return CmdsParse(CommandTable
, Cmd
);