1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // High frequency MIFARE commands
17 //-----------------------------------------------------------------------------
22 #include "bruteforce.h"
23 #include "cmdparser.h" // command_t
24 #include "commonutil.h" // ARRAYLEN
25 #include "comms.h" // clearCommandBuffer
26 #include "fileutils.h"
28 #include "mifare/mifaredefault.h" // mifare default key array
29 #include "cliparser.h" // argtable
30 #include "hardnested_bf_core.h" // SetSIMDInstr
31 #include "mifare/mad.h"
33 #include "protocols.h"
34 #include "util_posix.h" // msclock
35 #include "cmdhfmfhard.h"
36 #include "crapto1/crapto1.h" // prng_successor
37 #include "cmdhf14a.h" // exchange APDU
38 #include "crypto/libpcrypto.h"
39 #include "wiegand_formats.h"
40 #include "wiegand_formatutils.h"
41 #include "cmdhw.h" // set_fpga_mode
42 #include "loclass/cipherutils.h" // BitstreamOut_t
43 #include "proxendian.h"
44 #include "preferences.h"
45 #include "mifare/gen4.h"
46 #include "generator.h" // keygens.
49 static int CmdHelp(const char *Cmd
);
52 static int usage_hf14_keybrute(void) {
53 PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery");
54 PrintAndLogEx(NORMAL, "You have a known 4 last bytes of a key recovered with mf_nonce_brute tool.");
55 PrintAndLogEx(NORMAL, "First 2 bytes of key will be bruteforced");
56 PrintAndLogEx(NORMAL, "");
57 PrintAndLogEx(NORMAL, " ---[ This attack is obsolete, try hardnested instead ]---");
58 PrintAndLogEx(NORMAL, "Options:");
59 PrintAndLogEx(NORMAL, " h this help");
60 PrintAndLogEx(NORMAL, " <block number> target block number");
61 PrintAndLogEx(NORMAL, " <A|B> target key type");
62 PrintAndLogEx(NORMAL, " <key> candidate key from mf_nonce_brute tool");
63 PrintAndLogEx(NORMAL, "Examples:");
64 PrintAndLogEx(NORMAL, _YELLOW_(" hf mf keybrute --blk 1 -k 000011223344"));
69 int mfc_ev1_print_signature(uint8_t *uid
, uint8_t uidlen
, uint8_t *signature
, int signature_len
) {
71 // ref: MIFARE Classic EV1 Originality Signature Validation
72 #define PUBLIC_MFCEV1_ECDA_KEYLEN 33
73 const ecdsa_publickey_t nxp_mfc_public_keys
[] = {
74 {"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
75 {"MIFARE Classic / QL88", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
76 {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
77 {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
78 {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
79 {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
80 {"MIKRON Public key", "04F971EDA742A4A80D32DCF6A814A707CC3DC396D35902F72929FDCD698B3468F2"},
81 {"VivoKey Spark1 Public key", "04D64BB732C0D214E7EC580736ACF847284B502C25C0F7F2FA86AACE1DADA4387A"},
82 {"TruST25 (ST) key 01?", "041D92163650161A2548D33881C235D0FB2315C2C31A442F23C87ACF14497C0CBA"},
83 {"TruST25 (ST) key 04?", "04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},
87 bool is_valid
= false;
89 for (i
= 0; i
< ARRAYLEN(nxp_mfc_public_keys
); i
++) {
92 uint8_t key
[PUBLIC_MFCEV1_ECDA_KEYLEN
];
93 param_gethex_to_eol(nxp_mfc_public_keys
[i
].value
, 0, key
, PUBLIC_MFCEV1_ECDA_KEYLEN
, &dl
);
95 int res
= ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1
, key
, uid
, uidlen
, signature
, signature_len
, false);
96 is_valid
= (res
== 0);
101 PrintAndLogEx(INFO
, "");
102 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Signature"));
103 if (is_valid
== false || i
== ARRAYLEN(nxp_mfc_public_keys
)) {
104 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp128r1");
105 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 32));
106 PrintAndLogEx(SUCCESS
, " Signature verification: " _RED_("failed"));
110 PrintAndLogEx(INFO
, " IC signature public key name: " _GREEN_("%s"), nxp_mfc_public_keys
[i
].desc
);
111 PrintAndLogEx(INFO
, "IC signature public key value: %s", nxp_mfc_public_keys
[i
].value
);
112 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp128r1");
113 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 32));
114 PrintAndLogEx(SUCCESS
, " Signature verification: " _GREEN_("successful"));
118 static int mf_read_uid(uint8_t *uid
, int *uidlen
, int *nxptype
) {
119 clearCommandBuffer();
120 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
121 PacketResponseNG resp
;
122 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
123 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
128 iso14a_card_select_t card
;
129 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
132 uint64_t select_status
= resp
.oldarg
[0];
133 *nxptype
= detect_nxp_card(card
.sak
, ((card
.atqa
[1] << 8) + card
.atqa
[0]), select_status
);
136 memcpy(uid
, card
.uid
, card
.uidlen
* sizeof(uint8_t));
137 *uidlen
= card
.uidlen
;
141 static char *GenerateFilename(const char *prefix
, const char *suffix
) {
142 if (! IfPm3Iso14443a()) {
145 uint8_t uid
[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
147 char *fptr
= calloc(sizeof(char) * (strlen(prefix
) + strlen(suffix
)) + sizeof(uid
) * 2 + 1, sizeof(uint8_t));
149 int res
= mf_read_uid(uid
, &uidlen
, NULL
);
150 if (res
!= PM3_SUCCESS
|| !uidlen
) {
151 PrintAndLogEx(WARNING
, "No tag found.");
156 strcpy(fptr
, prefix
);
157 FillFileNameByUID(fptr
, uid
, suffix
, uidlen
);
161 static int initSectorTable(sector_t
**src
, size_t items
) {
163 (*src
) = calloc(items
, sizeof(sector_t
));
168 for (size_t i
= 0; i
< items
; i
++) {
169 for (uint8_t j
= 0; j
< 2; j
++) {
170 (*src
)[i
].Key
[j
] = 0xffffffffffff;
171 (*src
)[i
].foundKey
[j
] = 0;
177 static void decode_print_st(uint16_t blockno
, uint8_t *data
) {
178 if (mfIsSectorTrailer(blockno
)) {
179 PrintAndLogEx(NORMAL
, "");
180 PrintAndLogEx(INFO
, "-------------------------- " _CYAN_("Sector trailer decoder") " --------------------------");
181 PrintAndLogEx(INFO
, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data
, 6));
182 PrintAndLogEx(INFO
, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data
+ 6, 3));
183 PrintAndLogEx(INFO
, "user / gpb... " _GREEN_("%02x"), data
[9]);
184 PrintAndLogEx(INFO
, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data
+ 10, 6));
185 PrintAndLogEx(INFO
, "");
186 PrintAndLogEx(INFO
, " # | access rights");
187 PrintAndLogEx(INFO
, "----+-----------------------------------------------------------------------");
189 if (mfValidateAccessConditions(&data
[6]) == false) {
190 PrintAndLogEx(WARNING
, _RED_("Invalid Access Conditions"));
194 int bln
= mfFirstBlockOfSector(mfSectorNum(blockno
));
195 int blinc
= (mfNumBlocksPerSector(mfSectorNum(blockno
)) > 4) ? 5 : 1;
196 for (int i
= 0; i
< 4; i
++) {
197 PrintAndLogEx(INFO
, "%3d%c| " _YELLOW_("%s"), bln
, ((blinc
> 1) && (i
< 3) ? '+' : ' '), mfGetAccessConditionsDesc(i
, &data
[6]));
201 uint8_t cond
= mf_get_accesscondition(i
, &data
[6]);
202 if (cond
== 0 || cond
== 1 || cond
== 2) {
203 PrintAndLogEx(INFO
, "");
204 PrintAndLogEx(INFO
, "OBS! Key B is readable, it SHALL NOT be able to authenticate on original MFC");
210 PrintAndLogEx(INFO
, "----------------------------------------------------------------------------");
211 PrintAndLogEx(NORMAL
, "");
215 static uint8_t NumOfSectors(char card
) {
218 return MIFARE_MINI_MAXSECTOR
;
220 return MIFARE_1K_MAXSECTOR
;
222 return MIFARE_2K_MAXSECTOR
;
224 return MIFARE_4K_MAXSECTOR
;
230 static char GetFormatFromSector(uint8_t sectors
) {
232 case MIFARE_MINI_MAXSECTOR
:
234 case MIFARE_1K_MAXSECTOR
:
236 case MIFARE_2K_MAXSECTOR
:
238 case MIFARE_4K_MAXSECTOR
:
245 bool mfc_value(const uint8_t *d
, int32_t *val
) {
247 int32_t a
= (int32_t)MemLeToUint4byte(d
);
248 uint32_t a_inv
= MemLeToUint4byte(d
+ 4);
249 uint32_t b
= MemLeToUint4byte(d
+ 8);
252 (a
== b
) && (a
== ~a_inv
) &&
253 (d
[12] == (~d
[13] & 0xFF)) &&
254 (d
[14] == (~d
[15] & 0xFF))
263 void mf_print_block_one(uint8_t blockno
, uint8_t *d
, bool verbose
) {
266 char ascii
[24] = {0};
267 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
268 PrintAndLogEx(INFO
, "%3d | " _RED_("%s") "| " _RED_("%s"),
270 sprint_hex(d
, MFBLOCK_SIZE
),
273 } else if (mfIsSectorTrailer(blockno
)) {
276 hex_to_buffer((uint8_t *)keya
, d
, MIFARE_KEY_SIZE
, sizeof(keya
) - 1, 0, 1, true);
279 hex_to_buffer((uint8_t *)acl
, d
+ MIFARE_KEY_SIZE
, 3, sizeof(acl
) - 1, 0, 1, true);
282 hex_to_buffer((uint8_t *)keyb
, d
+ 10, MIFARE_KEY_SIZE
, sizeof(keyb
) - 1, 0, 1, true);
284 char ascii
[24] = {0};
285 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
287 PrintAndLogEx(INFO
, "%3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"),
298 if (verbose
&& mfc_value(d
, &value
)) {
299 PrintAndLogEx(INFO
, "%3d | " _CYAN_("%s") " %"PRIi32
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
), value
);
301 PrintAndLogEx(INFO
, "%3d | %s ", blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
));
306 static void mf_print_block(uint8_t blockno
, uint8_t *d
, bool verbose
) {
307 uint8_t sectorno
= mfSectorNum(blockno
);
309 char secstr
[6] = " ";
310 if (mfFirstBlockOfSector(sectorno
) == blockno
) {
311 sprintf(secstr
, " %3d ", sectorno
);
315 char ascii
[24] = {0};
316 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
317 PrintAndLogEx(INFO
, "%s| %3d | " _RED_("%s") "| " _RED_("%s"),
320 sprint_hex(d
, MFBLOCK_SIZE
),
324 } else if (mfIsSectorTrailer(blockno
)) {
327 hex_to_buffer((uint8_t *)keya
, d
, MIFARE_KEY_SIZE
, sizeof(keya
) - 1, 0, 1, true);
330 hex_to_buffer((uint8_t *)acl
, d
+ MIFARE_KEY_SIZE
, 3, sizeof(acl
) - 1, 0, 1, true);
333 hex_to_buffer((uint8_t *)keyb
, d
+ 10, MIFARE_KEY_SIZE
, sizeof(keyb
) - 1, 0, 1, true);
335 char ascii
[24] = {0};
336 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
338 PrintAndLogEx(INFO
, "%s| %3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"),
349 if (verbose
&& mfc_value(d
, &value
)) {
350 PrintAndLogEx(INFO
, "%s| %3d | " _CYAN_("%s") " %"PRIi32
, secstr
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
), value
);
352 PrintAndLogEx(INFO
, "%s| %3d | %s ", secstr
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
));
357 static void mf_print_blocks(uint16_t n
, uint8_t *d
, bool verbose
) {
358 PrintAndLogEx(NORMAL
, "");
359 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
360 PrintAndLogEx(INFO
, " sec | blk | data | ascii");
361 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
362 for (uint16_t i
= 0; i
< n
; i
++) {
363 mf_print_block(i
, d
+ (i
* MFBLOCK_SIZE
), verbose
);
365 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
367 PrintAndLogEx(HINT
, _CYAN_("cyan") " = value block with decoded value");
372 PrintAndLogEx(HINT
, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details");
374 PrintAndLogEx(NORMAL
, "");
377 // assumes n is in number of blocks 0..255
378 static int mf_print_keys(uint16_t n
, uint8_t *d
) {
381 case MIFARE_MINI_MAXBLOCK
:
382 sectors
= MIFARE_MINI_MAXSECTOR
;
384 case MIFARE_2K_MAXBLOCK
:
385 sectors
= MIFARE_2K_MAXSECTOR
;
387 case MIFARE_4K_MAXBLOCK
:
388 sectors
= MIFARE_4K_MAXSECTOR
;
390 case MIFARE_1K_MAXBLOCK
:
391 sectors
= MIFARE_1K_MAXSECTOR
;
394 sectors
= MIFARE_1K_MAXSECTOR
;
395 n
= MIFARE_1K_MAXBLOCK
;
399 sector_t
*e_sector
= calloc(sectors
, sizeof(sector_t
));
400 if (e_sector
== NULL
) {
404 for (uint16_t i
= 0; i
< n
; i
++) {
405 if (mfIsSectorTrailer(i
) == false) {
408 // zero based index...
409 uint8_t lookup
= mfSectorNum(i
);
410 uint8_t sec
= MIN(sectors
- 1, lookup
);
411 e_sector
[sec
].foundKey
[0] = 1;
412 e_sector
[sec
].Key
[0] = bytes_to_num(d
+ (i
* MFBLOCK_SIZE
), MIFARE_KEY_SIZE
);
413 e_sector
[sec
].foundKey
[1] = 1;
414 e_sector
[sec
].Key
[1] = bytes_to_num(d
+ (i
* MFBLOCK_SIZE
) + 10, MIFARE_KEY_SIZE
);
416 printKeyTable(sectors
, e_sector
);
421 // MFC dump , extract and save the keys to key file
422 // assumes n is in number of blocks 0..255
423 static int mf_save_keys_from_arr(uint16_t n
, uint8_t *d
) {
426 case MIFARE_MINI_MAXBLOCK
:
427 sectors
= MIFARE_MINI_MAXSECTOR
;
429 case MIFARE_2K_MAXBLOCK
:
430 sectors
= MIFARE_2K_MAXSECTOR
;
432 case MIFARE_4K_MAXBLOCK
:
433 sectors
= MIFARE_4K_MAXSECTOR
;
435 case MIFARE_1K_MAXBLOCK
:
437 sectors
= MIFARE_1K_MAXSECTOR
;
441 uint16_t keysize
= 2 * MIFARE_KEY_SIZE
* sectors
;
443 uint8_t *keys
= calloc(keysize
, sizeof(uint8_t));
449 for (uint16_t i
= 0; i
< n
; i
++) {
450 if (mfIsSectorTrailer(i
)) {
451 // key A offset in ST block
452 memcpy(keys
+ (MIFARE_KEY_SIZE
* sector
), d
+ (i
* MFBLOCK_SIZE
), MIFARE_KEY_SIZE
);
454 // key B offset in ST block
455 memcpy(keys
+ (MIFARE_KEY_SIZE
* sectors
) + (MIFARE_KEY_SIZE
* sector
), d
+ (i
* MFBLOCK_SIZE
) + 10, MIFARE_KEY_SIZE
);
461 char fn
[FILE_PATH_SIZE
] = {0};
462 snprintf(fn
, sizeof(fn
), "hf-mf-%s-key", sprint_hex_inrow(d
, 4));
463 saveFileEx(fn
, ".bin", keys
, keysize
, spDump
);
469 static void mf_print_values(uint16_t n, uint8_t *d) {
471 PrintAndLogEx(NORMAL, "");
472 PrintAndLogEx(INFO, "Looking for value blocks...");
473 PrintAndLogEx(NORMAL, "");
476 for (uint16_t i = 0; i < n; i++) {
478 if (mfc_value(d + (i * MFBLOCK_SIZE), &value)) {
479 PrintAndLogEx(INFO, "%03d | " _YELLOW_("%" PRIi32) " " _YELLOW_("0x%" PRIX32), i, value, value);
485 PrintAndLogEx(INFO, "Found %u value blocks in file", cnt);
486 PrintAndLogEx(NORMAL, "");
491 void mf_print_sector_hdr(uint8_t sector
) {
492 PrintAndLogEx(NORMAL
, "");
493 PrintAndLogEx(INFO
, " # | sector " _GREEN_("%02d") " / " _GREEN_("0x%02X") " | ascii", sector
, sector
);
494 PrintAndLogEx(INFO
, "----+-------------------------------------------------+-----------------");
497 static bool mf_write_block(const uint8_t *key
, uint8_t keytype
, uint8_t blockno
, uint8_t *block
) {
500 memcpy(data
, key
, MIFARE_KEY_SIZE
);
501 memcpy(data
+ 10, block
, MFBLOCK_SIZE
);
503 clearCommandBuffer();
504 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, keytype
, 0, data
, sizeof(data
));
505 PacketResponseNG resp
;
506 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
507 PrintAndLogEx(FAILED
, "command execution time out");
511 return ((resp
.oldarg
[0] & 0xff) == 1);
514 // assumes n is in number of blocks 0..255
515 static void mf_analyse_acl(uint16_t n
, uint8_t *d
) {
517 for (uint16_t b
= 3; b
< n
; b
++) {
518 if (mfIsSectorTrailer(b
) == false) {
522 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
523 memcpy(block
, d
+ (b
* MFBLOCK_SIZE
), MFBLOCK_SIZE
);
525 // ensure access right isn't messed up.
526 if (mfValidateAccessConditions(&block
[6]) == false) {
527 PrintAndLogEx(WARNING
, "Invalid Access Conditions on sector " _YELLOW_("%u"), mfSectorNum(b
));
530 // Warn if ACL is strict read-only
531 uint8_t bar
= mfNumBlocksPerSector(mfSectorNum(b
));
532 for (uint8_t foo
= 0; foo
< bar
; foo
++) {
533 if (mfReadOnlyAccessConditions(foo
, &block
[6])) {
534 PrintAndLogEx(WARNING
, _YELLOW_("s%u / b%u") " - Strict ReadOnly Access Conditions detected", mfSectorNum(b
), b
- bar
+ 1 + foo
);
541 Sector trailer sanity checks.
542 Warn if ACL is strict read-only, or invalid ACL.
544 static int mf_analyse_st_block(uint8_t blockno
, uint8_t *block
, bool force
) {
546 if (mfIsSectorTrailer(blockno
) == false) {
550 PrintAndLogEx(INFO
, "Sector trailer (ST) write detected");
552 // ensure access right isn't messed up.
553 if (mfValidateAccessConditions(&block
[6]) == false) {
554 PrintAndLogEx(WARNING
, "Invalid Access Conditions detected, replacing with default values");
555 memcpy(block
+ 6, "\xFF\x07\x80\x69", 4);
558 bool ro_detected
= false;
559 uint8_t bar
= mfNumBlocksPerSector(mfSectorNum(blockno
));
560 for (uint8_t foo
= 0; foo
< bar
; foo
++) {
561 if (mfReadOnlyAccessConditions(foo
, &block
[6])) {
562 PrintAndLogEx(WARNING
, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno
- bar
+ 1 + foo
);
568 PrintAndLogEx(WARNING
, " --force override, continuing...");
570 PrintAndLogEx(INFO
, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block
[6], 3));
571 PrintAndLogEx(INFO
, "Use `" _YELLOW_("--force") "` to override and write this data");
575 PrintAndLogEx(SUCCESS
, "ST checks ( " _GREEN_("ok") " )");
581 /* Reads data from tag
582 * @param card: (output) card info
583 * @param carddata: (output) card data
584 * @param numSectors: size of the card
585 * @param keyFileName: filename containing keys or NULL.
587 static int mfc_read_tag(iso14a_card_select_t
*card
, uint8_t *carddata
, uint8_t numSectors
, char *keyfn
) {
589 // Select card to get UID/UIDLEN/ATQA/SAK information
590 clearCommandBuffer();
591 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
592 PacketResponseNG resp
;
593 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
594 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
598 uint64_t select_status
= resp
.oldarg
[0];
599 if (select_status
== 0) {
600 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
605 memcpy(card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
608 if (keyfn
== NULL
|| keyfn
[0] == '\0') {
609 fptr
= GenerateFilename("hf-mf-", "-key.bin");
616 PrintAndLogEx(INFO
, "Using... %s", keyfn
);
618 size_t alen
= 0, blen
= 0;
619 uint8_t *keyA
, *keyB
;
620 if (loadFileBinaryKey(keyfn
, "", (void **)&keyA
, (void **)&keyB
, &alen
, &blen
) != PM3_SUCCESS
) {
625 PrintAndLogEx(INFO
, "Reading sector access bits...");
626 PrintAndLogEx(INFO
, "." NOLF
);
628 uint8_t rights
[40][4] = {0};
630 mf_readblock_t payload
;
632 for (uint8_t sectorNo
= 0; sectorNo
< numSectors
; sectorNo
++) {
633 current_key
= MF_KEY_A
;
634 for (uint8_t tries
= 0; tries
< MIFARE_SECTOR_RETRY
; tries
++) {
635 PrintAndLogEx(NORMAL
, "." NOLF
);
638 if (kbd_enter_pressed()) {
639 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
643 return PM3_EOPABORTED
;
646 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + mfNumBlocksPerSector(sectorNo
) - 1;
647 payload
.keytype
= current_key
;
649 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
651 clearCommandBuffer();
652 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
654 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) {
656 uint8_t *data
= resp
.data
.asBytes
;
657 if (resp
.status
== PM3_SUCCESS
) {
658 rights
[sectorNo
][0] = ((data
[7] & 0x10) >> 2) | ((data
[8] & 0x1) << 1) | ((data
[8] & 0x10) >> 4); // C1C2C3 for data area 0
659 rights
[sectorNo
][1] = ((data
[7] & 0x20) >> 3) | ((data
[8] & 0x2) << 0) | ((data
[8] & 0x20) >> 5); // C1C2C3 for data area 1
660 rights
[sectorNo
][2] = ((data
[7] & 0x40) >> 4) | ((data
[8] & 0x4) >> 1) | ((data
[8] & 0x40) >> 6); // C1C2C3 for data area 2
661 rights
[sectorNo
][3] = ((data
[7] & 0x80) >> 5) | ((data
[8] & 0x8) >> 2) | ((data
[8] & 0x80) >> 7); // C1C2C3 for sector trailer
663 } else if (tries
== (MIFARE_SECTOR_RETRY
/ 2)) { // after half unsuccessful tries, give key B a go
664 PrintAndLogEx(WARNING
, "\nTrying with " _YELLOW_("key B") " instead...");
665 current_key
= MF_KEY_B
;
666 PrintAndLogEx(INFO
, "." NOLF
);
667 } else if (tries
== (MIFARE_SECTOR_RETRY
- 1)) { // on last try set defaults
668 PrintAndLogEx(FAILED
, "\nFailed to read access rights for sector %2d ( fallback to default )", sectorNo
);
669 rights
[sectorNo
][0] = rights
[sectorNo
][1] = rights
[sectorNo
][2] = 0x00;
670 rights
[sectorNo
][3] = 0x01;
673 PrintAndLogEx(FAILED
, "\nTimeout reading access rights for sector... %2d ( fallback to default )", sectorNo
);
674 rights
[sectorNo
][0] = rights
[sectorNo
][1] = rights
[sectorNo
][2] = 0x00;
675 rights
[sectorNo
][3] = 0x01;
680 PrintAndLogEx(NORMAL
, "");
681 PrintAndLogEx(SUCCESS
, "Finished reading sector access bits");
682 PrintAndLogEx(INFO
, "Dumping all blocks from card...");
684 for (uint8_t sectorNo
= 0; sectorNo
< numSectors
; sectorNo
++) {
685 for (uint8_t blockNo
= 0; blockNo
< mfNumBlocksPerSector(sectorNo
); blockNo
++) {
686 bool received
= false;
687 current_key
= MF_KEY_A
;
688 uint8_t data_area
= (sectorNo
< 32) ? blockNo
: blockNo
/ 5;
689 if (rights
[sectorNo
][data_area
] == 0x07) { // no key would work
690 PrintAndLogEx(WARNING
, "Access rights prevent reading sector... " _YELLOW_("%2d") " block... " _YELLOW_("%3d") " ( skip )", sectorNo
, blockNo
);
694 for (uint8_t tries
= 0; tries
< MIFARE_SECTOR_RETRY
; tries
++) {
696 if (mfIsSectorTrailerBasedOnBlocks(sectorNo
, blockNo
)) {
698 // sector trailer. At least the Access Conditions can always be read with key A.
699 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
700 payload
.keytype
= current_key
;
701 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
703 clearCommandBuffer();
704 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
705 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
707 // data block. Check if it can be read with key A or key B
708 if ((rights
[sectorNo
][data_area
] == 0x03) || (rights
[sectorNo
][data_area
] == 0x05)) {
709 // only key B would work
710 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
711 payload
.keytype
= MF_KEY_B
;
712 memcpy(payload
.key
, keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
714 clearCommandBuffer();
715 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
716 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
719 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
720 payload
.keytype
= current_key
;
721 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
723 clearCommandBuffer();
724 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
725 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
730 if (resp
.status
== PM3_SUCCESS
) {
731 // break the re-try loop
734 if ((current_key
== MF_KEY_A
) && (tries
== (MIFARE_SECTOR_RETRY
/ 2))) {
735 // Half the tries failed with key A. Swap for key B
736 current_key
= MF_KEY_B
;
738 // clear out keyA since it failed.
739 memset(keyA
+ (sectorNo
* MIFARE_KEY_SIZE
), 0x00, MIFARE_KEY_SIZE
);
746 if (resp
.status
== PM3_SUCCESS
) {
748 uint8_t *data
= resp
.data
.asBytes
;
750 if (mfIsSectorTrailerBasedOnBlocks(sectorNo
, blockNo
)) {
751 // sector trailer. Fill in the keys.
752 memcpy(data
, keyA
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
753 memcpy(data
+ 10, keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
756 memcpy(carddata
+ (MFBLOCK_SIZE
* (mfFirstBlockOfSector(sectorNo
) + blockNo
)), data
, MFBLOCK_SIZE
);
757 PrintAndLogEx(INPLACE
, "Sector... " _YELLOW_("%2d") " block..." _YELLOW_("%2d") " ( " _GREEN_("ok") " )", sectorNo
, blockNo
);
759 PrintAndLogEx(FAILED
, "\nSector... %2d Block... %2d ( " _RED_("fail") " )", sectorNo
, blockNo
);
762 PrintAndLogEx(WARNING
, "Timeout reading sector... %2d block... %2d", sectorNo
, blockNo
);
770 PrintAndLogEx(SUCCESS
, "\nSucceeded in dumping all blocks");
774 static int mf_load_keys(uint8_t **pkeyBlock
, uint32_t *pkeycnt
, uint8_t *userkey
, int userkeylen
, const char *filename
, int fnlen
, bool load_default
) {
779 // Handle user supplied key
780 // (it considers *pkeycnt and *pkeyBlock as possibly non-null so logic can be easily reordered)
781 if (userkeylen
>= MIFARE_KEY_SIZE
) {
782 int numKeys
= userkeylen
/ MIFARE_KEY_SIZE
;
783 p
= realloc(*pkeyBlock
, numKeys
* MIFARE_KEY_SIZE
);
785 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
791 memcpy(*pkeyBlock
, userkey
, numKeys
* MIFARE_KEY_SIZE
);
793 for (int i
= 0; i
< numKeys
; i
++) {
794 PrintAndLogEx(DEBUG
, _YELLOW_("%2d") " - %s", i
, sprint_hex(*pkeyBlock
+ i
* MIFARE_KEY_SIZE
, MIFARE_KEY_SIZE
));
797 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%2d") " user keys", numKeys
);
801 // Handle default keys
802 p
= realloc(*pkeyBlock
, (*pkeycnt
+ ARRAYLEN(g_mifare_default_keys
)) * MIFARE_KEY_SIZE
);
804 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
809 // Copy default keys to list
810 for (int i
= 0; i
< ARRAYLEN(g_mifare_default_keys
); i
++) {
811 num_to_bytes(g_mifare_default_keys
[i
], MIFARE_KEY_SIZE
, (uint8_t *)(*pkeyBlock
+ (*pkeycnt
+ i
) * MIFARE_KEY_SIZE
));
812 PrintAndLogEx(DEBUG
, _YELLOW_("%2d") " - %s", *pkeycnt
+ i
, sprint_hex(*pkeyBlock
+ (*pkeycnt
+ i
) * MIFARE_KEY_SIZE
, MIFARE_KEY_SIZE
));
814 *pkeycnt
+= ARRAYLEN(g_mifare_default_keys
);
815 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%zu") " keys from hardcoded default array", ARRAYLEN(g_mifare_default_keys
));
818 // Handle user supplied dictionary file
820 uint32_t loaded_numKeys
= 0;
821 uint8_t *keyBlock_tmp
= NULL
;
822 int res
= loadFileDICTIONARY_safe(filename
, (void **) &keyBlock_tmp
, MIFARE_KEY_SIZE
, &loaded_numKeys
);
823 if (res
!= PM3_SUCCESS
|| loaded_numKeys
== 0 || keyBlock_tmp
== NULL
) {
824 PrintAndLogEx(FAILED
, "An error occurred while loading the dictionary!");
829 p
= realloc(*pkeyBlock
, (*pkeycnt
+ loaded_numKeys
) * MIFARE_KEY_SIZE
);
831 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
837 memcpy(*pkeyBlock
+ *pkeycnt
* MIFARE_KEY_SIZE
, keyBlock_tmp
, loaded_numKeys
* MIFARE_KEY_SIZE
);
838 *pkeycnt
+= loaded_numKeys
;
845 static int CmdHF14AMfAcl(const char *Cmd
) {
846 CLIParserContext
*ctx
;
847 CLIParserInit(&ctx
, "hf mf acl",
848 "Print decoded MIFARE access rights (ACL), \n"
851 " AB = both key A and B\n"
852 " ACCESS = access bytes inside sector trailer block\n"
853 " Increment, decrement, transfer, restore is for value blocks",
855 "hf mf acl -d FF0780\n");
859 arg_str1("d", "data", "<hex>", "ACL bytes specified as 3 hex bytes"),
862 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
865 uint8_t acl
[3] = {0};
866 CLIGetHexWithReturn(ctx
, 1, acl
, &acllen
);
870 PrintAndLogEx(NORMAL
, "");
872 // look up common default ACL bytes and print a fingerprint line about it.
873 if (memcmp(acl
, "\xFF\x07\x80", 3) == 0) {
874 PrintAndLogEx(INFO
, "ACL... " _GREEN_("%s") " (transport configuration)", sprint_hex(acl
, sizeof(acl
)));
876 if (mfValidateAccessConditions(acl
) == false) {
877 PrintAndLogEx(ERR
, _RED_("Invalid Access Conditions, NEVER write these on a card!"));
879 PrintAndLogEx(NORMAL
, "");
880 PrintAndLogEx(INFO
, " # | Access rights");
881 PrintAndLogEx(INFO
, "----+-----------------------------------------------------------------");
882 for (int i
= 0; i
< 4; i
++) {
883 PrintAndLogEx(INFO
, "%3d | " _YELLOW_("%s"), i
, mfGetAccessConditionsDesc(i
, acl
));
885 PrintAndLogEx(NORMAL
, "");
889 static int CmdHF14AMfDarkside(const char *Cmd
) {
890 CLIParserContext
*ctx
;
891 CLIParserInit(&ctx
, "hf mf darkside",
894 "hf mf darkside --blk 16\n"
895 "hf mf darkside --blk 16 -b\n");
899 arg_int0(NULL
, "blk", "<dec> ", "Target block"),
900 arg_lit0("b", NULL
, "Target key B instead of default key A"),
901 arg_int0("c", NULL
, "<dec>", "Target Auth 6x"),
904 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
906 uint8_t blockno
= arg_get_u32_def(ctx
, 1, 0) & 0xFF;
907 uint8_t key_type
= MIFARE_AUTH_KEYA
;
909 if (arg_get_lit(ctx
, 2)) {
910 PrintAndLogEx(INFO
, "Targeting key B");
911 key_type
= MIFARE_AUTH_KEYB
;
914 uint8_t ctype
= arg_get_u32_def(ctx
, 3, 0) & 0xFF;
915 if ((ctype
& 0x60) == 0x60) {
922 uint64_t t1
= msclock();
923 int ret
= mfDarkside(blockno
, key_type
, &key
);
926 if (ret
!= PM3_SUCCESS
) return ret
;
928 PrintAndLogEx(SUCCESS
, "found valid key: " _GREEN_("%012" PRIx64
), key
);
929 PrintAndLogEx(SUCCESS
, "time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
933 static int CmdHF14AMfWrBl(const char *Cmd
) {
935 CLIParserContext
*ctx
;
936 CLIParserInit(&ctx
, "hf mf wrbl",
937 "Write MIFARE Classic block with 16 hex bytes of data\n"
939 "Sector 0 / Block 0 - Manufacturer block\n"
940 "When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA)\n"
941 "Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. \n"
942 "Look in the magic_cards_notes.md file for help to resolve it.\n"
944 "`--force` param is used to override warnings like bad ACL and BLOCK 0 writes.\n"
945 " if not specified, it will exit if detected",
946 "hf mf wrbl --blk 1 -d 000102030405060708090a0b0c0d0e0f\n"
947 "hf mf wrbl --blk 1 -k A0A1A2A3A4A5 -d 000102030405060708090a0b0c0d0e0f\n"
951 arg_int1(NULL
, "blk", "<dec>", "block number"),
952 arg_lit0("a", NULL
, "input key type is key A (def)"),
953 arg_lit0("b", NULL
, "input key type is key B"),
954 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
955 arg_lit0(NULL
, "force", "override warnings"),
956 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
957 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
960 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
962 int b
= arg_get_int_def(ctx
, 1, 1);
964 uint8_t keytype
= MF_KEY_A
;
965 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
967 PrintAndLogEx(WARNING
, "Choose one single input key type");
969 } else if (arg_get_lit(ctx
, 3)) {
972 uint8_t prev_keytype
= keytype
;
973 keytype
= arg_get_int_def(ctx
, 4, keytype
);
974 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
976 PrintAndLogEx(WARNING
, "Choose one single input key type");
979 bool force
= arg_get_lit(ctx
, 5);
982 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
983 CLIGetHexWithReturn(ctx
, 6, key
, &keylen
);
985 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
987 CLIGetHexWithReturn(ctx
, 7, block
, &blen
);
990 if (keylen
&& keylen
!= 6) {
991 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
995 if (blen
!= MFBLOCK_SIZE
) {
996 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", blen
);
1004 // BLOCK 0 detection
1005 if (b
== 0 && force
== false) {
1006 PrintAndLogEx(NORMAL
, "");
1007 PrintAndLogEx(INFO
, "Targeting Sector 0 / Block 0 - Manufacturer block");
1008 PrintAndLogEx(INFO
, "Read the helptext for details before writing to this block");
1009 PrintAndLogEx(INFO
, "You must use param `" _YELLOW_("--force") "` to write to this block");
1010 PrintAndLogEx(NORMAL
, "");
1014 uint8_t blockno
= (uint8_t)b
;
1016 if (mf_analyse_st_block(blockno
, block
, force
) != PM3_SUCCESS
) {
1020 PrintAndLogEx(INFO
, "Writing block no %d, key %c - %s", blockno
, (keytype
== MF_KEY_B
) ? 'B' : 'A', sprint_hex_inrow(key
, sizeof(key
)));
1021 PrintAndLogEx(INFO
, "data: %s", sprint_hex(block
, sizeof(block
)));
1024 memcpy(data
, key
, sizeof(key
));
1025 memcpy(data
+ 10, block
, sizeof(block
));
1026 clearCommandBuffer();
1027 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, keytype
, 0, data
, sizeof(data
));
1029 PacketResponseNG resp
;
1030 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1031 PrintAndLogEx(FAILED
, "command execution time out");
1032 return PM3_ETIMEOUT
;
1035 int status
= resp
.oldarg
[0];
1037 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
1038 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf rdbl") "` to verify");
1039 } else if (status
== PM3_ETEAROFF
) {
1042 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
1043 // suggest the opposite keytype than what was used.
1044 PrintAndLogEx(HINT
, "Maybe access rights? Try specify keytype `" _YELLOW_("hf mf wrbl -%c ...") "` instead", (keytype
== MF_KEY_A
) ? 'b' : 'a');
1049 static int CmdHF14AMfRdBl(const char *Cmd
) {
1050 CLIParserContext
*ctx
;
1051 CLIParserInit(&ctx
, "hf mf rdbl",
1052 "Read MIFARE Classic block",
1053 "hf mf rdbl --blk 0\n"
1054 "hf mf rdbl --blk 0 -k A0A1A2A3A4A5\n"
1055 "hf mf rdbl --blk 3 -v -> get block 3, decode sector trailer\n"
1057 void *argtable
[] = {
1059 arg_int1(NULL
, "blk", "<dec>", "block number"),
1060 arg_lit0("a", NULL
, "input key type is key A (def)"),
1061 arg_lit0("b", NULL
, "input key type is key B"),
1062 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1063 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
1064 arg_lit0("v", "verbose", "verbose output"),
1067 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1068 int b
= arg_get_int_def(ctx
, 1, 0);
1070 uint8_t keytype
= MF_KEY_A
;
1071 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
1073 PrintAndLogEx(WARNING
, "Choose one single input key type");
1075 } else if (arg_get_lit(ctx
, 3)) {
1078 keytype
= arg_get_int_def(ctx
, 4, keytype
);
1079 uint8_t prev_keytype
= keytype
;
1080 keytype
= arg_get_int_def(ctx
, 4, keytype
);
1081 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
1083 PrintAndLogEx(WARNING
, "Choose one single input key type");
1088 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1089 CLIGetHexWithReturn(ctx
, 5, key
, &keylen
);
1090 bool verbose
= arg_get_lit(ctx
, 6);
1093 if (keylen
&& keylen
!= 6) {
1094 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
1101 uint8_t blockno
= (uint8_t)b
;
1103 uint8_t data
[16] = {0};
1104 int res
= mfReadBlock(blockno
, keytype
, key
, data
);
1105 if (res
== PM3_SUCCESS
) {
1107 uint8_t sector
= mfSectorNum(blockno
);
1108 mf_print_sector_hdr(sector
);
1109 mf_print_block_one(blockno
, data
, verbose
);
1111 decode_print_st(blockno
, data
);
1114 PrintAndLogEx(NORMAL
, "");
1118 static int CmdHF14AMfRdSc(const char *Cmd
) {
1120 CLIParserContext
*ctx
;
1121 CLIParserInit(&ctx
, "hf mf rdsc",
1122 "Read MIFARE Classic sector",
1124 "hf mf rdsc -s 0 -k A0A1A2A3A4A5\n"
1126 void *argtable
[] = {
1128 arg_lit0("a", NULL
, "input key specified is A key (def)"),
1129 arg_lit0("b", NULL
, "input key specified is B key"),
1130 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1131 arg_str0("k", "key", "<hex>", "key specified as 6 hex bytes"),
1132 arg_int1("s", "sec", "<dec>", "sector number"),
1133 arg_lit0("v", "verbose", "verbose output"),
1136 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1137 uint8_t keytype
= MF_KEY_A
;
1138 if (arg_get_lit(ctx
, 1) && arg_get_lit(ctx
, 2)) {
1140 PrintAndLogEx(WARNING
, "Choose one single input key type");
1142 } else if (arg_get_lit(ctx
, 2)) {
1145 uint8_t prev_keytype
= keytype
;
1146 keytype
= arg_get_int_def(ctx
, 3, keytype
);
1147 if ((arg_get_lit(ctx
, 1) || arg_get_lit(ctx
, 2)) && (keytype
!= prev_keytype
)) {
1149 PrintAndLogEx(WARNING
, "Choose one single input key type");
1154 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1155 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
1157 int s
= arg_get_int_def(ctx
, 5, 0);
1158 bool verbose
= arg_get_lit(ctx
, 6);
1161 if (keylen
&& keylen
!= 6) {
1162 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
1166 if (s
>= MIFARE_4K_MAXSECTOR
) {
1167 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
1171 uint8_t sector
= (uint8_t)s
;
1172 uint16_t sc_size
= mfNumBlocksPerSector(sector
) * MFBLOCK_SIZE
;
1174 uint8_t *data
= calloc(sc_size
, sizeof(uint8_t));
1176 PrintAndLogEx(ERR
, "failed to allocate memory");
1180 int res
= mfReadSector(sector
, keytype
, key
, data
);
1181 if (res
== PM3_SUCCESS
) {
1183 uint8_t blocks
= mfNumBlocksPerSector(sector
);
1184 uint8_t start
= mfFirstBlockOfSector(sector
);
1186 mf_print_sector_hdr(sector
);
1187 for (int i
= 0; i
< blocks
; i
++) {
1188 mf_print_block_one(start
+ i
, data
+ (i
* MFBLOCK_SIZE
), verbose
);
1192 decode_print_st(start
+ blocks
- 1, data
+ ((blocks
- 1) * MFBLOCK_SIZE
));
1196 PrintAndLogEx(NORMAL
, "");
1200 static int FastDumpWithEcFill(uint8_t numsectors
) {
1202 uint8_t dbg_curr
= DBG_NONE
;
1203 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
1208 if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) {
1213 mfc_eload_t payload
;
1214 payload
.sectorcnt
= numsectors
;
1215 payload
.keytype
= MF_KEY_A
;
1218 clearCommandBuffer();
1219 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
1221 PacketResponseNG resp
;
1222 bool res
= WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 2500);
1224 PrintAndLogEx(WARNING
, "command execution time out");
1225 return PM3_ETIMEOUT
;
1228 if (resp
.status
!= PM3_SUCCESS
) {
1229 PrintAndLogEx(FAILED
, "fast dump reported back failure w KEY A, swapping to KEY B");
1232 payload
.keytype
= MF_KEY_B
;
1234 clearCommandBuffer();
1235 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
1236 res
= WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 2500);
1238 PrintAndLogEx(WARNING
, "command execution time out");
1239 setDeviceDebugLevel(dbg_curr
, false);
1240 return PM3_ETIMEOUT
;
1243 if (resp
.status
!= PM3_SUCCESS
) {
1244 PrintAndLogEx(FAILED
, "fast dump reported back failure w KEY B");
1245 PrintAndLogEx(FAILED
, "Dump file is " _RED_("PARTIAL") " complete");
1249 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
1256 static int CmdHF14AMfDump(const char *Cmd
) {
1257 CLIParserContext
*ctx
;
1258 CLIParserInit(&ctx
, "hf mf dump",
1259 "Dump MIFARE Classic tag to file (bin/json)\n"
1260 "If no <name> given, UID will be used as filename",
1261 "hf mf dump --mini --> MIFARE Mini\n"
1262 "hf mf dump --1k --> MIFARE Classic 1k\n"
1263 "hf mf dump --2k --> MIFARE 2k\n"
1264 "hf mf dump --4k --> MIFARE 4k\n"
1265 "hf mf dump --keys hf-mf-066C8B78-key.bin --> MIFARE 1k with keys from specified file\n");
1267 void *argtable
[] = {
1269 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
1270 arg_str0("k", "keys", "<fn>", "filename of keys"),
1271 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1272 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
1273 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1274 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1275 arg_lit0(NULL
, "ns", "no save to file"),
1276 arg_lit0("v", "verbose", "verbose output"),
1279 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1282 char dataFilename
[FILE_PATH_SIZE
] = {0};
1283 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)dataFilename
, FILE_PATH_SIZE
, &datafnlen
);
1286 char keyFilename
[FILE_PATH_SIZE
] = {0};
1287 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
1289 bool m0
= arg_get_lit(ctx
, 3);
1290 bool m1
= arg_get_lit(ctx
, 4);
1291 bool m2
= arg_get_lit(ctx
, 5);
1292 bool m4
= arg_get_lit(ctx
, 6);
1293 bool nosave
= arg_get_lit(ctx
, 7);
1294 bool verbose
= arg_get_lit(ctx
, 8);
1297 uint64_t t1
= msclock();
1300 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1301 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1303 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
1307 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
1308 uint16_t bytes
= MIFARE_1K_MAX_BYTES
;
1309 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
1312 numSectors
= MIFARE_MINI_MAXSECTOR
;
1313 bytes
= MIFARE_MINI_MAX_BYTES
;
1314 block_cnt
= MIFARE_MINI_MAXBLOCK
;
1316 numSectors
= MIFARE_1K_MAXSECTOR
;
1317 bytes
= MIFARE_1K_MAX_BYTES
;
1318 block_cnt
= MIFARE_1K_MAXBLOCK
;
1320 numSectors
= MIFARE_2K_MAXSECTOR
;
1321 bytes
= MIFARE_2K_MAX_BYTES
;
1322 block_cnt
= MIFARE_2K_MAXBLOCK
;
1324 numSectors
= MIFARE_4K_MAXSECTOR
;
1325 bytes
= MIFARE_4K_MAX_BYTES
;
1326 block_cnt
= MIFARE_4K_MAXBLOCK
;
1328 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1333 iso14a_card_select_t card
;
1334 uint8_t *mem
= calloc(MIFARE_4K_MAX_BYTES
, sizeof(uint8_t));
1336 PrintAndLogEx(ERR
, "failed to allocate memory");
1339 int res
= mfc_read_tag(&card
, mem
, numSectors
, keyFilename
);
1340 if (res
!= PM3_SUCCESS
) {
1345 PrintAndLogEx(SUCCESS
, "time: %" PRIu64
" seconds\n", (msclock() - t1
) / 1000);
1347 mf_print_blocks(block_cnt
, mem
, verbose
);
1350 mf_print_keys(block_cnt
, mem
);
1351 mf_analyse_acl(block_cnt
, mem
);
1354 // Skip saving card data to file
1356 PrintAndLogEx(INFO
, "Called with no save option");
1362 if (strlen(dataFilename
) < 1) {
1363 char *fptr
= GenerateFilename("hf-mf-", "-dump");
1369 strcpy(dataFilename
, fptr
);
1373 pm3_save_mf_dump(dataFilename
, mem
, bytes
, jsfCardMemory
);
1378 static int CmdHF14AMfRestore(const char *Cmd
) {
1380 CLIParserContext
*ctx
;
1381 CLIParserInit(&ctx
, "hf mf restore",
1382 "Restore MIFARE Classic dump file to tag.\n"
1384 "The key file and dump file will program the card sector trailers.\n"
1385 "By default we authenticate to card with key 0xFFFFFFFFFFFF.\n"
1386 "If access rights in dump file is all zeros, it will be replaced with default values\n"
1388 "`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
1389 " if not specified, it will read the card uid instead.\n"
1390 " `--ka` param you can indicate that the key file should be used for authentication instead.\n"
1391 " if so we also try both B/A keys\n"
1392 "`--force` param is used to override warnings and allow bad ACL block writes.\n"
1393 " if not specified, it will skip blocks with bad ACL.\n",
1395 "hf mf restore --1k --uid 04010203\n"
1396 "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n"
1397 "hf mf restore --4k"
1400 void *argtable
[] = {
1402 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1403 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
1404 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1405 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1406 arg_str0("u", "uid", "<hex>", "uid, (4|7|10 hex bytes)"),
1407 arg_str0("f", "file", "<fn>", "specify a filename for dump file"),
1408 arg_str0("k", "kfn", "<fn>", "key filename"),
1409 arg_lit0(NULL
, "ka", "use specified keyfile to authenticate"),
1410 arg_lit0(NULL
, "force", "override warnings"),
1413 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1415 bool m0
= arg_get_lit(ctx
, 1);
1416 bool m1
= arg_get_lit(ctx
, 2);
1417 bool m2
= arg_get_lit(ctx
, 3);
1418 bool m4
= arg_get_lit(ctx
, 4);
1422 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
1425 char datafilename
[FILE_PATH_SIZE
] = {0};
1426 CLIParamStrToBuf(arg_get_str(ctx
, 6), (uint8_t *)datafilename
, FILE_PATH_SIZE
, &datafnlen
);
1429 char keyfilename
[FILE_PATH_SIZE
] = {0};
1430 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)keyfilename
, FILE_PATH_SIZE
, &keyfnlen
);
1432 bool use_keyfile_for_auth
= arg_get_lit(ctx
, 8);
1433 bool force
= arg_get_lit(ctx
, 9);
1438 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1439 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1441 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
1445 uint8_t sectors
= MIFARE_1K_MAXSECTOR
;
1448 sectors
= MIFARE_MINI_MAXSECTOR
;
1450 sectors
= MIFARE_1K_MAXSECTOR
;
1452 sectors
= MIFARE_2K_MAXSECTOR
;
1454 sectors
= MIFARE_4K_MAXSECTOR
;
1456 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1460 // if user specified UID, use it in file templates
1463 if (keyfnlen
== 0) {
1464 snprintf(keyfilename
, FILE_PATH_SIZE
, "hf-mf-%s-key.bin", uid
);
1465 keyfnlen
= strlen(keyfilename
);
1468 if (datafnlen
== 0) {
1469 snprintf(datafilename
, FILE_PATH_SIZE
, "hf-mf-%s-dump.bin", uid
);
1470 datafnlen
= strlen(datafilename
);
1474 // try reading card uid and create filename
1475 if (keyfnlen
== 0) {
1476 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
1480 strncpy(keyfilename
, fptr
, sizeof(keyfilename
) - 1);
1485 size_t alen
= 0, blen
= 0;
1486 uint8_t *keyA
, *keyB
;
1487 if (loadFileBinaryKey(keyfilename
, "", (void **)&keyA
, (void **)&keyB
, &alen
, &blen
) != PM3_SUCCESS
) {
1491 PrintAndLogEx(INFO
, "Using key file `" _YELLOW_("%s") "`", keyfilename
);
1493 // try reading card uid and create filename
1494 if (datafnlen
== 0) {
1495 char *fptr
= GenerateFilename("hf-mf-", "-dump.bin");
1505 strcpy(datafilename
, fptr
);
1510 uint8_t *dump
= NULL
;
1511 size_t bytes_read
= 0;
1512 int res
= pm3_load_dump(datafilename
, (void **)&dump
, &bytes_read
, (MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
));
1513 if (res
!= PM3_SUCCESS
) {
1519 // default authentication key
1520 uint8_t default_key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1522 PrintAndLogEx(NORMAL
, "");
1523 PrintAndLogEx(INFO
, " blk | data | status");
1524 PrintAndLogEx(INFO
, "-----+-------------------------------------------------+----------------");
1526 // main loop for restoring.
1527 // a bit more complicated than needed
1528 // this is because of two things.
1529 // 1. we are setting keys from a key file or using the existing ones in the dump
1530 // 2. we need to authenticate against a card which might not have default keys.
1531 uint8_t *ref_dump
= dump
;
1532 for (uint8_t s
= 0; s
< sectors
; s
++) {
1533 for (uint8_t b
= 0; b
< mfNumBlocksPerSector(s
); b
++) {
1535 uint8_t bldata
[MFBLOCK_SIZE
] = {0x00};
1536 memcpy(bldata
, dump
, MFBLOCK_SIZE
);
1539 // if sector trailer
1540 if (mfIsSectorTrailerBasedOnBlocks(s
, b
)) {
1541 // keep the current keys on the card
1542 if (use_keyfile_for_auth
== false) {
1544 memcpy(bldata
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1547 memcpy(bldata
+ 10, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1550 // ensure access right isn't messed up.
1551 if (mfValidateAccessConditions(&bldata
[6]) == false) {
1552 PrintAndLogEx(WARNING
, "Invalid Access Conditions on sector %i, replacing with default values", s
);
1553 memcpy(bldata
+ 6, "\xFF\x07\x80\x69", 4);
1556 // Warn if ACL is strict read-only
1557 for (uint8_t foo
= 0; foo
< mfNumBlocksPerSector(s
); foo
++) {
1558 if (mfReadOnlyAccessConditions(foo
, &bldata
[6])) {
1559 PrintAndLogEx(WARNING
, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", foo
);
1561 // if --force isn't used, skip writing this block
1562 if (force
== false) {
1563 PrintAndLogEx(INFO
, "Skipping, use `" _YELLOW_("--force") "` to override and write this data");
1571 dump
+= MFBLOCK_SIZE
;
1572 bytes_read
-= MFBLOCK_SIZE
;
1579 memcpy(wdata
+ 10, bldata
, sizeof(bldata
));
1581 for (int8_t kt
= MF_KEY_B
; kt
> -1; kt
--) {
1582 if (use_keyfile_for_auth
) {
1584 if (kt
== MF_KEY_A
) {
1585 memcpy(wdata
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1587 memcpy(wdata
, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1591 // use default key to authenticate for the write command
1592 memcpy(wdata
, default_key
, MIFARE_KEY_SIZE
);
1595 uint16_t blockno
= (mfFirstBlockOfSector(s
) + b
);
1597 clearCommandBuffer();
1598 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, kt
, 0, wdata
, sizeof(wdata
));
1599 PacketResponseNG resp
;
1600 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1601 PrintAndLogEx(WARNING
, "command execution time out");
1605 int isOK
= resp
.oldarg
[0] & 0xff;
1607 // if success, skip to next block
1608 PrintAndLogEx(INFO
, " %3d | %s| ( " _GREEN_("ok") " )", blockno
, sprint_hex(bldata
, sizeof(bldata
)));
1611 // write somehow failed. Lets determine why.
1612 if (isOK
== PM3_ETEAROFF
) {
1613 PrintAndLogEx(INFO
, "Tear off triggered. Recommendation is not to use tear-off with restore command");
1617 PrintAndLogEx(INFO
, " %3d | %s| ( " _RED_("fail") " ) key " _YELLOW_("%c"),
1619 sprint_hex(bldata
, sizeof(bldata
)),
1620 (kt
== MF_KEY_A
) ? 'A' : 'B'
1622 } // end loop key types
1630 PrintAndLogEx(INFO
, "-----+-------------------------------------------------+----------------");
1631 PrintAndLogEx(NORMAL
, "");
1632 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf dump --ns") "` to verify");
1633 PrintAndLogEx(INFO
, "Done!");
1637 static int CmdHF14AMfNested(const char *Cmd
) { //TODO: single mode broken? can't find keys...
1638 CLIParserContext
*ctx
;
1639 CLIParserInit(&ctx
, "hf mf nested",
1640 "Execute Nested attack against MIFARE Classic card for key recovery",
1641 "hf mf nested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta --> Use block 0 Key A to find block 4 Key A (single sector key recovery)\n"
1642 "hf mf nested --mini --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
1643 "hf mf nested --1k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
1644 "hf mf nested --2k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
1645 "hf mf nested --4k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k");
1647 void *argtable
[] = {
1649 arg_str0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
1650 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1651 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
1652 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1653 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1654 arg_int0(NULL
, "blk", "<dec>", "Input block number"),
1655 arg_lit0("a", NULL
, "Input key specified is A key (default)"),
1656 arg_lit0("b", NULL
, "Input key specified is B key"),
1657 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1658 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
1659 arg_lit0(NULL
, "ta", "Target A key (default)"),
1660 arg_lit0(NULL
, "tb", "Target B key"),
1661 arg_int0(NULL
, "tc", "<dec>", "Nested input key type is key A + offset (you must specify a single block as well!)"),
1662 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
1663 arg_lit0(NULL
, "dump", "Dump found keys to file"),
1664 arg_lit0(NULL
, "mem", "Use dictionary from flashmemory"),
1665 arg_lit0("i", NULL
, "Ignore static encrypted nonces"),
1668 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1671 uint8_t key
[6] = {0};
1672 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
1674 bool m0
= arg_get_lit(ctx
, 2);
1675 bool m1
= arg_get_lit(ctx
, 3);
1676 bool m2
= arg_get_lit(ctx
, 4);
1677 bool m4
= arg_get_lit(ctx
, 5);
1679 uint8_t blockNo
= arg_get_u32_def(ctx
, 6, 0);
1681 uint8_t keyType
= MF_KEY_A
;
1683 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
1685 PrintAndLogEx(WARNING
, "Choose one single input key type");
1687 } else if (arg_get_lit(ctx
, 8)) {
1690 uint8_t prev_keytype
= keyType
;
1691 keyType
= arg_get_int_def(ctx
, 9, keyType
);
1692 if ((arg_get_lit(ctx
, 7) || arg_get_lit(ctx
, 8)) && (keyType
!= prev_keytype
)) {
1694 PrintAndLogEx(WARNING
, "Choose one single input key type");
1698 int trgBlockNo
= arg_get_int_def(ctx
, 10, -1);
1700 uint8_t trgKeyType
= MF_KEY_A
;
1702 if (arg_get_lit(ctx
, 11) && arg_get_lit(ctx
, 12)) {
1704 PrintAndLogEx(WARNING
, "Choose one single target key type");
1706 } else if (arg_get_lit(ctx
, 12)) {
1707 trgKeyType
= MF_KEY_B
;
1709 uint8_t prev_trgkeytype
= trgKeyType
;
1710 trgKeyType
= arg_get_int_def(ctx
, 13, trgKeyType
);
1711 if ((arg_get_lit(ctx
, 11) || arg_get_lit(ctx
, 12)) && (trgKeyType
!= prev_trgkeytype
)) {
1713 PrintAndLogEx(WARNING
, "Choose one single target key type");
1716 bool transferToEml
= arg_get_lit(ctx
, 14);
1717 bool createDumpFile
= arg_get_lit(ctx
, 15);
1718 bool singleSector
= trgBlockNo
> -1;
1719 bool use_flashmemory
= arg_get_lit(ctx
, 16);
1720 bool ignore_static_encrypted
= arg_get_lit(ctx
, 17);
1725 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1726 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1730 uint8_t SectorsCnt
= 1;
1732 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1734 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1736 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
1738 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
1742 uint8_t MinSectorsCnt
= 0;
1743 // find a MIFARE type that can accommodate the provided block number
1744 uint8_t s
= MAX(mfSectorNum(trgBlockNo
), mfSectorNum(blockNo
));
1745 if (s
< MIFARE_MINI_MAXSECTOR
) {
1746 MinSectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1747 } else if (s
< MIFARE_1K_MAXSECTOR
) {
1748 MinSectorsCnt
= MIFARE_1K_MAXSECTOR
;
1749 } else if (s
< MIFARE_2K_MAXSECTOR
) {
1750 MinSectorsCnt
= MIFARE_2K_MAXSECTOR
;
1751 } else if (s
< MIFARE_4K_MAXSECTOR
) {
1752 MinSectorsCnt
= MIFARE_4K_MAXSECTOR
;
1754 PrintAndLogEx(WARNING
, "Provided block out of possible MIFARE Type memory map");
1757 if (SectorsCnt
== 1) {
1758 SectorsCnt
= MinSectorsCnt
;
1759 } else if (SectorsCnt
< MinSectorsCnt
) {
1760 PrintAndLogEx(WARNING
, "Provided block out of provided MIFARE Type memory map");
1764 if (SectorsCnt
== 1) {
1765 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1769 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
1773 sector_t
*e_sector
= NULL
;
1774 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
1777 // check if tag doesn't have static nonce
1778 if (detect_classic_static_nonce() == NONCE_STATIC
) {
1779 PrintAndLogEx(WARNING
, "Static nonce detected. Quitting...");
1780 PrintAndLogEx(INFO
, "\t Try use " _YELLOW_("`hf mf staticnested`"));
1781 return PM3_EOPABORTED
;
1784 // check if we can authenticate to sector
1785 if (mfCheckKeys(blockNo
, keyType
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
1787 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo
, keyType
? 'B' : 'A');
1789 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockNo
, MIFARE_AUTH_KEYA
+ keyType
);
1791 return PM3_EOPABORTED
;
1795 int16_t isOK
= mfnested(blockNo
, keyType
, key
, trgBlockNo
, trgKeyType
, keyBlock
, !ignore_static_encrypted
);
1798 PrintAndLogEx(ERR
, "command execution time out\n");
1800 case PM3_EOPABORTED
:
1801 PrintAndLogEx(WARNING
, "Button pressed. Aborted\n");
1804 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
1807 PrintAndLogEx(FAILED
, "No valid key found");
1809 case PM3_ESTATIC_NONCE
:
1810 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
1813 key64
= bytes_to_num(keyBlock
, 6);
1815 // transfer key to the emulator
1816 if (transferToEml
) {
1817 uint8_t sectortrailer
;
1819 if (trgBlockNo
< 32 * 4) { // 4 block sector
1820 sectortrailer
= trgBlockNo
| 0x03;
1821 } else { // 16 block sector
1822 sectortrailer
= trgBlockNo
| 0x0f;
1824 mfEmlGetMem(keyBlock
, sectortrailer
, 1);
1826 if (trgKeyType
== MF_KEY_A
)
1827 num_to_bytes(key64
, 6, keyBlock
);
1829 num_to_bytes(key64
, 6, &keyBlock
[10]);
1831 mfEmlSetMem(keyBlock
, sectortrailer
, 1);
1832 PrintAndLogEx(SUCCESS
, "Key transferred to emulator memory.");
1836 PrintAndLogEx(ERR
, "Unknown error\n");
1840 } else { // ------------------------------------ multiple sectors working
1841 uint64_t t1
= msclock();
1843 e_sector
= calloc(SectorsCnt
, sizeof(sector_t
));
1844 if (e_sector
== NULL
) return PM3_EMALLOC
;
1846 // add our known key
1847 e_sector
[mfSectorNum(blockNo
)].foundKey
[keyType
] = 1;
1848 e_sector
[mfSectorNum(blockNo
)].Key
[keyType
] = key64
;
1850 //test current key and additional standard keys first
1851 // add parameter key
1852 memcpy(keyBlock
+ (ARRAYLEN(g_mifare_default_keys
) * 6), key
, 6);
1854 for (int cnt
= 0; cnt
< ARRAYLEN(g_mifare_default_keys
); cnt
++) {
1855 num_to_bytes(g_mifare_default_keys
[cnt
], 6, (uint8_t *)(keyBlock
+ cnt
* 6));
1858 PrintAndLogEx(SUCCESS
, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt
);
1859 int res
= mfCheckKeys_fast(SectorsCnt
, true, true, 1, ARRAYLEN(g_mifare_default_keys
) + 1, keyBlock
, e_sector
, use_flashmemory
, false);
1860 if (res
== PM3_SUCCESS
) {
1861 PrintAndLogEx(SUCCESS
, "Fast check found all keys");
1865 uint64_t t2
= msclock() - t1
;
1866 PrintAndLogEx(SUCCESS
, "Time to check " _YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys
), (float)t2
/ 1000.0);
1867 PrintAndLogEx(SUCCESS
, "enter nested key recovery");
1870 bool calibrate
= !ignore_static_encrypted
;
1872 for (trgKeyType
= MF_KEY_A
; trgKeyType
<= MF_KEY_B
; ++trgKeyType
) {
1873 for (uint8_t sectorNo
= 0; sectorNo
< SectorsCnt
; ++sectorNo
) {
1874 for (int i
= 0; i
< MIFARE_SECTOR_RETRY
; i
++) {
1876 if (e_sector
[sectorNo
].foundKey
[trgKeyType
]) continue;
1878 int16_t isOK
= mfnested(blockNo
, keyType
, key
, mfFirstBlockOfSector(sectorNo
), trgKeyType
, keyBlock
, calibrate
);
1881 PrintAndLogEx(ERR
, "command execution time out\n");
1883 case PM3_EOPABORTED
:
1884 PrintAndLogEx(WARNING
, "button pressed. Aborted\n");
1887 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable)\n");
1893 case PM3_ESTATIC_NONCE
:
1894 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
1898 e_sector
[sectorNo
].foundKey
[trgKeyType
] = 1;
1899 e_sector
[sectorNo
].Key
[trgKeyType
] = bytes_to_num(keyBlock
, 6);
1901 mfCheckKeys_fast(SectorsCnt
, true, true, 2, 1, keyBlock
, e_sector
, false, false);
1904 PrintAndLogEx(ERR
, "Unknown error\n");
1912 t1
= msclock() - t1
;
1913 PrintAndLogEx(SUCCESS
, "time in nested " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
1916 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
1917 PrintAndLogEx(INFO
, "trying to read key B...");
1918 for (int i
= 0; i
< SectorsCnt
; i
++) {
1919 // KEY A but not KEY B
1920 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
1922 uint8_t sectrail
= (mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
1924 PrintAndLogEx(SUCCESS
, "reading block %d", sectrail
);
1926 mf_readblock_t payload
;
1927 payload
.blockno
= sectrail
;
1928 payload
.keytype
= MF_KEY_A
;
1930 num_to_bytes(e_sector
[i
].Key
[0], 6, payload
.key
); // KEY A
1932 clearCommandBuffer();
1933 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
1935 PacketResponseNG resp
;
1936 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) continue;
1938 if (resp
.status
!= PM3_SUCCESS
) continue;
1940 uint8_t *data
= resp
.data
.asBytes
;
1941 key64
= bytes_to_num(data
+ 10, 6);
1943 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
1944 e_sector
[i
].foundKey
[1] = true;
1945 e_sector
[i
].Key
[1] = key64
;
1952 PrintAndLogEx(NORMAL
, "");
1953 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
1956 printKeyTable(SectorsCnt
, e_sector
);
1958 // transfer them to the emulator
1959 if (transferToEml
) {
1961 g_conn
.block_after_ACK
= true;
1962 for (int i
= 0; i
< SectorsCnt
; i
++) {
1963 mfEmlGetMem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
1965 if (e_sector
[i
].foundKey
[0])
1966 num_to_bytes(e_sector
[i
].Key
[0], 6, keyBlock
);
1968 if (e_sector
[i
].foundKey
[1])
1969 num_to_bytes(e_sector
[i
].Key
[1], 6, &keyBlock
[10]);
1971 if (i
== SectorsCnt
- 1) {
1972 // Disable fast mode on last packet
1973 g_conn
.block_after_ACK
= false;
1975 mfEmlSetMem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
1977 PrintAndLogEx(SUCCESS
, "keys transferred to emulator memory.");
1981 if (createDumpFile
) {
1982 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
1983 if (createMfcKeyDump(fptr
, SectorsCnt
, e_sector
) != PM3_SUCCESS
) {
1984 PrintAndLogEx(ERR
, "Failed to save keys to file");
1996 static int CmdHF14AMfNestedStatic(const char *Cmd
) {
1997 CLIParserContext
*ctx
;
1998 CLIParserInit(&ctx
, "hf mf staticnested",
1999 "Execute static nested attack against MIFARE Classic card with static nonce for key recovery.\n"
2000 "Supply a known key from one block to recover all keys",
2001 "hf mf staticnested --mini --blk 0 -a -k FFFFFFFFFFFF\n"
2002 "hf mf staticnested --1k --blk 0 -a -k FFFFFFFFFFFF\n"
2003 "hf mf staticnested --2k --blk 0 -a -k FFFFFFFFFFFF\n"
2004 "hf mf staticnested --4k --blk 0 -a -k FFFFFFFFFFFF\n");
2006 void *argtable
[] = {
2008 arg_str0("k", "key", "<hex>", "Known key (12 hex symbols)"),
2009 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
2010 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
2011 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
2012 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
2013 arg_int0(NULL
, "blk", "<dec>", "Input block number"),
2014 arg_lit0("a", NULL
, "Input key specified is keyA (def)"),
2015 arg_lit0("b", NULL
, "Input key specified is keyB"),
2016 arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
2017 arg_lit0(NULL
, "dumpkeys", "Dump found keys to file"),
2020 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2023 uint8_t key
[6] = {0};
2024 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
2026 bool m0
= arg_get_lit(ctx
, 2);
2027 bool m1
= arg_get_lit(ctx
, 3);
2028 bool m2
= arg_get_lit(ctx
, 4);
2029 bool m4
= arg_get_lit(ctx
, 5);
2031 uint8_t blockNo
= arg_get_u32_def(ctx
, 6, 0);
2033 uint8_t keyType
= MF_KEY_A
;
2035 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
2037 PrintAndLogEx(WARNING
, "Choose one single input key type");
2039 } else if (arg_get_lit(ctx
, 8)) {
2043 bool transferToEml
= arg_get_lit(ctx
, 9);
2044 bool createDumpFile
= arg_get_lit(ctx
, 10);
2048 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2049 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2053 uint8_t SectorsCnt
= 1;
2055 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
2057 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
2059 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
2061 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
2063 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
2068 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
2072 sector_t
*e_sector
= NULL
;
2074 uint8_t trgKeyType
= MF_KEY_A
;
2076 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
2079 // check if tag have static nonce
2080 if (detect_classic_static_nonce() != NONCE_STATIC
) {
2081 PrintAndLogEx(WARNING
, "Normal nonce detected, or failed read of card. Quitting...");
2082 PrintAndLogEx(INFO
, "\t Try use " _YELLOW_("`hf mf nested`"));
2083 return PM3_EOPABORTED
;
2086 // check if we can authenticate to sector
2087 if (mfCheckKeys(blockNo
, keyType
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
2089 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo
, keyType
? 'B' : 'A');
2091 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockNo
, MIFARE_AUTH_KEYA
+ keyType
);
2093 return PM3_EOPABORTED
;
2097 PrintAndLogEx(INFO
, "RDV4 with flashmemory supported detected.");
2100 uint64_t t1
= msclock();
2102 e_sector
= calloc(SectorsCnt
, sizeof(sector_t
));
2103 if (e_sector
== NULL
)
2106 // add our known key
2107 e_sector
[mfSectorNum(blockNo
)].foundKey
[keyType
] = 1;
2108 e_sector
[mfSectorNum(blockNo
)].Key
[keyType
] = key64
;
2110 //test current key and additional standard keys first
2111 // add parameter key
2112 memcpy(keyBlock
+ (ARRAYLEN(g_mifare_default_keys
) * 6), key
, 6);
2114 for (int cnt
= 0; cnt
< ARRAYLEN(g_mifare_default_keys
); cnt
++) {
2115 num_to_bytes(g_mifare_default_keys
[cnt
], 6, (uint8_t *)(keyBlock
+ cnt
* 6));
2118 PrintAndLogEx(SUCCESS
, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt
);
2119 int res
= mfCheckKeys_fast(SectorsCnt
, true, true, 1, ARRAYLEN(g_mifare_default_keys
) + 1, keyBlock
, e_sector
, false, false);
2120 if (res
== PM3_SUCCESS
) {
2122 PrintAndLogEx(SUCCESS
, "Fast check found all keys");
2126 uint64_t t2
= msclock() - t1
;
2127 PrintAndLogEx(SUCCESS
, "Time to check "_YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys
), (float)t2
/ 1000.0);
2128 PrintAndLogEx(SUCCESS
, "enter static nested key recovery");
2131 for (trgKeyType
= MF_KEY_A
; trgKeyType
<= MF_KEY_B
; ++trgKeyType
) {
2132 for (uint8_t sectorNo
= 0; sectorNo
< SectorsCnt
; ++sectorNo
) {
2134 for (int i
= 0; i
< 1; i
++) {
2136 if (e_sector
[sectorNo
].foundKey
[trgKeyType
]) continue;
2138 int16_t isOK
= mfStaticNested(blockNo
, keyType
, key
, mfFirstBlockOfSector(sectorNo
), trgKeyType
, keyBlock
);
2141 PrintAndLogEx(ERR
, "command execution time out");
2143 case PM3_EOPABORTED
:
2144 PrintAndLogEx(WARNING
, "aborted via keyboard.");
2149 e_sector
[sectorNo
].foundKey
[trgKeyType
] = 1;
2150 e_sector
[sectorNo
].Key
[trgKeyType
] = bytes_to_num(keyBlock
, 6);
2152 // mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
2155 PrintAndLogEx(ERR
, "unknown error.\n");
2163 t1
= msclock() - t1
;
2164 PrintAndLogEx(SUCCESS
, "time in static nested " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
2167 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
2168 PrintAndLogEx(INFO
, "trying to read key B...");
2169 for (int i
= 0; i
< SectorsCnt
; i
++) {
2170 // KEY A but not KEY B
2171 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
2173 uint8_t sectrail
= (mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
2175 PrintAndLogEx(SUCCESS
, "reading block %d", sectrail
);
2177 mf_readblock_t payload
;
2178 payload
.blockno
= sectrail
;
2179 payload
.keytype
= MF_KEY_A
;
2181 num_to_bytes(e_sector
[i
].Key
[0], 6, payload
.key
); // KEY A
2183 clearCommandBuffer();
2184 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
2186 PacketResponseNG resp
;
2187 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500) == false) {
2191 if (resp
.status
!= PM3_SUCCESS
) continue;
2193 uint8_t *data
= resp
.data
.asBytes
;
2194 key64
= bytes_to_num(data
+ 10, 6);
2196 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
2197 e_sector
[i
].foundKey
[1] = true;
2198 e_sector
[i
].Key
[1] = key64
;
2205 PrintAndLogEx(NORMAL
, "");
2206 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
2209 printKeyTable(SectorsCnt
, e_sector
);
2211 // transfer them to the emulator
2212 if (transferToEml
) {
2214 g_conn
.block_after_ACK
= true;
2215 for (int i
= 0; i
< SectorsCnt
; i
++) {
2216 mfEmlGetMem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
2218 if (e_sector
[i
].foundKey
[0])
2219 num_to_bytes(e_sector
[i
].Key
[0], 6, keyBlock
);
2221 if (e_sector
[i
].foundKey
[1])
2222 num_to_bytes(e_sector
[i
].Key
[1], 6, &keyBlock
[10]);
2224 if (i
== SectorsCnt
- 1) {
2225 // Disable fast mode on last packet
2226 g_conn
.block_after_ACK
= false;
2228 mfEmlSetMem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
2230 PrintAndLogEx(SUCCESS
, "keys transferred to emulator memory.");
2234 if (createDumpFile
) {
2235 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
2236 if (createMfcKeyDump(fptr
, SectorsCnt
, e_sector
) != PM3_SUCCESS
) {
2237 PrintAndLogEx(ERR
, "Failed to save keys to file");
2249 static int CmdHF14AMfNestedHard(const char *Cmd
) {
2251 CLIParserContext
*ctx
;
2252 CLIParserInit(&ctx
, "hf mf hardnested",
2253 "Nested attack for hardened MIFARE Classic cards.\n"
2254 "if card is EV1, command can detect and use known key see example below\n"
2256 "`--i<X>` set type of SIMD instructions. Without this flag programs autodetect it.\n"
2258 " hf mf hardnested -r --tk [known target key]\n"
2259 "Add the known target key to check if it is present in the remaining key space\n"
2260 " hf mf hardnested --blk 0 -a -k A0A1A2A3A4A5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
2262 "hf mf hardnested --tblk 4 --ta --> works for MFC EV1\n"
2263 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta\n"
2264 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -w\n"
2265 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -f nonces.bin -w -s\n"
2266 "hf mf hardnested -r\n"
2267 "hf mf hardnested -r --tk a0a1a2a3a4a5\n"
2268 "hf mf hardnested -t --tk a0a1a2a3a4a5\n"
2269 "hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
2272 void *argtable
[] = {
2274 arg_str0("k", "key", "<hex>", "Key, 12 hex bytes"), // 1
2275 arg_int0(NULL
, "blk", "<dec>", "Input block number"), // 2
2276 arg_lit0("a", NULL
, "Input key A (def)"), // 3
2277 arg_lit0("b", NULL
, "Input key B"),
2278 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
2279 arg_lit0(NULL
, "ta", "Target key A"),
2280 arg_lit0(NULL
, "tb", "Target key B"),
2281 arg_str0(NULL
, "tk", "<hex>", "Target key, 12 hex bytes"), // 8
2282 arg_str0("u", "uid", "<hex>", "R/W `hf-mf-<UID>-nonces.bin` instead of default name"),
2283 arg_str0("f", "file", "<fn>", "R/W <name> instead of default name"),
2284 arg_lit0("r", "read", "Read `hf-mf-<UID>-nonces.bin` if tag present, otherwise `nonces.bin`, and start attack"),
2285 arg_lit0("s", "slow", "Slower acquisition (required by some non standard cards)"),
2286 arg_lit0("t", "tests", "Run tests"),
2287 arg_lit0("w", "wr", "Acquire nonces and UID, and write them to file `hf-mf-<UID>-nonces.bin`"),
2289 arg_lit0(NULL
, "in", "None (use CPU regular instruction set)"),
2290 #if defined(COMPILER_HAS_SIMD_X86)
2291 arg_lit0(NULL
, "im", "MMX"),
2292 arg_lit0(NULL
, "is", "SSE2"),
2293 arg_lit0(NULL
, "ia", "AVX"),
2294 arg_lit0(NULL
, "i2", "AVX2"),
2296 #if defined(COMPILER_HAS_SIMD_AVX512)
2297 arg_lit0(NULL
, "i5", "AVX512"),
2299 #if defined(COMPILER_HAS_SIMD_NEON)
2300 arg_lit0(NULL
, "ie", "NEON"),
2304 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2307 uint8_t key
[6] = {0};
2308 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
2310 uint8_t blockno
= arg_get_u32_def(ctx
, 2, 0);
2312 uint8_t keytype
= MF_KEY_A
;
2313 if (arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) {
2315 PrintAndLogEx(WARNING
, "Choose one single input key type");
2317 } else if (arg_get_lit(ctx
, 4)) {
2321 uint8_t trg_blockno
= arg_get_u32_def(ctx
, 5, 0);
2323 uint8_t trg_keytype
= MF_KEY_A
;
2324 if (arg_get_lit(ctx
, 6) && arg_get_lit(ctx
, 7)) {
2326 PrintAndLogEx(WARNING
, "Choose one single target key type");
2328 } else if (arg_get_lit(ctx
, 7)) {
2329 trg_keytype
= MF_KEY_B
;
2333 uint8_t trg_key
[6] = {0};
2334 CLIGetHexWithReturn(ctx
, 8, trg_key
, &trg_keylen
);
2338 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
2341 char filename
[FILE_PATH_SIZE
] = {0};
2342 CLIParamStrToBuf(arg_get_str(ctx
, 10), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2344 bool nonce_file_read
= arg_get_lit(ctx
, 11);
2345 bool slow
= arg_get_lit(ctx
, 12);
2346 bool tests
= arg_get_lit(ctx
, 13);
2347 bool nonce_file_write
= arg_get_lit(ctx
, 14);
2349 bool in
= arg_get_lit(ctx
, 15);
2350 #if defined(COMPILER_HAS_SIMD_X86)
2351 bool im
= arg_get_lit(ctx
, 16);
2352 bool is
= arg_get_lit(ctx
, 17);
2353 bool ia
= arg_get_lit(ctx
, 18);
2354 bool i2
= arg_get_lit(ctx
, 19);
2356 #if defined(COMPILER_HAS_SIMD_AVX512)
2357 bool i5
= arg_get_lit(ctx
, 20);
2359 #if defined(COMPILER_HAS_SIMD_NEON)
2360 bool ie
= arg_get_lit(ctx
, 16);
2364 // set SIM instructions
2365 SetSIMDInstr(SIMD_AUTO
);
2367 #if defined(COMPILER_HAS_SIMD_AVX512)
2369 SetSIMDInstr(SIMD_AVX512
);
2372 #if defined(COMPILER_HAS_SIMD_X86)
2374 SetSIMDInstr(SIMD_AVX2
);
2376 SetSIMDInstr(SIMD_AVX
);
2378 SetSIMDInstr(SIMD_SSE2
);
2380 SetSIMDInstr(SIMD_MMX
);
2383 #if defined(COMPILER_HAS_SIMD_NEON)
2385 SetSIMDInstr(SIMD_NEON
);
2389 SetSIMDInstr(SIMD_NONE
);
2392 bool known_target_key
= (trg_keylen
);
2394 if (nonce_file_read
) {
2395 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
2397 strncpy(filename
, "nonces.bin", FILE_PATH_SIZE
- 1);
2399 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
2403 if (nonce_file_write
) {
2404 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
2408 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
2413 snprintf(filename
, FILE_PATH_SIZE
, "hf-mf-%s-nonces.bin", uid
);
2416 if (g_session
.pm3_present
&& !tests
) {
2417 // detect MFC EV1 Signature
2418 if (detect_mfc_ev1_signature() && keylen
== 0) {
2419 PrintAndLogEx(INFO
, "MIFARE Classic EV1 card detected");
2422 memcpy(key
, g_mifare_signature_key_b
, sizeof(g_mifare_signature_key_b
));
2425 if (known_target_key
== false && nonce_file_read
== false) {
2426 // check if tag doesn't have static nonce
2427 if (detect_classic_static_nonce() == NONCE_STATIC
) {
2428 PrintAndLogEx(WARNING
, "Static nonce detected. Quitting...");
2429 PrintAndLogEx(HINT
, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
2430 return PM3_EOPABORTED
;
2434 // check if we can authenticate to sector
2435 if (mfCheckKeys(blockno
, keytype
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
2437 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockno
, keytype
? 'B' : 'A');
2439 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockno
, MIFARE_AUTH_KEYA
+ keytype
);
2441 return PM3_EWRONGANSWER
;
2446 PrintAndLogEx(INFO
, "Target block no " _YELLOW_("%3d") ", target key type: " _YELLOW_("%c") ", known target key: " _YELLOW_("%02x%02x%02x%02x%02x%02x%s"),
2448 (trg_keytype
== MF_KEY_B
) ? 'B' : 'A',
2449 trg_key
[0], trg_key
[1], trg_key
[2], trg_key
[3], trg_key
[4], trg_key
[5],
2450 known_target_key
? "" : " (not set)"
2452 PrintAndLogEx(INFO
, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"),
2453 nonce_file_write
? "write" : nonce_file_read
? "read" : "none",
2454 slow
? "Yes" : "No",
2457 uint64_t foundkey
= 0;
2458 int16_t isOK
= mfnestedhard(blockno
, keytype
, key
, trg_blockno
, trg_keytype
, known_target_key
? trg_key
: NULL
, nonce_file_read
, nonce_file_write
, slow
, tests
, &foundkey
, filename
);
2461 PrintAndLogEx(ERR
, "Error: No response from Proxmark3\n");
2463 case PM3_EOPABORTED
:
2464 PrintAndLogEx(WARNING
, "Button pressed. Aborted\n");
2466 case PM3_ESTATIC_NONCE
:
2467 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
2470 PrintAndLogEx(FAILED
, "\nFailed to recover a key...");
2477 if ((tests
== 0) && IfPm3Iso14443a()) {
2483 static int CmdHF14AMfAutoPWN(const char *Cmd
) {
2485 CLIParserContext
*ctx
;
2486 CLIParserInit(&ctx
, "hf mf autopwn",
2487 "This command automates the key recovery process on MIFARE Classic cards.\n"
2488 "It uses the fchk, chk, darkside, nested, hardnested and staticnested to recover keys.\n"
2489 "If all keys are found, it try dumping card content both to file and emulator memory.",
2491 "hf mf autopwn -s 0 -a -k FFFFFFFFFFFF --> target MFC 1K card, Sector 0 with known key A 'FFFFFFFFFFFF'\n"
2492 "hf mf autopwn --1k -f mfc_default_keys --> target MFC 1K card, default dictionary\n"
2493 "hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -f mfc_default_keys --> combo of the two above samples\n"
2494 "hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -k a0a1a2a3a4a5 --> multiple user supplied keys"
2497 void *argtable
[] = {
2499 arg_strx0("k", "key", "<hex>", "Known key, 12 hex bytes"),
2500 arg_int0("s", "sector", "<dec>", "Input sector number"),
2501 arg_lit0("a", NULL
, "Input key A (def)"),
2502 arg_lit0("b", NULL
, "Input key B"),
2503 arg_str0("f", "file", "<fn>", "filename of dictionary"),
2504 arg_lit0(NULL
, "slow", "Slower acquisition (required by some non standard cards)"),
2505 arg_lit0("l", "legacy", "legacy mode (use the slow `hf mf chk`)"),
2506 arg_lit0("v", "verbose", "verbose output"),
2508 arg_lit0(NULL
, "ns", "No save to file"),
2510 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
2511 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
2512 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
2513 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
2515 arg_lit0(NULL
, "in", "None (use CPU regular instruction set)"),
2516 #if defined(COMPILER_HAS_SIMD_X86)
2517 arg_lit0(NULL
, "im", "MMX"),
2518 arg_lit0(NULL
, "is", "SSE2"),
2519 arg_lit0(NULL
, "ia", "AVX"),
2520 arg_lit0(NULL
, "i2", "AVX2"),
2522 #if defined(COMPILER_HAS_SIMD_AVX512)
2523 arg_lit0(NULL
, "i5", "AVX512"),
2525 #if defined(COMPILER_HAS_SIMD_NEON)
2526 arg_lit0(NULL
, "ie", "NEON"),
2530 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
2532 int in_keys_len
= 0;
2533 uint8_t in_keys
[100 * MIFARE_KEY_SIZE
] = {0};
2534 CLIGetHexWithReturn(ctx
, 1, in_keys
, &in_keys_len
);
2536 uint8_t sectorno
= arg_get_u32_def(ctx
, 2, 0);
2538 uint8_t keytype
= MF_KEY_A
;
2539 if (arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) {
2541 PrintAndLogEx(WARNING
, "Choose one single input key type");
2543 } else if (arg_get_lit(ctx
, 4)) {
2548 char filename
[FILE_PATH_SIZE
] = {0};
2549 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2551 bool slow
= arg_get_lit(ctx
, 6);
2552 bool legacy_mfchk
= arg_get_lit(ctx
, 7);
2553 bool verbose
= arg_get_lit(ctx
, 8);
2555 bool no_save
= arg_get_lit(ctx
, 9);
2557 bool m0
= arg_get_lit(ctx
, 10);
2558 bool m1
= arg_get_lit(ctx
, 11);
2559 bool m2
= arg_get_lit(ctx
, 12);
2560 bool m4
= arg_get_lit(ctx
, 13);
2562 bool in
= arg_get_lit(ctx
, 14);
2563 #if defined(COMPILER_HAS_SIMD_X86)
2564 bool im
= arg_get_lit(ctx
, 15);
2565 bool is
= arg_get_lit(ctx
, 16);
2566 bool ia
= arg_get_lit(ctx
, 17);
2567 bool i2
= arg_get_lit(ctx
, 18);
2569 #if defined(COMPILER_HAS_SIMD_AVX512)
2570 bool i5
= arg_get_lit(ctx
, 19);
2572 #if defined(COMPILER_HAS_SIMD_NEON)
2573 bool ie
= arg_get_lit(ctx
, 15);
2579 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2580 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2582 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
2586 uint8_t sector_cnt
= MIFARE_1K_MAXSECTOR
;
2587 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
2590 sector_cnt
= MIFARE_MINI_MAXSECTOR
;
2591 block_cnt
= MIFARE_MINI_MAXBLOCK
;
2593 sector_cnt
= MIFARE_1K_MAXSECTOR
;
2594 block_cnt
= MIFARE_1K_MAXBLOCK
;
2596 sector_cnt
= MIFARE_2K_MAXSECTOR
;
2597 block_cnt
= MIFARE_2K_MAXBLOCK
;
2599 sector_cnt
= MIFARE_4K_MAXSECTOR
;
2600 block_cnt
= MIFARE_4K_MAXBLOCK
;
2602 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
2607 // set SIM instructions
2608 SetSIMDInstr(SIMD_AUTO
);
2610 #if defined(COMPILER_HAS_SIMD_AVX512)
2612 SetSIMDInstr(SIMD_AVX512
);
2615 #if defined(COMPILER_HAS_SIMD_X86)
2617 SetSIMDInstr(SIMD_AVX2
);
2619 SetSIMDInstr(SIMD_AVX
);
2621 SetSIMDInstr(SIMD_SSE2
);
2623 SetSIMDInstr(SIMD_MMX
);
2626 #if defined(COMPILER_HAS_SIMD_NEON)
2628 SetSIMDInstr(SIMD_NEON
);
2632 SetSIMDInstr(SIMD_NONE
);
2635 // Nested and Hardnested parameter
2637 bool calibrate
= true;
2639 // Attack key storage variables
2640 uint8_t *keyBlock
= NULL
;
2641 uint32_t key_cnt
= 0;
2642 uint8_t tmp_key
[MIFARE_KEY_SIZE
] = {0};
2644 // Nested and Hardnested returned status
2645 uint64_t foundkey
= 0;
2646 int current_sector_i
= 0, current_key_type_i
= 0;
2648 // Dumping and transfere to simulater memory
2649 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
2653 int prng_type
= PM3_EUNDEF
;
2655 // ------------------------------
2657 uint64_t tagT
= GetHF14AMfU_Type();
2658 if (tagT
!= MFU_TT_UL_ERROR
) {
2659 PrintAndLogEx(ERR
, "Detected a MIFARE Ultralight/C/NTAG Compatible card.");
2660 PrintAndLogEx(ERR
, "This command targets " _YELLOW_("MIFARE Classic"));
2664 // Select card to get UID/UIDLEN/ATQA/SAK information
2665 clearCommandBuffer();
2666 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
2667 PacketResponseNG resp
;
2668 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
2669 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
2670 return PM3_ETIMEOUT
;
2673 uint64_t select_status
= resp
.oldarg
[0];
2674 if (select_status
== 0) {
2675 // iso14443a card select failed
2676 PrintAndLogEx(FAILED
, "No tag detected or other tag communication error");
2677 PrintAndLogEx(HINT
, "Hint: Try some distance or position of the card");
2678 return PM3_ECARDEXCHANGE
;
2682 iso14a_card_select_t card
;
2683 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
2685 bool known_key
= (in_keys_len
> 5);
2686 uint8_t key
[MIFARE_KEY_SIZE
] = {0};
2688 memcpy(key
, in_keys
, sizeof(key
));
2692 uint16_t key1_offset
= in_keys_len
;
2695 // iceman: todo, need to add all generated keys
2696 mfc_algo_mizip_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2697 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (0 * MIFARE_KEY_SIZE
));
2699 mfc_algo_di_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2700 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (1 * MIFARE_KEY_SIZE
));
2702 mfc_algo_sky_one(card
.uid
, 15, MF_KEY_A
, &key1
);
2703 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (2 * MIFARE_KEY_SIZE
));
2706 mfc_algo_saflok_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2707 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (3 * MIFARE_KEY_SIZE
));
2709 mfc_algo_touch_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2710 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (4 * MIFARE_KEY_SIZE
));
2712 in_keys_len
+= (MIFARE_KEY_SIZE
* 5);
2714 // detect MFC EV1 Signature
2715 bool is_ev1
= detect_mfc_ev1_signature();
2717 // hidden sectors on MFC EV1
2721 // create/initialize key storage structure
2722 sector_t
*e_sector
= NULL
;
2723 size_t e_sector_cnt
= (sector_cnt
> sectorno
) ? sector_cnt
: sectorno
+ 1;
2724 if (initSectorTable(&e_sector
, e_sector_cnt
) != PM3_SUCCESS
) {
2729 PrintAndLogEx(INFO
, "MIFARE Classic EV1 card detected");
2731 // use found key if not supplied
2732 if (known_key
== false) {
2736 memcpy(key
, g_mifare_signature_key_b
, sizeof(g_mifare_signature_key_b
));
2740 // read uid to generate a filename for the key file
2741 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
2743 // check if tag doesn't have static nonce
2744 int has_staticnonce
= detect_classic_static_nonce();
2746 // card prng type (weak=1 / hard=0 / select/card comm error = negative value)
2747 if (has_staticnonce
== NONCE_NORMAL
) {
2748 prng_type
= detect_classic_prng();
2749 if (prng_type
< 0) {
2750 PrintAndLogEx(FAILED
, "\nNo tag detected or other tag communication error (%i)", prng_type
);
2759 PrintAndLogEx(INFO
, "======================= " _YELLOW_("SETTINGS") " =======================");
2760 PrintAndLogEx(INFO
, " card sectors .. " _YELLOW_("%d"), sector_cnt
);
2761 PrintAndLogEx(INFO
, " key supplied .. " _YELLOW_("%s"), known_key
? "True" : "False");
2762 PrintAndLogEx(INFO
, " known sector .. " _YELLOW_("%d"), sectorno
);
2763 PrintAndLogEx(INFO
, " keytype ....... " _YELLOW_("%c"), (keytype
== MF_KEY_B
) ? 'B' : 'A');
2764 PrintAndLogEx(INFO
, " known key ..... " _YELLOW_("%s"), sprint_hex_inrow(key
, sizeof(key
)));
2766 if (has_staticnonce
== NONCE_STATIC
)
2767 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("STATIC"));
2768 else if (has_staticnonce
== NONCE_NORMAL
)
2769 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("%s"), prng_type
? "WEAK" : "HARD");
2771 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("Could not determine PRNG,") " " _RED_("read failed."));
2773 PrintAndLogEx(INFO
, " dictionary .... " _YELLOW_("%s"), strlen(filename
) ? filename
: "NONE");
2774 PrintAndLogEx(INFO
, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk
? "True" : "False");
2776 PrintAndLogEx(INFO
, "========================================================================");
2779 // check the user supplied key
2780 if (known_key
== false) {
2781 PrintAndLogEx(WARNING
, "no known key was supplied, key recovery might fail");
2785 uint64_t t1
= msclock();
2787 int ret
= mf_load_keys(&keyBlock
, &key_cnt
, in_keys
, in_keys_len
, filename
, fnlen
, true);
2788 if (ret
!= PM3_SUCCESS
) {
2793 int32_t res
= PM3_SUCCESS
;
2795 // Use the dictionary to find sector keys on the card
2796 if (verbose
) PrintAndLogEx(INFO
, "======================= " _YELLOW_("START DICTIONARY ATTACK") " =======================");
2799 PrintAndLogEx(INFO
, "." NOLF
);
2800 // Check all the sectors
2801 for (int i
= 0; i
< sector_cnt
; i
++) {
2802 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2803 // Check if the key is known
2804 if (e_sector
[i
].foundKey
[j
] == 0) {
2805 for (uint32_t k
= 0; k
< key_cnt
; k
++) {
2806 PrintAndLogEx(NORMAL
, "." NOLF
);
2809 if (mfCheckKeys(mfFirstBlockOfSector(i
), j
, true, 1, (keyBlock
+ (MIFARE_KEY_SIZE
* k
)), &key64
) == PM3_SUCCESS
) {
2810 e_sector
[i
].Key
[j
] = bytes_to_num((keyBlock
+ (MIFARE_KEY_SIZE
* k
)), MIFARE_KEY_SIZE
);
2811 e_sector
[i
].foundKey
[j
] = 'D';
2818 PrintAndLogEx(NORMAL
, "");
2821 uint32_t chunksize
= key_cnt
> (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : key_cnt
;
2822 bool firstChunk
= true, lastChunk
= false;
2824 for (uint8_t strategy
= 1; strategy
< 3; strategy
++) {
2825 PrintAndLogEx(INFO
, "running strategy %u", strategy
);
2826 // main keychunk loop
2827 for (uint32_t i
= 0; i
< key_cnt
; i
+= chunksize
) {
2829 if (kbd_enter_pressed()) {
2830 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
2833 break; // Exit the loop
2835 uint32_t size
= ((key_cnt
- i
) > chunksize
) ? chunksize
: key_cnt
- i
;
2837 if (size
== key_cnt
- i
) {
2841 res
= mfCheckKeys_fast(sector_cnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* MIFARE_KEY_SIZE
), e_sector
, false, verbose
);
2845 // all keys, aborted
2846 if (res
== PM3_SUCCESS
) {
2849 break; // Exit the loop
2851 } // end chunks of keys
2857 // Analyse the dictionary attack
2858 uint8_t num_found_keys
= 0;
2859 for (int i
= 0; i
< sector_cnt
; i
++) {
2860 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2861 if (e_sector
[i
].foundKey
[j
] != 1) {
2867 e_sector
[i
].foundKey
[j
] = 'D';
2868 num_to_bytes(e_sector
[i
].Key
[j
], MIFARE_KEY_SIZE
, tmp_key
);
2870 // Store valid credentials for the nested / hardnested attack if none exist
2871 if (known_key
== false) {
2872 num_to_bytes(e_sector
[i
].Key
[j
], MIFARE_KEY_SIZE
, key
);
2876 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
2878 (j
== MF_KEY_B
) ? 'B' : 'A',
2879 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2882 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2884 (j
== MF_KEY_B
) ? 'B' : 'A',
2885 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2891 if (num_found_keys
== sector_cnt
* 2) {
2895 // Check if at least one sector key was found
2896 if (known_key
== false) {
2898 // Check if the darkside attack can be used
2899 if (prng_type
&& has_staticnonce
!= NONCE_STATIC
) {
2901 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
2904 PrintAndLogEx(NORMAL
, "");
2906 isOK
= mfDarkside(mfFirstBlockOfSector(sectorno
), MIFARE_AUTH_KEYA
+ keytype
, &key64
);
2908 if (isOK
!= PM3_SUCCESS
)
2909 goto noValidKeyFound
;
2911 PrintAndLogEx(SUCCESS
, "Found valid key [ " _GREEN_("%012" PRIx64
) " ]\n", key64
);
2914 num_to_bytes(key64
, MIFARE_KEY_SIZE
, key
);
2915 e_sector
[sectorno
].Key
[keytype
] = key64
;
2916 e_sector
[sectorno
].foundKey
[keytype
] = 'S';
2917 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%012" PRIx64
) " ] (used for nested / hardnested attack)",
2919 (keytype
== MF_KEY_B
) ? 'B' : 'A',
2925 PrintAndLogEx(FAILED
, "No usable key was found!");
2934 // Clear the needed variables
2935 num_to_bytes(0, MIFARE_KEY_SIZE
, tmp_key
);
2936 bool nested_failed
= false;
2938 // Iterate over each sector and key(A/B)
2939 for (current_sector_i
= 0; current_sector_i
< sector_cnt
; current_sector_i
++) {
2941 for (current_key_type_i
= MF_KEY_A
; current_key_type_i
<= MF_KEY_B
; current_key_type_i
++) {
2943 // If the key is already known, just skip it
2944 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
] == 0) {
2946 if (has_staticnonce
== NONCE_STATIC
)
2947 goto tryStaticnested
;
2949 // Try the found keys are reused
2950 if (bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
) != 0) {
2951 // <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false, verbose);
2952 // <!> Returns false keys, so we just stick to the slower mfchk.
2953 for (int i
= 0; i
< sector_cnt
; i
++) {
2954 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2955 // Check if the sector key is already broken
2956 if (e_sector
[i
].foundKey
[j
])
2959 // Check if the key works
2960 if (mfCheckKeys(mfFirstBlockOfSector(i
), j
, true, 1, tmp_key
, &key64
) == PM3_SUCCESS
) {
2961 e_sector
[i
].Key
[j
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
2962 e_sector
[i
].foundKey
[j
] = 'R';
2963 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2965 (j
== MF_KEY_B
) ? 'B' : 'A',
2966 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2972 // Clear the last found key
2973 num_to_bytes(0, MIFARE_KEY_SIZE
, tmp_key
);
2975 if (current_key_type_i
== MF_KEY_B
) {
2976 if (e_sector
[current_sector_i
].foundKey
[0] && !e_sector
[current_sector_i
].foundKey
[1]) {
2978 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START READ B KEY ATTACK") " =======================");
2979 PrintAndLogEx(INFO
, "reading B key of sector %3d with key type %c",
2981 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
2983 uint8_t sectrail
= (mfFirstBlockOfSector(current_sector_i
) + mfNumBlocksPerSector(current_sector_i
) - 1);
2985 mf_readblock_t payload
;
2986 payload
.blockno
= sectrail
;
2987 payload
.keytype
= MF_KEY_A
;
2989 num_to_bytes(e_sector
[current_sector_i
].Key
[0], MIFARE_KEY_SIZE
, payload
.key
); // KEY A
2991 clearCommandBuffer();
2992 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
2994 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500) == false) goto skipReadBKey
;
2996 if (resp
.status
!= PM3_SUCCESS
) goto skipReadBKey
;
2998 uint8_t *data
= resp
.data
.asBytes
;
2999 key64
= bytes_to_num(data
+ 10, MIFARE_KEY_SIZE
);
3001 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'A';
3002 e_sector
[current_sector_i
].Key
[current_key_type_i
] = key64
;
3003 num_to_bytes(key64
, MIFARE_KEY_SIZE
, tmp_key
);
3004 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
3006 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3007 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
3011 PrintAndLogEx(WARNING
, "unknown B key: sector: %3d key type: %c",
3013 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A'
3015 PrintAndLogEx(INFO
, " -- reading the B key was not possible, maybe due to access rights?");
3023 // Use the nested / hardnested attack
3025 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
] == 0) {
3027 if (has_staticnonce
== NONCE_STATIC
)
3028 goto tryStaticnested
;
3030 if (prng_type
&& (nested_failed
== false)) {
3031 uint8_t retries
= 0;
3033 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START NESTED ATTACK") " =======================");
3034 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
3036 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
3039 isOK
= mfnested(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, tmp_key
, calibrate
);
3042 case PM3_ETIMEOUT
: {
3043 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3.");
3048 case PM3_EOPABORTED
: {
3049 PrintAndLogEx(WARNING
, "\nButton pressed. Aborted.");
3055 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable).");
3056 PrintAndLogEx(FAILED
, "Nested attack failed --> try hardnested");
3062 // this can happen on some old cards, it's worth trying some more before switching to slower hardnested
3063 if (retries
++ < MIFARE_SECTOR_RETRY
) {
3064 PrintAndLogEx(FAILED
, "Nested attack failed, trying again (%i/%i)", retries
, MIFARE_SECTOR_RETRY
);
3067 PrintAndLogEx(FAILED
, "Nested attack failed, moving to hardnested");
3068 nested_failed
= true;
3073 case PM3_ESTATIC_NONCE
: {
3074 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
3076 e_sector
[current_sector_i
].Key
[current_key_type_i
] = 0xffffffffffff;
3077 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = false;
3078 // Show the results to the user
3079 PrintAndLogEx(NORMAL
, "");
3080 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3081 printKeyTable(sector_cnt
, e_sector
);
3082 PrintAndLogEx(NORMAL
, "");
3089 e_sector
[current_sector_i
].Key
[current_key_type_i
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
3090 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'N';
3094 PrintAndLogEx(ERR
, "unknown Error.\n");
3102 tryHardnested
: // If the nested attack fails then we try the hardnested attack
3104 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START HARDNESTED ATTACK") " =======================");
3105 PrintAndLogEx(INFO
, "sector no %3d, target key type %c, Slow %s",
3107 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3108 slow
? "Yes" : "No");
3112 isOK
= mfnestedhard(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, NULL
, false, false, slow
, 0, &foundkey
, NULL
);
3114 if (isOK
!= PM3_SUCCESS
) {
3116 case PM3_ETIMEOUT
: {
3117 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
3120 case PM3_EOPABORTED
: {
3121 PrintAndLogEx(NORMAL
, "\nButton pressed, user aborted");
3124 case PM3_ESTATIC_NONCE
: {
3125 PrintAndLogEx(ERR
, "\nError: Static encrypted nonce detected. Aborted\n");
3127 e_sector
[current_sector_i
].Key
[current_key_type_i
] = 0xffffffffffff;
3128 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = false;
3130 // Show the results to the user
3131 PrintAndLogEx(NORMAL
, "");
3132 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3133 printKeyTable(sector_cnt
, e_sector
);
3134 PrintAndLogEx(NORMAL
, "");
3138 PrintAndLogEx(FAILED
, "\nFailed to recover a key...");
3150 // Copy the found key to the tmp_key variale (for the following print statement, and the mfCheckKeys above)
3151 num_to_bytes(foundkey
, MIFARE_KEY_SIZE
, tmp_key
);
3152 e_sector
[current_sector_i
].Key
[current_key_type_i
] = foundkey
;
3153 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'H';
3156 if (has_staticnonce
== NONCE_STATIC
) {
3159 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
3160 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
3162 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
3165 isOK
= mfStaticNested(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, tmp_key
);
3168 case PM3_ETIMEOUT
: {
3169 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
3174 case PM3_EOPABORTED
: {
3175 PrintAndLogEx(WARNING
, "\nButton pressed, user aborted");
3181 e_sector
[current_sector_i
].Key
[current_key_type_i
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
3182 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'C';
3191 // Check if the key was found
3192 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
]) {
3193 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
3195 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3196 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
3206 // Show the results to the user
3207 PrintAndLogEx(NORMAL
, "");
3208 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3210 printKeyTable(sector_cnt
, e_sector
);
3212 if (no_save
== false) {
3215 PrintAndLogEx(NORMAL
, "");
3216 if (createMfcKeyDump(fptr
, sector_cnt
, e_sector
) != PM3_SUCCESS
) {
3217 PrintAndLogEx(ERR
, "Failed to save keys to file");
3221 // clear emulator mem
3222 clearCommandBuffer();
3223 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR
, NULL
, 0);
3225 PrintAndLogEx(INFO
, "transferring keys to simulator memory " NOLF
);
3227 bool transfer_status
= true;
3228 for (current_sector_i
= 0; current_sector_i
< sector_cnt
; current_sector_i
++) {
3229 mfEmlGetMem(block
, current_sector_i
, 1);
3230 if (e_sector
[current_sector_i
].foundKey
[0])
3231 num_to_bytes(e_sector
[current_sector_i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3232 if (e_sector
[current_sector_i
].foundKey
[1])
3233 num_to_bytes(e_sector
[current_sector_i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3235 transfer_status
|= mfEmlSetMem(block
, mfFirstBlockOfSector(current_sector_i
) + mfNumBlocksPerSector(current_sector_i
) - 1, 1);
3237 PrintAndLogEx(NORMAL
, "( %s )", (transfer_status
) ? _GREEN_("ok") : _RED_("fail"));
3239 PrintAndLogEx(INFO
, "dumping card content to emulator memory (Cmd Error: 04 can occur)");
3242 FastDumpWithEcFill(sector_cnt
);
3245 PrintAndLogEx(INFO
, "Called with no save option");
3246 PrintAndLogEx(NORMAL
, "");
3250 bytes
= block_cnt
* MFBLOCK_SIZE
;
3251 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
3253 PrintAndLogEx(ERR
, "Fail, cannot allocate memory");
3259 PrintAndLogEx(INFO
, "downloading card content from emulator memory");
3260 if (GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false) == false) {
3261 PrintAndLogEx(ERR
, "Fail, transfer from device time-out");
3265 return PM3_ETIMEOUT
;
3269 fptr
= GenerateFilename("hf-mf-", "-dump");
3277 strncpy(filename
, fptr
, sizeof(filename
) - 1);
3280 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
3284 // Generate and show statistics
3285 t1
= msclock() - t1
;
3286 PrintAndLogEx(INFO
, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1
/ 1000.0);
3292 static int CmdHF14AMfChk_fast(const char *Cmd
) {
3293 CLIParserContext
*ctx
;
3294 CLIParserInit(&ctx
, "hf mf fchk",
3295 "This is a improved checkkeys method speedwise. It checks MIFARE Classic tags sector keys against a dictionary file with keys",
3296 "hf mf fchk --mini -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
3297 "hf mf fchk --1k -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
3298 "hf mf fchk --2k -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
3299 "hf mf fchk --4k -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k\n"
3300 "hf mf fchk --1k -f mfc_default_keys.dic --> Target 1K using default dictionary file\n"
3301 "hf mf fchk --1k --emu --> Target 1K, write keys to emulator memory\n"
3302 "hf mf fchk --1k --dump --> Target 1K, write keys to file\n"
3303 "hf mf fchk --1k --mem --> Target 1K, use dictionary from flash memory");
3305 void *argtable
[] = {
3307 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
3308 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3309 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3310 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3311 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3312 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3313 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3314 arg_lit0(NULL
, "mem", "Use dictionary from flashmemory"),
3315 arg_str0("f", "file", "<fn>", "filename of dictionary"),
3316 arg_int0(NULL
, "blk", "<dec>", "block number (single block recovery mode)"),
3317 arg_lit0("a", NULL
, "single block recovery key A"),
3318 arg_lit0("b", NULL
, "single block recovery key B"),
3319 arg_lit0(NULL
, "no-default", "Skip check default keys"),
3322 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3325 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0};
3326 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
3328 bool m0
= arg_get_lit(ctx
, 2);
3329 bool m1
= arg_get_lit(ctx
, 3);
3330 bool m2
= arg_get_lit(ctx
, 4);
3331 bool m4
= arg_get_lit(ctx
, 5);
3333 bool transferToEml
= arg_get_lit(ctx
, 6);
3334 bool createDumpFile
= arg_get_lit(ctx
, 7);
3335 bool use_flashmemory
= arg_get_lit(ctx
, 8);
3338 char filename
[FILE_PATH_SIZE
] = {0};
3339 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3341 int blockn
= arg_get_int_def(ctx
, 10, -1);
3342 uint8_t keytype
= MF_KEY_A
;
3343 if (arg_get_lit(ctx
, 11) && arg_get_lit(ctx
, 12)) {
3345 PrintAndLogEx(WARNING
, "Choose one single input key type");
3347 } else if (arg_get_lit(ctx
, 12)) {
3350 bool load_default
= ! arg_get_lit(ctx
, 13);
3356 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3357 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3359 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3363 uint8_t sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3365 sectorsCnt
= MIFARE_MINI_MAXSECTOR
;
3367 sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3369 sectorsCnt
= MIFARE_2K_MAXSECTOR
;
3371 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
3373 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3377 uint8_t *keyBlock
= NULL
;
3378 uint32_t keycnt
= 0;
3379 int ret
= mf_load_keys(&keyBlock
, &keycnt
, key
, keylen
, filename
, fnlen
, load_default
);
3380 if (ret
!= PM3_SUCCESS
) {
3384 // create/initialize key storage structure
3385 sector_t
*e_sector
= NULL
;
3386 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
3391 uint32_t chunksize
= keycnt
> (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : keycnt
;
3392 bool firstChunk
= true, lastChunk
= false;
3397 uint64_t t1
= msclock();
3399 uint16_t singleSectorParams
= 0;
3401 singleSectorParams
= (blockn
& 0xFF) | keytype
<< 8 | 1 << 15;
3403 if (use_flashmemory
) {
3404 PrintAndLogEx(SUCCESS
, "Using dictionary in flash memory");
3405 mfCheckKeys_fast_ex(sectorsCnt
, true, true, 1, 0, keyBlock
, e_sector
, use_flashmemory
, false, false, singleSectorParams
);
3408 // strategies. 1= deep first on sector 0 AB, 2= width first on all sectors
3409 for (uint8_t strategy
= 1; strategy
< 3; strategy
++) {
3410 PrintAndLogEx(INFO
, "Running strategy %u", strategy
);
3412 // main keychunk loop
3413 for (i
= 0; i
< keycnt
; i
+= chunksize
) {
3415 if (kbd_enter_pressed()) {
3416 PrintAndLogEx(NORMAL
, "");
3417 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
3418 // field is still ON if not on last chunk
3419 clearCommandBuffer();
3420 SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF
, NULL
, 0);
3421 // TODO: we're missing these cleanups on arm side, not sure if it's important...
3422 // set_tracing(false);
3424 // BigBuf_Clear_ext(false);
3427 PrintAndLogEx(INPLACE
, "Testing %5i/%5i %02.1f%%", i
, keycnt
, (float)i
* 100 / keycnt
);
3428 uint32_t size
= ((keycnt
- i
) > chunksize
) ? chunksize
: keycnt
- i
;
3431 if (size
== keycnt
- i
)
3434 int res
= mfCheckKeys_fast_ex(sectorsCnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* MIFARE_KEY_SIZE
), e_sector
, false, false, true, singleSectorParams
);
3438 // all keys, aborted
3439 if (res
== PM3_SUCCESS
|| res
== 2) {
3440 PrintAndLogEx(NORMAL
, "");
3443 } // end chunks of keys
3444 PrintAndLogEx(INPLACE
, "Testing %5i/%5i 100.00%%", keycnt
, keycnt
);
3445 PrintAndLogEx(NORMAL
, "");
3448 if (blockn
!= -1) break;
3452 t1
= msclock() - t1
;
3453 PrintAndLogEx(INFO
, "Time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1
/ 1000.0));
3460 uint8_t found_keys
= 0;
3461 for (i
= 0; i
< sectorsCnt
; ++i
) {
3463 if (e_sector
[i
].foundKey
[0])
3466 if (e_sector
[i
].foundKey
[1])
3470 if (found_keys
== 0) {
3471 PrintAndLogEx(WARNING
, "No keys found");
3474 PrintAndLogEx(NORMAL
, "");
3475 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3477 printKeyTable(sectorsCnt
, e_sector
);
3479 if (use_flashmemory
&& found_keys
== (sectorsCnt
<< 1)) {
3480 PrintAndLogEx(SUCCESS
, "Card dumped as well. run " _YELLOW_("`%s %c`"),
3482 GetFormatFromSector(sectorsCnt
)
3486 if (transferToEml
) {
3488 g_conn
.block_after_ACK
= true;
3489 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3490 for (i
= 0; i
< sectorsCnt
; ++i
) {
3491 uint8_t b
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3492 mfEmlGetMem(block
, b
, 1);
3494 if (e_sector
[i
].foundKey
[0])
3495 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3497 if (e_sector
[i
].foundKey
[1])
3498 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3500 if (i
== sectorsCnt
- 1) {
3501 // Disable fast mode on last packet
3502 g_conn
.block_after_ACK
= false;
3504 mfEmlSetMem(block
, b
, 1);
3506 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
3508 if (found_keys
== (sectorsCnt
<< 1)) {
3509 FastDumpWithEcFill(sectorsCnt
);
3513 if (createDumpFile
) {
3515 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
3516 if (createMfcKeyDump(fptr
, sectorsCnt
, e_sector
) != PM3_SUCCESS
) {
3517 PrintAndLogEx(ERR
, "Failed to save keys to file");
3525 PrintAndLogEx(NORMAL
, "");
3529 static int CmdHF14AMfSmartBrute(const char *Cmd
) {
3530 CLIParserContext
*ctx
;
3531 CLIParserInit(&ctx
, "hf mf brute",
3532 "This is a smart bruteforce, exploiting common patterns, bugs and bad designs in key generators.",
3533 "hf mf brute --mini --> Key recovery against MIFARE Mini\n"
3534 "hf mf brute --1k --> Key recovery against MIFARE Classic 1k\n"
3535 "hf mf brute --2k --> Key recovery against MIFARE 2k\n"
3536 "hf mf brute --4k --> Key recovery against MIFARE 4k\n"
3537 "hf mf brute --1k --emu --> Target 1K, write keys to emulator memory\n"
3538 "hf mf brute --1k --dump --> Target 1K, write keys to file\n");
3540 void *argtable
[] = {
3542 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3543 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3544 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3545 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3546 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3547 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3550 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3553 bool m0
= arg_get_lit(ctx
, 2);
3554 bool m1
= arg_get_lit(ctx
, 3);
3555 bool m2
= arg_get_lit(ctx
, 4);
3556 bool m4
= arg_get_lit(ctx
, 5);
3558 bool transferToEml
= arg_get_lit(ctx
, 6);
3559 bool createDumpFile
= arg_get_lit(ctx
, 7);
3565 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3566 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3568 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3572 uint8_t sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3574 sectorsCnt
= MIFARE_MINI_MAXSECTOR
;
3576 sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3578 sectorsCnt
= MIFARE_2K_MAXSECTOR
;
3580 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
3582 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3586 uint32_t chunksize
= 100 > (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : 100;
3587 uint8_t *keyBlock
= calloc(MIFARE_KEY_SIZE
, chunksize
);
3589 if (keyBlock
== NULL
)
3592 // create/initialize key storage structure
3593 sector_t
*e_sector
= NULL
;
3594 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
3599 // initialize bruteforce engine
3600 generator_context_t bctx
;
3601 bf_generator_init(&bctx
, BF_MODE_SMART
, BF_KEY_SIZE_48
);
3604 int smart_mode_stage
= -1;
3605 uint64_t generator_key
;
3608 uint64_t t0
= msclock();
3609 uint64_t t1
= msclock();
3610 uint64_t keys_checked
= 0;
3611 uint64_t total_keys_checked
= 0;
3613 uint32_t keycnt
= 0;
3614 bool firstChunk
= true, lastChunk
= false;
3616 while (!lastChunk
) {
3619 // generate block of keys from generator
3620 memset(keyBlock
, 0, MIFARE_KEY_SIZE
* chunksize
);
3622 for (i
= 0; i
< chunksize
; i
++) {
3624 ret
= bf_generate(&bctx
);
3626 if (ret
== BF_GENERATOR_ERROR
) {
3627 PrintAndLogEx(ERR
, "Internal bruteforce generator error");
3632 } else if (ret
== BF_GENERATOR_END
) {
3637 } else if (ret
== BF_GENERATOR_NEXT
) {
3639 generator_key
= bf_get_key48(&bctx
);
3640 num_to_bytes(generator_key
, MIFARE_KEY_SIZE
, keyBlock
+ (i
* MIFARE_KEY_SIZE
));
3643 if (smart_mode_stage
!= bctx
.smart_mode_stage
) {
3645 smart_mode_stage
= bctx
.smart_mode_stage
;
3646 PrintAndLogEx(INFO
, "Running bruteforce stage %d", smart_mode_stage
);
3650 PrintAndLogEx(INFO
, "Current cracking speed (keys/s): %lu",
3651 keys_checked
/ ((msclock() - t1
) / 1000)
3661 int strategy
= 2; // width first on all sectors
3662 ret
= mfCheckKeys_fast(sectorsCnt
, firstChunk
, lastChunk
, strategy
, keycnt
, keyBlock
, e_sector
, false, false);
3664 keys_checked
+= keycnt
;
3665 total_keys_checked
+= keycnt
;
3670 if (ret
== PM3_SUCCESS
|| ret
== 2)
3676 PrintAndLogEx(INFO
, "Time in brute mode: " _YELLOW_("%.1fs") "\n", (float)((msclock() - t0
) / 1000.0));
3677 PrintAndLogEx(INFO
, "Total keys checked: " _YELLOW_("%lu") "\n", total_keys_checked
);
3679 uint8_t found_keys
= 0;
3680 for (i
= 0; i
< sectorsCnt
; ++i
) {
3682 if (e_sector
[i
].foundKey
[0]) {
3686 if (e_sector
[i
].foundKey
[1]) {
3691 if (found_keys
== 0) {
3692 PrintAndLogEx(WARNING
, "No keys found");
3695 PrintAndLogEx(NORMAL
, "");
3696 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3698 printKeyTable(sectorsCnt
, e_sector
);
3700 if (transferToEml
) {
3702 g_conn
.block_after_ACK
= true;
3703 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3704 for (i
= 0; i
< sectorsCnt
; ++i
) {
3705 uint8_t b
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3706 mfEmlGetMem(block
, b
, 1);
3708 if (e_sector
[i
].foundKey
[0])
3709 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3711 if (e_sector
[i
].foundKey
[1])
3712 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3714 if (i
== sectorsCnt
- 1) {
3715 // Disable fast mode on last packet
3716 g_conn
.block_after_ACK
= false;
3718 mfEmlSetMem(block
, b
, 1);
3720 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
3722 if (found_keys
== (sectorsCnt
<< 1)) {
3723 FastDumpWithEcFill(sectorsCnt
);
3727 if (createDumpFile
) {
3729 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
3730 if (createMfcKeyDump(fptr
, sectorsCnt
, e_sector
) != PM3_SUCCESS
) {
3731 PrintAndLogEx(ERR
, "Failed to save keys to file");
3740 PrintAndLogEx(NORMAL
, "");
3744 static int CmdHF14AMfChk(const char *Cmd
) {
3745 CLIParserContext
*ctx
;
3746 CLIParserInit(&ctx
, "hf mf chk",
3747 "Check keys on MIFARE Classic card",
3748 "hf mf chk --mini -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Mini\n"
3749 "hf mf chk --1k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Classic 1k\n"
3750 "hf mf chk --2k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 2k\n"
3751 "hf mf chk --4k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 4k\n"
3752 "hf mf chk --1k --emu --> Check all sectors, all keys, 1K, and write to emulator memory\n"
3753 "hf mf chk --1k --dump --> Check all sectors, all keys, 1K, and write to file\n"
3754 "hf mf chk -a --tblk 0 -f mfc_default_keys.dic --> Check dictionary against block 0, key A");
3756 void *argtable
[] = {
3758 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
3759 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
3760 arg_lit0("a", NULL
, "Target Key A"),
3761 arg_lit0("b", NULL
, "Target Key B"),
3762 arg_lit0("*", "all", "Target both key A & B (default)"),
3763 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3764 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3765 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3766 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3767 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3768 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3769 arg_str0("f", "file", "<fn>", "Filename of dictionary"),
3770 arg_lit0(NULL
, "no-default", "Skip check default keys"),
3773 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3776 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0};
3777 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
3779 int blockNo
= arg_get_int_def(ctx
, 2, -1);
3781 uint8_t keyType
= 2;
3783 if ((arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) || arg_get_lit(ctx
, 5)) {
3785 } else if (arg_get_lit(ctx
, 3)) {
3787 } else if (arg_get_lit(ctx
, 4)) {
3791 bool m0
= arg_get_lit(ctx
, 6);
3792 bool m1
= arg_get_lit(ctx
, 7);
3793 bool m2
= arg_get_lit(ctx
, 8);
3794 bool m4
= arg_get_lit(ctx
, 9);
3796 bool transferToEml
= arg_get_lit(ctx
, 10);
3797 bool createDumpFile
= arg_get_lit(ctx
, 11);
3800 char filename
[FILE_PATH_SIZE
] = {0};
3801 CLIParamStrToBuf(arg_get_str(ctx
, 12), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3802 bool load_default
= ! arg_get_lit(ctx
, 13);
3806 bool singleSector
= (blockNo
> -1);
3807 if (singleSector
== false) {
3808 // start from first trailer block
3813 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3814 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3818 size_t sectors_cnt
= 1;
3820 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
3822 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3824 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
3826 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
3831 // find a MIFARE type that can accommodate the provided block number
3832 size_t min_sectors_cnt
= 0;
3833 uint8_t s
= mfSectorNum(blockNo
);
3835 if (s
< MIFARE_MINI_MAXSECTOR
) {
3836 min_sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
3837 } else if (s
< MIFARE_1K_MAXSECTOR
) {
3838 min_sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3839 } else if (s
< MIFARE_2K_MAXSECTOR
) {
3840 min_sectors_cnt
= MIFARE_2K_MAXSECTOR
;
3841 } else if (s
< MIFARE_4K_MAXSECTOR
) {
3842 min_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
3844 PrintAndLogEx(WARNING
, "Provided block out of possible MIFARE Type memory map");
3848 if (sectors_cnt
== 1) {
3849 sectors_cnt
= min_sectors_cnt
;
3850 } else if (sectors_cnt
< min_sectors_cnt
) {
3851 PrintAndLogEx(WARNING
, "Provided block out of provided MIFARE Type memory map");
3856 if (sectors_cnt
== 1) {
3857 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3860 uint8_t *keyBlock
= NULL
;
3861 uint32_t keycnt
= 0;
3862 int ret
= mf_load_keys(&keyBlock
, &keycnt
, key
, keylen
, filename
, fnlen
, load_default
);
3863 if (ret
!= PM3_SUCCESS
) {
3869 // create/initialize key storage structure
3870 sector_t
*e_sector
= NULL
;
3871 if (initSectorTable(&e_sector
, sectors_cnt
) != PM3_SUCCESS
) {
3876 uint8_t trgKeyType
= MF_KEY_A
;
3877 uint16_t max_keys
= keycnt
> KEYS_IN_BLOCK
? KEYS_IN_BLOCK
: keycnt
;
3879 PrintAndLogEx(INFO
, "Start check for keys...");
3880 PrintAndLogEx(INFO
, "." NOLF
);
3883 g_conn
.block_after_ACK
= true;
3885 // clear trace log by first check keys call only
3886 bool clearLog
= true;
3889 uint64_t t1
= msclock();
3892 for (trgKeyType
= (keyType
== 2) ? 0 : keyType
; trgKeyType
< 2; (keyType
== 2) ? (++trgKeyType
) : (trgKeyType
= 2)) {
3894 // loop sectors but block is used as to keep track of from which blocks to test
3896 for (int i
= mfSectorNum(b
); i
< sectors_cnt
; ++i
) {
3898 // skip already found keys.
3899 if (e_sector
[i
].foundKey
[trgKeyType
]) continue;
3901 for (uint32_t c
= 0; c
< keycnt
; c
+= max_keys
) {
3903 PrintAndLogEx(NORMAL
, "." NOLF
);
3906 if (kbd_enter_pressed()) {
3907 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
3911 uint32_t size
= keycnt
- c
> max_keys
? max_keys
: keycnt
- c
;
3913 if (mfCheckKeys(b
, trgKeyType
, clearLog
, size
, &keyBlock
[MIFARE_KEY_SIZE
* c
], &key64
) == PM3_SUCCESS
) {
3914 e_sector
[i
].Key
[trgKeyType
] = key64
;
3915 e_sector
[i
].foundKey
[trgKeyType
] = true;
3924 b
< 127 ? (b
+= 4) : (b
+= 16);
3927 t1
= msclock() - t1
;
3928 PrintAndLogEx(INFO
, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
3930 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
3931 if (keyType
!= MF_KEY_B
) {
3932 PrintAndLogEx(INFO
, "testing to read key B...");
3934 // loop sectors but block is used as to keep track of from which blocks to test
3936 for (int i
= mfSectorNum(b
); i
< sectors_cnt
; i
++) {
3938 // KEY A but not KEY B
3939 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
3941 uint8_t sectrail
= mfSectorTrailerOfSector(i
);
3942 PrintAndLogEx(INFO
, "Sector: %u, First block: %u, Last block: %u, Num of blocks: %u", i
, mfFirstBlockOfSector(i
), sectrail
, mfNumBlocksPerSector(i
));
3943 PrintAndLogEx(INFO
, "Reading sector trailer");
3945 mf_readblock_t payload
;
3946 payload
.blockno
= sectrail
;
3947 payload
.keytype
= MF_KEY_A
;
3950 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, payload
.key
);
3952 clearCommandBuffer();
3953 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
3955 PacketResponseNG resp
;
3956 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) continue;
3958 if (resp
.status
!= PM3_SUCCESS
) continue;
3960 uint8_t *data
= resp
.data
.asBytes
;
3961 key64
= bytes_to_num(data
+ 10, MIFARE_KEY_SIZE
);
3963 PrintAndLogEx(NORMAL
, "Data:%s", sprint_hex(data
+ 10, MIFARE_KEY_SIZE
));
3964 e_sector
[i
].foundKey
[1] = 1;
3965 e_sector
[i
].Key
[1] = key64
;
3970 b
< 127 ? (b
+= 4) : (b
+= 16);
3975 PrintAndLogEx(NORMAL
, "");
3976 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3979 // if (singleSector)
3980 // printKeyTableEx(1, e_sector, mfSectorNum(blockNo));
3982 printKeyTable(sectors_cnt
, e_sector
);
3984 if (transferToEml
) {
3986 g_conn
.block_after_ACK
= true;
3987 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3988 for (int i
= 0; i
< sectors_cnt
; ++i
) {
3989 uint8_t blockno
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3990 mfEmlGetMem(block
, blockno
, 1);
3992 if (e_sector
[i
].foundKey
[0])
3993 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3995 if (e_sector
[i
].foundKey
[1])
3996 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3998 if (i
== sectors_cnt
- 1) {
3999 // Disable fast mode on last packet
4000 g_conn
.block_after_ACK
= false;
4002 mfEmlSetMem(block
, blockno
, 1);
4004 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
4007 if (createDumpFile
) {
4008 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
4009 if (createMfcKeyDump(fptr
, sectors_cnt
, e_sector
) != PM3_SUCCESS
) {
4010 PrintAndLogEx(ERR
, "Failed to save keys to file");
4018 // Disable fast mode and send a dummy command to make it effective
4019 g_conn
.block_after_ACK
= false;
4020 SendCommandNG(CMD_PING
, NULL
, 0);
4021 if (!WaitForResponseTimeout(CMD_PING
, NULL
, 1000)) {
4022 PrintAndLogEx(WARNING
, "command execution time out");
4023 return PM3_ETIMEOUT
;
4026 PrintAndLogEx(NORMAL
, "");
4030 void showSectorTable(sector_t
*k_sector
, size_t k_sectors_cnt
) {
4031 if (k_sector
!= NULL
) {
4032 printKeyTable(k_sectors_cnt
, k_sector
);
4037 void readerAttack(sector_t
*k_sector
, size_t k_sectors_cnt
, nonces_t data
, bool setEmulatorMem
, bool verbose
) {
4040 if (k_sector
== NULL
) {
4041 if (initSectorTable(&k_sector
, k_sectors_cnt
) != PM3_SUCCESS
) {
4048 if ((nonce_state
)data
.state
== SECOND
) {
4049 found
= mfkey32_moebius(&data
, &key
);
4050 } else if ((nonce_state
)data
.state
== NESTED
) {
4051 found
= mfkey32_nested(&data
, &key
);
4054 uint8_t sector
= data
.sector
;
4055 uint8_t keytype
= data
.keytype
;
4057 PrintAndLogEx(INFO
, "Reader is trying authenticate with: Key %s, sector %02d: [%012" PRIx64
"]"
4058 , (keytype
== MF_KEY_B
) ? "B" : "A"
4063 k_sector
[sector
].Key
[keytype
] = key
;
4064 k_sector
[sector
].foundKey
[keytype
] = true;
4066 //set emulator memory for keys
4067 if (setEmulatorMem
) {
4068 uint8_t memBlock
[16];
4069 mfEmlGetMem(memBlock
, (sector
* 4) + 3, 1);
4070 if ((memBlock
[6]==0) && (memBlock
[7]==0) && (memBlock
[8]==0)) {
4076 num_to_bytes(k_sector
[sector
].Key
[keytype
], 6, memBlock
+ ((keytype
== MF_KEY_B
) ? 10 : 0));
4077 //iceman, guessing this will not work so well for 4K tags.
4078 PrintAndLogEx(INFO
, "Setting Emulator Memory Block %02d: [%s]"
4080 , sprint_hex(memBlock
, sizeof(memBlock
))
4082 mfEmlSetMem(memBlock
, (sector
* 4) + 3, 1);
4089 static int CmdHF14AMfSim(const char *Cmd
) {
4090 CLIParserContext
*ctx
;
4091 CLIParserInit(&ctx
, "hf mf sim",
4092 "Simulate MIFARE Classic family type based upon\n"
4093 "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
4094 "from emulator memory. See `hf mf eload` first.\n"
4095 "The UID from emulator memory will be used if not specified.",
4096 "hf mf sim --mini --> MIFARE Mini\n"
4097 "hf mf sim --1k --> MIFARE Classic 1k (default)\n"
4098 "hf mf sim --1k -u 0a0a0a0a --> MIFARE Classic 1k with 4b UID\n"
4099 "hf mf sim --1k -u 11223344556677 --> MIFARE Classic 1k with 7b UID\n"
4100 "hf mf sim --1k -u 11223344 -i -x --> Perform reader attack in interactive mode\n"
4101 "hf mf sim --2k --> MIFARE 2k\n"
4102 "hf mf sim --4k --> MIFARE 4k"
4103 "hf mf sim --1k -x -e --> Keep simulation running and populate with found reader keys\n"
4106 void *argtable
[] = {
4108 arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
4109 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4110 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
4111 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4112 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4113 arg_str0(NULL
, "atqa", "<hex>", "Provide explicit ATQA (2 bytes, overrides option t)"),
4114 arg_str0(NULL
, "sak", "<hex>", "Provide explicit SAK (1 bytes, overrides option t)"),
4115 arg_int0("n", "num", "<dec> ", "Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite"),
4116 arg_lit0("i", "interactive", "Console will not be returned until simulation finishes or is aborted"),
4117 arg_lit0("x", NULL
, "Performs the 'reader attack', nr/ar attack against a reader."),
4118 arg_lit0("y", NULL
, "Performs the nested 'reader attack'. This requires preloading nt & nt_enc in emulator memory. Implies -x."),
4119 arg_lit0("e", "emukeys", "Fill simulator keys from found keys. Requires -x or -y. Implies -i. Simulation will restart automatically."),
4120 arg_lit0("v", "verbose", "verbose output"),
4121 arg_lit0(NULL
, "cve", "trigger CVE 2021_0430"),
4124 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4129 uint8_t uid
[10] = {0};
4130 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
4132 char uidsize
[8] = {0};
4136 flags
|= FLAG_10B_UID_IN_DATA
;
4137 snprintf(uidsize
, sizeof(uidsize
), "10 byte");
4140 flags
|= FLAG_7B_UID_IN_DATA
;
4141 snprintf(uidsize
, sizeof(uidsize
), "7 byte");
4144 flags
|= FLAG_4B_UID_IN_DATA
;
4145 snprintf(uidsize
, sizeof(uidsize
), "4 byte");
4148 PrintAndLogEx(WARNING
, "Invalid parameter for UID");
4154 bool m0
= arg_get_lit(ctx
, 2);
4155 bool m1
= arg_get_lit(ctx
, 3);
4156 bool m2
= arg_get_lit(ctx
, 4);
4157 bool m4
= arg_get_lit(ctx
, 5);
4160 uint8_t atqa
[2] = {0};
4161 CLIGetHexWithReturn(ctx
, 6, atqa
, &atqalen
);
4164 uint8_t sak
[1] = {0};
4165 CLIGetHexWithReturn(ctx
, 7, sak
, &saklen
);
4167 uint8_t exitAfterNReads
= arg_get_u32_def(ctx
, 8, 0);
4169 if (arg_get_lit(ctx
, 9)) {
4170 flags
|= FLAG_INTERACTIVE
;
4173 if (arg_get_lit(ctx
, 10)) {
4174 flags
|= FLAG_NR_AR_ATTACK
;
4177 if (arg_get_lit(ctx
, 11)) {
4178 flags
|= FLAG_NESTED_AUTH_ATTACK
;
4181 bool setEmulatorMem
= arg_get_lit(ctx
, 12);
4183 bool verbose
= arg_get_lit(ctx
, 13);
4185 if (arg_get_lit(ctx
, 14)) {
4186 flags
|= FLAG_CVE21_0430
;
4193 PrintAndLogEx(WARNING
, "Wrong ATQA length");
4196 flags
|= FLAG_FORCED_ATQA
;
4201 PrintAndLogEx(WARNING
, "Wrong SAK length");
4204 flags
|= FLAG_FORCED_SAK
;
4207 // Use UID, SAK, ATQA from EMUL, if uid not defined
4208 if ((flags
& (FLAG_4B_UID_IN_DATA
| FLAG_7B_UID_IN_DATA
| FLAG_10B_UID_IN_DATA
)) == 0) {
4209 flags
|= FLAG_UID_IN_EMUL
;
4212 size_t k_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4213 char csize
[13] = { 0 };
4215 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4216 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4221 flags
|= FLAG_MF_MINI
;
4222 snprintf(csize
, sizeof(csize
), "MINI");
4223 k_sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
4225 flags
|= FLAG_MF_1K
;
4226 snprintf(csize
, sizeof(csize
), "1K");
4227 k_sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4229 flags
|= FLAG_MF_2K
;
4230 snprintf(csize
, sizeof(csize
), "2K with RATS");
4231 k_sectors_cnt
= MIFARE_2K_MAXSECTOR
;
4233 flags
|= FLAG_MF_4K
;
4234 snprintf(csize
, sizeof(csize
), "4K");
4235 k_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4237 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4241 if ((flags
& FLAG_NESTED_AUTH_ATTACK
) == FLAG_NESTED_AUTH_ATTACK
) {
4242 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
) {
4243 PrintAndLogEx(INFO
, "Note: option -y implies -x");
4244 flags
|= FLAG_NR_AR_ATTACK
;
4248 if (setEmulatorMem
) {
4249 if ((flags
& FLAG_INTERACTIVE
) != FLAG_INTERACTIVE
) {
4250 PrintAndLogEx(INFO
, "Note: option -e implies -i");
4251 flags
|= FLAG_INTERACTIVE
;
4253 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
) {
4254 PrintAndLogEx(WARNING
, "Option -e requires -x or -y");
4259 PrintAndLogEx(INFO
, _YELLOW_("MIFARE %s") " | %s UID " _YELLOW_("%s") ""
4262 , (uidlen
== 0) ? "n/a" : sprint_hex(uid
, uidlen
)
4265 PrintAndLogEx(INFO
, "Options [ numreads: %d, flags: %d (0x%02x) ]"
4278 payload
.flags
= flags
;
4279 payload
.exitAfter
= exitAfterNReads
;
4280 memcpy(payload
.uid
, uid
, uidlen
);
4281 payload
.atqa
= (atqa
[1] << 8) | atqa
[0];
4282 payload
.sak
= sak
[0];
4284 clearCommandBuffer();
4286 if (flags
& FLAG_INTERACTIVE
) {
4287 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " or a key to abort simulation");
4289 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation");
4294 SendCommandNG(CMD_HF_MIFARE_SIMULATE
, (uint8_t *)&payload
, sizeof(payload
));
4295 if (flags
& FLAG_INTERACTIVE
) {
4296 PacketResponseNG resp
;
4297 sector_t
*k_sector
= NULL
;
4299 bool keypress
= kbd_enter_pressed();
4300 while (keypress
== false) {
4302 if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE
, &resp
, 1500) == 0) {
4303 keypress
= kbd_enter_pressed();
4307 if (resp
.status
!= PM3_SUCCESS
)
4310 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
)
4313 const nonces_t
*data
= (nonces_t
*)resp
.data
.asBytes
;
4314 readerAttack(k_sector
, k_sectors_cnt
, data
[0], setEmulatorMem
, verbose
);
4315 if (setEmulatorMem
) {
4321 if ((flags
& FLAG_NR_AR_ATTACK
) == FLAG_NR_AR_ATTACK
) {
4322 // inform device to break the sim loop since client has exited
4323 PrintAndLogEx(INFO
, "Key pressed, please wait a few seconds for the pm3 to stop...");
4324 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
4334 static int CmdHF14AMfKeyBrute(const char *Cmd) {
4336 uint8_t blockNo = 0, keytype = MF_KEY_A;
4337 uint8_t key[6] = {0, 0, 0, 0, 0, 0};
4338 uint64_t foundkey = 0;
4340 char cmdp = tolower(param_getchar(Cmd, 0));
4341 if (cmdp == 'h') return usage_hf14_keybrute();
4344 blockNo = param_get8(Cmd, 0);
4347 cmdp = tolower(param_getchar(Cmd, 1));
4348 if (cmdp == 'b') keytype = MF_KEY_B;
4352 if (param_gethex_ex(Cmd, 2, key, &keylen) && (keylen != 12)) {
4353 return usage_hf14_keybrute();
4356 uint64_t t1 = msclock();
4358 if (mfKeyBrute(blockNo, keytype, key, &foundkey))
4359 PrintAndLogEx(SUCCESS, "found valid key: %012" PRIx64 " \n", foundkey);
4361 PrintAndLogEx(FAILED, "key not found");
4363 t1 = msclock() - t1;
4364 PrintAndLogEx(SUCCESS, "\ntime in keybrute " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
4369 void printKeyTable(size_t sectorscnt
, sector_t
*e_sector
) {
4370 printKeyTableEx(sectorscnt
, e_sector
, 0);
4373 void printKeyTableEx(size_t sectorscnt
, sector_t
*e_sector
, uint8_t start_sector
) {
4374 char strA
[26 + 1] = {0};
4375 char strB
[26 + 1] = {0};
4376 char resA
[20 + 1] = {0};
4377 char resB
[20 + 1] = {0};
4379 uint64_t ndef_key
= 0xD3F7D3F7D3F7;
4380 bool has_ndef_key
= false;
4381 bool extended_legend
= false;
4383 PrintAndLogEx(NORMAL
, "");
4384 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4385 PrintAndLogEx(SUCCESS
, " Sec | Blk | key A |res| key B |res");
4386 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4388 for (size_t i
= 0; i
< sectorscnt
; i
++) {
4390 if ((e_sector
[i
].foundKey
[0] > 1) || (e_sector
[i
].foundKey
[1] > 1)) {
4391 extended_legend
= true;
4394 if (e_sector
[i
].Key
[0] == ndef_key
|| e_sector
[i
].Key
[1] == ndef_key
) {
4395 has_ndef_key
= true;
4398 if (e_sector
[i
].foundKey
[0]) {
4399 snprintf(strA
, sizeof(strA
), _GREEN_("%012" PRIX64
), e_sector
[i
].Key
[0]);
4400 if (extended_legend
) {
4401 snprintf(resA
, sizeof(resA
), _BRIGHT_GREEN_("%c"), e_sector
[i
].foundKey
[0]);
4403 snprintf(resA
, sizeof(resA
), _BRIGHT_GREEN_("%d"), e_sector
[i
].foundKey
[0]);
4406 snprintf(strA
, sizeof(strA
), _RED_("%s"), "------------");
4407 snprintf(resA
, sizeof(resA
), _RED_("0"));
4410 if (e_sector
[i
].foundKey
[1]) {
4411 snprintf(strB
, sizeof(strB
), _GREEN_("%012" PRIX64
), e_sector
[i
].Key
[1]);
4412 if (extended_legend
) {
4413 snprintf(resB
, sizeof(resB
), _BRIGHT_GREEN_("%c"), e_sector
[i
].foundKey
[1]);
4415 snprintf(resB
, sizeof(resB
), _BRIGHT_GREEN_("%d"), e_sector
[i
].foundKey
[1]);
4418 snprintf(strB
, sizeof(strB
), _RED_("%s"), "------------");
4419 snprintf(resB
, sizeof(resB
), _RED_("0"));
4422 // keep track if we use start_sector or i
4423 // show one sector or all.
4424 uint8_t s
= start_sector
;
4425 if (start_sector
== 0) {
4429 char extra
[24] = {0x00};
4430 if (sectorscnt
== 18 && i
> 15) {
4431 strcat(extra
, "( " _MAGENTA_("*") " )");
4434 PrintAndLogEx(SUCCESS
, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s %s"
4436 , mfSectorTrailerOfSector(s
)
4443 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4445 if (extended_legend
) {
4446 PrintAndLogEx(INFO
, "( "
4447 _YELLOW_("D") ":Dictionary / "
4448 _YELLOW_("S") ":darkSide / "
4449 _YELLOW_("U") ":User / "
4450 _YELLOW_("R") ":Reused / "
4451 _YELLOW_("N") ":Nested / "
4452 _YELLOW_("H") ":Hardnested / "
4453 _YELLOW_("C") ":statiCnested / "
4454 _YELLOW_("A") ":keyA "
4457 if (sectorscnt
== 18) {
4458 PrintAndLogEx(INFO
, "( " _MAGENTA_("*") " ) These sectors used for signature. Lays outside of user memory");
4462 PrintAndLogEx(SUCCESS
, "( " _RED_("0") ":Failed / " _GREEN_("1") ":Success )");
4466 if (e_sector
[MF_MAD1_SECTOR
].foundKey
[0] && e_sector
[MF_MAD1_SECTOR
].Key
[0] == 0xA0A1A2A3A4A5) {
4467 PrintAndLogEx(HINT
, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details");
4471 PrintAndLogEx(HINT
, "NDEF key detected. Try " _YELLOW_("`hf mf ndefread`") " for more details");
4473 PrintAndLogEx(NORMAL
, "");
4477 // EMULATOR COMMANDS
4478 static int CmdHF14AMfEGetBlk(const char *Cmd
) {
4479 CLIParserContext
*ctx
;
4480 CLIParserInit(&ctx
, "hf mf egetblk",
4481 "Get emulator memory block",
4482 "hf mf egetblk --blk 0 -> get block 0 (manufacturer)\n"
4483 "hf mf egetblk --blk 3 -v -> get block 3, decode sector trailer\n"
4485 void *argtable
[] = {
4487 arg_int1("b", "blk", "<dec>", "block number"),
4488 arg_lit0("v", "verbose", "verbose output"),
4491 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4492 int b
= arg_get_int_def(ctx
, 1, 0);
4493 bool verbose
= arg_get_lit(ctx
, 2);
4499 uint8_t blockno
= (uint8_t)b
;
4501 uint8_t data
[16] = {0x00};
4502 if (mfEmlGetMem(data
, blockno
, 1) == PM3_SUCCESS
) {
4504 uint8_t sector
= mfSectorNum(blockno
);
4505 mf_print_sector_hdr(sector
);
4506 mf_print_block_one(blockno
, data
, verbose
);
4509 decode_print_st(blockno
, data
);
4511 PrintAndLogEx(NORMAL
, "");
4516 static int CmdHF14AMfEGetSc(const char *Cmd
) {
4517 CLIParserContext
*ctx
;
4518 CLIParserInit(&ctx
, "hf mf egetsc",
4519 "Get emulator memory sector",
4522 void *argtable
[] = {
4524 arg_int1("s", "sec", "<dec>", "sector number"),
4525 arg_lit0("v", "verbose", "verbose output"),
4528 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4529 int s
= arg_get_int_def(ctx
, 1, 0);
4530 bool verbose
= arg_get_lit(ctx
, 2);
4533 if (s
>= MIFARE_4K_MAXSECTOR
) {
4534 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
4538 uint8_t sector
= (uint8_t)s
;
4539 mf_print_sector_hdr(sector
);
4541 uint8_t blocks
= mfNumBlocksPerSector(sector
);
4542 uint8_t start
= mfFirstBlockOfSector(sector
);
4544 uint8_t data
[16] = {0};
4545 for (int i
= 0; i
< blocks
; i
++) {
4546 int res
= mfEmlGetMem(data
, start
+ i
, 1);
4547 if (res
== PM3_SUCCESS
) {
4548 mf_print_block_one(start
+ i
, data
, verbose
);
4552 decode_print_st(start
+ blocks
- 1, data
);
4554 PrintAndLogEx(NORMAL
, "");
4559 static int CmdHF14AMfEClear(const char *Cmd
) {
4560 CLIParserContext
*ctx
;
4561 CLIParserInit(&ctx
, "hf mf eclr",
4562 "It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF",
4565 void *argtable
[] = {
4569 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4571 clearCommandBuffer();
4572 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR
, NULL
, 0);
4576 static int CmdHF14AMfESet(const char *Cmd
) {
4578 CLIParserContext
*ctx
;
4579 CLIParserInit(&ctx
, "hf mf esetblk",
4580 "Set emulator memory block",
4581 "hf mf esetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
4583 void *argtable
[] = {
4585 arg_int1("b", "blk", "<dec>", "block number"),
4586 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
4589 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4591 int b
= arg_get_int_def(ctx
, 1, 0);
4593 uint8_t data
[16] = {0x00};
4595 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), data
, sizeof(data
), &datalen
);
4598 PrintAndLogEx(FAILED
, "Error parsing bytes");
4606 if (datalen
!= sizeof(data
)) {
4607 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", datalen
);
4612 return mfEmlSetMem(data
, b
, 1);
4615 int CmdHF14AMfELoad(const char *Cmd
) {
4617 CLIParserContext
*ctx
;
4618 CLIParserInit(&ctx
, "hf mf eload",
4619 "Load emulator memory with data from (bin/eml/json) dump file",
4620 "hf mf eload -f hf-mf-01020304.bin\n"
4621 "hf mf eload --4k -f hf-mf-01020304.eml\n"
4623 void *argtable
[] = {
4625 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
4626 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4627 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4628 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4629 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4630 arg_lit0(NULL
, "ul", "MIFARE Ultralight family"),
4631 arg_lit0("m", "mem", "use RDV4 spiffs"),
4632 arg_int0("q", "qty", "<dec>", "manually set number of blocks (overrides)"),
4633 arg_lit0("v", "verbose", "verbose output"),
4636 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4639 char filename
[FILE_PATH_SIZE
];
4640 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
4642 bool m0
= arg_get_lit(ctx
, 2);
4643 bool m1
= arg_get_lit(ctx
, 3);
4644 bool m2
= arg_get_lit(ctx
, 4);
4645 bool m4
= arg_get_lit(ctx
, 5);
4646 bool mu
= arg_get_lit(ctx
, 6);
4648 bool use_spiffs
= arg_get_lit(ctx
, 7);
4649 int numblks
= arg_get_int_def(ctx
, 8, -1);
4650 bool verbose
= arg_get_lit(ctx
, 9);
4654 if ((m0
+ m1
+ m2
+ m4
+ mu
) > 1) {
4655 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4657 } else if ((m0
+ m1
+ m2
+ m4
+ mu
) == 0) {
4661 uint8_t block_width
= 16;
4662 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4663 uint8_t hdr_len
= 0;
4666 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4668 block_cnt
= MIFARE_1K_MAXBLOCK
;
4670 block_cnt
= MIFARE_2K_MAXBLOCK
;
4672 block_cnt
= MIFARE_4K_MAXBLOCK
;
4674 block_cnt
= MFU_MAX_BLOCKS
;
4675 block_width
= MFU_BLOCK_SIZE
;
4676 hdr_len
= MFU_DUMP_PREFIX_LENGTH
;
4678 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4682 PrintAndLogEx(INFO
, "Upload " _YELLOW_("%u") " blocks " _YELLOW_("%u") " bytes", block_cnt
, block_cnt
* block_width
);
4685 block_cnt
= MIN(numblks
, block_cnt
);
4686 PrintAndLogEx(INFO
, "overriding number of blocks, will use " _YELLOW_("%u") " blocks " _YELLOW_("%u") " bytes", block_cnt
, block_cnt
* block_width
);
4689 // ICEMAN: bug. if device has been using ICLASS commands,
4690 // the device needs to load the HF fpga image. It takes 1.5 second.
4691 set_fpga_mode(FPGA_BITSTREAM_HF
);
4694 if (use_spiffs
&& IfPm3Flash() == false) {
4695 PrintAndLogEx(WARNING
, "Device not compiled to support spiffs");
4702 PrintAndLogEx(WARNING
, "filename too long for spiffs, expected 32, got %u", fnlen
);
4706 clearCommandBuffer();
4707 SendCommandNG(CMD_SPIFFS_ELOAD
, (uint8_t *)filename
, fnlen
);
4708 PacketResponseNG resp
;
4709 if (WaitForResponseTimeout(CMD_SPIFFS_ELOAD
, &resp
, 2000) == false) {
4710 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
4711 return PM3_ETIMEOUT
;
4714 if (resp
.status
!= PM3_SUCCESS
) {
4715 PrintAndLogEx(FAILED
, "Loading file from spiffs to emulator memory failed");
4719 PrintAndLogEx(SUCCESS
, "File transfered from spiffs to device emulator memory");
4723 uint8_t *data
= NULL
;
4724 size_t bytes_read
= 0;
4725 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (block_width
* block_cnt
+ hdr_len
));
4726 if (res
!= PM3_SUCCESS
) {
4730 // 64 or 256 blocks.
4731 if ((bytes_read
% block_width
) != 0) {
4732 PrintAndLogEx(FAILED
, "File content error. Size doesn't match blockwidth ");
4737 // convert plain or old mfu format to new format
4738 if (block_width
== MFU_BLOCK_SIZE
) {
4739 res
= convert_mfu_dump_format(&data
, &bytes_read
, true);
4740 if (res
!= PM3_SUCCESS
) {
4741 PrintAndLogEx(FAILED
, "Failed convert on load to new Ultralight/NTAG format");
4747 mfu_dump_t
*mfu_dump
= (mfu_dump_t
*)data
;
4748 mfu_print_dump(mfu_dump
, mfu_dump
->pages
+ 1, 0, false);
4751 // update expected blocks to match converted data.
4752 block_cnt
= bytes_read
/ MFU_BLOCK_SIZE
;
4753 PrintAndLogEx(INFO
, "MIFARE Ultralight override, will use %d blocks ( %u bytes )", block_cnt
, block_cnt
* block_width
);
4756 PrintAndLogEx(INFO
, "Uploading to emulator memory");
4757 PrintAndLogEx(INFO
, "." NOLF
);
4760 g_conn
.block_after_ACK
= true;
4765 // 12 is the size of the struct the fct mfEmlSetMem_xt uses to transfer to device
4766 uint16_t max_avail_blocks
= ((PM3_CMD_DATA_SIZE
- 12) / block_width
) * block_width
;
4768 while (bytes_read
&& cnt
< block_cnt
) {
4769 if (bytes_read
== block_width
) {
4770 // Disable fast mode on last packet
4771 g_conn
.block_after_ACK
= false;
4774 uint16_t chunk_size
= MIN(max_avail_blocks
, bytes_read
);
4775 uint16_t blocks_to_send
= chunk_size
/ block_width
;
4777 if (mfEmlSetMem_xt(data
+ offset
, cnt
, blocks_to_send
, block_width
) != PM3_SUCCESS
) {
4778 PrintAndLogEx(FAILED
, "Can't set emulator mem at block: %3d", cnt
);
4782 cnt
+= blocks_to_send
;
4783 offset
+= chunk_size
;
4784 bytes_read
-= chunk_size
;
4785 PrintAndLogEx(NORMAL
, "." NOLF
);
4789 PrintAndLogEx(NORMAL
, "");
4791 if (block_width
== MFU_BLOCK_SIZE
) {
4792 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mfu sim -h`"));
4794 if ((cnt
!= block_cnt
)) {
4795 PrintAndLogEx(WARNING
, "Warning, Ultralight/Ntag file content, Loaded %d blocks of expected %d blocks into emulator memory", cnt
, block_cnt
);
4799 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mf sim -h`"));
4801 if ((cnt
!= block_cnt
)) {
4802 PrintAndLogEx(WARNING
, "Error, file content, Only loaded %d blocks, must be %d blocks into emulator memory", cnt
, block_cnt
);
4805 PrintAndLogEx(INFO
, "Done!");
4810 static int CmdHF14AMfESave(const char *Cmd
) {
4812 CLIParserContext
*ctx
;
4813 CLIParserInit(&ctx
, "hf mf esave",
4814 "Save emulator memory to file (bin/json) ",
4816 "hf mf esave --4k\n"
4817 "hf mf esave --4k -f hf-mf-01020304.eml"
4819 void *argtable
[] = {
4821 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
4822 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4823 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4824 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4825 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4828 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4831 char filename
[FILE_PATH_SIZE
];
4832 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
4834 bool m0
= arg_get_lit(ctx
, 2);
4835 bool m1
= arg_get_lit(ctx
, 3);
4836 bool m2
= arg_get_lit(ctx
, 4);
4837 bool m4
= arg_get_lit(ctx
, 5);
4841 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4842 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4844 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4848 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4851 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4853 block_cnt
= MIFARE_1K_MAXBLOCK
;
4855 block_cnt
= MIFARE_2K_MAXBLOCK
;
4857 block_cnt
= MIFARE_4K_MAXBLOCK
;
4860 int bytes
= block_cnt
* MFBLOCK_SIZE
;
4863 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4865 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
4868 memset(dump
, 0, bytes
);
4870 PrintAndLogEx(INFO
, "downloading %u bytes from emulator memory", bytes
);
4871 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
4872 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
4874 return PM3_ETIMEOUT
;
4877 // user supplied filename?
4879 char *fptr
= filename
;
4880 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
4881 FillFileNameByUID(fptr
, dump
, "-dump", 4);
4884 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
4889 static int CmdHF14AMfEView(const char *Cmd
) {
4891 CLIParserContext
*ctx
;
4892 CLIParserInit(&ctx
, "hf mf eview",
4893 "It displays emulator memory",
4897 void *argtable
[] = {
4899 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4900 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4901 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4902 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4903 arg_lit0("v", "verbose", "verbose output"),
4904 arg_lit0(NULL
, "sk", "Save extracted keys to binary file"),
4907 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4908 bool m0
= arg_get_lit(ctx
, 1);
4909 bool m1
= arg_get_lit(ctx
, 2);
4910 bool m2
= arg_get_lit(ctx
, 3);
4911 bool m4
= arg_get_lit(ctx
, 4);
4912 bool verbose
= arg_get_lit(ctx
, 5);
4913 bool save_keys
= arg_get_lit(ctx
, 6);
4917 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4918 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4920 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4924 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4927 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4929 block_cnt
= MIFARE_1K_MAXBLOCK
;
4931 block_cnt
= MIFARE_2K_MAXBLOCK
;
4933 block_cnt
= MIFARE_4K_MAXBLOCK
;
4935 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4939 int bytes
= block_cnt
* MFBLOCK_SIZE
;
4941 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4943 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
4947 PrintAndLogEx(INFO
, "downloading emulator memory");
4948 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
4949 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
4951 return PM3_ETIMEOUT
;
4954 mf_print_blocks(block_cnt
, dump
, verbose
);
4957 mf_print_keys(block_cnt
, dump
);
4961 mf_save_keys_from_arr(block_cnt
, dump
);
4968 static int CmdHF14AMfECFill(const char *Cmd
) {
4970 CLIParserContext
*ctx
;
4971 CLIParserInit(&ctx
, "hf mf ecfill",
4972 "Dump card and transfer the data to emulator memory.\n"
4973 "Keys must be in the emulator memory",
4974 "hf mf ecfill --> use key type A\n"
4975 "hf mf ecfill --4k -b --> target 4K card with key type B"
4977 void *argtable
[] = {
4979 arg_lit0("a", NULL
, "input key type is key A(def)"),
4980 arg_lit0("b", NULL
, "input key type is key B"),
4981 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
4982 arg_str0("k", "key", "<hex>", "key, 6 hex bytes, only for option -c"),
4983 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4984 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4985 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4986 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4989 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4990 uint8_t keytype
= MF_KEY_A
;
4991 if (arg_get_lit(ctx
, 1) && arg_get_lit(ctx
, 2)) {
4993 PrintAndLogEx(WARNING
, "Choose one single input key type");
4995 } else if (arg_get_lit(ctx
, 2)) {
4998 uint8_t prev_keytype
= keytype
;
4999 keytype
= arg_get_int_def(ctx
, 3, keytype
);
5000 if ((arg_get_lit(ctx
, 1) || arg_get_lit(ctx
, 2)) && (keytype
!= prev_keytype
)) {
5002 PrintAndLogEx(WARNING
, "Choose one single input key type");
5006 uint8_t key
[6] = {0};
5007 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
5008 if ((keytype
> MF_KEY_B
) && (keylen
!= 6)) {
5009 PrintAndLogEx(WARNING
, "Missing key");
5012 if ((keytype
<= MF_KEY_B
) && (keylen
> 0)) {
5013 PrintAndLogEx(WARNING
, "Ignoring provided key");
5016 bool m0
= arg_get_lit(ctx
, 5);
5017 bool m1
= arg_get_lit(ctx
, 6);
5018 bool m2
= arg_get_lit(ctx
, 7);
5019 bool m4
= arg_get_lit(ctx
, 8);
5023 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5024 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5026 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5030 uint8_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5033 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
5035 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5037 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
5039 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
5041 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5045 mfc_eload_t payload
= {
5046 .sectorcnt
= sectors_cnt
,
5049 memcpy(payload
.key
, key
, sizeof(payload
.key
));
5051 clearCommandBuffer();
5052 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
5054 PacketResponseNG resp
;
5055 if (WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 1500) == false) {
5056 PrintAndLogEx(WARNING
, "command execution time out");
5057 return PM3_ETIMEOUT
;
5060 if (resp
.status
== PM3_SUCCESS
)
5061 PrintAndLogEx(SUCCESS
, "Fill ( " _GREEN_("ok") " )");
5063 PrintAndLogEx(FAILED
, "Fill ( " _RED_("fail") " )");
5068 static int CmdHF14AMfEKeyPrn(const char *Cmd
) {
5070 CLIParserContext
*ctx
;
5071 CLIParserInit(&ctx
, "hf mf ekeyprn",
5072 "Download and print the keys from emulator memory",
5073 "hf mf ekeyprn --1k --> print MFC 1K keyset\n"
5074 "hf mf ekeyprn -w --> write keys to binary file"
5076 void *argtable
[] = {
5078 arg_lit0("w", "write", "write keys to binary file `hf-mf-<UID>-key.bin`"),
5079 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5080 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5081 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5082 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5085 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5087 bool create_dumpfile
= arg_get_lit(ctx
, 1);
5088 bool m0
= arg_get_lit(ctx
, 2);
5089 bool m1
= arg_get_lit(ctx
, 3);
5090 bool m2
= arg_get_lit(ctx
, 4);
5091 bool m4
= arg_get_lit(ctx
, 5);
5095 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5096 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5098 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5102 size_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5105 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
5107 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5109 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
5111 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
5113 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5117 // create/initialize key storage structure
5118 sector_t
*e_sector
= NULL
;
5119 if (initSectorTable(&e_sector
, sectors_cnt
) != PM3_SUCCESS
) {
5123 // read UID from EMUL
5125 if (mfEmlGetMem(data
, 0, 1) != PM3_SUCCESS
) {
5126 PrintAndLogEx(WARNING
, "error get block 0");
5131 // assuming 4byte UID.
5133 memcpy(uid
, data
, sizeof(uid
));
5135 // download keys from EMUL
5136 for (int i
= 0; i
< sectors_cnt
; i
++) {
5138 if (mfEmlGetMem(data
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1) != PM3_SUCCESS
) {
5139 PrintAndLogEx(WARNING
, "error get block %d", mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
5140 e_sector
[i
].foundKey
[0] = false;
5141 e_sector
[i
].foundKey
[1] = false;
5143 e_sector
[i
].foundKey
[0] = true;
5144 e_sector
[i
].Key
[0] = bytes_to_num(data
, 6);
5145 e_sector
[i
].foundKey
[1] = true;
5146 e_sector
[i
].Key
[1] = bytes_to_num(data
+ 10, 6);
5151 printKeyTable(sectors_cnt
, e_sector
);
5154 if (create_dumpfile
) {
5156 char filename
[FILE_PATH_SIZE
] = {0};
5157 char *fptr
= filename
;
5158 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
5159 FillFileNameByUID(fptr
+ strlen(fptr
), uid
, "-key", sizeof(uid
));
5160 createMfcKeyDump(filename
, sectors_cnt
, e_sector
);
5167 // CHINESE MAGIC COMMANDS
5168 static int CmdHF14AMfCSetUID(const char *Cmd
) {
5170 CLIParserContext
*ctx
;
5171 CLIParserInit(&ctx
, "hf mf csetuid",
5172 "Set UID, ATQA, and SAK for magic gen1a card",
5173 "hf mf csetuid -u 01020304\n"
5174 "hf mf csetuid -w -u 01020304 --atqa 0004 --sak 08"
5176 void *argtable
[] = {
5178 arg_lit0("w", "wipe", "wipes card with backdoor cmd`"),
5179 arg_str0("u", "uid", "<hex>", "UID, 4/7 hex bytes"),
5180 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
5181 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
5184 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5186 uint8_t wipe_card
= arg_get_lit(ctx
, 1);
5189 uint8_t uid
[7] = {0x00};
5190 CLIGetHexWithReturn(ctx
, 2, uid
, &uidlen
);
5193 uint8_t atqa
[2] = {0x00};
5194 CLIGetHexWithReturn(ctx
, 3, atqa
, &alen
);
5197 uint8_t sak
[1] = {0x00};
5198 CLIGetHexWithReturn(ctx
, 4, sak
, &slen
);
5202 if (uidlen
!= 4 && uidlen
!= 7) {
5203 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
5206 if (alen
&& alen
!= 2) {
5207 PrintAndLogEx(FAILED
, "ATQA must be 2 hex bytes. Got %d", alen
);
5210 if (slen
&& slen
!= 1) {
5211 PrintAndLogEx(FAILED
, "SAK must be 1 hex byte. Got %d", slen
);
5215 uint8_t old_uid
[7] = {0};
5216 uint8_t verify_uid
[7] = {0};
5218 int res
= mfCSetUID(
5221 (alen
) ? atqa
: NULL
,
5222 (slen
) ? sak
: NULL
,
5229 PrintAndLogEx(ERR
, "Can't set UID. error %d", res
);
5233 res
= memcmp(uid
, verify_uid
, uidlen
);
5235 PrintAndLogEx(SUCCESS
, "Old UID... %s", sprint_hex(old_uid
, uidlen
));
5236 PrintAndLogEx(SUCCESS
, "New UID... %s ( %s )",
5237 sprint_hex(verify_uid
, uidlen
),
5238 (res
== 0) ? _GREEN_("verified") : _RED_("fail")
5243 static int CmdHF14AMfCWipe(const char *cmd
) {
5244 CLIParserContext
*ctx
;
5245 CLIParserInit(&ctx
, "hf mf cwipe",
5246 "Wipe gen1 magic chinese card.\n"
5247 "Set UID / ATQA / SAK / Data / Keys / Access to default values",
5249 "hf mf cwipe -u 09080706 -a 0004 -s 18 --> set UID, ATQA and SAK and wipe card");
5251 void *argtable
[] = {
5253 arg_str0("u", "uid", "<hex>", "UID, 4 hex bytes"),
5254 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
5255 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
5258 CLIExecWithReturn(ctx
, cmd
, argtable
, true);
5261 uint8_t uid
[8] = {0x00};
5262 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
5265 uint8_t atqa
[2] = {0x00};
5266 CLIGetHexWithReturn(ctx
, 2, atqa
, &alen
);
5269 uint8_t sak
[1] = {0x00};
5270 CLIGetHexWithReturn(ctx
, 3, sak
, &slen
);
5273 if (uidlen
&& uidlen
!= 4) {
5274 PrintAndLogEx(ERR
, "UID length must be 4 bytes, got %d", uidlen
);
5277 if (alen
&& alen
!= 2) {
5278 PrintAndLogEx(ERR
, "ATQA length must be 2 bytes, got %d", alen
);
5281 if (slen
&& slen
!= 1) {
5282 PrintAndLogEx(ERR
, "SAK length must be 1 byte, got %d", slen
);
5286 int res
= mfCWipe((uidlen
) ? uid
: NULL
, (alen
) ? atqa
: NULL
, (slen
) ? sak
: NULL
);
5288 PrintAndLogEx(ERR
, "Can't wipe card. error %d", res
);
5292 PrintAndLogEx(SUCCESS
, "Card wiped successfully");
5296 static int CmdHF14AMfCSetBlk(const char *Cmd
) {
5298 CLIParserContext
*ctx
;
5299 CLIParserInit(&ctx
, "hf mf csetblk",
5300 "Set block data on a magic gen1a card",
5301 "hf mf csetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
5303 void *argtable
[] = {
5305 arg_int1("b", "blk", "<dec>", "block number"),
5306 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
5307 arg_lit0("w", "wipe", "wipes card with backdoor cmd before writing"),
5310 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5312 int b
= arg_get_int_def(ctx
, 1, -1);
5314 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
5316 CLIGetHexWithReturn(ctx
, 2, data
, &datalen
);
5318 uint8_t wipe_card
= arg_get_lit(ctx
, 3);
5321 if (b
< 0 || b
>= MIFARE_1K_MAXBLOCK
) {
5322 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
5326 if (datalen
!= MFBLOCK_SIZE
) {
5327 PrintAndLogEx(FAILED
, "expected 16 bytes data, got %i", datalen
);
5331 uint8_t params
= MAGIC_SINGLE
;
5333 params
|= MAGIC_WIPE
;
5336 PrintAndLogEx(INFO
, "Writing block number:%2d data:%s", b
, sprint_hex_inrow(data
, sizeof(data
)));
5338 int res
= mfCSetBlock(b
, data
, NULL
, params
);
5340 PrintAndLogEx(ERR
, "Can't write block. error=%d", res
);
5346 static int CmdHF14AMfCLoad(const char *Cmd
) {
5348 CLIParserContext
*ctx
;
5349 CLIParserInit(&ctx
, "hf mf cload",
5350 "Load magic gen1a card with data from (bin/eml/json) dump file\n"
5351 "or from emulator memory.",
5352 "hf mf cload --emu\n"
5353 "hf mf cload -f hf-mf-01020304.eml\n"
5355 void *argtable
[] = {
5357 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
5358 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5359 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5360 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5361 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5362 arg_lit0(NULL
, "emu", "from emulator memory"),
5365 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5368 char filename
[FILE_PATH_SIZE
] = {0};
5369 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5371 bool m0
= arg_get_lit(ctx
, 2);
5372 bool m1
= arg_get_lit(ctx
, 3);
5373 bool m2
= arg_get_lit(ctx
, 4);
5374 bool m4
= arg_get_lit(ctx
, 5);
5375 bool fill_from_emulator
= arg_get_lit(ctx
, 6);
5379 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5380 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5382 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5387 memset(s
, 0, sizeof(s
));
5388 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5390 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5391 strncpy(s
, "Mini", 5);
5393 block_cnt
= MIFARE_1K_MAXBLOCK
;
5394 strncpy(s
, "1K", 3);
5396 block_cnt
= MIFARE_2K_MAXBLOCK
;
5397 strncpy(s
, "2K", 3);
5399 block_cnt
= MIFARE_4K_MAXBLOCK
;
5400 strncpy(s
, "4K", 3);
5402 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5407 if (fill_from_emulator
) {
5409 PrintAndLogEx(INFO
, "Start upload to emulator memory");
5410 PrintAndLogEx(INFO
, "." NOLF
);
5412 for (int b
= 0; b
< block_cnt
; b
++) {
5414 uint8_t buf8
[MFBLOCK_SIZE
] = {0x00};
5416 // read from emul memory
5417 if (mfEmlGetMem(buf8
, b
, 1)) {
5418 PrintAndLogEx(WARNING
, "Can't read from emul block: %d", b
);
5422 // switch on field and send magic sequence
5424 flags
= MAGIC_INIT
+ MAGIC_WUPC
;
5432 // Done. Magic Halt and switch off field.
5433 if (b
== (block_cnt
- 1)) {
5434 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5438 if (mfCSetBlock(b
, buf8
, NULL
, flags
)) {
5439 PrintAndLogEx(WARNING
, "Can't set magic card block: %d", b
);
5442 PrintAndLogEx(NORMAL
, "." NOLF
);
5445 PrintAndLogEx(NORMAL
, "");
5450 uint8_t *data
= NULL
;
5451 size_t bytes_read
= 0;
5452 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (MFBLOCK_SIZE
* block_cnt
));
5453 if (res
!= PM3_SUCCESS
) {
5457 if (bytes_read
!= (block_cnt
* MFBLOCK_SIZE
)) {
5458 PrintAndLogEx(ERR
, "File content error. Read %zu bytes", bytes_read
);
5463 PrintAndLogEx(INFO
, "Copying to magic gen1a card");
5464 PrintAndLogEx(INFO
, "." NOLF
);
5468 while (bytes_read
) {
5470 // switch on field and send magic sequence
5472 flags
= MAGIC_INIT
+ MAGIC_WUPC
;
5481 if (blockno
== (block_cnt
- 1)) {
5482 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5485 if (mfCSetBlock(blockno
, data
+ (MFBLOCK_SIZE
* blockno
), NULL
, flags
)) {
5486 PrintAndLogEx(WARNING
, "Can't set magic card block: %d", blockno
);
5491 bytes_read
-= MFBLOCK_SIZE
;
5493 PrintAndLogEx(NORMAL
, "." NOLF
);
5498 if (blockno
>= block_cnt
) break;
5500 PrintAndLogEx(NORMAL
, "\n");
5504 // confirm number written blocks. Must be 20, 64 or 256 blocks
5505 if (blockno
!= block_cnt
) {
5506 PrintAndLogEx(ERR
, "File content error. There must be %d blocks", block_cnt
);
5510 PrintAndLogEx(SUCCESS
, "Card loaded " _YELLOW_("%d") " blocks from file", block_cnt
);
5511 PrintAndLogEx(INFO
, "Done!");
5515 static int CmdHF14AMfCGetBlk(const char *Cmd
) {
5516 CLIParserContext
*ctx
;
5517 CLIParserInit(&ctx
, "hf mf cgetblk",
5518 "Get block data from magic Chinese card.\n"
5519 "Only works with magic gen1a cards",
5520 "hf mf cgetblk --blk 0 --> get block 0 (manufacturer)\n"
5521 "hf mf cgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
5523 void *argtable
[] = {
5525 arg_int1("b", "blk", "<dec>", "block number"),
5526 arg_lit0("v", "verbose", "verbose output"),
5529 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5530 int b
= arg_get_int_def(ctx
, 1, 0);
5531 bool verbose
= arg_get_lit(ctx
, 2);
5538 uint8_t blockno
= (uint8_t)b
;
5539 uint8_t data
[16] = {0};
5540 int res
= mfCGetBlock(blockno
, data
, MAGIC_SINGLE
);
5542 PrintAndLogEx(ERR
, "Can't read block. error=%d", res
);
5546 uint8_t sector
= mfSectorNum(blockno
);
5547 mf_print_sector_hdr(sector
);
5548 mf_print_block_one(blockno
, data
, verbose
);
5551 decode_print_st(blockno
, data
);
5553 PrintAndLogEx(NORMAL
, "");
5558 static int CmdHF14AMfCGetSc(const char *Cmd
) {
5559 CLIParserContext
*ctx
;
5560 CLIParserInit(&ctx
, "hf mf cgetsc",
5561 "Get sector data from magic Chinese card.\n"
5562 "Only works with magic gen1a cards",
5565 void *argtable
[] = {
5567 arg_int1("s", "sec", "<dec>", "sector number"),
5568 arg_lit0("v", "verbose", "verbose output"),
5571 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5572 int s
= arg_get_int_def(ctx
, 1, 0);
5573 bool verbose
= arg_get_lit(ctx
, 2);
5576 if (s
>= MIFARE_4K_MAXSECTOR
) {
5577 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
5581 uint8_t sector
= (uint8_t)s
;
5582 mf_print_sector_hdr(sector
);
5585 uint8_t start
= sector
* 4;
5588 start
= 128 + (sector
- 32) * 16;
5591 int flags
= MAGIC_INIT
+ MAGIC_WUPC
;
5592 uint8_t data
[16] = {0};
5593 for (int i
= 0; i
< blocks
; i
++) {
5594 if (i
== 1) flags
= 0;
5595 if (i
== blocks
- 1) flags
= MAGIC_HALT
+ MAGIC_OFF
;
5597 int res
= mfCGetBlock(start
+ i
, data
, flags
);
5599 PrintAndLogEx(ERR
, "Can't read block. %d error=%d", start
+ i
, res
);
5602 mf_print_block_one(start
+ i
, data
, verbose
);
5605 decode_print_st(start
+ blocks
- 1, data
);
5607 PrintAndLogEx(NORMAL
, "");
5612 static int CmdHF14AMfCSave(const char *Cmd
) {
5613 CLIParserContext
*ctx
;
5614 CLIParserInit(&ctx
, "hf mf csave",
5615 "Save magic gen1a card memory to file (bin/json)"
5616 "or into emulator memory",
5620 void *argtable
[] = {
5622 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
5623 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5624 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5625 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5626 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5627 arg_lit0(NULL
, "emu", "to emulator memory"),
5630 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5633 char filename
[FILE_PATH_SIZE
];
5634 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5636 bool m0
= arg_get_lit(ctx
, 2);
5637 bool m1
= arg_get_lit(ctx
, 3);
5638 bool m2
= arg_get_lit(ctx
, 4);
5639 bool m4
= arg_get_lit(ctx
, 5);
5640 bool fill_emulator
= arg_get_lit(ctx
, 6);
5644 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5645 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5647 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5652 memset(s
, 0, sizeof(s
));
5653 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5655 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5656 strncpy(s
, "Mini", 5);
5658 block_cnt
= MIFARE_1K_MAXBLOCK
;
5659 strncpy(s
, "1K", 3);
5661 block_cnt
= MIFARE_2K_MAXBLOCK
;
5662 strncpy(s
, "2K", 3);
5664 block_cnt
= MIFARE_4K_MAXBLOCK
;
5665 strncpy(s
, "4K", 3);
5667 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5671 PrintAndLogEx(SUCCESS
, "Dumping magic Gen1a MIFARE Classic " _GREEN_("%s") " card memory", s
);
5672 PrintAndLogEx(INFO
, "." NOLF
);
5674 // Select card to get UID/UIDLEN information
5675 clearCommandBuffer();
5676 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
5677 PacketResponseNG resp
;
5678 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
5679 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
5680 return PM3_ETIMEOUT
;
5687 3: proprietary Anticollision
5689 uint64_t select_status
= resp
.oldarg
[0];
5690 if (select_status
== 0) {
5691 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
5696 iso14a_card_select_t card
;
5697 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
5700 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
5701 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
5703 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5707 // switch on field and send magic sequence
5708 uint8_t flags
= MAGIC_INIT
+ MAGIC_WUPC
;
5709 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
5716 if (i
== block_cnt
- 1) {
5717 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5720 if (mfCGetBlock(i
, dump
+ (i
* MFBLOCK_SIZE
), flags
)) {
5721 PrintAndLogEx(WARNING
, "Can't get magic card block: %d", i
);
5722 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
5726 PrintAndLogEx(NORMAL
, "." NOLF
);
5729 PrintAndLogEx(NORMAL
, "");
5731 if (fill_emulator
) {
5732 PrintAndLogEx(INFO
, "uploading to emulator memory");
5733 PrintAndLogEx(INFO
, "." NOLF
);
5735 g_conn
.block_after_ACK
= true;
5736 for (int i
= 0; i
< block_cnt
; i
+= 5) {
5737 if (i
== block_cnt
- 1) {
5738 // Disable fast mode on last packet
5739 g_conn
.block_after_ACK
= false;
5741 if (mfEmlSetMem(dump
+ (i
* MFBLOCK_SIZE
), i
, 5) != PM3_SUCCESS
) {
5742 PrintAndLogEx(WARNING
, "Can't set emul block: " _YELLOW_("%d"), i
);
5745 PrintAndLogEx(NORMAL
, "");
5746 PrintAndLogEx(INFO
, "" NOLF
) ;
5748 PrintAndLogEx(NORMAL
, "." NOLF
);
5751 PrintAndLogEx(NORMAL
, "");
5752 PrintAndLogEx(SUCCESS
, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes
);
5755 // user supplied filename?
5757 char *fptr
= filename
;
5758 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
5759 FillFileNameByUID(fptr
, card
.uid
, "-dump", card
.uidlen
);
5762 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
5767 static int CmdHF14AMfCView(const char *Cmd
) {
5769 CLIParserContext
*ctx
;
5770 CLIParserInit(&ctx
, "hf mf cview",
5771 "View `magic gen1a` card memory",
5775 void *argtable
[] = {
5777 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5778 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5779 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5780 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5781 arg_lit0("v", "verbose", "verbose output"),
5784 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5785 bool m0
= arg_get_lit(ctx
, 1);
5786 bool m1
= arg_get_lit(ctx
, 2);
5787 bool m2
= arg_get_lit(ctx
, 3);
5788 bool m4
= arg_get_lit(ctx
, 4);
5789 bool verbose
= arg_get_lit(ctx
, 5);
5793 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5794 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5796 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5801 memset(s
, 0, sizeof(s
));
5802 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5804 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5805 strncpy(s
, "Mini", 5);
5807 block_cnt
= MIFARE_1K_MAXBLOCK
;
5808 strncpy(s
, "1K", 3);
5810 block_cnt
= MIFARE_2K_MAXBLOCK
;
5811 strncpy(s
, "2K", 3);
5813 block_cnt
= MIFARE_4K_MAXBLOCK
;
5814 strncpy(s
, "4K", 3);
5816 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5819 PrintAndLogEx(SUCCESS
, "View magic Gen1a MIFARE Classic " _GREEN_("%s"), s
);
5820 PrintAndLogEx(INFO
, "." NOLF
);
5822 // Select card to get UID/UIDLEN information
5823 clearCommandBuffer();
5824 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
5825 PacketResponseNG resp
;
5826 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
5827 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
5828 return PM3_ETIMEOUT
;
5835 3: proprietary Anticollision
5837 uint64_t select_status
= resp
.oldarg
[0];
5839 if (select_status
== 0) {
5840 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
5841 return PM3_ERFTRANS
;
5844 iso14a_card_select_t card
;
5845 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
5848 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
5849 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
5851 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5855 // switch on field and send magic sequence
5856 uint8_t flags
= MAGIC_INIT
+ MAGIC_WUPC
;
5857 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
5863 if (i
== block_cnt
- 1) {
5864 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5867 if (mfCGetBlock(i
, dump
+ (i
* MFBLOCK_SIZE
), flags
)) {
5868 PrintAndLogEx(WARNING
, "Can't get magic card block: " _YELLOW_("%u"), i
);
5869 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
5873 PrintAndLogEx(NORMAL
, "." NOLF
);
5877 PrintAndLogEx(NORMAL
, "");
5878 mf_print_blocks(block_cnt
, dump
, verbose
);
5881 mf_print_keys(block_cnt
, dump
);
5888 //needs nt, ar, at, Data to decrypt
5889 static int CmdHf14AMfDecryptBytes(const char *Cmd
) {
5890 CLIParserContext
*ctx
;
5891 CLIParserInit(&ctx
, "hf mf decrypt",
5892 "Decrypt Crypto-1 encrypted bytes given some known state of crypto. See tracelog to gather needed values",
5893 "hf mf decrypt --nt b830049b --ar 9248314a --at 9280e203 -d 41e586f9\n"
5894 " -> 41e586f9 becomes 3003999a\n"
5895 " -> which annotates 30 03 [99 9a] read block 3 [crc]"
5897 void *argtable
[] = {
5899 arg_str1(NULL
, "nt", "<hex>", "tag nonce"),
5900 arg_str1(NULL
, "ar", "<hex>", "ar_enc, encrypted reader response"),
5901 arg_str1(NULL
, "at", "<hex>", "at_enc, encrypted tag response"),
5902 arg_str1("d", "data", "<hex>", "encrypted data, taken directly after at_enc and forward"),
5905 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5908 int res
= arg_get_u32_hexstr_def(ctx
, 1, 0, &nt
);
5911 PrintAndLogEx(WARNING
, "check `nt` parameter");
5915 uint32_t ar_enc
= 0;
5916 res
= arg_get_u32_hexstr_def(ctx
, 2, 0, &ar_enc
);
5919 PrintAndLogEx(WARNING
, "check `ar` parameter");
5923 uint32_t at_enc
= 0;
5924 res
= arg_get_u32_hexstr_def(ctx
, 3, 0, &at_enc
);
5927 PrintAndLogEx(WARNING
, "check `at` parameter");
5932 uint8_t data
[512] = {0x00};
5933 CLIGetHexWithReturn(ctx
, 4, data
, &datalen
);
5936 PrintAndLogEx(INFO
, "nt....... %08X", nt
);
5937 PrintAndLogEx(INFO
, "ar enc... %08X", ar_enc
);
5938 PrintAndLogEx(INFO
, "at enc... %08X", at_enc
);
5940 return tryDecryptWord(nt
, ar_enc
, at_enc
, data
, datalen
);
5943 static int CmdHf14AMfSetMod(const char *Cmd
) {
5945 CLIParserContext
*ctx
;
5946 CLIParserInit(&ctx
, "hf mf setmod",
5947 "Sets the load modulation strength of a MIFARE Classic EV1 card",
5948 "hf mf setmod -k ffffffffffff -0"
5950 void *argtable
[] = {
5952 arg_lit0("0", NULL
, "normal modulation"),
5953 arg_lit0("1", NULL
, "strong modulation (def)"),
5954 arg_str0("k", "key", "<hex>", "key A, Sector 0, 6 hex bytes"),
5957 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5958 bool m0
= arg_get_lit(ctx
, 1);
5959 bool m1
= arg_get_lit(ctx
, 2);
5962 uint8_t key
[6] = {0};
5963 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
5967 PrintAndLogEx(WARNING
, "please select one modulation");
5971 uint8_t data
[7] = {0};
5972 memcpy(data
+ 1, key
, 6);
5980 clearCommandBuffer();
5981 SendCommandNG(CMD_HF_MIFARE_SETMOD
, data
, sizeof(data
));
5982 PacketResponseNG resp
;
5983 if (WaitForResponseTimeout(CMD_HF_MIFARE_SETMOD
, &resp
, 1500) == false) {
5984 PrintAndLogEx(WARNING
, "command execution time out");
5985 return PM3_ETIMEOUT
;
5988 if (resp
.status
== PM3_SUCCESS
)
5989 PrintAndLogEx(SUCCESS
, "Change ( " _GREEN_("ok") " )");
5991 PrintAndLogEx(FAILED
, "Change ( " _RED_("fail") " )");
5996 // MIFARE NACK bug detection
5997 static int CmdHf14AMfNack(const char *Cmd
) {
5998 CLIParserContext
*ctx
;
5999 CLIParserInit(&ctx
, "hf mf nack",
6000 "Test a MIFARE Classic based card for the NACK bug",
6003 void *argtable
[] = {
6005 arg_lit0("v", "verbose", "verbose output`"),
6008 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6009 bool verbose
= arg_get_lit(ctx
, 1);
6013 PrintAndLogEx(INFO
, "Started testing card for NACK bug. Press Enter to abort");
6015 detect_classic_nackbug(verbose
);
6020 static int CmdHF14AMfice(const char *Cmd) {
6021 CLIParserContext *ctx;
6022 CLIParserInit(&ctx, "hf mf ice",
6023 "Collect MIFARE Classic nonces to file",
6025 "hf mf ice -f nonces.bin");
6027 void *argtable[] = {
6029 arg_str0("f", "file", "<fn>", "filename of nonce dump"),
6030 arg_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
6033 CLIExecWithReturn(ctx, Cmd, argtable, true);
6036 char filename[FILE_PATH_SIZE] = {0};
6037 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
6039 uint32_t limit = arg_get_u32_def(ctx, 2, 50000);
6046 if (filename[0] == '\0') {
6047 fptr = GenerateFilename("hf-mf-", "-nonces.bin");
6050 strncpy(filename, fptr, sizeof(filename) - 1);
6054 uint8_t blockNo = 0;
6055 uint8_t keyType = MF_KEY_A;
6056 uint8_t trgBlockNo = 0;
6057 uint8_t trgKeyType = MF_KEY_B;
6059 bool initialize = true;
6060 bool acquisition_completed = false;
6061 uint32_t total_num_nonces = 0;
6062 PacketResponseNG resp;
6064 uint32_t part_limit = 3000;
6066 PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit);
6068 FILE *fnonces = NULL;
6069 if ((fnonces = fopen(filename, "wb")) == NULL) {
6070 PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), filename);
6074 clearCommandBuffer();
6076 uint64_t t1 = msclock();
6079 if (kbd_enter_pressed()) {
6080 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
6085 flags |= initialize ? 0x0001 : 0;
6086 flags |= slow ? 0x0002 : 0;
6087 clearCommandBuffer();
6088 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0);
6090 if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out;
6091 if (resp.oldarg[0]) goto out;
6093 uint32_t items = resp.oldarg[2];
6094 fwrite(resp.data.asBytes, 1, items * 4, fnonces);
6097 total_num_nonces += items;
6098 if (total_num_nonces > part_limit) {
6099 PrintAndLogEx(INFO, "Total nonces %u\n", total_num_nonces);
6103 acquisition_completed = (total_num_nonces > limit);
6107 } while (!acquisition_completed);
6110 PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000);
6117 clearCommandBuffer();
6118 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, NULL, 0);
6123 static int CmdHF14AMfAuth4(const char *Cmd
) {
6124 uint8_t keyn
[20] = {0};
6126 uint8_t key
[16] = {0};
6129 CLIParserContext
*ctx
;
6130 CLIParserInit(&ctx
, "hf mf auth4",
6131 "Executes AES authentication command in ISO14443-4",
6132 "hf mf auth4 -n 4000 -k 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
6133 "hf mf auth4 -n 9003 -k FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n");
6135 void *argtable
[] = {
6137 arg_str1("n", NULL
, "<hex>", "key num, 2 hex bytes"),
6138 arg_str1("k", "key", "<hex>", "key, 16 hex bytes"),
6141 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6142 CLIGetHexWithReturn(ctx
, 1, keyn
, &keynlen
);
6143 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
6147 PrintAndLogEx(ERR
, "Key number must be 2 bytes. Got... %d", keynlen
);
6152 PrintAndLogEx(ERR
, "Key must be 16 bytes. Got... %d", keylen
);
6156 return MifareAuth4(NULL
, keyn
, key
, true, false, true, true, false);
6159 // https://www.nxp.com/docs/en/application-note/AN10787.pdf
6160 static int CmdHF14AMfMAD(const char *Cmd
) {
6162 CLIParserContext
*ctx
;
6163 CLIParserInit(&ctx
, "hf mf mad",
6164 "Checks and prints MIFARE Application Directory (MAD)",
6165 "hf mf mad -> shows MAD if exists\n"
6166 "hf mf mad --aid e103 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"
6167 "hf mf mad --dch -k ffffffffffff -> decode CardHolder information\n");
6169 void *argtable
[] = {
6171 arg_lit0("v", "verbose", "verbose output"),
6172 arg_str0(NULL
, "aid", "<hex>", "print all sectors with specified aid"),
6173 arg_str0("k", "key", "<hex>", "key for printing sectors"),
6174 arg_lit0("b", "keyb", "use key B for access printing sectors (by default: key A)"),
6175 arg_lit0(NULL
, "be", "(optional, BigEndian)"),
6176 arg_lit0(NULL
, "dch", "decode Card Holder information"),
6177 arg_str0("f", "file", "<fn>", "load dump file and decode MAD"),
6180 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6181 bool verbose
= arg_get_lit(ctx
, 1);
6182 uint8_t aid
[2] = {0};
6184 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
6185 uint8_t userkey
[6] = {0};
6187 CLIGetHexWithReturn(ctx
, 3, userkey
, &keylen
);
6188 bool keyB
= arg_get_lit(ctx
, 4);
6189 bool swapmad
= arg_get_lit(ctx
, 5);
6190 bool decodeholder
= arg_get_lit(ctx
, 6);
6193 char filename
[FILE_PATH_SIZE
] = {0};
6194 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6200 uint8_t *dump
= NULL
;
6201 size_t bytes_read
= 0;
6202 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, MIFARE_4K_MAX_BYTES
);
6203 if (res
!= PM3_SUCCESS
) {
6207 uint16_t block_cnt
= MIN(MIFARE_1K_MAXBLOCK
, (bytes_read
/ MFBLOCK_SIZE
));
6208 if (bytes_read
== MIFARE_MINI_MAX_BYTES
)
6209 block_cnt
= MIFARE_MINI_MAXBLOCK
;
6210 else if (bytes_read
== MIFARE_2K_MAX_BYTES
)
6211 block_cnt
= MIFARE_2K_MAXBLOCK
;
6212 else if (bytes_read
== MIFARE_4K_MAX_BYTES
)
6213 block_cnt
= MIFARE_4K_MAXBLOCK
;
6216 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
6220 if (HasMADKey(dump
) == false) {
6221 PrintAndLogEx(FAILED
, "No MAD key was detected in the dump file");
6227 bool haveMAD2
= false;
6228 MAD1DecodeAndPrint(dump
, swapmad
, verbose
, &haveMAD2
);
6230 int sector
= DetectHID(dump
, 0x484d);
6234 PrintAndLogEx(INFO
, "");
6235 PrintAndLogEx(INFO
, _CYAN_("HID PACS detected"));
6237 uint8_t pacs_sector
[MFBLOCK_SIZE
* 3] = {0};
6238 memcpy(pacs_sector
, dump
+ (sector
* 4 * 16), sizeof(pacs_sector
));
6240 if (pacs_sector
[16] == 0x02) {
6242 PrintAndLogEx(SUCCESS
, "Raw...... " _GREEN_("%s"), sprint_hex_inrow(pacs_sector
+ 24, 8));
6244 //todo: remove preamble/sentinel
6245 uint32_t top
= 0, mid
= 0, bot
= 0;
6246 char hexstr
[16 + 1] = {0};
6247 hex_to_buffer((uint8_t *)hexstr
, pacs_sector
+ 24, 8, sizeof(hexstr
) - 1, 0, 0, true);
6248 hexstring_to_u96(&top
, &mid
, &bot
, hexstr
);
6250 char binstr
[64 + 1];
6251 hextobinstring(binstr
, hexstr
);
6252 char *pbin
= binstr
;
6253 while (strlen(pbin
) && *(++pbin
) == '0');
6255 PrintAndLogEx(SUCCESS
, "Binary... " _GREEN_("%s"), pbin
);
6257 PrintAndLogEx(INFO
, "Wiegand decode");
6258 wiegand_message_t packed
= initialize_message_object(top
, mid
, bot
, 0);
6259 HIDTryUnpack(&packed
);
6263 sector
= DetectHID(dump
, 0x4910);
6266 PrintAndLogEx(INFO
, "");
6267 PrintAndLogEx(INFO
, _CYAN_("VIGIK PACS detected"));
6271 MAD2DecodeAndPrint(dump
+ (MIFARE_1K_MAXBLOCK
* MF_MAD2_SECTOR
), swapmad
, verbose
);
6274 if (aidlen
== 2 || decodeholder
) {
6275 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6277 if (MADDecode(dump
, dump
+ (0x10 * MIFARE_1K_MAXBLOCK
), mad
, &madlen
, swapmad
)) {
6278 PrintAndLogEx(ERR
, "can't decode MAD");
6283 uint16_t aaid
= 0x0004;
6285 aaid
= (aid
[0] << 8) + aid
[1];
6288 PrintAndLogEx(NORMAL
, "");
6289 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
6291 MADCardHolderInfoDecode(dump
, bytes_read
, verbose
);
6297 if (g_session
.pm3_present
== false)
6301 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6302 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6304 bool got_first
= true;
6305 if (mfReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifare_mad_key
, sector0
) != PM3_SUCCESS
) {
6306 PrintAndLogEx(WARNING
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
6309 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6312 // User supplied key
6313 if (got_first
== false && keylen
== 6) {
6314 PrintAndLogEx(INFO
, "Trying user specified key...");
6315 if (mfReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, userkey
, sector0
) != PM3_SUCCESS
) {
6316 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or the custom key is wrong");
6318 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6323 // Both default and user supplied key failed
6324 if (got_first
== false) {
6329 if (mfReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifare_mad_key
, sector10
) != PM3_SUCCESS
) {
6331 PrintAndLogEx(ERR
, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys");
6335 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6338 // User supplied key
6339 if (got_first
== false && keylen
== 6) {
6340 PrintAndLogEx(INFO
, "Trying user specified key...");
6341 if (mfReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, userkey
, sector10
) != PM3_SUCCESS
) {
6343 PrintAndLogEx(ERR
, "error, read sector 10. card doesn't have MAD 2 or the custom key is wrong");
6346 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6352 bool haveMAD2
= false;
6353 MAD1DecodeAndPrint(sector0
, swapmad
, verbose
, &haveMAD2
);
6356 MAD2DecodeAndPrint(sector10
, swapmad
, verbose
);
6359 if (aidlen
== 2 || decodeholder
) {
6360 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6362 if (MADDecode(sector0
, sector10
, mad
, &madlen
, swapmad
)) {
6363 PrintAndLogEx(ERR
, "can't decode MAD");
6367 // copy default NDEF key
6368 uint8_t akey
[6] = {0};
6369 memcpy(akey
, g_mifare_ndef_key
, 6);
6371 // user specified key
6373 memcpy(akey
, userkey
, sizeof(akey
));
6376 uint16_t aaid
= 0x0004;
6379 aaid
= (aid
[0] << 8) + aid
[1];
6381 PrintAndLogEx(NORMAL
, "");
6382 PrintAndLogEx(INFO
, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid
);
6384 for (int i
= 0; i
< madlen
; i
++) {
6385 if (aaid
== mad
[i
]) {
6386 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6387 if (mfReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
)) {
6388 PrintAndLogEx(NORMAL
, "");
6389 PrintAndLogEx(ERR
, "error, read sector %d", i
+ 1);
6393 for (int j
= 0; j
< (verbose
? 4 : 3); j
++)
6394 PrintAndLogEx(NORMAL
, " [%03d] %s", (i
+ 1) * 4 + j
, sprint_hex(&vsector
[j
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6401 PrintAndLogEx(NORMAL
, "");
6402 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
6404 uint8_t data
[MIFARE_4K_MAX_BYTES
] = {0};
6407 for (int i
= 0; i
< madlen
; i
++) {
6408 if (aaid
== mad
[i
]) {
6410 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6411 if (mfReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
)) {
6412 PrintAndLogEx(NORMAL
, "");
6413 PrintAndLogEx(ERR
, "error, read sector %d", i
+ 1);
6417 // skip ST block hence only 3 blocks copy
6418 memcpy(&data
[datalen
], vsector
, MFBLOCK_SIZE
* 3);
6419 datalen
+= MFBLOCK_SIZE
* 3;
6424 PrintAndLogEx(WARNING
, "no Card Holder Info data");
6427 MADCardHolderInfoDecode(data
, datalen
, verbose
);
6432 PrintAndLogEx(NORMAL
, "");
6433 PrintAndLogEx(INFO
, "------------ " _CYAN_("MAD v1 sector raw") " -------------");
6434 for (int i
= 0; i
< 4; i
++) {
6435 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex(§or0
[i
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6438 PrintAndLogEx(NORMAL
, "");
6439 PrintAndLogEx(INFO
, "------------ " _CYAN_("MAD v2 sector raw") " -------------");
6440 for (int i
= 0; i
< 4; i
++) {
6441 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex(§or10
[i
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6448 int CmdHFMFNDEFRead(const char *Cmd
) {
6450 CLIParserContext
*ctx
;
6451 CLIParserInit(&ctx
, "hf mf ndefread",
6452 "Prints NFC Data Exchange Format (NDEF)",
6453 "hf mf ndefread -> shows NDEF parsed data\n"
6454 "hf mf ndefread -vv -> shows NDEF parsed and raw data\n"
6455 "hf mf ndefread --aid e103 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"
6456 "hf mf ndefread -f myfilename -> save raw NDEF to file"
6459 void *argtable
[] = {
6461 arg_litn("v", "verbose", 0, 2, "Verbose output"),
6462 arg_str0(NULL
, "aid", "<aid>", "replace default aid for NDEF"),
6463 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
6464 arg_lit0("b", "keyb", "use key B for access sectors (by default: key A)"),
6465 arg_str0("f", "file", "<fn>", "save raw NDEF to file"),
6468 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6470 bool verbose
= arg_get_lit(ctx
, 1);
6471 bool verbose2
= arg_get_lit(ctx
, 1) > 1;
6472 uint8_t aid
[2] = {0};
6475 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
6476 uint8_t key
[6] = {0};
6479 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
6480 bool keyB
= arg_get_lit(ctx
, 4);
6483 char filename
[FILE_PATH_SIZE
] = {0};
6484 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6488 uint16_t ndef_aid
= NDEF_MFC_AID
;
6490 ndef_aid
= (aid
[0] << 8) + aid
[1];
6493 uint8_t ndefkey
[6] = {0};
6494 memcpy(ndefkey
, g_mifare_ndef_key
, 6);
6496 memcpy(ndefkey
, key
, 6);
6499 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6500 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6501 uint8_t data
[4096] = {0};
6505 PrintAndLogEx(INFO
, "reading MAD v1 sector");
6508 if (mfReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector0
)) {
6509 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
6510 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
6515 PrintAndLogEx(INFO
, "reading MAD v2 sector");
6518 if (mfReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector10
)) {
6520 PrintAndLogEx(ERR
, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys");
6521 PrintAndLogEx(INFO
, "Skipping MAD 2");
6525 bool haveMAD2
= false;
6526 int res
= MADCheck(sector0
, sector10
, verbose
, &haveMAD2
);
6527 if (res
!= PM3_SUCCESS
) {
6528 PrintAndLogEx(ERR
, "MAD error %d", res
);
6532 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6534 res
= MADDecode(sector0
, sector10
, mad
, &madlen
, false);
6535 if (res
!= PM3_SUCCESS
) {
6536 PrintAndLogEx(ERR
, "can't decode MAD");
6540 PrintAndLogEx(INFO
, "reading data from tag");
6541 for (int i
= 0; i
< madlen
; i
++) {
6542 if (ndef_aid
== mad
[i
]) {
6543 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6544 if (mfReadSector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, ndefkey
, vsector
)) {
6545 PrintAndLogEx(ERR
, "error, reading sector %d ", i
+ 1);
6549 memcpy(&data
[datalen
], vsector
, MFBLOCK_SIZE
* 3);
6550 datalen
+= MFBLOCK_SIZE
* 3;
6552 PrintAndLogEx(INPLACE
, "%d", i
);
6555 PrintAndLogEx(NORMAL
, "");
6558 PrintAndLogEx(WARNING
, "no NDEF data");
6563 PrintAndLogEx(NORMAL
, "");
6564 PrintAndLogEx(INFO
, "--- " _CYAN_("MFC NDEF raw") " ----------------");
6565 print_buffer(data
, datalen
, 1);
6568 res
= NDEFDecodeAndPrint(data
, datalen
, verbose
);
6569 if (res
!= PM3_SUCCESS
) {
6570 PrintAndLogEx(INFO
, "Trying to parse NDEF records w/o NDEF header");
6571 res
= NDEFRecordsDecodeAndPrint(data
, datalen
, verbose
);
6574 // if given a filename, save it
6576 // get total NDEF length before save. If fails, we save it all
6578 if (NDEFGetTotalLength(data
, datalen
, &n
) != PM3_SUCCESS
) {
6582 pm3_save_dump(filename
, data
, n
, jsfNDEF
);
6585 if (verbose
== false) {
6586 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -v`") " for more details");
6588 if (verbose2
== false) {
6589 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -vv`") " for more details");
6595 // https://www.nxp.com/docs/en/application-note/AN1305.pdf
6596 int CmdHFMFNDEFFormat(const char *Cmd
) {
6598 CLIParserContext
*ctx
;
6599 CLIParserInit(&ctx
, "hf mf ndefformat",
6600 "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF)\n"
6601 "If no <name> given, UID will be used as filename. \n"
6602 "It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
6604 "If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
6605 "hf mf ndefformat\n"
6606 // "hf mf ndefformat --mini --> MIFARE Mini\n"
6607 "hf mf ndefformat --1k --> MIFARE Classic 1k\n"
6608 // "hf mf ndefformat --2k --> MIFARE 2k\n"
6609 // "hf mf ndefformat --4k --> MIFARE 4k\n"
6610 "hf mf ndefformat --keys hf-mf-01020304-key.bin --> MIFARE 1k with keys from specified file\n"
6613 void *argtable
[] = {
6615 arg_str0("k", "keys", "<fn>", "filename of keys"),
6616 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
6617 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
6618 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
6619 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
6622 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6625 char keyFilename
[FILE_PATH_SIZE
] = {0};
6626 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
6628 bool m0
= arg_get_lit(ctx
, 2);
6629 bool m1
= arg_get_lit(ctx
, 3);
6630 bool m2
= arg_get_lit(ctx
, 4);
6631 bool m4
= arg_get_lit(ctx
, 5);
6636 if ((m0
+ m1
+ m2
+ m4
) > 1) {
6637 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
6639 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
6643 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
6646 numSectors
= MIFARE_MINI_MAXSECTOR
;
6648 numSectors
= MIFARE_1K_MAXSECTOR
;
6650 numSectors
= MIFARE_2K_MAXSECTOR
;
6652 numSectors
= MIFARE_4K_MAXSECTOR
;
6654 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
6659 if (g_session
.pm3_present
== false)
6662 // Select card to get UID/UIDLEN/ATQA/SAK information
6663 clearCommandBuffer();
6664 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
6665 PacketResponseNG resp
;
6666 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
6667 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
6668 return PM3_ETIMEOUT
;
6671 uint64_t select_status
= resp
.oldarg
[0];
6672 if (select_status
== 0) {
6673 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
6680 // init keys to default key
6681 uint8_t keyA
[MIFARE_4K_MAXSECTOR
][MIFARE_KEY_SIZE
];
6682 uint8_t keyB
[MIFARE_4K_MAXSECTOR
][MIFARE_KEY_SIZE
];
6684 for (uint8_t i
= 0; i
< MIFARE_4K_MAXSECTOR
; i
++) {
6685 memcpy(keyA
[i
], g_mifare_default_key
, sizeof(g_mifare_default_key
));
6686 memcpy(keyB
[i
], g_mifare_default_key
, sizeof(g_mifare_default_key
));
6689 // test if MAD key is used
6692 // check if we can authenticate to sector
6693 if (mfCheckKeys(0, MF_KEY_A
, true, 1, (uint8_t *)g_mifare_mad_key
, &key64
) == PM3_SUCCESS
) {
6695 // if used, assume KEY A is MAD/NDEF set.
6696 memcpy(keyA
[0], g_mifare_mad_key
, sizeof(g_mifare_mad_key
));
6697 memcpy(keyB
[0], g_mifare_mad_key_b
, sizeof(g_mifare_mad_key_b
));
6698 for (uint8_t i
= 1; i
< MIFARE_4K_MAXSECTOR
; i
++) {
6699 memcpy(keyA
[i
], g_mifare_ndef_key
, sizeof(g_mifare_ndef_key
));
6703 // Do we have a keyfile based from UID?
6704 if (keyfnlen
== 0) {
6705 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
6707 strncpy(keyFilename
, fptr
, sizeof(keyFilename
) - 1);
6713 // load key file if exist
6714 if (strlen(keyFilename
)) {
6716 size_t alen
= 0, blen
= 0;
6717 uint8_t *tmpA
, *tmpB
;
6718 if (loadFileBinaryKey(keyFilename
, "", (void **)&tmpA
, (void **)&tmpB
, &alen
, &blen
) != PM3_SUCCESS
) {
6722 PrintAndLogEx(INFO
, "Using `" _YELLOW_("%s") "`", keyFilename
);
6724 for (int i
= 0; i
< numSectors
; i
++) {
6725 memcpy(keyA
[i
], tmpA
+ (i
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
6726 memcpy(keyB
[i
], tmpB
+ (i
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
6735 uint8_t firstblocks
[8][16] = {
6736 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6737 { 0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1 },
6738 { 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1 },
6739 { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A },
6740 { 0x03, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6741 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6742 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6743 { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
6747 for (int i
= 0; i
< numSectors
; i
++) {
6748 for (int j
= 0; j
< mfNumBlocksPerSector(j
); j
++) {
6750 uint8_t b
= (mfFirstBlockOfSector(i
) + j
);
6751 uint8_t block
[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
6763 memcpy(block
, firstblocks
[b
], MFBLOCK_SIZE
);
6766 if (mfIsSectorTrailerBasedOnBlocks(i
, j
)) {
6768 memcpy(block
, firstblocks
[7], MFBLOCK_SIZE
);
6774 // write to card, try B key first
6775 if (mf_write_block(keyB
[i
], MF_KEY_B
, b
, block
) == 0) {
6777 if (mf_write_block(keyA
[i
], MF_KEY_A
, b
, block
) == 0) {
6781 PrintAndLogEx(INPLACE
, "Formatting block %u", b
);
6785 PrintAndLogEx(NORMAL
, "");
6789 int CmdHFMFNDEFWrite(const char *Cmd
) {
6791 CLIParserContext
*ctx
;
6792 CLIParserInit(&ctx
, "hf mf ndefwrite",
6793 "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
6794 "hf mf ndefwrite -d 0300FE -> write empty record to tag\n"
6795 "hf mf ndefwrite -f myfilename\n"
6796 "hf mf ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
6799 void *argtable
[] = {
6801 arg_str0("d", NULL
, "<hex>", "raw NDEF hex bytes"),
6802 arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
6803 arg_lit0("p", NULL
, "fix NDEF record headers / terminator block if missing"),
6804 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
6805 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
6806 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
6807 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
6808 arg_lit0("v", "verbose", "verbose output"),
6811 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
6813 uint8_t raw
[4096] = {0};
6815 CLIGetHexWithReturn(ctx
, 1, raw
, &rawlen
);
6818 char filename
[FILE_PATH_SIZE
] = {0};
6819 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6821 bool fix_msg
= arg_get_lit(ctx
, 3);
6823 bool m0
= arg_get_lit(ctx
, 4);
6824 bool m1
= arg_get_lit(ctx
, 5);
6825 bool m2
= arg_get_lit(ctx
, 6);
6826 bool m4
= arg_get_lit(ctx
, 7);
6827 bool verbose
= arg_get_lit(ctx
, 8);
6832 if ((m0
+ m1
+ m2
+ m4
) > 1) {
6833 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
6835 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
6839 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
6842 numSectors
= MIFARE_MINI_MAXSECTOR
;
6844 numSectors
= MIFARE_1K_MAXSECTOR
;
6846 numSectors
= MIFARE_2K_MAXSECTOR
;
6848 numSectors
= MIFARE_4K_MAXSECTOR
;
6850 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
6855 PrintAndLogEx(INFO
, "Number of sectors selected: %u", numSectors
);
6858 if (g_session
.pm3_present
== false) {
6859 PrintAndLogEx(FAILED
, "No Proxmark3 device present");
6863 if ((rawlen
&& fnlen
) || (rawlen
== 0 && fnlen
== 0)) {
6864 PrintAndLogEx(WARNING
, "Please specify either raw hex or filename");
6868 // test if MAD key is used
6871 // check if we can authenticate to sector
6872 int res
= mfCheckKeys(0, MF_KEY_A
, true, 1, (uint8_t *)g_mifare_mad_key
, &key64
);
6873 if (res
!= PM3_SUCCESS
) {
6874 PrintAndLogEx(FAILED
, "Sector 0 failed to authenticate with MAD default key");
6875 PrintAndLogEx(HINT
, "Verify that the tag NDEF formatted");
6879 // NDEF for MIFARE CLASSIC has different memory size available.
6881 int32_t bytes
= rawlen
;
6885 uint8_t *dump
= NULL
;
6886 size_t bytes_read
= 0;
6887 res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, sizeof(raw
));
6888 if (res
!= PM3_SUCCESS
) {
6891 memcpy(raw
, dump
, bytes_read
);
6896 // Has raw bytes ndef message header?bytes
6906 if (fix_msg
== false) {
6907 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a proper header, continuing...");
6909 if (bytes
+ 2 > sizeof(raw
)) {
6910 PrintAndLogEx(WARNING
, "no room for header, exiting...");
6913 uint8_t tmp_raw
[4096];
6914 memcpy(tmp_raw
, raw
, sizeof(tmp_raw
));
6917 memcpy(raw
+ 2, tmp_raw
, sizeof(raw
) - 2);
6919 PrintAndLogEx(SUCCESS
, "Added generic message header (0x03)");
6924 // Has raw bytes ndef a terminator block?
6925 if (raw
[bytes
- 1] != 0xFE) {
6926 if (fix_msg
== false) {
6927 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a terminator block, continuing...");
6930 if (bytes
+ 1 > sizeof(raw
)) {
6931 PrintAndLogEx(WARNING
, "no room for terminator block, exiting...");
6936 PrintAndLogEx(SUCCESS
, "Added terminator block (0xFE)");
6941 PrintAndLogEx(INFO
, "Num of Bytes... %u", bytes
);
6942 print_buffer(raw
, bytes
, 0);
6945 // read MAD Sector 0, block1,2
6946 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6947 if (mfReadSector(MF_MAD1_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector0
)) {
6948 PrintAndLogEx(ERR
, "error, reading sector 0. Card doesn't have MAD or doesn't have MAD on default keys");
6949 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
6953 // read MAD Sector 10, block1,2
6954 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6956 if (mfReadSector(MF_MAD2_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector10
)) {
6957 PrintAndLogEx(ERR
, "error, reading sector 10. Card doesn't have MAD or doesn't have MAD on default keys");
6958 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
6964 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6966 res
= MADDecode(sector0
, sector10
, mad
, &madlen
, false);
6967 if (res
!= PM3_SUCCESS
) {
6968 PrintAndLogEx(ERR
, "can't decode MAD");
6972 // how much memory do I have available ?
6973 // Skip sector 0 since its used for MAD
6974 uint8_t freemem
[MIFARE_4K_MAXSECTOR
] = {0};
6976 uint8_t block_no
= 0;
6977 for (uint8_t i
= 1; i
< (madlen
& 0xFF); i
++) {
6979 freemem
[i
] = (mad
[i
] == NDEF_MFC_AID
);
6983 if (block_no
== 0) {
6984 block_no
= mfFirstBlockOfSector(i
);
6988 PrintAndLogEx(INFO
, "Sector %u is NDEF formatted", i
);
6990 sum
+= (MFBLOCK_SIZE
* 3);
6995 PrintAndLogEx(INFO
, "Total avail ndef mem... %u", sum
);
6996 PrintAndLogEx(INFO
, "First block............ %u", block_no
);
7000 PrintAndLogEx(WARNING
, "Raw NDEF message is larger than available NDEF formatted memory");
7004 // main loop - write blocks
7005 uint8_t *ptr_raw
= raw
;
7008 uint8_t block
[MFBLOCK_SIZE
] = { 0x00 };
7010 if (bytes
< MFBLOCK_SIZE
) {
7011 memcpy(block
, ptr_raw
, bytes
);
7013 memcpy(block
, ptr_raw
, MFBLOCK_SIZE
);
7014 ptr_raw
+= MFBLOCK_SIZE
;
7017 // write to card, try B key first
7018 if (mf_write_block(g_mifare_default_key
, MF_KEY_B
, block_no
, block
) == 0) {
7021 if (mf_write_block(g_mifare_ndef_key
, MF_KEY_A
, block_no
, block
) == 0) {
7026 PrintAndLogEx(INPLACE
, "%u", block_no
);
7028 // find next available block
7031 if (mfIsSectorTrailer(block_no
)) {
7033 // skip sectors which isn't ndef formatted
7034 while (freemem
[mfSectorNum(block_no
)] == 0) {
7039 bytes
-= MFBLOCK_SIZE
;
7042 PrintAndLogEx(NORMAL
, "");
7046 static int CmdHFMFPersonalize(const char *Cmd
) {
7047 CLIParserContext
*ctx
;
7048 CLIParserInit(&ctx
, "hf mf personalize",
7049 "Personalize the UID of a MIFARE Classic EV1 card. This is only possible \n"
7050 "if it is a 7Byte UID card and if it is not already personalized.",
7051 "hf mf personalize --f0 -> double size UID\n"
7052 "hf mf personalize --f1 -> double size UID, optional usage of selection process shortcut\n"
7053 "hf mf personalize --f2 -> single size random ID\n"
7054 "hf mf personalize --f3 -> single size NUID\n"
7055 "hf mf personalize -b -k B0B1B2B3B4B5 --f3 -> use key B = 0xB0B1B2B3B4B5"
7058 void *argtable
[] = {
7060 arg_lit0("a", NULL
, "use key A to authenticate sector 0 (def)"),
7061 arg_lit0("b", NULL
, "use key B to authenticate sector 0"),
7062 arg_str0("k", "key", "<hex>", "key (def FFFFFFFFFFFF)"),
7063 arg_lit0(NULL
, "f0", "UIDFO, double size UID"),
7064 arg_lit0(NULL
, "f1", "UIDF1, double size UID, optional usage of selection process shortcut"),
7065 arg_lit0(NULL
, "f2", "UIDF2, single size random ID"),
7066 arg_lit0(NULL
, "f3", "UIDF3, single size NUID"),
7069 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7071 bool use_a
= arg_get_lit(ctx
, 1);
7072 bool use_b
= arg_get_lit(ctx
, 2);
7074 if (use_a
+ use_b
> 1) {
7075 PrintAndLogEx(ERR
, "error, use only one key type");
7080 uint8_t keytype
= 0;
7085 uint8_t key
[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
7087 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), key
, 6, &key_len
);
7088 if (res
|| (!res
&& key_len
&& key_len
!= 6)) {
7089 PrintAndLogEx(ERR
, "ERROR: not a valid key. Key must be 12 hex digits");
7094 bool f0
= arg_get_lit(ctx
, 4);
7095 bool f1
= arg_get_lit(ctx
, 5);
7096 bool f2
= arg_get_lit(ctx
, 6);
7097 bool f3
= arg_get_lit(ctx
, 7);
7100 uint8_t tmp
= f0
+ f1
+ f2
+ f3
;
7102 PrintAndLogEx(WARNING
, "select only one key type");
7106 PrintAndLogEx(WARNING
, "select one key type");
7110 uint8_t pers_option
= MIFARE_EV1_UIDF3
;
7112 pers_option
= MIFARE_EV1_UIDF0
;
7114 pers_option
= MIFARE_EV1_UIDF1
;
7116 pers_option
= MIFARE_EV1_UIDF2
;
7123 uint8_t pers_option
;
7126 payload
.keytype
= keytype
;
7127 payload
.pers_option
= pers_option
;
7128 memcpy(payload
.key
, key
, sizeof(payload
.key
));
7130 clearCommandBuffer();
7131 SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID
, (uint8_t *)&payload
, sizeof(payload
));
7132 PacketResponseNG resp
;
7133 if (WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID
, &resp
, 2500) == false) {
7134 return PM3_ETIMEOUT
;
7137 if (resp
.status
== PM3_SUCCESS
) {
7138 PrintAndLogEx(SUCCESS
, "Personalization ( %s )", _GREEN_("ok"));
7140 PrintAndLogEx(FAILED
, "Personalization ( %s )", _RED_("fail"));
7145 static int CmdHF14AMfList(const char *Cmd
) {
7146 return CmdTraceListAlias(Cmd
, "hf mf", "mf -c");
7149 static int CmdHf14AGen3UID(const char *Cmd
) {
7150 CLIParserContext
*ctx
;
7151 CLIParserInit(&ctx
, "hf mf gen3uid",
7152 "Set UID for magic Gen3 card _without_ changes to manufacturer block 0",
7153 "hf mf gen3uid --uid 01020304 --> set 4 byte uid\n"
7154 "hf mf gen3uid --uid 01020304050607 --> set 7 byte uid"
7156 void *argtable
[] = {
7158 arg_str0("u", "uid", "<hex>", "UID 4/7 hex bytes"),
7161 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7163 uint8_t uid
[7] = {0};
7165 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
7169 if (uidlen
!= 4 && uidlen
!= 7) {
7170 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
7174 uint8_t old_uid
[10] = {0};
7176 int res
= mfGen3UID(uid
, uidlen
, old_uid
);
7177 if (res
!= PM3_SUCCESS
) {
7178 PrintAndLogEx(ERR
, "Can't set UID");
7179 PrintAndLogEx(HINT
, "Are you sure your card is a Gen3 ?");
7183 PrintAndLogEx(SUCCESS
, "Old UID... %s", sprint_hex(old_uid
, uidlen
));
7184 PrintAndLogEx(SUCCESS
, "New UID... %s", sprint_hex(uid
, uidlen
));
7188 static int CmdHf14AGen3Block(const char *Cmd
) {
7189 CLIParserContext
*ctx
;
7190 CLIParserInit(&ctx
, "hf mf gen3blk",
7191 "Overwrite full manufacturer block for magic Gen3 card\n"
7192 " - You can specify part of manufacturer block as\n"
7193 " 4/7-bytes for UID change only\n"
7195 "NOTE: BCC, SAK, ATQA will be calculated automatically"
7197 "hf mf gen3blk --> print current data\n"
7198 "hf mf gen3blk -d 01020304 --> set 4 byte uid\n"
7199 "hf mf gen3blk -d 01020304050607 --> set 7 byte uid \n"
7200 "hf mf gen3blk -d 01020304FFFFFFFF0102030405060708"
7203 void *argtable
[] = {
7205 arg_str0("d", "data", "<hex>", "manufacturer block data up to 16 hex bytes"),
7208 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7210 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
7212 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
7215 uint8_t new_block
[MFBLOCK_SIZE
] = {0x00};
7216 int res
= mfGen3Block(data
, datalen
, new_block
);
7218 PrintAndLogEx(ERR
, "Can't change manufacturer block data. error %d", res
);
7222 PrintAndLogEx(SUCCESS
, "Current block... %s", sprint_hex_inrow(new_block
, sizeof(new_block
)));
7226 static int CmdHf14AGen3Freeze(const char *Cmd
) {
7227 CLIParserContext
*ctx
;
7228 CLIParserInit(&ctx
, "hf mf gen3freeze",
7229 "Perma lock further UID changes. No more UID changes available after operation completed\n"
7230 "\nNote: operation is " _RED_("! irreversible !"),
7232 "hf mf gen3freeze -y"
7234 void *argtable
[] = {
7236 arg_lit1("y", "yes", "confirm UID lock operation"),
7239 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
7240 bool confirm
= arg_get_lit(ctx
, 1);
7242 if (confirm
== false) {
7243 PrintAndLogEx(INFO
, "please confirm that you want to perma lock the card");
7247 int res
= mfGen3Freeze();
7248 if (res
!= PM3_SUCCESS
) {
7249 PrintAndLogEx(ERR
, "Can't lock UID changes. error %d", res
);
7251 PrintAndLogEx(SUCCESS
, "MFC Gen3 UID card is now perma-locked");
7256 #define FURUI_MAX_TRACES 8
7257 static int mfc_furui_recovery(uint8_t items
, uint8_t tracedata
[FURUI_MAX_TRACES
][18]) {
7258 // recover key from collected traces
7260 for (uint8_t i
= 0; i
< items
; i
++) {
7264 data
.cuid
= bytes_to_num(tracedata
[i
], 4);
7265 data
.nonce
= bytes_to_num(tracedata
[i
] + 6, 4);
7266 data
.nr
= bytes_to_num(tracedata
[i
] + 10, 4);
7267 data
.ar
= bytes_to_num(tracedata
[i
] + 14, 4);
7271 for (uint8_t j
= i
+ 1; j
< items
; j
++) {
7273 uint8_t *p
= tracedata
[j
];
7274 PrintAndLogEx(INFO
, "%u... %s", i
, sprint_hex_inrow(p
, 18));
7276 // since data stored as block number but its the same key for all blocks in one sector
7277 // we compare with sector number here
7278 uint8_t s
= mfSectorNum(tracedata
[i
][4]);
7279 if (mfSectorNum(p
[4]) == s
) {
7281 data
.nonce2
= bytes_to_num(p
+ 6, 4);
7282 data
.nr2
= bytes_to_num(p
+ 10, 4);
7283 data
.ar2
= bytes_to_num(p
+ 14, 4);
7285 data
.keytype
= tracedata
[i
][5];
7288 uint64_t key64
= -1;
7289 if (mfkey32_moebius(&data
, &key64
)) {
7290 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64
) " ]",
7291 sprint_hex_inrow(tracedata
[i
], 4),
7293 (data
.keytype
== 0x60) ? 'A' : 'B',
7304 static int mfc_supercard_gen2_recovery(uint8_t items
, uint8_t tracedata
[FURUI_MAX_TRACES
][18]) {
7305 for (uint8_t i
= 0; i
< items
; i
++) {
7306 uint8_t *tmp
= tracedata
[i
];
7309 uint16_t NT0
= (tmp
[6] << 8) | tmp
[7];
7312 data
.cuid
= bytes_to_num(tmp
, 4);
7313 data
.nonce
= prng_successor(NT0
, 31);
7314 data
.nr
= bytes_to_num(tmp
+ 8, 4);
7315 data
.ar
= bytes_to_num(tmp
+ 12, 4);
7319 for (uint8_t j
= i
+ 1; j
< items
; j
++) {
7320 uint8_t *p
= tracedata
[j
];
7322 // since data stored as block number but its the same key for all blocks in one sector
7323 // we compare with sector number here
7324 uint8_t s
= mfSectorNum(tmp
[5]);
7325 if (mfSectorNum(p
[5]) == s
) {
7327 NT0
= (p
[6] << 8) | p
[7];
7329 data
.nonce2
= prng_successor(NT0
, 31);
7330 data
.nr2
= bytes_to_num(p
+ 8, 4);
7331 data
.ar2
= bytes_to_num(p
+ 12, 4);
7333 data
.keytype
= tmp
[4];
7336 uint64_t key64
= -1;
7337 if (mfkey32_moebius(&data
, &key64
)) {
7338 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64
) " ]",
7339 sprint_hex_inrow(tmp
, 4),
7341 (data
.keytype
== 0x60) ? 'A' : 'B',
7352 static int CmdHf14AMfSuperCard(const char *Cmd
) {
7353 CLIParserContext
*ctx
;
7354 CLIParserInit(&ctx
, "hf mf supercard",
7355 "Extract info from a `super card`",
7356 "hf mf supercard -> recover key\n"
7357 "hf mf supercard -r -> reset card\n"
7358 "hf mf supercard -u 11223344 -> change UID\n");
7360 void *argtable
[] = {
7362 arg_lit0("r", "reset", "Reset card"),
7363 arg_str0("u", "uid", "<hex>", "New UID (4 hex bytes)"),
7364 arg_lit0(NULL
, "furui", "Furui detection card"),
7367 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7368 bool reset_card
= arg_get_lit(ctx
, 1);
7371 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), uid
, sizeof(uid
), &uidlen
);
7372 bool is_furui
= arg_get_lit(ctx
, 3);
7377 if (res
|| (!res
&& uidlen
&& uidlen
!= sizeof(uid
))) {
7378 PrintAndLogEx(ERR
, "UID must include 4 hex bytes");
7382 uint8_t tracedata
[FURUI_MAX_TRACES
][18];
7387 // no reset on super card FURUI
7388 if (uidlen
|| reset_card
) {
7389 PrintAndLogEx(FAILED
, "Not supported on this card");
7395 for (i
= 0; i
< FURUI_MAX_TRACES
; i
++) {
7397 uint8_t data
[] = {0xAA, 0xA8, 0x00, i
};
7398 uint32_t flags
= ISO14A_CONNECT
| ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_RATS
;
7399 clearCommandBuffer();
7400 SendCommandMIX(CMD_HF_ISO14443A_READER
, flags
, sizeof(data
), 0, data
, sizeof(data
));
7401 if (WaitForResponseTimeout(CMD_ACK
, NULL
, 1500) == false) {
7405 PacketResponseNG resp
;
7406 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
7410 uint16_t len
= resp
.oldarg
[0] & 0xFFFF;
7412 break; // Not trace data
7415 PrintAndLogEx(DEBUG
, ">>> %s", sprint_hex_inrow(resp
.data
.asBytes
, len
));
7416 memcpy(&tracedata
[i
], resp
.data
.asBytes
, len
- 2);
7419 return mfc_furui_recovery(i
, tracedata
);
7422 #define SUPER_MAX_TRACES 7
7424 // read 7 traces from super card generation 1,2
7426 for (i
= 0; i
< SUPER_MAX_TRACES
; i
++) {
7428 uint8_t data
[] = {0x30, i
};
7429 uint32_t flags
= ISO14A_CONNECT
| ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_RATS
;
7430 clearCommandBuffer();
7431 SendCommandMIX(CMD_HF_ISO14443A_READER
, flags
, sizeof(data
), 0, data
, sizeof(data
));
7432 if (WaitForResponseTimeout(CMD_ACK
, NULL
, 1500) == false) {
7436 PacketResponseNG resp
;
7437 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
7441 uint16_t len
= resp
.oldarg
[0] & 0xFFFF;
7443 break; // Not trace data
7446 PrintAndLogEx(DEBUG
, ">>> %s", sprint_hex_inrow(resp
.data
.asBytes
, len
));
7447 memcpy(&tracedata
[i
], resp
.data
.asBytes
, len
- 2);
7450 // Super card generation 2
7451 if (i
== SUPER_MAX_TRACES
) {
7453 // no reset on super card generation 2.
7454 if (uidlen
|| reset_card
) {
7455 PrintAndLogEx(FAILED
, "Not supported on this card");
7459 // recover key from collected traces
7460 return mfc_supercard_gen2_recovery(i
, tracedata
);
7463 // Super card generation 1
7469 bool activate_field
= true;
7470 bool keep_field_on
= true;
7472 // change UID on a super card generation 1
7474 keep_field_on
= false;
7475 uint8_t response
[6];
7478 // --------------- CHANGE UID ----------------
7479 uint8_t aCHANGE
[] = {0x00, 0xa6, 0xa0, 0x00, 0x05, 0xff, 0xff, 0xff, 0xff, 0x00};
7480 memcpy(aCHANGE
+ 5, uid
, uidlen
);
7481 res
= ExchangeAPDU14a(
7482 aCHANGE
, sizeof(aCHANGE
),
7485 response
, sizeof(response
),
7489 if (res
!= PM3_SUCCESS
) {
7490 PrintAndLogEx(FAILED
, "Super card UID change [ " _RED_("fail") " ]");
7495 PrintAndLogEx(SUCCESS
, "Super card UID change ( " _GREEN_("ok") " )");
7499 // reset a super card generation 1
7501 keep_field_on
= false;
7502 uint8_t response
[6];
7505 // --------------- RESET CARD ----------------
7506 uint8_t aRESET
[] = {0x00, 0xa6, 0xc0, 0x00};
7507 res
= ExchangeAPDU14a(
7508 aRESET
, sizeof(aRESET
),
7511 response
, sizeof(response
),
7515 if (res
!= PM3_SUCCESS
) {
7516 PrintAndLogEx(FAILED
, "Super card reset [ " _RED_("fail") " ]");
7520 PrintAndLogEx(SUCCESS
, "Super card reset ( " _GREEN_("ok") " )");
7524 uint8_t responseA
[22];
7525 uint8_t responseB
[22];
7529 // --------------- First ----------------
7530 uint8_t aFIRST
[] = {0x00, 0xa6, 0xb0, 0x00, 0x10};
7531 res
= ExchangeAPDU14a(aFIRST
, sizeof(aFIRST
), activate_field
, keep_field_on
, responseA
, sizeof(responseA
), &respAlen
);
7532 if (res
!= PM3_SUCCESS
) {
7537 // --------------- Second ----------------
7538 activate_field
= false;
7539 keep_field_on
= false;
7541 uint8_t aSECOND
[] = {0x00, 0xa6, 0xb0, 0x01, 0x10};
7542 res
= ExchangeAPDU14a(aSECOND
, sizeof(aSECOND
), activate_field
, keep_field_on
, responseB
, sizeof(responseB
), &respBlen
);
7543 if (res
!= PM3_SUCCESS
) {
7548 uint8_t outA
[16] = {0};
7549 uint8_t outB
[16] = {0};
7551 uint8_t key
[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
7552 for (i
= 0; i
< 16; i
+= 8) {
7553 des_decrypt(outA
+ i
, responseA
+ i
, key
);
7554 des_decrypt(outB
+ i
, responseB
+ i
, key
);
7557 PrintAndLogEx(DEBUG
, " in : %s", sprint_hex_inrow(responseA
, respAlen
));
7558 PrintAndLogEx(DEBUG
, "out : %s", sprint_hex_inrow(outA
, sizeof(outA
)));
7559 PrintAndLogEx(DEBUG
, " in : %s", sprint_hex_inrow(responseB
, respAlen
));
7560 PrintAndLogEx(DEBUG
, "out : %s", sprint_hex_inrow(outB
, sizeof(outB
)));
7562 if (memcmp(outA
, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
7563 PrintAndLogEx(INFO
, "No trace recorded");
7568 if (memcmp(outB
, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
7569 PrintAndLogEx(INFO
, "Only one trace recorded");
7576 uint16_t NT0
= (outA
[6] << 8) | outA
[7];
7577 data
.cuid
= bytes_to_num(outA
, 4);
7578 data
.nonce
= prng_successor(NT0
, 31);
7579 data
.nr
= bytes_to_num(outA
+ 8, 4);
7580 data
.ar
= bytes_to_num(outA
+ 12, 4);
7584 NT0
= (outB
[6] << 8) | outB
[7];
7585 data
.nonce2
= prng_successor(NT0
, 31);
7586 data
.nr2
= bytes_to_num(outB
+ 8, 4);
7587 data
.ar2
= bytes_to_num(outB
+ 12, 4);
7588 data
.sector
= mfSectorNum(outA
[5]);
7589 data
.keytype
= outA
[4];
7592 PrintAndLogEx(DEBUG
, "A Sector %02x", data
.sector
);
7593 PrintAndLogEx(DEBUG
, "A NT %08x", data
.nonce
);
7594 PrintAndLogEx(DEBUG
, "A NR %08x", data
.nr
);
7595 PrintAndLogEx(DEBUG
, "A AR %08x", data
.ar
);
7596 PrintAndLogEx(DEBUG
, "");
7597 PrintAndLogEx(DEBUG
, "B NT %08x", data
.nonce2
);
7598 PrintAndLogEx(DEBUG
, "B NR %08x", data
.nr2
);
7599 PrintAndLogEx(DEBUG
, "B AR %08x", data
.ar2
);
7601 uint64_t key64
= -1;
7602 if (mfkey32_moebius(&data
, &key64
)) {
7603 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ " _GREEN_("%012" PRIX64
) " ]",
7604 sprint_hex_inrow(outA
, 4),
7606 (data
.keytype
== 0x60) ? 'A' : 'B',
7610 PrintAndLogEx(FAILED
, "failed to recover any key");
7615 static int CmdHF14AMfWipe(const char *Cmd
) {
7616 CLIParserContext
*ctx
;
7617 CLIParserInit(&ctx
, "hf mf wipe",
7618 "Wipe card to zeros and default keys/acc. This command takes a key file to wipe card\n"
7619 "Will use UID from card to generate keyfile name if not specified.\n"
7620 "New A/B keys..... FF FF FF FF FF FF\n"
7621 "New acc rights... FF 07 80\n"
7622 "New GPB.......... 69",
7623 "hf mf wipe --> reads card uid to generate file name\n"
7624 "hf mf wipe --gen2 --> force write to S0, B0 manufacture block\n"
7625 "hf mf wipe -f mykey.bin --> use mykey.bin\n"
7627 void *argtable
[] = {
7629 arg_str0("f", "file", "<fn>", "key filename"),
7630 arg_lit0(NULL
, "gen2", "force write to Sector 0, block 0 (GEN2)"),
7633 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7636 char keyFilename
[FILE_PATH_SIZE
] = {0};
7637 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
7639 bool gen2
= arg_get_lit(ctx
, 2);
7643 if (keyfnlen
== 0) {
7644 fptr
= GenerateFilename("hf-mf-", "-key.bin");
7648 strncpy(keyFilename
, fptr
, sizeof(keyFilename
) - 1);
7654 if (loadFile_safeEx(keyFilename
, ".bin", (void **)&keys
, (size_t *)&keyslen
, false) != PM3_SUCCESS
) {
7655 PrintAndLogEx(FAILED
, "failed to load key file");
7659 uint8_t keyA
[MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
];
7660 uint8_t keyB
[MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
];
7661 uint8_t num_sectors
= 0;
7663 uint8_t mf
[MFBLOCK_SIZE
];
7665 case (MIFARE_MINI_MAX_KEY_SIZE
): {
7666 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic Mini 320b");
7667 memcpy(keyA
, keys
, (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
));
7668 memcpy(keyB
, keys
+ (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
));
7669 num_sectors
= NumOfSectors('0');
7670 memcpy(mf
, "\x11\x22\x33\x44\x44\x09\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7673 case (MIFARE_1K_EV1_MAX_KEY_SIZE
): {
7674 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 1K Ev1");
7675 memcpy(keyA
, keys
, (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
));
7676 memcpy(keyB
, keys
+ (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
));
7677 num_sectors
= NumOfSectors('1');
7678 memcpy(mf
, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7681 case (MIFARE_1K_MAX_KEY_SIZE
): {
7682 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 1K");
7683 memcpy(keyA
, keys
, (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7684 memcpy(keyB
, keys
+ (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7685 num_sectors
= NumOfSectors('1');
7687 memcpy(mf
, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7690 case (MIFARE_4K_MAX_KEY_SIZE
): {
7691 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 4K");
7692 memcpy(keyA
, keys
, (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7693 memcpy(keyB
, keys
+ (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7694 num_sectors
= NumOfSectors('4');
7695 memcpy(mf
, "\x11\x22\x33\x44\x44\x18\x02\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7699 PrintAndLogEx(INFO
, "wrong key file size. got %zu", keyslen
);
7705 PrintAndLogEx(INFO
, "Forcing overwrite of sector 0 / block 0 ");
7707 PrintAndLogEx(INFO
, "Skipping sector 0 / block 0");
7709 PrintAndLogEx(NORMAL
, "");
7711 uint8_t zeros
[MFBLOCK_SIZE
] = {0};
7712 memset(zeros
, 0x00, sizeof(zeros
));
7713 uint8_t st
[MFBLOCK_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
7715 PrintAndLogEx(INFO
, " blk | ");
7716 PrintAndLogEx(INFO
, "-----+------------------------------------------------------------");
7717 // time to wipe card
7718 for (uint8_t s
= 0; s
< num_sectors
; s
++) {
7720 for (uint8_t b
= 0; b
< mfNumBlocksPerSector(s
); b
++) {
7722 if (kbd_enter_pressed()) {
7723 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
7727 // Skip write to manufacture block if not enforced
7728 if (s
== 0 && b
== 0 && gen2
== false) {
7733 memset(data
, 0, sizeof(data
));
7734 if (mfIsSectorTrailerBasedOnBlocks(s
, b
)) {
7735 memcpy(data
+ 10, st
, sizeof(st
));
7737 memcpy(data
+ 10, zeros
, sizeof(zeros
));
7740 // add correct manufacture block if UID Gen2
7741 if (s
== 0 && b
== 0 && gen2
) {
7742 memcpy(data
+ 10, mf
, sizeof(mf
));
7745 // try both A/B keys, start with B key first
7746 for (int8_t kt
= MF_KEY_B
; kt
> -1; kt
--) {
7749 memcpy(data
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
7751 memcpy(data
, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
7753 PrintAndLogEx(INFO
, " %3d | %s" NOLF
, mfFirstBlockOfSector(s
) + b
, sprint_hex(data
+ 10, MFBLOCK_SIZE
));
7754 clearCommandBuffer();
7755 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, mfFirstBlockOfSector(s
) + b
, kt
, 0, data
, sizeof(data
));
7756 PacketResponseNG resp
;
7757 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
7758 int8_t isOK
= resp
.oldarg
[0];
7760 PrintAndLogEx(NORMAL
, "- key %c ( " _GREEN_("ok") " )", (kt
== MF_KEY_A
) ? 'A' : 'B');
7763 PrintAndLogEx(NORMAL
, "- key %c ( " _RED_("fail") " )", (kt
== MF_KEY_A
) ? 'A' : 'B');
7766 PrintAndLogEx(WARNING
, "command execution time out");
7772 PrintAndLogEx(INFO
, "-----+------------------------------------------------------------");
7773 PrintAndLogEx(NORMAL
, "");
7774 PrintAndLogEx(INFO
, "Done!");
7780 static int CmdHF14AMfView(const char *Cmd
) {
7782 CLIParserContext
*ctx
;
7783 CLIParserInit(&ctx
, "hf mf view",
7784 "Print a MIFARE Classic dump file (bin/eml/json)",
7785 "hf mf view -f hf-mf-01020304-dump.bin"
7787 void *argtable
[] = {
7789 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
7790 arg_lit0("v", "verbose", "verbose output"),
7791 arg_lit0(NULL
, "sk", "Save extracted keys to binary file"),
7794 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
7796 char filename
[FILE_PATH_SIZE
];
7797 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
7798 bool verbose
= arg_get_lit(ctx
, 2);
7799 bool save_keys
= arg_get_lit(ctx
, 3);
7803 uint8_t *dump
= NULL
;
7804 size_t bytes_read
= 0;
7805 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, MIFARE_4K_MAX_BYTES
);
7806 if (res
!= PM3_SUCCESS
) {
7810 uint16_t block_cnt
= MIN(MIFARE_1K_MAXBLOCK
, (bytes_read
/ MFBLOCK_SIZE
));
7811 if (bytes_read
== MIFARE_MINI_MAX_BYTES
)
7812 block_cnt
= MIFARE_MINI_MAXBLOCK
;
7813 else if (bytes_read
== MIFARE_2K_MAX_BYTES
)
7814 block_cnt
= MIFARE_2K_MAXBLOCK
;
7815 else if (bytes_read
== MIFARE_4K_MAX_BYTES
)
7816 block_cnt
= MIFARE_4K_MAXBLOCK
;
7819 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
7822 mf_print_blocks(block_cnt
, dump
, verbose
);
7825 mf_print_keys(block_cnt
, dump
);
7826 mf_analyse_acl(block_cnt
, dump
);
7830 mf_save_keys_from_arr(block_cnt
, dump
);
7833 int sector
= DetectHID(dump
, 0x4910);
7836 PrintAndLogEx(INFO
, "");
7837 PrintAndLogEx(INFO
, _CYAN_("VIGIK PACS detected"));
7840 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
7842 res
= MADDecode(dump
, NULL
, mad
, &madlen
, false);
7843 if (res
!= PM3_SUCCESS
) {
7844 PrintAndLogEx(ERR
, "can't decode MAD");
7848 typedef union UDATA
{
7854 d
.bytes
= calloc(bytes_read
, sizeof(uint8_t));
7855 if (d
.bytes
== NULL
) {
7860 // vigik struture sector 0
7861 uint8_t *pdump
= dump
;
7863 memcpy(d
.bytes
+ dlen
, pdump
, MFBLOCK_SIZE
* 3);
7864 dlen
+= MFBLOCK_SIZE
* 3;
7865 pdump
+= (MFBLOCK_SIZE
* 4); // skip sectortrailer
7867 // extract memory from MAD sectors
7868 for (int i
= 0; i
<= madlen
; i
++) {
7869 if (0x4910 == mad
[i
] || 0x4916 == mad
[i
]) {
7870 memcpy(d
.bytes
+ dlen
, pdump
, MFBLOCK_SIZE
* 3);
7871 dlen
+= MFBLOCK_SIZE
* 3;
7874 pdump
+= (MFBLOCK_SIZE
* 4); // skip sectortrailer
7877 // convert_mfc_2_arr(pdump, bytes_read, d, &dlen);
7878 vigik_annotate(d
.vigik
);
7886 static int parse_gtu_cfg(uint8_t *d
, size_t n
) {
7888 PrintAndLogEx(NORMAL
, "");
7889 PrintAndLogEx(INFO
, "---------- " _CYAN_("GTU Gen4 Configuration") " -------------------------------------");
7890 if (n
!= 30 && n
!= 32) {
7891 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
, n
));
7892 PrintAndLogEx(INFO
, "%zu bytes", n
);
7893 PrintAndLogEx(WARNING
, "Unknown config format");
7897 PrintAndLogEx(INFO
, _YELLOW_("%s"), sprint_hex_inrow(d
, n
));
7898 PrintAndLogEx(INFO
, "%zu bytes", n
);
7899 PrintAndLogEx(INFO
, "");
7900 PrintAndLogEx(INFO
, _CYAN_("Config 1 - UID & modes"));
7901 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
, 8));
7902 PrintAndLogEx(INFO
, "%02X.............. " NOLF
, d
[0]);
7903 bool is_ul_enabled
= (d
[0] == 1);
7906 PrintAndLogEx(NORMAL
, "MIFARE Classic mode");
7909 PrintAndLogEx(NORMAL
, "MIFARE Ultralight/NTAG mode");
7912 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7916 PrintAndLogEx(INFO
, "..%02X............ UID " NOLF
, d
[1]);
7920 PrintAndLogEx(NORMAL
, _GREEN_("4") " byte");
7923 PrintAndLogEx(NORMAL
, _GREEN_("7") " byte");
7926 PrintAndLogEx(NORMAL
, _GREEN_("10") " byte");
7929 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7933 PrintAndLogEx(INFO
, "...." _YELLOW_("%s") ".... " _YELLOW_("Password"), sprint_hex_inrow(&d
[2], 4));
7934 PrintAndLogEx(INFO
, "............%02X.. GTU mode " NOLF
, d
[6]);
7937 PrintAndLogEx(NORMAL
, _GREEN_("pre-write") " - shadow data can be written");
7940 PrintAndLogEx(NORMAL
, _GREEN_("restore mode"));
7943 PrintAndLogEx(NORMAL
, "disabled");
7946 PrintAndLogEx(NORMAL
, "disabled, high speed R/W mode for Ultralight ?");
7949 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7953 uint8_t atslen
= d
[7];
7955 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _YELLOW_("zero"));
7956 } else if (atslen
<= 16) {
7957 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _GREEN_("ok"));
7959 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _RED_("fail"));
7963 PrintAndLogEx(INFO
, "");
7965 // ATS seems to have 16 bytes reserved
7966 PrintAndLogEx(INFO
, _CYAN_("Config 2 - ATS"));
7967 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
+ 8, 16));
7969 PrintAndLogEx(INFO
, "%s.............. ATS ( %d bytes )", sprint_hex_inrow(&d
[8], d
[7]), d
[7]);
7970 PrintAndLogEx(INFO
, "..................%s Reserved for ATS", sprint_hex_inrow(d
+ 8 + d
[7], 16 - d
[7]));
7972 PrintAndLogEx(INFO
, "%s.............. %u Reserved for ATS", sprint_hex_inrow(&d
[8], 16), 16);
7975 PrintAndLogEx(INFO
, "");
7976 PrintAndLogEx(INFO
, _CYAN_("Config 3 - Limits"));
7977 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
+ 24, (n
- 24)));
7978 PrintAndLogEx(INFO
, "%02X%02X............ ATQA", d
[24], d
[25]);
7979 PrintAndLogEx(INFO
, "....%02X.......... SAK", d
[26]);
7980 PrintAndLogEx(INFO
, "......%02X........ " NOLF
, d
[27]);
7983 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight EV1") : "Ultralight Ev1");
7986 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("NTAG") : "NTAG");
7989 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight C") : "Ultralight C");
7992 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight") : "Ultralight");
7995 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7999 PrintAndLogEx(INFO
, "........%02X...... Max R/W sectors", d
[28]);
8000 PrintAndLogEx(INFO
, "..........%02X.... " NOLF
, d
[29]);
8003 PrintAndLogEx(NORMAL
, _GREEN_("CUID enabled"));
8006 PrintAndLogEx(NORMAL
, "CUID disabled");
8009 PrintAndLogEx(NORMAL
, "Default value. Same behaviour as 00?");
8012 PrintAndLogEx(NORMAL
, _RED_("unknown"));
8015 PrintAndLogEx(INFO
, "............%s unknown", sprint_hex_inrow(d
+ 30, n
- 30));
8016 PrintAndLogEx(INFO
, "");
8020 // info about Gen4 GTU card
8021 static int CmdHF14AGen4Info(const char *cmd
) {
8022 CLIParserContext
*ctx
;
8023 CLIParserInit(&ctx
, "hf mf ginfo",
8024 "Read info about magic gen4 GTU card.",
8025 "hf mf ginfo --> get info with default password 00000000\n"
8026 "hf mf ginfo --pwd 01020304 --> get info with password\n"
8027 "hf mf ginfo -d 00000000000002090978009102BDAC19131011121314151604001800FF0002FD -v --> decode config block"
8029 void *argtable
[] = {
8031 arg_lit0("v", "verbose", "verbose output"),
8032 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8033 arg_str0("d", "data", "<hex>", "config bytes 32 bytes"),
8036 CLIExecWithReturn(ctx
, cmd
, argtable
, true);
8037 bool verbose
= arg_get_lit(ctx
, 1);
8040 uint8_t pwd
[4] = {0};
8041 CLIGetHexWithReturn(ctx
, 2, pwd
, &pwd_len
);
8044 uint8_t data
[32] = {0};
8045 CLIGetHexWithReturn(ctx
, 3, data
, &dlen
);
8048 if (pwd_len
!= 0 && pwd_len
!= 4) {
8049 PrintAndLogEx(FAILED
, "Password must be 4 bytes length, got " _YELLOW_("%u"), pwd_len
);
8053 uint8_t resp
[40] = {0};
8058 res
= mfG4GetConfig(pwd
, resp
, &resplen
, verbose
);
8059 if (res
!= PM3_SUCCESS
|| resplen
== 0) {
8060 if (res
== PM3_ETIMEOUT
)
8061 PrintAndLogEx(ERR
, "No card in the field or card command timeout.");
8063 PrintAndLogEx(ERR
, "Error get config. Maybe not a Gen4 card?. error=%d rlen=%zu", res
, resplen
);
8067 memcpy(resp
, data
, dlen
);
8071 parse_gtu_cfg(resp
, resplen
);
8073 uint8_t uid_len
= resp
[1];
8075 res
= mfG4GetFactoryTest(pwd
, resp
, &resplen
, false);
8076 if (res
== PM3_SUCCESS
&& resplen
> 2) {
8077 PrintAndLogEx(INFO
, "");
8078 PrintAndLogEx(INFO
, _CYAN_("Factory test"));
8080 PrintAndLogEx(INFO
, "Raw......... %s", sprint_hex_inrow(resp
, resplen
));
8083 if (memcmp(resp
+ resplen
- 2, "\x66\x66", 2) == 0) {
8084 PrintAndLogEx(INFO
, "Card type... Generic");
8086 } else if (memcmp(resp
+ resplen
- 2, "\x02\xAA", 2) == 0) {
8087 PrintAndLogEx(INFO
, "Card type... " _RED_("Limited functionality"));
8089 } else if (memcmp(resp
+ resplen
- 2, "\x03\xA0", 2) == 0) {
8090 PrintAndLogEx(INFO
, "Card type... Old card version");
8092 } else if (memcmp(resp
+ resplen
- 2, "\x06\xA0", 2) == 0) {
8093 PrintAndLogEx(INFO
, "Card type... " _GREEN_("New card version"));
8096 PrintAndLogEx(INFO
, "Card type... " _RED_("unknown %02X%02X"), resp
[resplen
- 2], resp
[resplen
- 1]);
8101 res
= mfG4GetBlock(pwd
, 0, resp
, MAGIC_INIT
| MAGIC_OFF
);
8102 if (res
== PM3_SUCCESS
) {
8103 PrintAndLogEx(INFO
, "");
8104 PrintAndLogEx(INFO
, _CYAN_("Block 0 test"));
8105 PrintAndLogEx(INFO
, "Block 0..... %s", sprint_hex_inrow(resp
, 16));
8109 PrintAndLogEx(INFO
, "UID [4]..... %s", sprint_hex_inrow(resp
, 4));
8112 PrintAndLogEx(INFO
, "UID [7]..... %s", sprint_hex_inrow(resp
, 7));
8115 PrintAndLogEx(INFO
, "UID [10..... %s", sprint_hex_inrow(resp
, 10));
8122 PrintAndLogEx(NORMAL
, "");
8126 // Read block from Gen4 GTU card
8127 static int CmdHF14AGen4GetBlk(const char *cmd
) {
8128 CLIParserContext
*ctx
;
8129 CLIParserInit(&ctx
, "hf mf ggetblk",
8130 "Get block data from magic gen4 GTU card.",
8131 "hf mf ggetblk --blk 0 --> get block 0 (manufacturer)\n"
8132 "hf mf ggetblk --blk 3 -v --> get block 3, decode sector trailer\n"
8134 void *argtable
[] = {
8136 arg_int1("b", "blk", "<dec>", "block number"),
8137 arg_lit0("v", "verbose", "verbose output"),
8138 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8141 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8142 int b
= arg_get_int_def(ctx
, 1, 0);
8143 bool verbose
= arg_get_lit(ctx
, 2);
8146 uint8_t pwd
[4] = {0};
8147 CLIGetHexWithReturn(ctx
, 3, pwd
, &pwd_len
);
8151 if (b
> MIFARE_4K_MAXBLOCK
) {
8155 if (pwd_len
!= 4 && pwd_len
!= 0) {
8156 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8160 uint8_t blockno
= (uint8_t)b
;
8161 uint8_t data
[16] = {0};
8163 PrintAndLogEx(NORMAL
, "Block: %x", blockno
) ;
8165 int res
= mfG4GetBlock(pwd
, blockno
, data
, MAGIC_INIT
| MAGIC_OFF
);
8167 PrintAndLogEx(ERR
, "Can't read block. error=%d", res
);
8171 uint8_t sector
= mfSectorNum(blockno
);
8172 mf_print_sector_hdr(sector
);
8173 mf_print_block_one(blockno
, data
, verbose
);
8176 decode_print_st(blockno
, data
);
8178 PrintAndLogEx(NORMAL
, "");
8184 // Load dump to Gen4 GTU card
8185 static int CmdHF14AGen4Load(const char *cmd
) {
8187 CLIParserContext
*ctx
;
8188 CLIParserInit(&ctx
, "hf mf gload",
8189 "Load magic gen4 gtu card with data from (bin/eml/json) dump file\n"
8190 "or from emulator memory.",
8191 "hf mf gload --emu\n"
8192 "hf mf gload -f hf-mf-01020304.eml\n"
8193 "hf mf gload -p AABBCCDD --4k -v -f hf-mf-01020304-dump.bin\n"
8195 "Card must be configured beforehand with `script run hf_mf_ultimatecard`.\n"
8196 "Blocks are 16 bytes long."
8198 void *argtable
[] = {
8200 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8201 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8202 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8203 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8204 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8205 arg_lit0("v", "verbose", "verbose output"),
8206 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
8207 arg_lit0(NULL
, "emu", "from emulator memory"),
8208 arg_int0(NULL
, "start", "<dec>", "index of block to start writing (default 0)"),
8209 arg_int0(NULL
, "end", "<dec>", "index of block to end writing (default last block)"),
8213 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8214 bool m0
= arg_get_lit(ctx
, 1);
8215 bool m1
= arg_get_lit(ctx
, 2);
8216 bool m2
= arg_get_lit(ctx
, 3);
8217 bool m4
= arg_get_lit(ctx
, 4);
8220 uint8_t pwd
[4] = {0};
8221 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8223 bool verbose
= arg_get_lit(ctx
, 6);
8226 char filename
[FILE_PATH_SIZE
] = {0};
8227 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
8229 bool fill_from_emulator
= arg_get_lit(ctx
, 8);
8231 int start
= arg_get_int_def(ctx
, 9, 0);
8232 int end
= arg_get_int_def(ctx
, 10, -1);
8237 if (pwd_len
!= 4 && pwd_len
!= 0) {
8238 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8242 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8243 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8245 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8250 memset(s
, 0, sizeof(s
));
8251 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8253 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8254 strncpy(s
, "Mini", 5);
8256 block_cnt
= MIFARE_1K_MAXBLOCK
;
8257 strncpy(s
, "1K", 3);
8259 block_cnt
= MIFARE_2K_MAXBLOCK
;
8260 strncpy(s
, "2K", 3);
8262 block_cnt
= MIFARE_4K_MAXBLOCK
;
8263 strncpy(s
, "4K", 3);
8265 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8269 if (fill_from_emulator
&& (fnlen
!= 0)) {
8270 PrintAndLogEx(WARNING
, "Please specify file or emulator memory, but not both");
8274 if (!fill_from_emulator
&& (fnlen
== 0)) {
8275 PrintAndLogEx(WARNING
, "Please specify file or emulator memory");
8280 end
= block_cnt
- 1;
8283 if (start
< 0 || end
< 0) {
8284 PrintAndLogEx(WARNING
, "start and end must be positive integers");
8285 return PM3_EINVARG
;
8289 PrintAndLogEx(WARNING
, "start cannot be more than end");
8290 return PM3_EINVARG
;
8293 if (start
>= block_cnt
) {
8294 PrintAndLogEx(WARNING
, "Last block for Mifare %s is %d. Start is too high.", s
, block_cnt
- 1) ;
8295 return PM3_EINVARG
;
8298 if (end
>= block_cnt
) {
8299 PrintAndLogEx(WARNING
, "Last block for Mifare %s is %d. End is too high.", s
, block_cnt
- 1) ;
8300 return PM3_EINVARG
;
8303 uint8_t *data
= NULL
;
8304 size_t bytes_read
= 0;
8306 if (fill_from_emulator
) {
8307 data
= calloc(block_cnt
* MFBLOCK_SIZE
, sizeof(uint8_t));
8309 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8313 PrintAndLogEx(INFO
, "downloading emulator memory");
8314 if (GetFromDevice(BIG_BUF_EML
, data
, block_cnt
* MFBLOCK_SIZE
, 0, NULL
, 0, NULL
, 2500, false) == false) {
8315 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
8317 return PM3_ETIMEOUT
;
8322 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
));
8323 if (res
!= PM3_SUCCESS
) {
8327 // check file size corresponds to card size.
8328 if (bytes_read
!= (block_cnt
* MFBLOCK_SIZE
)) {
8329 PrintAndLogEx(ERR
, "File content error. Read %zu bytes, expected %i", bytes_read
, block_cnt
* MFBLOCK_SIZE
);
8330 if (data
!= NULL
) free(data
);
8337 PrintAndLogEx(INFO
, "File: " _YELLOW_("%s"), filename
);
8338 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
8340 PrintAndLogEx(INFO
, "Read %d blocks from emulator memory", block_cnt
);
8344 PrintAndLogEx(INFO
, "Copying to magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s
);
8345 PrintAndLogEx(INFO
, "Starting block: %d. Ending block: %d.", start
, end
);
8348 for (uint16_t blockno
= start
; blockno
<= end
; blockno
++) {
8350 // 4k writes can be long, so we split status each 64 block boundary.
8351 if (blockno
% 64 == 0 || blockno
== start
) {
8352 PrintAndLogEx(NORMAL
, "");
8353 PrintAndLogEx(INFO
, "" NOLF
) ;
8355 PrintAndLogEx(NORMAL
, "." NOLF
);
8360 if (blockno
== start
) flags
|= MAGIC_INIT
;
8361 if (blockno
== end
) flags
|= MAGIC_OFF
;
8363 int res
= mfG4SetBlock(pwd
, blockno
, data
+ (blockno
* MFBLOCK_SIZE
), flags
);
8364 if (res
!= PM3_SUCCESS
) {
8365 PrintAndLogEx(WARNING
, "Can't set magic card block: %d. error=%d", blockno
, res
);
8366 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8371 PrintAndLogEx(NORMAL
, "\n");
8373 if (data
!= NULL
) free(data
);
8375 PrintAndLogEx(SUCCESS
, "Card loaded " _YELLOW_("%d") " blocks from %s", end
- start
+ 1,
8376 (fill_from_emulator
? "emulator memory" : "file"));
8377 PrintAndLogEx(INFO
, "Done!");
8381 // Write block to Gen4 GTU card
8382 static int CmdHF14AGen4SetBlk(const char *cmd
) {
8383 CLIParserContext
*ctx
;
8384 CLIParserInit(&ctx
, "hf mf gsetblk",
8385 "Set block data on a magic gen4 GTU card",
8386 "hf mf gsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
8388 void *argtable
[] = {
8390 arg_int1("b", "blk", "<dec>", "block number"),
8391 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8392 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8395 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8397 int b
= arg_get_int_def(ctx
, 1, -1);
8399 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
8401 CLIGetHexWithReturn(ctx
, 2, data
, &datalen
);
8404 uint8_t pwd
[4] = {0};
8405 CLIGetHexWithReturn(ctx
, 3, pwd
, &pwd_len
);
8410 if (pwd_len
!= 4 && pwd_len
!= 0) {
8411 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8417 if (b
< 0 || b
>= MIFARE_4K_MAXBLOCK
) {
8418 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
8422 if (datalen
!= MFBLOCK_SIZE
) {
8423 PrintAndLogEx(FAILED
, "expected 16 bytes data, got %i", datalen
);
8428 PrintAndLogEx(INFO
, "Writing block number:%2d data:%s", b
, sprint_hex_inrow(data
, sizeof(data
)));
8430 uint8_t blockno
= (uint8_t)b
;
8431 int res
= mfG4SetBlock(pwd
, blockno
, data
, MAGIC_INIT
| MAGIC_OFF
);
8433 PrintAndLogEx(ERR
, "Can't write block. error=%d", res
);
8440 static int CmdHF14AGen4View(const char *Cmd
) {
8442 CLIParserContext
*ctx
;
8443 CLIParserInit(&ctx
, "hf mf gview",
8444 "View `magic gen4 gtu` card memory",
8448 void *argtable
[] = {
8450 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8451 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8452 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8453 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8454 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8455 arg_lit0("v", "verbose", "verbose output"),
8458 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8459 bool m0
= arg_get_lit(ctx
, 1);
8460 bool m1
= arg_get_lit(ctx
, 2);
8461 bool m2
= arg_get_lit(ctx
, 3);
8462 bool m4
= arg_get_lit(ctx
, 4);
8465 uint8_t pwd
[4] = {0};
8466 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8468 bool verbose
= arg_get_lit(ctx
, 6);
8472 if (pwd_len
!= 4 && pwd_len
!= 0) {
8473 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8477 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8478 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8480 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8485 memset(s
, 0, sizeof(s
));
8486 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8488 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8489 strncpy(s
, "Mini", 5);
8491 block_cnt
= MIFARE_1K_MAXBLOCK
;
8492 strncpy(s
, "1K", 3);
8494 block_cnt
= MIFARE_2K_MAXBLOCK
;
8495 strncpy(s
, "2K", 3);
8497 block_cnt
= MIFARE_4K_MAXBLOCK
;
8498 strncpy(s
, "4K", 3);
8500 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8503 PrintAndLogEx(SUCCESS
, "View magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s
);
8506 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
8507 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
8509 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8513 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
8516 if (i
== 0) flags
|= MAGIC_INIT
;
8517 if (i
+ 1 == block_cnt
) flags
|= MAGIC_OFF
;
8519 int res
= mfG4GetBlock(pwd
, i
, dump
+ (i
* MFBLOCK_SIZE
), flags
);
8520 if (res
!= PM3_SUCCESS
) {
8521 PrintAndLogEx(WARNING
, "Can't get magic card block: %u. error=%d", i
, res
);
8522 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8527 PrintAndLogEx(NORMAL
, "." NOLF
);
8529 // 4k READs can be long, so we split status each 64 blocks.
8531 PrintAndLogEx(NORMAL
, "");
8532 PrintAndLogEx(INFO
, "" NOLF
) ;
8536 PrintAndLogEx(NORMAL
, "");
8537 mf_print_blocks(block_cnt
, dump
, verbose
);
8540 mf_print_keys(block_cnt
, dump
);
8547 // save contents of Gent4 GTU card to file / emulator
8548 static int CmdHF14AGen4Save(const char *Cmd
) {
8550 CLIParserContext
*ctx
;
8551 CLIParserInit(&ctx
, "hf mf gsave",
8552 "Save `magic gen4 gtu` card memory to file (bin/json)"
8553 "or into emulator memory",
8555 "hf mf gsave --4k\n"
8556 "hf mf gsave -p DEADBEEF -f hf-mf-01020304.json"
8558 void *argtable
[] = {
8560 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8561 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8562 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8563 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8564 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8565 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
8566 arg_lit0(NULL
, "emu", "to emulator memory"),
8569 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8570 bool m0
= arg_get_lit(ctx
, 1);
8571 bool m1
= arg_get_lit(ctx
, 2);
8572 bool m2
= arg_get_lit(ctx
, 3);
8573 bool m4
= arg_get_lit(ctx
, 4);
8576 uint8_t pwd
[4] = {0};
8577 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8580 char filename
[FILE_PATH_SIZE
];
8581 CLIParamStrToBuf(arg_get_str(ctx
, 6), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
8583 bool fill_emulator
= arg_get_lit(ctx
, 7);
8586 // ICEMAN: bug. if device has been using ICLASS commands,
8587 // the device needs to load the HF fpga image. It takes 1.5 second.
8588 set_fpga_mode(FPGA_BITSTREAM_HF
);
8591 if (pwd_len
!= 4 && pwd_len
!= 0) {
8592 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8596 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8597 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8599 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8604 memset(s
, 0, sizeof(s
));
8605 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8607 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8608 strncpy(s
, "Mini", 5);
8610 block_cnt
= MIFARE_1K_MAXBLOCK
;
8611 strncpy(s
, "1K", 3);
8613 block_cnt
= MIFARE_2K_MAXBLOCK
;
8614 strncpy(s
, "2K", 3);
8616 block_cnt
= MIFARE_4K_MAXBLOCK
;
8617 strncpy(s
, "4K", 3);
8619 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8623 // Select card to get UID/UIDLEN information
8624 clearCommandBuffer();
8625 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
8626 PacketResponseNG resp
;
8627 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
8628 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
8629 return PM3_ETIMEOUT
;
8636 3: proprietary Anticollision
8638 uint64_t select_status
= resp
.oldarg
[0];
8639 if (select_status
== 0) {
8640 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
8645 iso14a_card_select_t card
;
8646 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
8649 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
8650 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
8652 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8656 PrintAndLogEx(SUCCESS
, "Dumping magic gen4 GTU MIFARE Classic " _GREEN_("%s") " card memory", s
);
8657 PrintAndLogEx(INFO
, "." NOLF
);
8659 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
8662 flags
|= MAGIC_INIT
;
8664 if (i
+ 1 == block_cnt
) {
8668 int res
= mfG4GetBlock(pwd
, i
, dump
+ (i
* MFBLOCK_SIZE
), flags
);
8669 if (res
!= PM3_SUCCESS
) {
8670 PrintAndLogEx(NORMAL
, "");
8671 PrintAndLogEx(WARNING
, "Can't get magic card block: %u. error=%d", i
, res
);
8672 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8678 PrintAndLogEx(NORMAL
, "." NOLF
);
8680 // 4k READs can be long, so we split status each 64 blocks.
8681 if (i
% 64 == 0 && i
!= 0) {
8682 PrintAndLogEx(NORMAL
, "");
8683 PrintAndLogEx(INFO
, "" NOLF
) ;
8687 PrintAndLogEx(NORMAL
, "");
8689 if (fill_emulator
) {
8690 PrintAndLogEx(INFO
, "uploading to emulator memory");
8691 PrintAndLogEx(INFO
, "." NOLF
);
8693 g_conn
.block_after_ACK
= true;
8697 uint16_t bytes_left
= bytes
;
8699 // 12 is the size of the struct the fct mfEmlSetMem_xt uses to transfer to device
8700 uint16_t max_avail_blocks
= ((PM3_CMD_DATA_SIZE
- 12) / MFBLOCK_SIZE
) * MFBLOCK_SIZE
;
8702 while (bytes_left
> 0 && cnt
< block_cnt
) {
8703 if (bytes_left
== MFBLOCK_SIZE
) {
8704 // Disable fast mode on last packet
8705 g_conn
.block_after_ACK
= false;
8708 uint16_t chunk_size
= MIN(max_avail_blocks
, bytes_left
);
8709 uint16_t blocks_to_send
= chunk_size
/ MFBLOCK_SIZE
;
8711 if (mfEmlSetMem_xt(dump
+ offset
, cnt
, blocks_to_send
, MFBLOCK_SIZE
) != PM3_SUCCESS
) {
8712 PrintAndLogEx(FAILED
, "Can't set emulator mem at block: %3d", cnt
);
8717 cnt
+= blocks_to_send
;
8718 offset
+= chunk_size
;
8719 bytes_left
-= chunk_size
;
8720 PrintAndLogEx(NORMAL
, "." NOLF
);
8724 PrintAndLogEx(NORMAL
, "");
8725 PrintAndLogEx(SUCCESS
, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes
);
8728 // user supplied filename?
8730 char *fptr
= filename
;
8731 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
8732 FillFileNameByUID(fptr
, card
.uid
, "-dump", card
.uidlen
);
8735 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
8740 // change Gent4 GTU card access password
8741 static int CmdHF14AGen4ChangePwd(const char *Cmd
) {
8743 CLIParserContext
*ctx
;
8744 CLIParserInit(&ctx
, "hf mf gchpwd",
8745 "Change access password for Gen4 GTU card. WARNING! If you dont KNOW the password - you CAN'T access it!!!",
8746 "hf mf gchpwd --pwd 00000000 --newpwd 01020304"
8748 void *argtable
[] = {
8750 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8751 arg_str0("n", "newpwd", "<hex>", "new password 4 bytes"),
8752 arg_lit0("v", "verbose", "verbose output"),
8755 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8758 uint8_t pwd
[4] = {0};
8759 CLIGetHexWithReturn(ctx
, 1, pwd
, &pwd_len
);
8761 int new_pwd_len
= 0;
8762 uint8_t new_pwd
[4] = {0};
8763 CLIGetHexWithReturn(ctx
, 2, new_pwd
, &new_pwd_len
);
8765 bool verbose
= arg_get_lit(ctx
, 3);
8770 PrintAndLogEx(FAILED
, "Old password must be 4 bytes long, got " _YELLOW_("%u"), pwd_len
);
8774 if (new_pwd_len
!= 4) {
8775 PrintAndLogEx(FAILED
, "New password must be 4 bytes long, got " _YELLOW_("%u"), new_pwd_len
);
8779 int res
= mfG4ChangePassword(pwd
, new_pwd
, verbose
);
8780 if (res
!= PM3_SUCCESS
) {
8781 PrintAndLogEx(ERR
, "Change password error");
8785 PrintAndLogEx(SUCCESS
, "Change password ( " _GREEN_("ok") " )");
8789 static void parse_gdm_cfg(const uint8_t *d
) {
8790 PrintAndLogEx(NORMAL
, "");
8791 PrintAndLogEx(SUCCESS
, "------------------- " _CYAN_("GDM Gen4 Configuration") " -----------------------------------------");
8792 PrintAndLogEx(SUCCESS
, _YELLOW_("%s"), sprint_hex_inrow(d
, MFBLOCK_SIZE
));
8793 PrintAndLogEx(SUCCESS
, _YELLOW_("%02X%02X") "............................ %s %s"
8796 , (d
[0] == 0x85 && d
[1] == 0x00) ? "Magic wakeup disabled" : _GREEN_("Magic wakeup enabled")
8797 , (d
[0] == 0x85 && d
[1] == 0x00) ? "" : ((d
[0] == 0x7A && d
[1] == 0xFF) ? _GREEN_("with GDM cfg block access") : _RED_(", no GDM cfg block access"))
8799 PrintAndLogEx(SUCCESS
, "...." _YELLOW_("%02X") ".......................... Magic wakeup style " _YELLOW_("%s"), d
[2], ((d
[2] == 0x85) ? "GDM 20(7)/23" : "Gen1a 40(7)/43"));
8800 PrintAndLogEx(SUCCESS
, "......" _YELLOW_("%02X%02X%02X") ".................... unknown", d
[3], d
[4], d
[5]);
8801 PrintAndLogEx(SUCCESS
, "............" _YELLOW_("%02X") ".................. %s", d
[6], (d
[6] == 0x5A) ? "Key B use blocked when readable by ACL" : "Key B use allowed when readable by ACL");
8802 PrintAndLogEx(SUCCESS
, ".............." _YELLOW_("%02X") "................ %s", d
[7], (d
[7] == 0x5A) ? _GREEN_("CUID enabled") : "CUID Disabled");
8803 PrintAndLogEx(SUCCESS
, "................" _YELLOW_("%02X") ".............. n/a", d
[8]);
8808 pers
= _YELLOW_("Unfused");
8811 pers
= _CYAN_("UIDFO, double size UID");
8814 pers
= _CYAN_("UIDF1, double size UID, optional usage of selection process shortcut");
8817 pers
= _GREEN_("UIDF2, single size random ID");
8820 pers
= _GREEN_("UIDF3, single size NUID");
8823 pers
= "4B UID from Block 0";
8826 PrintAndLogEx(SUCCESS
, ".................." _YELLOW_("%02X") "............ MFC EV1 perso. " _YELLOW_("%s"), d
[9], pers
);
8827 PrintAndLogEx(SUCCESS
, "...................." _YELLOW_("%02X") ".......... %s", d
[10], (d
[10] == 0x5A) ? _GREEN_("Shadow mode enabled") : "Shadow mode disabled");
8828 PrintAndLogEx(SUCCESS
, "......................" _YELLOW_("%02X") "........ %s", d
[11], (d
[11] == 0x5A) ? _GREEN_("Magic auth enabled") : "Magic auth disabled");
8829 PrintAndLogEx(SUCCESS
, "........................" _YELLOW_("%02X") "...... %s", d
[12], (d
[12] == 0x5A) ? _GREEN_("Static encrypted nonce enabled") : "Static encrypted nonce disabled");
8830 PrintAndLogEx(SUCCESS
, ".........................." _YELLOW_("%02X") ".... %s", d
[13], (d
[13] == 0x5A) ? _GREEN_("MFC EV1 signature enabled") : "MFC EV1 signature disabled");
8831 PrintAndLogEx(SUCCESS
, "............................" _YELLOW_("%02X") ".. n/a", d
[14]);
8832 PrintAndLogEx(SUCCESS
, ".............................." _YELLOW_("%02X") " SAK", d
[15]);
8833 PrintAndLogEx(NORMAL
, "");
8836 static int CmdHF14AGen4_GDM_ParseCfg(const char *Cmd
) {
8837 CLIParserContext
*ctx
;
8838 CLIParserInit(&ctx
, "hf mf gdmparsecfg",
8839 "Parse configuration data on a magic gen4 GDM card",
8840 "hf mf gdmparsecfg -d 850000000000000000005A5A00000008"
8842 void *argtable
[] = {
8844 arg_str1("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8847 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8849 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
8851 CLIGetHexWithReturn(ctx
, 1, block
, &blen
);
8854 if (blen
!= MFBLOCK_SIZE
) {
8855 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
8859 parse_gdm_cfg(block
);
8864 static int CmdHF14AGen4_GDM_Cfg(const char *Cmd
) {
8865 CLIParserContext
*ctx
;
8866 CLIParserInit(&ctx
, "hf mf gdmcfg",
8867 "Get configuration data from magic gen4 GDM card.",
8870 void *argtable
[] = {
8872 arg_str0("k", "key", "<hex>", "key 6 bytes (only for regular wakeup)"),
8873 arg_lit0(NULL
, "gen1a", "use gen1a (40/43) magic wakeup"),
8874 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
8877 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8880 uint8_t key
[6] = {0};
8881 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
8882 bool gen1a
= arg_get_lit(ctx
, 2);
8883 bool gdm
= arg_get_lit(ctx
, 3);
8887 if (keylen
!= 6 && keylen
!= 0) {
8888 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
8893 PrintAndLogEx(FAILED
, "Can only specify a single magic wakeup command");
8897 if ((gen1a
|| gdm
) && keylen
!= 0) {
8898 PrintAndLogEx(FAILED
, "Cannot use a key in combination with a magic wakeup");
8902 mf_readblock_ex_t payload
= {
8903 .read_cmd
= MIFARE_MAGIC_GDM_READ_CFG
,
8906 memcpy(payload
.key
, key
, sizeof(payload
.key
));
8909 payload
.wakeup
= MF_WAKE_GEN1A
;
8910 payload
.auth_cmd
= 0;
8912 payload
.wakeup
= MF_WAKE_GDM_ALT
;
8913 payload
.auth_cmd
= 0;
8915 payload
.wakeup
= MF_WAKE_WUPA
;
8916 payload
.auth_cmd
= MIFARE_MAGIC_GDM_AUTH_KEY
;
8919 clearCommandBuffer();
8920 SendCommandNG(CMD_HF_MIFARE_READBL_EX
, (uint8_t *)&payload
, sizeof(payload
));
8921 PacketResponseNG resp
;
8922 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX
, &resp
, 1500) == false) {
8923 PrintAndLogEx(WARNING
, "command execution time out");
8924 return PM3_ETIMEOUT
;
8927 if (resp
.status
== PM3_SUCCESS
&& resp
.length
== MFBLOCK_SIZE
) {
8928 parse_gdm_cfg(resp
.data
.asBytes
);
8930 PrintAndLogEx(NORMAL
, "");
8936 static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd
) {
8937 CLIParserContext
*ctx
;
8938 CLIParserInit(&ctx
, "hf mf gdmsetcfg",
8939 "Set configuration data on a magic gen4 GDM card",
8940 "hf mf gdmsetcfg -d 850000000000000000005A5A00000008"
8942 void *argtable
[] = {
8944 arg_str1("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8945 arg_str0("k", "key", "<hex>", "key 6 bytes (only for regular wakeup)"),
8946 arg_lit0(NULL
, "gen1a", "use gen1a (40/43) magic wakeup"),
8947 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
8950 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8952 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
8954 CLIGetHexWithReturn(ctx
, 1, block
, &blen
);
8956 uint8_t key
[6] = {0};
8957 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
8958 bool gen1a
= arg_get_lit(ctx
, 3);
8959 bool gdm
= arg_get_lit(ctx
, 4);
8962 if (blen
!= MFBLOCK_SIZE
) {
8963 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
8967 if (keylen
!= 6 && keylen
!= 0) {
8968 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
8973 PrintAndLogEx(FAILED
, "Can only specify a single magic wakeup command");
8977 if ((gen1a
|| gdm
) && keylen
!= 0) {
8978 PrintAndLogEx(FAILED
, "Cannot use a key in combination with a magic wakeup");
8982 mf_writeblock_ex_t payload
= {
8983 .write_cmd
= MIFARE_MAGIC_GDM_WRITE_CFG
,
8986 memcpy(payload
.block_data
, block
, sizeof(payload
.block_data
));
8987 memcpy(payload
.key
, key
, sizeof(payload
.key
));
8990 payload
.wakeup
= MF_WAKE_GEN1A
;
8991 payload
.auth_cmd
= 0;
8993 payload
.wakeup
= MF_WAKE_GDM_ALT
;
8994 payload
.auth_cmd
= 0;
8996 payload
.wakeup
= MF_WAKE_WUPA
;
8997 payload
.auth_cmd
= MIFARE_MAGIC_GDM_AUTH_KEY
;
9000 clearCommandBuffer();
9001 SendCommandNG(CMD_HF_MIFARE_WRITEBL_EX
, (uint8_t *)&payload
, sizeof(payload
));
9002 PacketResponseNG resp
;
9003 if (WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX
, &resp
, 1500) == false) {
9004 PrintAndLogEx(WARNING
, "command execution time out");
9005 return PM3_ETIMEOUT
;
9008 if (resp
.status
== PM3_SUCCESS
) {
9009 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
9010 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf gdmcfg") "` to verify");
9012 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
9017 static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd
) {
9019 CLIParserContext
*ctx
;
9020 CLIParserInit(&ctx
, "hf mf gdmsetblk",
9021 "Set block data on a magic gen4 GDM card\n"
9022 "`--force` param is used to override warnings like bad ACL writes.\n"
9023 " if not specified, it will exit if detected",
9024 "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
9026 void *argtable
[] = {
9028 arg_int1(NULL
, "blk", "<dec>", "block number"),
9029 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
9030 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9031 arg_lit0(NULL
, "force", "override warnings"),
9034 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9036 int b
= arg_get_int_def(ctx
, 1, 1);
9038 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
9040 CLIGetHexWithReturn(ctx
, 2, block
, &blen
);
9043 uint8_t key
[6] = {0};
9044 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
9046 bool force
= arg_get_lit(ctx
, 4);
9049 if (blen
!= MFBLOCK_SIZE
) {
9050 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
9054 if (b
< 0 || b
>= MIFARE_4K_MAXBLOCK
) {
9055 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
9059 if (keylen
!= 6 && keylen
!= 0) {
9060 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
9064 uint8_t blockno
= (uint8_t)b
;
9066 if (mf_analyse_st_block(blockno
, block
, force
) != PM3_SUCCESS
) {
9070 PrintAndLogEx(INFO
, "Writing block no %d, key %s", blockno
, sprint_hex_inrow(key
, sizeof(key
)));
9071 PrintAndLogEx(INFO
, "data: %s", sprint_hex(block
, sizeof(block
)));
9076 uint8_t data
[MFBLOCK_SIZE
]; // data to be written
9079 payload
.blockno
= blockno
;
9080 memcpy(payload
.key
, key
, sizeof(payload
.key
));
9081 memcpy(payload
.data
, block
, sizeof(payload
.data
));
9083 clearCommandBuffer();
9084 SendCommandNG(CMD_HF_MIFARE_G4_GDM_WRBL
, (uint8_t *)&payload
, sizeof(payload
));
9085 PacketResponseNG resp
;
9086 if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_WRBL
, &resp
, 1500) == false) {
9087 PrintAndLogEx(WARNING
, "command execution time out");
9088 return PM3_ETIMEOUT
;
9091 if (resp
.status
== PM3_SUCCESS
) {
9092 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
9093 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf rdbl") "` to verify");
9094 } else if (resp
.status
== PM3_ETEAROFF
) {
9095 PrintAndLogEx(INFO
, "Tear off triggered");
9098 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
9103 static int CmdHF14AMfValue(const char *Cmd
) {
9105 CLIParserContext
*ctx
;
9106 CLIParserInit(&ctx
, "hf mf value",
9107 "MIFARE Classic value data commands\n",
9108 "hf mf value --blk 16 -k FFFFFFFFFFFF --set 1000\n"
9109 "hf mf value --blk 16 -k FFFFFFFFFFFF --inc 10\n"
9110 "hf mf value --blk 16 -k FFFFFFFFFFFF -b --dec 10\n"
9111 "hf mf value --blk 16 -k FFFFFFFFFFFF -b --get\n"
9112 "hf mf value --blk 16 -k FFFFFFFFFFFF --res --transfer 30 --tk FFFFFFFFFFFF --> transfer block 16 value to block 30 (even if block can't be incremented by ACL)\n"
9113 "hf mf value --get -d 87D612007829EDFF87D6120011EE11EE\n"
9115 void *argtable
[] = {
9117 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9118 arg_lit0("a", NULL
, "input key type is key A (def)"),
9119 arg_lit0("b", NULL
, "input key type is key B"),
9120 arg_u64_0(NULL
, "inc", "<dec>", "Increment value by X (0 - 2147483647)"),
9121 arg_u64_0(NULL
, "dec", "<dec>", "Decrement value by X (0 - 2147483647)"),
9122 arg_u64_0(NULL
, "set", "<dec>", "Set value to X (-2147483647 - 2147483647)"),
9123 arg_u64_0(NULL
, "transfer", "<dec>", "Transfer value to other block (after inc/dec/restore)"),
9124 arg_str0(NULL
, "tkey", "<hex>", "transfer key, 6 hex bytes (if transfer is preformed to other sector)"),
9125 arg_lit0(NULL
, "ta", "transfer key type is key A (def)"),
9126 arg_lit0(NULL
, "tb", "transfer key type is key B"),
9127 arg_lit0(NULL
, "get", "Get value from block"),
9128 arg_lit0(NULL
, "res", "Restore (copy value to card buffer, should be used with --transfer)"),
9129 arg_int0(NULL
, "blk", "<dec>", "block number"),
9130 arg_str0("d", "data", "<hex>", "block data to extract values from (16 hex bytes)"),
9133 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9135 uint8_t blockno
= (uint8_t)arg_get_int_def(ctx
, 13, 1);
9137 uint8_t keytype
= MF_KEY_A
;
9138 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9140 PrintAndLogEx(WARNING
, "Choose one single input key type");
9142 } else if (arg_get_lit(ctx
, 3)) {
9146 uint8_t transferkeytype
= MF_KEY_A
;
9147 if (arg_get_lit(ctx
, 9) && arg_get_lit(ctx
, 10)) {
9149 PrintAndLogEx(WARNING
, "Choose one single transfer key type");
9151 } else if (arg_get_lit(ctx
, 10)) {
9152 transferkeytype
= MF_KEY_B
;
9156 uint8_t key
[6] = {0};
9157 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
9159 int transferkeylen
= 0;
9160 uint8_t transferkey
[6] = {0};
9161 CLIGetHexWithReturn(ctx
, 8, transferkey
, &transferkeylen
);
9164 Value /Value Value BLK /BLK BLK /BLK
9165 00000000 FFFFFFFF 00000000 10 EF 10 EF
9166 BLK is used to reference where the backup come from, I suspect it's just the current block for the actual value ?
9167 increment and decrement are an unsigned value
9168 set value is a signed value
9170 We are getting signed and/or bigger values to allow a default to be set meaning users did not supply that option.
9172 int64_t incval
= (int64_t)arg_get_u64_def(ctx
, 4, -1); // Inc by -1 is invalid, so not set.
9173 int64_t decval
= (int64_t)arg_get_u64_def(ctx
, 5, -1); // Dec by -1 is invalid, so not set.
9174 int64_t setval
= (int64_t)arg_get_u64_def(ctx
, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set
9175 int64_t trnval
= (int64_t)arg_get_u64_def(ctx
, 7, -1); // block to transfer to
9176 bool getval
= arg_get_lit(ctx
, 11);
9177 bool resval
= arg_get_lit(ctx
, 12);
9179 uint8_t data
[16] = {0};
9180 CLIGetHexWithReturn(ctx
, 14, data
, &dlen
);
9186 // Action: 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
9187 // iceman: TODO - should be enum
9191 // Need to check we only have 1 of inc/dec/set and get the value from the selected option
9192 int optionsprovided
= 0;
9197 if ((incval
<= 0) || (incval
> 2147483647)) {
9198 PrintAndLogEx(WARNING
, "increment value must be between 1 and 2147483647. Got %lli", incval
);
9201 value
= (uint32_t)incval
;
9207 if ((decval
<= 0) || (decval
> 2147483647)) {
9208 PrintAndLogEx(WARNING
, "decrement value must be between 1 and 2147483647. Got %lli", decval
);
9211 value
= (uint32_t)decval
;
9214 if (setval
!= 0x7FFFFFFFFFFFFFFF) {
9217 if ((setval
< -2147483647) || (setval
> 2147483647)) {
9218 PrintAndLogEx(WARNING
, "set value must be between -2147483647 and 2147483647. Got %lli", setval
);
9221 value
= (uint32_t)setval
;
9226 PrintAndLogEx(WARNING
, "You can't use restore without using transfer");
9238 PrintAndLogEx(WARNING
, "date length must be 16 hex bytes long, got %d", dlen
);
9243 if (optionsprovided
> 1) {
9244 PrintAndLogEx(WARNING
, "must have one and only one of --inc, --dec, --set or --data");
9248 if (trnval
!= -1 && action
> 2) {
9249 PrintAndLogEx(WARNING
, "You can't use transfer without using --inc, --dec or --res");
9253 if (trnval
!= -1 && transferkeylen
== 0 && mfSectorNum(trnval
) != mfSectorNum(blockno
)) {
9254 PrintAndLogEx(WARNING
, "Transfer is preformed to other sector, but no key for new sector provided");
9258 // don't want to write value data and break something
9259 if ((blockno
== 0) ||
9260 (mfIsSectorTrailer(blockno
)) ||
9262 (trnval
!= -1 && mfIsSectorTrailer(trnval
))) {
9263 PrintAndLogEx(WARNING
, "invalid block number, should be a data block");
9269 uint8_t isok
= true;
9270 if (g_session
.pm3_present
== false)
9273 // 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
9276 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
9277 memcpy(block
, (uint8_t *)&value
, 4);
9279 uint8_t cmddata
[34];
9280 memcpy(cmddata
, key
, sizeof(key
));
9281 // Key == 6 data went to 10, so lets offset 9 for inc/dec
9284 PrintAndLogEx(INFO
, "Value incremented by : %d", (int32_t)value
);
9287 PrintAndLogEx(INFO
, "Value decremented by : %d", (int32_t)value
);
9290 // 00 if increment, 01 if decrement, 02 if restore
9291 cmddata
[9] = action
;
9295 // transfer to block
9296 cmddata
[10] = trnval
;
9298 memcpy(cmddata
+ 27, transferkey
, sizeof(transferkey
));
9299 if (mfSectorNum(trnval
) != mfSectorNum(blockno
)) {
9300 cmddata
[33] = 1; // should send nested auth
9302 PrintAndLogEx(INFO
, "Transfer block no %u to block %" PRId64
, blockno
, trnval
);
9306 PrintAndLogEx(INFO
, "Writing block no %u, key %c - %s", blockno
, (keytype
== MF_KEY_B
) ? 'B' : 'A', sprint_hex_inrow(key
, sizeof(key
)));
9309 memcpy(cmddata
+ 11, block
, sizeof(block
));
9311 clearCommandBuffer();
9312 SendCommandMIX(CMD_HF_MIFARE_VALUE
, blockno
, keytype
, transferkeytype
, cmddata
, sizeof(cmddata
));
9314 PacketResponseNG resp
;
9315 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
9316 PrintAndLogEx(FAILED
, "command execution time out");
9317 return PM3_ETIMEOUT
;
9319 isok
= resp
.oldarg
[0] & 0xff;
9320 } else { // set value
9321 // To set a value block (or setup) we can use the normal mifare classic write block
9322 // So build the command options can call CMD_HF_MIFARE_WRITEBL
9323 PrintAndLogEx(INFO
, "set value to : %d", (int32_t)value
);
9325 uint8_t writedata
[26] = {0x00};
9326 int32_t invertvalue
= value
^ 0xFFFFFFFF;
9327 memcpy(writedata
, key
, sizeof(key
));
9328 memcpy(writedata
+ 10, (uint8_t *)&value
, 4);
9329 memcpy(writedata
+ 14, (uint8_t *)&invertvalue
, 4);
9330 memcpy(writedata
+ 18, (uint8_t *)&value
, 4);
9331 writedata
[22] = blockno
;
9332 writedata
[23] = (blockno
^ 0xFF);
9333 writedata
[24] = blockno
;
9334 writedata
[25] = (blockno
^ 0xFF);
9336 clearCommandBuffer();
9337 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, keytype
, 0, writedata
, sizeof(writedata
));
9339 PacketResponseNG resp
;
9340 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
9341 PrintAndLogEx(FAILED
, "command execution time out");
9342 return PM3_ETIMEOUT
;
9345 isok
= resp
.oldarg
[0] & 0xff;
9349 PrintAndLogEx(SUCCESS
, "Update ... : " _GREEN_("success"));
9351 // all ok so set flag to read current value
9353 PrintAndLogEx(FAILED
, "Update ... : " _RED_("failed"));
9357 // If all went well getval will be true, so read the current value and display
9364 // already have data from command line
9367 res
= mfReadBlock(blockno
, keytype
, key
, data
);
9369 if (mfSectorNum(trnval
) != mfSectorNum(blockno
))
9370 res
= mfReadBlock(trnval
, transferkeytype
, transferkey
, data
);
9372 res
= mfReadBlock(trnval
, keytype
, key
, data
);
9376 if (res
== PM3_SUCCESS
) {
9377 if (mfc_value(data
, &readvalue
)) {
9378 PrintAndLogEx(SUCCESS
, "Dec ...... : " _YELLOW_("%" PRIi32
), readvalue
);
9379 PrintAndLogEx(SUCCESS
, "Hex ...... : " _YELLOW_("0x%" PRIX32
), readvalue
);
9381 PrintAndLogEx(FAILED
, "No value block detected");
9384 PrintAndLogEx(FAILED
, "failed to read value block");
9391 static int CmdHFMFHidEncode(const char *Cmd
) {
9392 CLIParserContext
*ctx
;
9393 CLIParserInit(&ctx
, "hf mf encodehid",
9394 "Encode binary wiegand to card\n"
9395 "Use either --bin or --wiegand/--fc/--cn",
9396 "hf mf encodehid --bin 10001111100000001010100011 -> FC 31 CN 337 (H10301)\n"
9397 "hf mf encodehid -w H10301 --fc 31 --cn 337\n"
9400 void *argtable
[] = {
9402 arg_str0(NULL
, "bin", "<bin>", "Binary string i.e 0001001001"),
9403 arg_u64_0(NULL
, "fc", "<dec>", "facility code"),
9404 arg_u64_0(NULL
, "cn", "<dec>", "card number"),
9405 arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
9406 arg_lit0("v", "verbose", "verbose output"),
9409 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9411 uint8_t bin
[121] = {0};
9412 int bin_len
= sizeof(bin
) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
9413 CLIGetStrWithReturn(ctx
, 1, bin
, &bin_len
);
9415 wiegand_card_t card
;
9416 memset(&card
, 0, sizeof(wiegand_card_t
));
9417 card
.FacilityCode
= arg_get_u32_def(ctx
, 2, 0);
9418 card
.CardNumber
= arg_get_u32_def(ctx
, 3, 0);
9420 char format
[16] = {0};
9422 CLIParamStrToBuf(arg_get_str(ctx
, 4), (uint8_t *)format
, sizeof(format
), &format_len
);
9424 bool verbose
= arg_get_lit(ctx
, 5);
9428 if (bin_len
> 120) {
9429 PrintAndLogEx(ERR
, "Binary wiegand string must be less than 120 bits");
9433 if (bin_len
== 0 && card
.FacilityCode
== 0 && card
.CardNumber
== 0) {
9434 PrintAndLogEx(ERR
, "Must provide either --cn/--fc or --bin");
9438 uint8_t blocks
[] = {
9439 0x1B, 0x01, 0x4D, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9440 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9441 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A,
9442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9443 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9445 0x48, 0x49, 0x44, 0x20, 0x49, 0x53, 0x78, 0x77, 0x88, 0xAA, 0x20, 0x47, 0x52, 0x45, 0x41, 0x54,
9449 char mfcbin
[121] = {0};
9451 memcpy(mfcbin
+ 1, bin
, bin_len
);
9454 uint8_t hex
[15] = {0};
9455 binstr_2_bytes(hex
, &hexlen
, mfcbin
);
9457 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 1 + (15 - hexlen
), hex
, hexlen
);
9459 wiegand_message_t packed
;
9460 memset(&packed
, 0, sizeof(wiegand_message_t
));
9462 int format_idx
= HIDFindCardFormat(format
);
9463 if (format_idx
== -1) {
9464 PrintAndLogEx(WARNING
, "Unknown format: " _YELLOW_("%s"), format
);
9468 if (HIDPack(format_idx
, &card
, &packed
, false) == false) {
9469 PrintAndLogEx(WARNING
, "The card data could not be encoded in the selected format.");
9473 // iceman: only for formats w length smaller than 37.
9476 // increase length to allow setting bit just above real data
9479 set_bit_by_position(&packed
, true, 0);
9481 #ifdef HOST_LITTLE_ENDIAN
9482 packed
.Mid
= BSWAP_32(packed
.Mid
);
9483 packed
.Bot
= BSWAP_32(packed
.Bot
);
9486 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 8, &packed
.Mid
, sizeof(packed
.Mid
));
9487 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 12, &packed
.Bot
, sizeof(packed
.Bot
));
9490 uint8_t empty
[MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9492 for (uint8_t i
= 0; i
< (sizeof(blocks
) / MFBLOCK_SIZE
); i
++) {
9495 PrintAndLogEx(INFO
, "Writing %u - %s", (i
+ 1), sprint_hex_inrow(blocks
+ (i
* MFBLOCK_SIZE
), MFBLOCK_SIZE
));
9498 if (mf_write_block(empty
, MF_KEY_A
, (i
+ 1), blocks
+ (i
* MFBLOCK_SIZE
)) == false) {
9499 if (mf_write_block(empty
, MF_KEY_B
, (i
+ 1), blocks
+ (i
* MFBLOCK_SIZE
)) == false) {
9500 PrintAndLogEx(WARNING
, "failed writing block %d using default empty key", (i
+ 1));
9507 PrintAndLogEx(WARNING
, "Make sure card is wiped before running this command");
9509 PrintAndLogEx(NORMAL
, "");
9513 static int CmdHF14AMfInfo(const char *Cmd
) {
9514 CLIParserContext
*ctx
;
9515 CLIParserInit(&ctx
, "hf mf info",
9516 "Information and check vulnerabilities in a MIFARE Classic card\n"
9517 "Some cards in order to extract information you need to specify key\n"
9518 "and/or specific keys in the command line",
9520 "hf mf info -k FFFFFFFFFFFF -n -v\n"
9523 void *argtable
[] = {
9525 arg_int0(NULL
, "blk", "<dec>", "block number"),
9526 arg_lit0("a", NULL
, "input key type is key A (def)"),
9527 arg_lit0("b", NULL
, "input key type is key B"),
9528 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9529 arg_lit0("n", "nack", "do nack test"),
9530 arg_lit0("v", "verbose", "verbose output"),
9533 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
9535 int blockn
= arg_get_int_def(ctx
, 1, 0);
9537 uint8_t keytype
= MF_KEY_A
;
9538 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9540 PrintAndLogEx(WARNING
, "Choose one single input key type");
9542 } else if (arg_get_lit(ctx
, 3)) {
9547 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9548 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
9550 bool do_nack_test
= arg_get_lit(ctx
, 5);
9551 bool verbose
= arg_get_lit(ctx
, 6);
9554 uint8_t dbg_curr
= DBG_NONE
;
9555 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
9559 if (keylen
!= 0 && keylen
!= MIFARE_KEY_SIZE
) {
9560 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9564 clearCommandBuffer();
9565 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
9566 PacketResponseNG resp
;
9567 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
9568 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
9572 iso14a_card_select_t card
;
9573 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
9579 3: proprietary Anticollision
9581 uint64_t select_status
= resp
.oldarg
[0];
9583 if (select_status
== 0) {
9584 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
9585 return select_status
;
9588 if (select_status
== 3) {
9589 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
9592 PrintAndLogEx(SUCCESS
, "ATQA: %02X %02X", card
.atqa
[1], card
.atqa
[0]);
9594 return select_status
;
9597 PrintAndLogEx(NORMAL
, "");
9598 PrintAndLogEx(INFO
, "--- " _CYAN_("ISO14443-a Information") " ---------------------");
9599 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
9600 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
9601 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
9603 if (setDeviceDebugLevel(verbose
? MAX(dbg_curr
, DBG_INFO
) : DBG_NONE
, false) != PM3_SUCCESS
) {
9607 uint8_t signature
[32] = {0};
9608 int res
= read_mfc_ev1_signature(signature
);
9609 if (res
== PM3_SUCCESS
) {
9610 mfc_ev1_print_signature(card
.uid
, card
.uidlen
, signature
, sizeof(signature
));
9613 PrintAndLogEx(NORMAL
, "");
9614 PrintAndLogEx(INFO
, "--- " _CYAN_("Keys Information"));
9616 uint8_t fkey
[MIFARE_KEY_SIZE
] = {0};
9617 uint8_t fKeyType
= 0xff;
9619 uint64_t tmpkey
= 0;
9620 mfc_algo_saflok_one(card
.uid
, 0, MF_KEY_A
, &tmpkey
);
9621 num_to_bytes(tmpkey
, MIFARE_KEY_SIZE
, key
+ MIFARE_KEY_SIZE
);
9624 uint8_t *keyBlock
= NULL
;
9625 uint32_t keycnt
= 0;
9626 res
= mf_load_keys(&keyBlock
, &keycnt
, key
, MIFARE_KEY_SIZE
* 2, NULL
, 0, true);
9627 if (res
!= PM3_SUCCESS
) {
9631 // create/initialize key storage structure
9632 sector_t
*e_sector
= NULL
;
9633 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
9638 uint8_t blockdata
[MFBLOCK_SIZE
] = {0};
9639 res
= mfCheckKeys_fast(sectorsCnt
, true, true, 1, keycnt
, keyBlock
, e_sector
, false, verbose
);
9640 if (res
== PM3_SUCCESS
|| res
== PM3_EPARTIAL
) {
9642 if (e_sector
[0].foundKey
[MF_KEY_A
]) {
9643 PrintAndLogEx(SUCCESS
, "Sector 0 key A... " _GREEN_("%012" PRIX64
), e_sector
[0].Key
[MF_KEY_A
]);
9645 num_to_bytes(e_sector
[0].Key
[MF_KEY_A
], MIFARE_KEY_SIZE
, fkey
);
9646 if (mfReadBlock(0, MF_KEY_A
, key
, blockdata
) == PM3_SUCCESS
) {
9647 fKeyType
= MF_KEY_A
;
9651 if (e_sector
[0].foundKey
[MF_KEY_B
]) {
9652 PrintAndLogEx(SUCCESS
, "Sector 0 key B... " _GREEN_("%012" PRIX64
), e_sector
[0].Key
[MF_KEY_B
]);
9654 if (fKeyType
== 0xFF) {
9655 num_to_bytes(e_sector
[0].Key
[MF_KEY_B
], MIFARE_KEY_SIZE
, fkey
);
9656 if (mfReadBlock(0, MF_KEY_B
, key
, blockdata
) == PM3_SUCCESS
) {
9657 fKeyType
= MF_KEY_B
;
9662 if (e_sector
[1].foundKey
[MF_KEY_A
]) {
9663 PrintAndLogEx(SUCCESS
, "Sector 1 key A... " _GREEN_("%012" PRIX64
), e_sector
[1].Key
[MF_KEY_A
]);
9667 uint8_t k08s
[6] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F};
9668 uint8_t k08
[6] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1};
9669 uint8_t k32
[6] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
9670 if (mfReadBlock(0, 4, k08s
, blockdata
) == PM3_SUCCESS
) {
9671 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s
, sizeof(k08s
)));
9672 fKeyType
= MF_KEY_BD08S
;
9673 } else if (mfReadBlock(0, 4, k08
, blockdata
) == PM3_SUCCESS
) {
9674 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08
, sizeof(k08
)));
9675 fKeyType
= MF_KEY_BD08
;
9676 } else if (mfReadBlock(0, 4, k32
, blockdata
) == PM3_SUCCESS
) {
9677 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32
, sizeof(k32
)));
9678 fKeyType
= MF_KEY_BD32
;
9681 if (fKeyType
!= 0xFF) {
9682 PrintAndLogEx(SUCCESS
, "Block 0.......... %s", sprint_hex_ascii(blockdata
, MFBLOCK_SIZE
));
9685 PrintAndLogEx(NORMAL
, "");
9686 PrintAndLogEx(INFO
, "--- " _CYAN_("Fingerprint"));
9688 if (fKeyType
!= 0xFF) {
9689 // cards with known backdoor
9690 if (card
.sak
!= 0x20 && memcmp(blockdata
+ 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) {
9691 // backdoor might be present, or just a clone reusing Fudan MF data...
9692 PrintAndLogEx(SUCCESS
, "Fudan based card");
9693 } else if (fKeyType
== MF_KEY_BD08S
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9694 && (blockdata
[8] == 0x03 || blockdata
[8] == 0x04) && blockdata
[15] == 0x90) {
9695 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S");
9696 } else if (fKeyType
== MF_KEY_BD08S
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x00\x03\x00\x10", 4) == 0
9697 && blockdata
[15] == 0x90) {
9698 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S-7B");
9699 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9700 && blockdata
[15] == 0x98) {
9701 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S **98");
9702 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9703 && (blockdata
[8] >= 0x01 && blockdata
[8] <= 0x03) && blockdata
[15] == 0x1D) {
9704 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08");
9705 } else if (fKeyType
== MF_KEY_BD32
&& card
.sak
== 0x18 && memcmp(blockdata
+ 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) {
9706 PrintAndLogEx(SUCCESS
, "Fudan FM11RF32");
9707 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x20 && memcmp(blockdata
+ 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) {
9708 PrintAndLogEx(SUCCESS
, "Fudan FM11RF32 (SAK=20)");
9709 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x28 && memcmp(blockdata
+ 5, "\x28\x04\x00\x90\x10\x15\x01\x00\x00\x00\x00", 11) == 0) {
9710 // Note: it also has ATS =
9711 // 10 78 80 90 02 20 90 00 00 00 00 00 + UID + CRC
9712 PrintAndLogEx(SUCCESS
, "Fudan FM1208-10");
9713 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x88 && memcmp(blockdata
+ 5, "\x88\x04\x00\x43", 4) == 0) {
9714 PrintAndLogEx(SUCCESS
, "Infineon SLE66R35");
9715 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x44", 4) == 0) {
9716 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5003");
9717 } else if (fKeyType
== MF_KEY_BD08
&& card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x45", 4) == 0) {
9718 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5004");
9719 } else if (fKeyType
== MF_KEY_BD08
|| fKeyType
== MF_KEY_BD08S
|| fKeyType
== MF_KEY_BD32
) {
9720 PrintAndLogEx(SUCCESS
, _RED_("Unknown card with backdoor, please report details!"));
9723 if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x46", 4) == 0) {
9724 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5005");
9725 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x47", 4) == 0) {
9726 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5006");
9727 } else if (card
.sak
== 0x09 && memcmp(blockdata
+ 5, "\x89\x04\x00\x47", 4) == 0) {
9728 PrintAndLogEx(SUCCESS
, "NXP MF1ICS2006");
9729 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x48", 4) == 0) {
9730 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5007");
9731 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\xc0", 4) == 0) {
9732 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5035");
9734 PrintAndLogEx(SUCCESS
, "unknown");
9737 if (e_sector
[1].foundKey
[MF_KEY_A
] && (e_sector
[1].Key
[MF_KEY_A
] == 0x2A2C13CC242A)) {
9738 PrintAndLogEx(SUCCESS
, "Dorma Kaba SAFLOK detected");
9742 PrintAndLogEx(INFO
, "<n/a>");
9745 PrintAndLogEx(NORMAL
, "");
9746 PrintAndLogEx(INFO
, "--- " _CYAN_("Magic Tag Information"));
9747 if (detect_mf_magic(true, MF_KEY_B
, e_sector
[0].Key
[MF_KEY_B
]) == MAGIC_FLAG_NONE
) {
9748 if (detect_mf_magic(true, MF_KEY_A
, e_sector
[0].Key
[MF_KEY_A
]) == MAGIC_FLAG_NONE
) {
9749 PrintAndLogEx(INFO
, "<n/a>");
9756 PrintAndLogEx(NORMAL
, "");
9757 PrintAndLogEx(INFO
, "--- " _CYAN_("PRNG Information"));
9759 res
= detect_classic_static_nonce();
9760 if (res
== NONCE_STATIC
) {
9761 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes"));
9765 if (res
== NONCE_NORMAL
) {
9767 res
= detect_classic_prng();
9769 PrintAndLogEx(SUCCESS
, "Prng....... " _GREEN_("weak"));
9770 } else if (res
== 0) {
9771 PrintAndLogEx(SUCCESS
, "Prng....... " _YELLOW_("hard"));
9773 PrintAndLogEx(FAILED
, "Prng........ " _RED_("fail"));
9776 // detect static encrypted nonce
9777 if (keylen
== MIFARE_KEY_SIZE
) {
9778 res
= detect_classic_static_encrypted_nonce(blockn
, keytype
, key
);
9779 if (res
== NONCE_STATIC
) {
9780 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes"));
9781 fKeyType
= 0xFF; // dont detect twice
9783 if (res
== NONCE_STATIC_ENC
) {
9784 PrintAndLogEx(SUCCESS
, "Static enc nonce... " _RED_("yes"));
9785 fKeyType
= 0xFF; // dont detect twice
9789 if (fKeyType
!= 0xFF) {
9790 res
= detect_classic_static_encrypted_nonce(0, fKeyType
, fkey
);
9791 if (res
== NONCE_STATIC
) {
9792 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes"));
9795 if (res
== NONCE_STATIC_ENC
) {
9796 PrintAndLogEx(SUCCESS
, "Static enc nonce... " _RED_("yes"));
9801 detect_classic_nackbug(verbose
);
9805 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
9809 PrintAndLogEx(NORMAL
, "");
9813 static int CmdHF14AMfISEN(const char *Cmd
) {
9814 CLIParserContext
*ctx
;
9815 CLIParserInit(&ctx
, "hf mf isen",
9816 "Information about Static Encrypted Nonce properties in a MIFARE Classic card",
9818 "Default behavior:\n"
9819 "auth(blk)-auth(blk2)-auth(blk2)-...\n"
9820 "Default behavior when wrong key2:\n"
9821 "auth(blk)-auth(blk2) auth(blk)-auth(blk2) ...\n"
9824 void *argtable
[] = {
9826 arg_int0(NULL
, "blk", "<dec>", "block number"),
9827 arg_lit0("a", NULL
, "input key type is key A (def)"),
9828 arg_lit0("b", NULL
, "input key type is key B"),
9829 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
9830 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9831 arg_int0(NULL
, "blk2", "<dec>", "nested block number (default=same)"),
9832 arg_lit0(NULL
, "a2", "nested input key type is key A (default=same)"),
9833 arg_lit0(NULL
, "b2", "nested input key type is key B (default=same)"),
9834 arg_int0(NULL
, "c2", "<dec>", "nested input key type is key A + offset"),
9835 arg_str0(NULL
, "key2", "<hex>", "nested key, 6 hex bytes (default=same)"),
9836 arg_int0("n", NULL
, "<dec>", "number of nonces (default=2)"),
9837 arg_lit0(NULL
, "reset", "reset between attempts, even if auth was successful"),
9838 arg_lit0(NULL
, "hardreset", "hard reset (RF off/on) between attempts, even if auth was successful"),
9839 arg_lit0(NULL
, "addread", "auth(blk)-read(blk)-auth(blk2)"),
9840 arg_lit0(NULL
, "addauth", "auth(blk)-auth(blk)-auth(blk2)"),
9841 arg_lit0(NULL
, "incblk2", "auth(blk)-auth(blk2)-auth(blk2+4)-..."),
9842 arg_lit0(NULL
, "corruptnrar", "corrupt {nR}{aR}, but with correct parity"),
9843 arg_lit0(NULL
, "corruptnrarparity", "correct {nR}{aR}, but with corrupted parity"),
9845 arg_rem("FM11RF08S specific options:", "Incompatible with above options, except -k; output in JSON"),
9846 arg_lit0(NULL
, "collect_fm11rf08s", "collect all nT/{nT}/par_err."),
9847 arg_lit0(NULL
, "collect_fm11rf08s_with_data", "collect all nT/{nT}/par_err and data blocks."),
9848 arg_str0("f", "file", "<fn>", "Specify a filename for collected data"),
9851 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
9853 int blockn
= arg_get_int_def(ctx
, 1, 0);
9855 uint8_t keytype
= MF_KEY_A
;
9856 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9858 PrintAndLogEx(WARNING
, "Choose one single input key type");
9860 } else if (arg_get_lit(ctx
, 3)) {
9863 uint8_t prev_keytype
= keytype
;
9864 keytype
= arg_get_int_def(ctx
, 4, keytype
);
9865 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
9867 PrintAndLogEx(WARNING
, "Choose one single input key type");
9872 uint8_t key
[MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9873 CLIGetHexWithReturn(ctx
, 5, key
, &keylen
);
9875 int blockn_nested
= arg_get_int_def(ctx
, 6, blockn
);
9877 uint8_t keytype_nested
= keytype
;
9878 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
9880 PrintAndLogEx(WARNING
, "Choose one single nested input key type");
9882 } else if (arg_get_lit(ctx
, 7)) {
9883 keytype_nested
= MF_KEY_A
;
9884 } else if (arg_get_lit(ctx
, 8)) {
9885 keytype_nested
= MF_KEY_B
;
9887 uint8_t prev_keytype_nested
= keytype_nested
;
9888 keytype_nested
= arg_get_int_def(ctx
, 9, keytype_nested
);
9889 if ((arg_get_lit(ctx
, 7) || arg_get_lit(ctx
, 8)) && (keytype_nested
!= prev_keytype_nested
)) {
9891 PrintAndLogEx(WARNING
, "Choose one single nested input key type");
9895 int keylen_nested
= 0;
9896 uint8_t key_nested
[MIFARE_KEY_SIZE
];
9897 memcpy(key_nested
, key
, MIFARE_KEY_SIZE
);
9898 CLIGetHexWithReturn(ctx
, 10, key_nested
, &keylen_nested
);
9900 int nr_nested
= arg_get_int_def(ctx
, 11, 2);
9902 bool reset
= arg_get_lit(ctx
, 12);
9903 bool hardreset
= arg_get_lit(ctx
, 13);
9904 if (reset
&& hardreset
) {
9906 PrintAndLogEx(WARNING
, "Choose one single type of reset");
9909 bool addread
= arg_get_lit(ctx
, 14);
9910 bool addauth
= arg_get_lit(ctx
, 15);
9911 bool incblk2
= arg_get_lit(ctx
, 16);
9912 bool corruptnrar
= arg_get_lit(ctx
, 17);
9913 bool corruptnrarparity
= arg_get_lit(ctx
, 18);
9914 bool collect_fm11rf08s
= arg_get_lit(ctx
, 21);
9915 bool collect_fm11rf08s_with_data
= arg_get_lit(ctx
, 22);
9916 if (collect_fm11rf08s_with_data
) {
9917 collect_fm11rf08s
= 1;
9920 char filename
[FILE_PATH_SIZE
] = {0};
9921 CLIParamStrToBuf(arg_get_str(ctx
, 23), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
9925 uint8_t dbg_curr
= DBG_NONE
;
9926 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
9930 if (keylen
!= 0 && keylen
!= MIFARE_KEY_SIZE
) {
9931 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9935 if (keylen_nested
!= 0 && keylen_nested
!= MIFARE_KEY_SIZE
) {
9936 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9940 clearCommandBuffer();
9941 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
9942 PacketResponseNG resp
;
9943 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
9944 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
9948 iso14a_card_select_t card
;
9949 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
9955 3: proprietary Anticollision
9957 uint64_t select_status
= resp
.oldarg
[0];
9959 if (select_status
== 0) {
9960 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
9961 return select_status
;
9964 if (select_status
== 3) {
9965 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
9968 if (collect_fm11rf08s
) {
9969 uint32_t flags
= collect_fm11rf08s_with_data
;
9970 SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES
, flags
, 0, 0, key
, sizeof(key
));
9971 if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE
, &resp
, 1000)) {
9972 if (resp
.status
== PM3_ESOFT
) {
9976 uint8_t num_sectors
= MIFARE_1K_MAXSECTOR
+ 1;
9977 iso14a_fm11rf08s_nonces_with_data_t nonces_dump
= {0};
9978 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
9979 // reconstruct full nt
9981 nt
= bytes_to_num(resp
.data
.asBytes
+ ((sec
* 2) * 8), 2);
9982 nt
= nt
<< 16 | prng_successor(nt
, 16);
9983 num_to_bytes(nt
, 4, nonces_dump
.nt
[sec
][0]);
9984 nt
= bytes_to_num(resp
.data
.asBytes
+ (((sec
* 2) + 1) * 8), 2);
9985 nt
= nt
<< 16 | prng_successor(nt
, 16);
9986 num_to_bytes(nt
, 4, nonces_dump
.nt
[sec
][1]);
9988 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
9989 memcpy(nonces_dump
.nt_enc
[sec
][0], resp
.data
.asBytes
+ ((sec
* 2) * 8) + 4, 4);
9990 memcpy(nonces_dump
.nt_enc
[sec
][1], resp
.data
.asBytes
+ (((sec
* 2) + 1) * 8) + 4, 4);
9992 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
9993 nonces_dump
.par_err
[sec
][0] = resp
.data
.asBytes
[((sec
* 2) * 8) + 2];
9994 nonces_dump
.par_err
[sec
][1] = resp
.data
.asBytes
[(((sec
* 2) + 1) * 8) + 2];
9996 if (collect_fm11rf08s_with_data
) {
9997 int bytes
= MIFARE_1K_MAXBLOCK
* MFBLOCK_SIZE
;
9999 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
10000 if (dump
== NULL
) {
10001 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
10002 return PM3_EFAILED
;
10004 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
10005 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
10007 return PM3_ETIMEOUT
;
10009 for (uint8_t blk
= 0; blk
< MIFARE_1K_MAXBLOCK
; blk
++) {
10010 memcpy(nonces_dump
.blocks
[blk
], dump
+ blk
* MFBLOCK_SIZE
, MFBLOCK_SIZE
);
10015 snprintf(filename
, sizeof(filename
), "hf-mf-%s-nonces%s", sprint_hex_inrow(card
.uid
, card
.uidlen
), collect_fm11rf08s_with_data
? "_with_data" : "");
10017 if (pm3_save_fm11rf08s_nonces(filename
, &nonces_dump
, collect_fm11rf08s_with_data
) != PM3_SUCCESS
) {
10018 return PM3_EFAILED
;
10020 return PM3_SUCCESS
;
10023 PrintAndLogEx(NORMAL
, "");
10024 PrintAndLogEx(INFO
, "--- " _CYAN_("ISO14443-a Information") " ---------------------");
10025 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
10026 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
10027 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
10029 // if (setDeviceDebugLevel(DBG_DEBUG, false) != PM3_SUCCESS) {
10030 if (setDeviceDebugLevel(DBG_EXTENDED
, false) != PM3_SUCCESS
) {
10031 return PM3_EFAILED
;
10034 int res
= detect_classic_static_encrypted_nonce_ex(blockn
, keytype
, key
, blockn_nested
, keytype_nested
, key_nested
, nr_nested
, reset
, hardreset
, addread
, addauth
, incblk2
, corruptnrar
, corruptnrarparity
, true);
10035 if (res
== NONCE_STATIC
)
10036 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes"));
10037 if (res
== NONCE_STATIC_ENC
)
10038 PrintAndLogEx(SUCCESS
, "Static enc nonce..... " _RED_("yes"));
10040 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
10041 return PM3_EFAILED
;
10044 PrintAndLogEx(NORMAL
, "");
10045 return PM3_SUCCESS
;
10048 static command_t CommandTable
[] = {
10049 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
10050 {"list", CmdHF14AMfList
, AlwaysAvailable
, "List MIFARE history"},
10051 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("recovery") " -----------------------"},
10052 {"info", CmdHF14AMfInfo
, IfPm3Iso14443a
, "mfc card Info"},
10053 {"isen", CmdHF14AMfISEN
, IfPm3Iso14443a
, "mfc card Info Static Encrypted Nonces"},
10054 {"darkside", CmdHF14AMfDarkside
, IfPm3Iso14443a
, "Darkside attack"},
10055 {"nested", CmdHF14AMfNested
, IfPm3Iso14443a
, "Nested attack"},
10056 {"hardnested", CmdHF14AMfNestedHard
, AlwaysAvailable
, "Nested attack for hardened MIFARE Classic cards"},
10057 {"staticnested", CmdHF14AMfNestedStatic
, IfPm3Iso14443a
, "Nested attack against static nonce MIFARE Classic cards"},
10058 {"brute", CmdHF14AMfSmartBrute
, IfPm3Iso14443a
, "Smart bruteforce to exploit weak key generators"},
10059 {"autopwn", CmdHF14AMfAutoPWN
, IfPm3Iso14443a
, "Automatic key recovery tool for MIFARE Classic"},
10060 // {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
10061 {"nack", CmdHf14AMfNack
, IfPm3Iso14443a
, "Test for MIFARE NACK bug"},
10062 {"chk", CmdHF14AMfChk
, IfPm3Iso14443a
, "Check keys"},
10063 {"fchk", CmdHF14AMfChk_fast
, IfPm3Iso14443a
, "Check keys fast, targets all keys on card"},
10064 {"decrypt", CmdHf14AMfDecryptBytes
, AlwaysAvailable
, "Decrypt Crypto1 data from sniff or trace"},
10065 {"supercard", CmdHf14AMfSuperCard
, IfPm3Iso14443a
, "Extract info from a `super card`"},
10066 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("operations") " -----------------------"},
10067 {"auth4", CmdHF14AMfAuth4
, IfPm3Iso14443a
, "ISO14443-4 AES authentication"},
10068 {"acl", CmdHF14AMfAcl
, AlwaysAvailable
, "Decode and print MIFARE Classic access rights bytes"},
10069 {"dump", CmdHF14AMfDump
, IfPm3Iso14443a
, "Dump MIFARE Classic tag to binary file"},
10070 {"mad", CmdHF14AMfMAD
, AlwaysAvailable
, "Checks and prints MAD"},
10071 {"personalize", CmdHFMFPersonalize
, IfPm3Iso14443a
, "Personalize UID (MIFARE Classic EV1 only)"},
10072 {"rdbl", CmdHF14AMfRdBl
, IfPm3Iso14443a
, "Read MIFARE Classic block"},
10073 {"rdsc", CmdHF14AMfRdSc
, IfPm3Iso14443a
, "Read MIFARE Classic sector"},
10074 {"restore", CmdHF14AMfRestore
, IfPm3Iso14443a
, "Restore MIFARE Classic binary file to tag"},
10075 {"setmod", CmdHf14AMfSetMod
, IfPm3Iso14443a
, "Set MIFARE Classic EV1 load modulation strength"},
10076 {"value", CmdHF14AMfValue
, AlwaysAvailable
, "Value blocks"},
10077 {"view", CmdHF14AMfView
, AlwaysAvailable
, "Display content from tag dump file"},
10078 {"wipe", CmdHF14AMfWipe
, IfPm3Iso14443a
, "Wipe card to zeros and default keys/acc"},
10079 {"wrbl", CmdHF14AMfWrBl
, IfPm3Iso14443a
, "Write MIFARE Classic block"},
10080 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("simulation") " -----------------------"},
10081 {"sim", CmdHF14AMfSim
, IfPm3Iso14443a
, "Simulate MIFARE card"},
10082 {"ecfill", CmdHF14AMfECFill
, IfPm3Iso14443a
, "Fill emulator memory with help of keys from emulator"},
10083 {"eclr", CmdHF14AMfEClear
, IfPm3Iso14443a
, "Clear emulator memory"},
10084 {"egetblk", CmdHF14AMfEGetBlk
, IfPm3Iso14443a
, "Get emulator memory block"},
10085 {"egetsc", CmdHF14AMfEGetSc
, IfPm3Iso14443a
, "Get emulator memory sector"},
10086 {"ekeyprn", CmdHF14AMfEKeyPrn
, IfPm3Iso14443a
, "Print keys from emulator memory"},
10087 {"eload", CmdHF14AMfELoad
, IfPm3Iso14443a
, "Upload file into emulator memory"},
10088 {"esave", CmdHF14AMfESave
, IfPm3Iso14443a
, "Save emulator memory to file"},
10089 {"esetblk", CmdHF14AMfESet
, IfPm3Iso14443a
, "Set emulator memory block"},
10090 {"eview", CmdHF14AMfEView
, IfPm3Iso14443a
, "View emulator memory"},
10091 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("magic gen1") " -----------------------"},
10092 {"cgetblk", CmdHF14AMfCGetBlk
, IfPm3Iso14443a
, "Read block from card"},
10093 {"cgetsc", CmdHF14AMfCGetSc
, IfPm3Iso14443a
, "Read sector from card"},
10094 {"cload", CmdHF14AMfCLoad
, IfPm3Iso14443a
, "Load dump to card"},
10095 {"csave", CmdHF14AMfCSave
, IfPm3Iso14443a
, "Save dump from card into file or emulator"},
10096 {"csetblk", CmdHF14AMfCSetBlk
, IfPm3Iso14443a
, "Write block to card"},
10097 {"csetuid", CmdHF14AMfCSetUID
, IfPm3Iso14443a
, "Set UID on card"},
10098 {"cview", CmdHF14AMfCView
, IfPm3Iso14443a
, "View card"},
10099 {"cwipe", CmdHF14AMfCWipe
, IfPm3Iso14443a
, "Wipe card to default UID/Sectors/Keys"},
10100 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
10101 {"gen3uid", CmdHf14AGen3UID
, IfPm3Iso14443a
, "Set UID without changing manufacturer block"},
10102 {"gen3blk", CmdHf14AGen3Block
, IfPm3Iso14443a
, "Overwrite manufacturer block"},
10103 {"gen3freeze", CmdHf14AGen3Freeze
, IfPm3Iso14443a
, "Perma lock UID changes. irreversible"},
10104 {"-----------", CmdHelp
, IfPm3Iso14443a
, "-------------------- " _CYAN_("magic gen4 GTU") " --------------------------"},
10105 {"ginfo", CmdHF14AGen4Info
, IfPm3Iso14443a
, "Info about configuration of the card"},
10106 {"ggetblk", CmdHF14AGen4GetBlk
, IfPm3Iso14443a
, "Read block from card"},
10107 {"gload", CmdHF14AGen4Load
, IfPm3Iso14443a
, "Load dump to card"},
10108 {"gsave", CmdHF14AGen4Save
, IfPm3Iso14443a
, "Save dump from card into file or emulator"},
10109 {"gsetblk", CmdHF14AGen4SetBlk
, IfPm3Iso14443a
, "Write block to card"},
10110 {"gview", CmdHF14AGen4View
, IfPm3Iso14443a
, "View card"},
10111 {"gchpwd", CmdHF14AGen4ChangePwd
, IfPm3Iso14443a
, "Change card access password. Warning!"},
10112 {"-----------", CmdHelp
, IfPm3Iso14443a
, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
10113 {"gdmcfg", CmdHF14AGen4_GDM_Cfg
, IfPm3Iso14443a
, "Read config block from card"},
10114 {"gdmsetcfg", CmdHF14AGen4_GDM_SetCfg
, IfPm3Iso14443a
, "Write config block to card"},
10115 {"gdmparsecfg", CmdHF14AGen4_GDM_ParseCfg
, AlwaysAvailable
, "Parse config block to card"},
10116 {"gdmsetblk", CmdHF14AGen4_GDM_SetBlk
, IfPm3Iso14443a
, "Write block to card"},
10117 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("ndef") " -----------------------"},
10118 // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
10119 {"ndefformat", CmdHFMFNDEFFormat
, IfPm3Iso14443a
, "Format MIFARE Classic Tag as NFC Tag"},
10120 {"ndefread", CmdHFMFNDEFRead
, IfPm3Iso14443a
, "Read and print NDEF records from card"},
10121 {"ndefwrite", CmdHFMFNDEFWrite
, IfPm3Iso14443a
, "Write NDEF records to card"},
10122 {"encodehid", CmdHFMFHidEncode
, IfPm3Iso14443a
, "Encode a HID Credential / NDEF record to card"},
10123 {NULL
, NULL
, NULL
, NULL
}
10127 static int CmdHelp(const char *Cmd
) {
10128 (void)Cmd
; // Cmd is not used so far
10129 CmdsHelp(CommandTable
);
10130 return PM3_SUCCESS
;
10133 int CmdHFMF(const char *Cmd
) {
10134 clearCommandBuffer();
10135 return CmdsParse(CommandTable
, Cmd
);