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.
48 #include "mifare/mifarehost.h"
50 static int CmdHelp(const char *Cmd
);
53 static int usage_hf14_keybrute(void) {
54 PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery");
55 PrintAndLogEx(NORMAL, "You have a known 4 last bytes of a key recovered with mf_nonce_brute tool.");
56 PrintAndLogEx(NORMAL, "First 2 bytes of key will be bruteforced");
57 PrintAndLogEx(NORMAL, "");
58 PrintAndLogEx(NORMAL, " ---[ This attack is obsolete, try hardnested instead ]---");
59 PrintAndLogEx(NORMAL, "Options:");
60 PrintAndLogEx(NORMAL, " h this help");
61 PrintAndLogEx(NORMAL, " <block number> target block number");
62 PrintAndLogEx(NORMAL, " <A|B> target key type");
63 PrintAndLogEx(NORMAL, " <key> candidate key from mf_nonce_brute tool");
64 PrintAndLogEx(NORMAL, "Examples:");
65 PrintAndLogEx(NORMAL, _YELLOW_(" hf mf keybrute --blk 1 -k 000011223344"));
70 int mfc_ev1_print_signature(uint8_t *uid
, uint8_t uidlen
, uint8_t *signature
, int signature_len
) {
72 // ref: MIFARE Classic EV1 Originality Signature Validation
73 #define PUBLIC_MFCEV1_ECDA_KEYLEN 33
74 const ecdsa_publickey_t nxp_mfc_public_keys
[] = {
75 {"NXP MIFARE Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
76 {"MIFARE Classic / QL88", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
77 {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
78 {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
79 {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
80 {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
81 {"MIKRON Public key", "04F971EDA742A4A80D32DCF6A814A707CC3DC396D35902F72929FDCD698B3468F2"},
82 {"VivoKey Spark1 Public key", "04D64BB732C0D214E7EC580736ACF847284B502C25C0F7F2FA86AACE1DADA4387A"},
83 {"TruST25 (ST) key 01?", "041D92163650161A2548D33881C235D0FB2315C2C31A442F23C87ACF14497C0CBA"},
84 {"TruST25 (ST) key 04?", "04101E188A8B4CDDBC62D5BC3E0E6850F0C2730E744B79765A0E079907FBDB01BC"},
88 bool is_valid
= false;
90 for (i
= 0; i
< ARRAYLEN(nxp_mfc_public_keys
); i
++) {
93 uint8_t key
[PUBLIC_MFCEV1_ECDA_KEYLEN
];
94 param_gethex_to_eol(nxp_mfc_public_keys
[i
].value
, 0, key
, PUBLIC_MFCEV1_ECDA_KEYLEN
, &dl
);
96 int res
= ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1
, key
, uid
, uidlen
, signature
, signature_len
, false);
97 is_valid
= (res
== 0);
102 PrintAndLogEx(INFO
, "");
103 PrintAndLogEx(INFO
, "--- " _CYAN_("Tag Signature"));
104 if (is_valid
== false || i
== ARRAYLEN(nxp_mfc_public_keys
)) {
105 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp128r1");
106 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 32));
107 PrintAndLogEx(SUCCESS
, " Signature verification: " _RED_("failed"));
111 PrintAndLogEx(INFO
, " IC signature public key name: " _GREEN_("%s"), nxp_mfc_public_keys
[i
].desc
);
112 PrintAndLogEx(INFO
, "IC signature public key value: %s", nxp_mfc_public_keys
[i
].value
);
113 PrintAndLogEx(INFO
, " Elliptic curve parameters: NID_secp128r1");
114 PrintAndLogEx(INFO
, " TAG IC Signature: %s", sprint_hex_inrow(signature
, 32));
115 PrintAndLogEx(SUCCESS
, " Signature verification: " _GREEN_("successful"));
119 static int mf_read_uid(uint8_t *uid
, int *uidlen
, int *nxptype
) {
120 clearCommandBuffer();
121 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
122 PacketResponseNG resp
;
123 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
124 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
129 iso14a_card_select_t card
;
130 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
133 uint64_t select_status
= resp
.oldarg
[0];
134 *nxptype
= detect_nxp_card(card
.sak
, ((card
.atqa
[1] << 8) + card
.atqa
[0]), select_status
);
137 memcpy(uid
, card
.uid
, card
.uidlen
* sizeof(uint8_t));
138 *uidlen
= card
.uidlen
;
142 static char *GenerateFilename(const char *prefix
, const char *suffix
) {
143 if (! IfPm3Iso14443a()) {
146 uint8_t uid
[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
148 char *fptr
= calloc(sizeof(char) * (strlen(prefix
) + strlen(suffix
)) + sizeof(uid
) * 2 + 1, sizeof(uint8_t));
150 int res
= mf_read_uid(uid
, &uidlen
, NULL
);
151 if (res
!= PM3_SUCCESS
|| !uidlen
) {
152 PrintAndLogEx(WARNING
, "No tag found.");
157 strcpy(fptr
, prefix
);
158 FillFileNameByUID(fptr
, uid
, suffix
, uidlen
);
162 static int initSectorTable(sector_t
**src
, size_t items
) {
164 (*src
) = calloc(items
, sizeof(sector_t
));
169 for (size_t i
= 0; i
< items
; i
++) {
170 for (uint8_t j
= 0; j
< 2; j
++) {
171 (*src
)[i
].Key
[j
] = 0xffffffffffff;
172 (*src
)[i
].foundKey
[j
] = 0;
178 static void decode_print_st(uint16_t blockno
, uint8_t *data
) {
179 if (mfIsSectorTrailer(blockno
)) {
180 PrintAndLogEx(NORMAL
, "");
181 PrintAndLogEx(INFO
, "-------------------------- " _CYAN_("Sector trailer decoder") " --------------------------");
182 PrintAndLogEx(INFO
, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data
, 6));
183 PrintAndLogEx(INFO
, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data
+ 6, 3));
184 PrintAndLogEx(INFO
, "user / gpb... " _GREEN_("%02x"), data
[9]);
185 PrintAndLogEx(INFO
, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data
+ 10, 6));
186 PrintAndLogEx(INFO
, "");
187 PrintAndLogEx(INFO
, " # | access rights");
188 PrintAndLogEx(INFO
, "----+-----------------------------------------------------------------------");
190 if (mfValidateAccessConditions(&data
[6]) == false) {
191 PrintAndLogEx(WARNING
, _RED_("Invalid Access Conditions"));
195 int bln
= mfFirstBlockOfSector(mfSectorNum(blockno
));
196 int blinc
= (mfNumBlocksPerSector(mfSectorNum(blockno
)) > 4) ? 5 : 1;
197 for (int i
= 0; i
< 4; i
++) {
198 PrintAndLogEx(INFO
, "%3d%c| " _YELLOW_("%s"), bln
, ((blinc
> 1) && (i
< 3) ? '+' : ' '), mfGetAccessConditionsDesc(i
, &data
[6]));
202 uint8_t cond
= mf_get_accesscondition(i
, &data
[6]);
203 if (cond
== 0 || cond
== 1 || cond
== 2) {
204 PrintAndLogEx(INFO
, "");
205 PrintAndLogEx(INFO
, "OBS! Key B is readable, it SHALL NOT be able to authenticate on original MFC");
211 PrintAndLogEx(INFO
, "----------------------------------------------------------------------------");
212 PrintAndLogEx(NORMAL
, "");
216 static uint8_t NumOfSectors(char card
) {
219 return MIFARE_MINI_MAXSECTOR
;
221 return MIFARE_1K_MAXSECTOR
;
223 return MIFARE_2K_MAXSECTOR
;
225 return MIFARE_4K_MAXSECTOR
;
231 static char GetFormatFromSector(uint8_t sectors
) {
233 case MIFARE_MINI_MAXSECTOR
:
235 case MIFARE_1K_MAXSECTOR
:
237 case MIFARE_2K_MAXSECTOR
:
239 case MIFARE_4K_MAXSECTOR
:
246 bool mfc_value(const uint8_t *d
, int32_t *val
) {
248 int32_t a
= (int32_t)MemLeToUint4byte(d
);
249 uint32_t a_inv
= MemLeToUint4byte(d
+ 4);
250 uint32_t b
= MemLeToUint4byte(d
+ 8);
253 (a
== b
) && (a
== ~a_inv
) &&
254 (d
[12] == (~d
[13] & 0xFF)) &&
255 (d
[14] == (~d
[15] & 0xFF))
264 void mf_print_block_one(uint8_t blockno
, uint8_t *d
, bool verbose
) {
267 char ascii
[24] = {0};
268 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
269 PrintAndLogEx(INFO
, "%3d | " _RED_("%s") "| " _RED_("%s"),
271 sprint_hex(d
, MFBLOCK_SIZE
),
274 } else if (mfIsSectorTrailer(blockno
)) {
277 hex_to_buffer((uint8_t *)keya
, d
, MIFARE_KEY_SIZE
, sizeof(keya
) - 1, 0, 1, true);
280 hex_to_buffer((uint8_t *)acl
, d
+ MIFARE_KEY_SIZE
, 3, sizeof(acl
) - 1, 0, 1, true);
283 hex_to_buffer((uint8_t *)keyb
, d
+ 10, MIFARE_KEY_SIZE
, sizeof(keyb
) - 1, 0, 1, true);
285 char ascii
[24] = {0};
286 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
288 PrintAndLogEx(INFO
, "%3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"),
299 if (verbose
&& mfc_value(d
, &value
)) {
300 PrintAndLogEx(INFO
, "%3d | " _CYAN_("%s") " %"PRIi32
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
), value
);
302 PrintAndLogEx(INFO
, "%3d | %s ", blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
));
307 static void mf_print_block(uint8_t blockno
, uint8_t *d
, bool verbose
) {
308 uint8_t sectorno
= mfSectorNum(blockno
);
310 char secstr
[6] = " ";
311 if (mfFirstBlockOfSector(sectorno
) == blockno
) {
312 sprintf(secstr
, " %3d ", sectorno
);
316 char ascii
[24] = {0};
317 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
318 PrintAndLogEx(INFO
, "%s| %3d | " _RED_("%s") "| " _RED_("%s"),
321 sprint_hex(d
, MFBLOCK_SIZE
),
325 } else if (mfIsSectorTrailer(blockno
)) {
328 hex_to_buffer((uint8_t *)keya
, d
, MIFARE_KEY_SIZE
, sizeof(keya
) - 1, 0, 1, true);
331 hex_to_buffer((uint8_t *)acl
, d
+ MIFARE_KEY_SIZE
, 3, sizeof(acl
) - 1, 0, 1, true);
334 hex_to_buffer((uint8_t *)keyb
, d
+ 10, MIFARE_KEY_SIZE
, sizeof(keyb
) - 1, 0, 1, true);
336 char ascii
[24] = {0};
337 ascii_to_buffer((uint8_t *)ascii
, d
, MFBLOCK_SIZE
, sizeof(ascii
) - 1, 1);
339 PrintAndLogEx(INFO
, "%s| %3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"),
350 if (verbose
&& mfc_value(d
, &value
)) {
351 PrintAndLogEx(INFO
, "%s| %3d | " _CYAN_("%s") " %"PRIi32
, secstr
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
), value
);
353 PrintAndLogEx(INFO
, "%s| %3d | %s ", secstr
, blockno
, sprint_hex_ascii(d
, MFBLOCK_SIZE
));
358 static void mf_print_blocks(uint16_t n
, uint8_t *d
, bool verbose
) {
359 PrintAndLogEx(NORMAL
, "");
360 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
361 PrintAndLogEx(INFO
, " sec | blk | data | ascii");
362 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
363 for (uint16_t i
= 0; i
< n
; i
++) {
364 mf_print_block(i
, d
+ (i
* MFBLOCK_SIZE
), verbose
);
366 PrintAndLogEx(INFO
, "-----+-----+-------------------------------------------------+-----------------");
368 PrintAndLogEx(HINT
, _CYAN_("cyan") " = value block with decoded value");
373 PrintAndLogEx(HINT
, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details");
375 PrintAndLogEx(NORMAL
, "");
378 // assumes n is in number of blocks 0..255
379 static int mf_print_keys(uint16_t n
, uint8_t *d
) {
382 case MIFARE_MINI_MAXBLOCK
:
383 sectors
= MIFARE_MINI_MAXSECTOR
;
385 case MIFARE_2K_MAXBLOCK
:
386 sectors
= MIFARE_2K_MAXSECTOR
;
388 case MIFARE_4K_MAXBLOCK
:
389 sectors
= MIFARE_4K_MAXSECTOR
;
391 case MIFARE_1K_MAXBLOCK
:
392 sectors
= MIFARE_1K_MAXSECTOR
;
395 sectors
= MIFARE_1K_MAXSECTOR
;
396 n
= MIFARE_1K_MAXBLOCK
;
400 sector_t
*e_sector
= calloc(sectors
, sizeof(sector_t
));
401 if (e_sector
== NULL
) {
405 for (uint16_t i
= 0; i
< n
; i
++) {
406 if (mfIsSectorTrailer(i
) == false) {
409 // zero based index...
410 uint8_t lookup
= mfSectorNum(i
);
411 uint8_t sec
= MIN(sectors
- 1, lookup
);
412 e_sector
[sec
].foundKey
[0] = 1;
413 e_sector
[sec
].Key
[0] = bytes_to_num(d
+ (i
* MFBLOCK_SIZE
), MIFARE_KEY_SIZE
);
414 e_sector
[sec
].foundKey
[1] = 1;
415 e_sector
[sec
].Key
[1] = bytes_to_num(d
+ (i
* MFBLOCK_SIZE
) + 10, MIFARE_KEY_SIZE
);
417 printKeyTable(sectors
, e_sector
);
422 // MFC dump , extract and save the keys to key file
423 // assumes n is in number of blocks 0..255
424 static int mf_save_keys_from_arr(uint16_t n
, uint8_t *d
) {
427 case MIFARE_MINI_MAXBLOCK
:
428 sectors
= MIFARE_MINI_MAXSECTOR
;
430 case MIFARE_2K_MAXBLOCK
:
431 sectors
= MIFARE_2K_MAXSECTOR
;
433 case MIFARE_4K_MAXBLOCK
:
434 sectors
= MIFARE_4K_MAXSECTOR
;
436 case MIFARE_1K_MAXBLOCK
:
438 sectors
= MIFARE_1K_MAXSECTOR
;
442 uint16_t keysize
= 2 * MIFARE_KEY_SIZE
* sectors
;
444 uint8_t *keys
= calloc(keysize
, sizeof(uint8_t));
450 for (uint16_t i
= 0; i
< n
; i
++) {
451 if (mfIsSectorTrailer(i
)) {
452 // key A offset in ST block
453 memcpy(keys
+ (MIFARE_KEY_SIZE
* sector
), d
+ (i
* MFBLOCK_SIZE
), MIFARE_KEY_SIZE
);
455 // key B offset in ST block
456 memcpy(keys
+ (MIFARE_KEY_SIZE
* sectors
) + (MIFARE_KEY_SIZE
* sector
), d
+ (i
* MFBLOCK_SIZE
) + 10, MIFARE_KEY_SIZE
);
462 char fn
[FILE_PATH_SIZE
] = {0};
463 snprintf(fn
, sizeof(fn
), "hf-mf-%s-key", sprint_hex_inrow(d
, 4));
464 saveFileEx(fn
, ".bin", keys
, keysize
, spDump
);
470 static void mf_print_values(uint16_t n, uint8_t *d) {
472 PrintAndLogEx(NORMAL, "");
473 PrintAndLogEx(INFO, "Looking for value blocks...");
474 PrintAndLogEx(NORMAL, "");
477 for (uint16_t i = 0; i < n; i++) {
479 if (mfc_value(d + (i * MFBLOCK_SIZE), &value)) {
480 PrintAndLogEx(INFO, "%03d | " _YELLOW_("%" PRIi32) " " _YELLOW_("0x%" PRIX32), i, value, value);
486 PrintAndLogEx(INFO, "Found %u value blocks in file", cnt);
487 PrintAndLogEx(NORMAL, "");
492 void mf_print_sector_hdr(uint8_t sector
) {
493 PrintAndLogEx(NORMAL
, "");
494 PrintAndLogEx(INFO
, " # | sector " _GREEN_("%02d") " / " _GREEN_("0x%02X") " | ascii", sector
, sector
);
495 PrintAndLogEx(INFO
, "----+-------------------------------------------------+-----------------");
499 // assumes n is in number of blocks 0..255
500 static void mf_analyse_acl(uint16_t n
, uint8_t *d
) {
502 for (uint16_t b
= 3; b
< n
; b
++) {
503 if (mfIsSectorTrailer(b
) == false) {
507 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
508 memcpy(block
, d
+ (b
* MFBLOCK_SIZE
), MFBLOCK_SIZE
);
510 // ensure access right isn't messed up.
511 if (mfValidateAccessConditions(&block
[6]) == false) {
512 PrintAndLogEx(WARNING
, "Invalid Access Conditions on sector " _YELLOW_("%u"), mfSectorNum(b
));
515 // Warn if ACL is strict read-only
516 uint8_t bar
= mfNumBlocksPerSector(mfSectorNum(b
));
517 for (uint8_t foo
= 0; foo
< bar
; foo
++) {
518 if (mfReadOnlyAccessConditions(foo
, &block
[6])) {
519 PrintAndLogEx(WARNING
, _YELLOW_("s%u / b%u") " - Strict ReadOnly Access Conditions detected", mfSectorNum(b
), b
- bar
+ 1 + foo
);
526 Sector trailer sanity checks.
527 Warn if ACL is strict read-only, or invalid ACL.
529 static int mf_analyse_st_block(uint8_t blockno
, uint8_t *block
, bool force
) {
531 if (mfIsSectorTrailer(blockno
) == false) {
535 PrintAndLogEx(INFO
, "Sector trailer (ST) write detected");
537 // ensure access right isn't messed up.
538 if (mfValidateAccessConditions(&block
[6]) == false) {
539 PrintAndLogEx(WARNING
, "Invalid Access Conditions detected, replacing with default values");
540 memcpy(block
+ 6, "\xFF\x07\x80\x69", 4);
543 bool ro_detected
= false;
544 uint8_t bar
= mfNumBlocksPerSector(mfSectorNum(blockno
));
545 for (uint8_t foo
= 0; foo
< bar
; foo
++) {
546 if (mfReadOnlyAccessConditions(foo
, &block
[6])) {
547 PrintAndLogEx(WARNING
, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", blockno
- bar
+ 1 + foo
);
553 PrintAndLogEx(WARNING
, " --force override, continuing...");
555 PrintAndLogEx(INFO
, "Exiting, please run `" _YELLOW_("hf mf acl -d %s") "` to understand", sprint_hex_inrow(&block
[6], 3));
556 PrintAndLogEx(INFO
, "Use `" _YELLOW_("--force") "` to override and write this data");
560 PrintAndLogEx(SUCCESS
, "ST checks ( " _GREEN_("ok") " )");
566 /* Reads data from tag
567 * @param card: (output) card info
568 * @param carddata: (output) card data
569 * @param numSectors: size of the card
570 * @param keyFileName: filename containing keys or NULL.
572 static int mfc_read_tag(iso14a_card_select_t
*card
, uint8_t *carddata
, uint8_t numSectors
, char *keyfn
) {
574 // Select card to get UID/UIDLEN/ATQA/SAK information
575 clearCommandBuffer();
576 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
577 PacketResponseNG resp
;
578 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
579 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
583 uint64_t select_status
= resp
.oldarg
[0];
584 if (select_status
== 0) {
585 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
590 memcpy(card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
593 if (keyfn
== NULL
|| keyfn
[0] == '\0') {
594 fptr
= GenerateFilename("hf-mf-", "-key.bin");
601 PrintAndLogEx(INFO
, "Using... %s", keyfn
);
603 size_t alen
= 0, blen
= 0;
604 uint8_t *keyA
, *keyB
;
605 if (loadFileBinaryKey(keyfn
, "", (void **)&keyA
, (void **)&keyB
, &alen
, &blen
) != PM3_SUCCESS
) {
610 PrintAndLogEx(INFO
, "Reading sector access bits...");
611 PrintAndLogEx(INFO
, "." NOLF
);
613 uint8_t rights
[40][4] = {0};
615 mf_readblock_t payload
;
617 for (uint8_t sectorNo
= 0; sectorNo
< numSectors
; sectorNo
++) {
618 current_key
= MF_KEY_A
;
619 for (uint8_t tries
= 0; tries
< MIFARE_SECTOR_RETRY
; tries
++) {
620 PrintAndLogEx(NORMAL
, "." NOLF
);
623 if (kbd_enter_pressed()) {
624 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
628 return PM3_EOPABORTED
;
631 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + mfNumBlocksPerSector(sectorNo
) - 1;
632 payload
.keytype
= current_key
;
634 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
636 clearCommandBuffer();
637 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
639 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) {
641 uint8_t *data
= resp
.data
.asBytes
;
642 if (resp
.status
== PM3_SUCCESS
) {
643 rights
[sectorNo
][0] = ((data
[7] & 0x10) >> 2) | ((data
[8] & 0x1) << 1) | ((data
[8] & 0x10) >> 4); // C1C2C3 for data area 0
644 rights
[sectorNo
][1] = ((data
[7] & 0x20) >> 3) | ((data
[8] & 0x2) << 0) | ((data
[8] & 0x20) >> 5); // C1C2C3 for data area 1
645 rights
[sectorNo
][2] = ((data
[7] & 0x40) >> 4) | ((data
[8] & 0x4) >> 1) | ((data
[8] & 0x40) >> 6); // C1C2C3 for data area 2
646 rights
[sectorNo
][3] = ((data
[7] & 0x80) >> 5) | ((data
[8] & 0x8) >> 2) | ((data
[8] & 0x80) >> 7); // C1C2C3 for sector trailer
648 } else if (tries
== (MIFARE_SECTOR_RETRY
/ 2)) { // after half unsuccessful tries, give key B a go
649 PrintAndLogEx(WARNING
, "\nTrying with " _YELLOW_("key B") " instead...");
650 current_key
= MF_KEY_B
;
651 PrintAndLogEx(INFO
, "." NOLF
);
652 } else if (tries
== (MIFARE_SECTOR_RETRY
- 1)) { // on last try set defaults
653 PrintAndLogEx(FAILED
, "\nFailed to read access rights for sector %2d ( fallback to default )", sectorNo
);
654 rights
[sectorNo
][0] = rights
[sectorNo
][1] = rights
[sectorNo
][2] = 0x00;
655 rights
[sectorNo
][3] = 0x01;
658 PrintAndLogEx(FAILED
, "\nTimeout reading access rights for sector... %2d ( fallback to default )", sectorNo
);
659 rights
[sectorNo
][0] = rights
[sectorNo
][1] = rights
[sectorNo
][2] = 0x00;
660 rights
[sectorNo
][3] = 0x01;
665 PrintAndLogEx(NORMAL
, "");
666 PrintAndLogEx(SUCCESS
, "Finished reading sector access bits");
667 PrintAndLogEx(INFO
, "Dumping all blocks from card...");
669 for (uint8_t sectorNo
= 0; sectorNo
< numSectors
; sectorNo
++) {
670 for (uint8_t blockNo
= 0; blockNo
< mfNumBlocksPerSector(sectorNo
); blockNo
++) {
671 bool received
= false;
672 current_key
= MF_KEY_A
;
673 uint8_t data_area
= (sectorNo
< 32) ? blockNo
: blockNo
/ 5;
674 if (rights
[sectorNo
][data_area
] == 0x07) { // no key would work
675 PrintAndLogEx(WARNING
, "Access rights prevent reading sector... " _YELLOW_("%2d") " block... " _YELLOW_("%3d") " ( skip )", sectorNo
, blockNo
);
679 for (uint8_t tries
= 0; tries
< MIFARE_SECTOR_RETRY
; tries
++) {
681 if (mfIsSectorTrailerBasedOnBlocks(sectorNo
, blockNo
)) {
683 // sector trailer. At least the Access Conditions can always be read with key A.
684 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
685 payload
.keytype
= current_key
;
686 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
688 clearCommandBuffer();
689 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
690 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
692 // data block. Check if it can be read with key A or key B
693 if ((rights
[sectorNo
][data_area
] == 0x03) || (rights
[sectorNo
][data_area
] == 0x05)) {
694 // only key B would work
695 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
696 payload
.keytype
= MF_KEY_B
;
697 memcpy(payload
.key
, keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
699 clearCommandBuffer();
700 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
701 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
704 payload
.blockno
= mfFirstBlockOfSector(sectorNo
) + blockNo
;
705 payload
.keytype
= current_key
;
706 memcpy(payload
.key
, (current_key
== MF_KEY_A
) ? keyA
+ (sectorNo
* MIFARE_KEY_SIZE
) : keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
708 clearCommandBuffer();
709 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
710 received
= WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500);
715 if (resp
.status
== PM3_SUCCESS
) {
716 // break the re-try loop
719 if ((current_key
== MF_KEY_A
) && (tries
== (MIFARE_SECTOR_RETRY
/ 2))) {
720 // Half the tries failed with key A. Swap for key B
721 current_key
= MF_KEY_B
;
723 // clear out keyA since it failed.
724 memset(keyA
+ (sectorNo
* MIFARE_KEY_SIZE
), 0x00, MIFARE_KEY_SIZE
);
731 if (resp
.status
== PM3_SUCCESS
) {
733 uint8_t *data
= resp
.data
.asBytes
;
735 if (mfIsSectorTrailerBasedOnBlocks(sectorNo
, blockNo
)) {
736 // sector trailer. Fill in the keys.
737 memcpy(data
, keyA
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
738 memcpy(data
+ 10, keyB
+ (sectorNo
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
741 memcpy(carddata
+ (MFBLOCK_SIZE
* (mfFirstBlockOfSector(sectorNo
) + blockNo
)), data
, MFBLOCK_SIZE
);
742 PrintAndLogEx(INPLACE
, "Sector... " _YELLOW_("%2d") " block..." _YELLOW_("%2d") " ( " _GREEN_("ok") " )", sectorNo
, blockNo
);
744 PrintAndLogEx(FAILED
, "\nSector... %2d Block... %2d ( " _RED_("fail") " )", sectorNo
, blockNo
);
747 PrintAndLogEx(WARNING
, "Timeout reading sector... %2d block... %2d", sectorNo
, blockNo
);
755 PrintAndLogEx(SUCCESS
, "\nSucceeded in dumping all blocks");
759 static int mf_load_keys(uint8_t **pkeyBlock
, uint32_t *pkeycnt
, uint8_t *userkey
, int userkeylen
, const char *filename
, int fnlen
, bool load_default
) {
764 // Handle user supplied key
765 // (it considers *pkeycnt and *pkeyBlock as possibly non-null so logic can be easily reordered)
766 if (userkeylen
>= MIFARE_KEY_SIZE
) {
767 int numKeys
= userkeylen
/ MIFARE_KEY_SIZE
;
768 p
= realloc(*pkeyBlock
, numKeys
* MIFARE_KEY_SIZE
);
770 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
776 memcpy(*pkeyBlock
, userkey
, numKeys
* MIFARE_KEY_SIZE
);
778 for (int i
= 0; i
< numKeys
; i
++) {
779 PrintAndLogEx(DEBUG
, _YELLOW_("%2d") " - %s", i
, sprint_hex(*pkeyBlock
+ i
* MIFARE_KEY_SIZE
, MIFARE_KEY_SIZE
));
782 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%2d") " user keys", numKeys
);
786 // Handle default keys
787 p
= realloc(*pkeyBlock
, (*pkeycnt
+ ARRAYLEN(g_mifare_default_keys
)) * MIFARE_KEY_SIZE
);
789 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
794 // Copy default keys to list
795 for (int i
= 0; i
< ARRAYLEN(g_mifare_default_keys
); i
++) {
796 num_to_bytes(g_mifare_default_keys
[i
], MIFARE_KEY_SIZE
, (uint8_t *)(*pkeyBlock
+ (*pkeycnt
+ i
) * MIFARE_KEY_SIZE
));
797 PrintAndLogEx(DEBUG
, _YELLOW_("%2d") " - %s", *pkeycnt
+ i
, sprint_hex(*pkeyBlock
+ (*pkeycnt
+ i
) * MIFARE_KEY_SIZE
, MIFARE_KEY_SIZE
));
799 *pkeycnt
+= ARRAYLEN(g_mifare_default_keys
);
800 PrintAndLogEx(SUCCESS
, "loaded " _GREEN_("%zu") " hardcoded keys", ARRAYLEN(g_mifare_default_keys
));
803 // Handle user supplied dictionary file
805 uint32_t loaded_numKeys
= 0;
806 uint8_t *keyBlock_tmp
= NULL
;
807 int res
= loadFileDICTIONARY_safe(filename
, (void **) &keyBlock_tmp
, MIFARE_KEY_SIZE
, &loaded_numKeys
);
808 if (res
!= PM3_SUCCESS
|| loaded_numKeys
== 0 || keyBlock_tmp
== NULL
) {
809 PrintAndLogEx(FAILED
, "An error occurred while loading the dictionary!");
814 p
= realloc(*pkeyBlock
, (*pkeycnt
+ loaded_numKeys
) * MIFARE_KEY_SIZE
);
816 PrintAndLogEx(FAILED
, "cannot allocate memory for Keys");
822 memcpy(*pkeyBlock
+ *pkeycnt
* MIFARE_KEY_SIZE
, keyBlock_tmp
, loaded_numKeys
* MIFARE_KEY_SIZE
);
823 *pkeycnt
+= loaded_numKeys
;
830 static int CmdHF14AMfAcl(const char *Cmd
) {
831 CLIParserContext
*ctx
;
832 CLIParserInit(&ctx
, "hf mf acl",
833 "Print decoded MIFARE access rights (ACL), \n"
836 " AB = both key A and B\n"
837 " ACCESS = access bytes inside sector trailer block\n"
838 " Increment, decrement, transfer, restore is for value blocks",
840 "hf mf acl -d FF0780\n");
844 arg_str1("d", "data", "<hex>", "ACL bytes specified as 3 hex bytes"),
847 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
850 uint8_t acl
[3] = {0};
851 CLIGetHexWithReturn(ctx
, 1, acl
, &acllen
);
855 PrintAndLogEx(NORMAL
, "");
857 // look up common default ACL bytes and print a fingerprint line about it.
858 if (memcmp(acl
, "\xFF\x07\x80", 3) == 0) {
859 PrintAndLogEx(INFO
, "ACL... " _GREEN_("%s") " (transport configuration)", sprint_hex(acl
, sizeof(acl
)));
861 if (mfValidateAccessConditions(acl
) == false) {
862 PrintAndLogEx(ERR
, _RED_("Invalid Access Conditions, NEVER write these on a card!"));
864 PrintAndLogEx(NORMAL
, "");
865 PrintAndLogEx(INFO
, " # | Access rights");
866 PrintAndLogEx(INFO
, "----+-----------------------------------------------------------------");
867 for (int i
= 0; i
< 4; i
++) {
868 PrintAndLogEx(INFO
, "%3d | " _YELLOW_("%s"), i
, mfGetAccessConditionsDesc(i
, acl
));
870 PrintAndLogEx(NORMAL
, "");
874 static int CmdHF14AMfDarkside(const char *Cmd
) {
875 CLIParserContext
*ctx
;
876 CLIParserInit(&ctx
, "hf mf darkside",
879 "hf mf darkside --blk 16\n"
880 "hf mf darkside --blk 16 -b\n");
884 arg_int0(NULL
, "blk", "<dec> ", "Target block"),
885 arg_lit0("b", NULL
, "Target key B instead of default key A"),
886 arg_int0("c", NULL
, "<dec>", "Target key type is key A + offset"),
889 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
891 uint8_t blockno
= arg_get_u32_def(ctx
, 1, 0) & 0xFF;
892 uint8_t key_type
= MF_KEY_A
;
894 if (arg_get_lit(ctx
, 2)) {
895 PrintAndLogEx(INFO
, "Targeting key B");
899 uint8_t prev_keytype
= key_type
;
900 key_type
= arg_get_int_def(ctx
, 3, key_type
);
901 if (arg_get_lit(ctx
, 2) && (key_type
!= prev_keytype
)) {
903 PrintAndLogEx(WARNING
, "Choose one single target key type");
906 // mf_dark_side expects the full command byte 0x6x
907 key_type
+= MIFARE_AUTH_KEYA
;
912 uint64_t t1
= msclock();
913 int ret
= mf_dark_side(blockno
, key_type
, &key
);
916 if (ret
!= PM3_SUCCESS
) return ret
;
918 PrintAndLogEx(SUCCESS
, "found valid key: " _GREEN_("%012" PRIx64
), key
);
919 PrintAndLogEx(SUCCESS
, "time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
923 static int CmdHF14AMfWrBl(const char *Cmd
) {
925 CLIParserContext
*ctx
;
926 CLIParserInit(&ctx
, "hf mf wrbl",
927 "Write MIFARE Classic block with 16 hex bytes of data\n"
929 "Sector 0 / Block 0 - Manufacturer block\n"
930 "When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA)\n"
931 "Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. \n"
932 "Look in the magic_cards_notes.md file for help to resolve it.\n"
934 "`--force` param is used to override warnings like bad ACL and BLOCK 0 writes.\n"
935 " if not specified, it will exit if detected",
936 "hf mf wrbl --blk 1 -d 000102030405060708090a0b0c0d0e0f\n"
937 "hf mf wrbl --blk 1 -k A0A1A2A3A4A5 -d 000102030405060708090a0b0c0d0e0f\n"
941 arg_int1(NULL
, "blk", "<dec>", "block number"),
942 arg_lit0("a", NULL
, "input key type is key A (def)"),
943 arg_lit0("b", NULL
, "input key type is key B"),
944 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
945 arg_lit0(NULL
, "force", "override warnings"),
946 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
947 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
950 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
952 int b
= arg_get_int_def(ctx
, 1, 1);
954 uint8_t keytype
= MF_KEY_A
;
955 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
957 PrintAndLogEx(WARNING
, "Choose one single input key type");
959 } else if (arg_get_lit(ctx
, 3)) {
962 uint8_t prev_keytype
= keytype
;
963 keytype
= arg_get_int_def(ctx
, 4, keytype
);
964 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
966 PrintAndLogEx(WARNING
, "Choose one single input key type");
969 bool force
= arg_get_lit(ctx
, 5);
972 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
973 CLIGetHexWithReturn(ctx
, 6, key
, &keylen
);
975 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
977 CLIGetHexWithReturn(ctx
, 7, block
, &blen
);
980 if (keylen
&& keylen
!= 6) {
981 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
985 if (blen
!= MFBLOCK_SIZE
) {
986 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", blen
);
995 if (b
== 0 && force
== false) {
996 PrintAndLogEx(NORMAL
, "");
997 PrintAndLogEx(INFO
, "Targeting Sector 0 / Block 0 - Manufacturer block");
998 PrintAndLogEx(INFO
, "Read the helptext for details before writing to this block");
999 PrintAndLogEx(INFO
, "You must use param `" _YELLOW_("--force") "` to write to this block");
1000 PrintAndLogEx(NORMAL
, "");
1004 uint8_t blockno
= (uint8_t)b
;
1006 if (mf_analyse_st_block(blockno
, block
, force
) != PM3_SUCCESS
) {
1011 PrintAndLogEx(INFO
, "Writing block no %d, key type:%c - %s", blockno
, (keytype
== MF_KEY_B
) ? 'B' : 'A', sprint_hex_inrow(key
, sizeof(key
)));
1013 PrintAndLogEx(INFO
, "Writing block no %d, key type:%02x - %s", blockno
, MIFARE_AUTH_KEYA
+ keytype
, sprint_hex_inrow(key
, sizeof(key
)));
1016 PrintAndLogEx(INFO
, "data: %s", sprint_hex(block
, sizeof(block
)));
1019 memcpy(data
, key
, sizeof(key
));
1020 memcpy(data
+ 10, block
, sizeof(block
));
1021 clearCommandBuffer();
1022 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, keytype
, 0, data
, sizeof(data
));
1024 PacketResponseNG resp
;
1025 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1026 PrintAndLogEx(FAILED
, "command execution time out");
1027 return PM3_ETIMEOUT
;
1030 int status
= resp
.oldarg
[0];
1032 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
1033 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf rdbl") "` to verify");
1034 } else if (status
== PM3_ETEAROFF
) {
1037 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
1038 // suggest the opposite keytype than what was used.
1039 PrintAndLogEx(HINT
, "Maybe access rights? Try specify keytype `" _YELLOW_("hf mf wrbl -%c ...") "` instead", (keytype
== MF_KEY_A
) ? 'b' : 'a');
1044 static int CmdHF14AMfRdBl(const char *Cmd
) {
1045 CLIParserContext
*ctx
;
1046 CLIParserInit(&ctx
, "hf mf rdbl",
1047 "Read MIFARE Classic block",
1048 "hf mf rdbl --blk 0\n"
1049 "hf mf rdbl --blk 0 -k A0A1A2A3A4A5\n"
1050 "hf mf rdbl --blk 3 -v -> get block 3, decode sector trailer\n"
1052 void *argtable
[] = {
1054 arg_int1(NULL
, "blk", "<dec>", "block number"),
1055 arg_lit0("a", NULL
, "input key type is key A (def)"),
1056 arg_lit0("b", NULL
, "input key type is key B"),
1057 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1058 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
1059 arg_lit0("v", "verbose", "verbose output"),
1062 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1063 int b
= arg_get_int_def(ctx
, 1, 0);
1065 uint8_t keytype
= MF_KEY_A
;
1066 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
1068 PrintAndLogEx(WARNING
, "Choose one single input key type");
1070 } else if (arg_get_lit(ctx
, 3)) {
1073 keytype
= arg_get_int_def(ctx
, 4, keytype
);
1074 uint8_t prev_keytype
= keytype
;
1075 keytype
= arg_get_int_def(ctx
, 4, keytype
);
1076 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
1078 PrintAndLogEx(WARNING
, "Choose one single input key type");
1083 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1084 CLIGetHexWithReturn(ctx
, 5, key
, &keylen
);
1085 bool verbose
= arg_get_lit(ctx
, 6);
1088 if (keylen
&& keylen
!= 6) {
1089 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
1096 uint8_t blockno
= (uint8_t)b
;
1098 uint8_t data
[16] = {0};
1099 int res
= mf_read_block(blockno
, keytype
, key
, data
);
1100 if (res
== PM3_SUCCESS
) {
1102 uint8_t sector
= mfSectorNum(blockno
);
1103 mf_print_sector_hdr(sector
);
1104 mf_print_block_one(blockno
, data
, verbose
);
1106 decode_print_st(blockno
, data
);
1109 PrintAndLogEx(NORMAL
, "");
1113 static int CmdHF14AMfRdSc(const char *Cmd
) {
1115 CLIParserContext
*ctx
;
1116 CLIParserInit(&ctx
, "hf mf rdsc",
1117 "Read MIFARE Classic sector",
1119 "hf mf rdsc -s 0 -k A0A1A2A3A4A5\n"
1121 void *argtable
[] = {
1123 arg_lit0("a", NULL
, "input key specified is A key (def)"),
1124 arg_lit0("b", NULL
, "input key specified is B key"),
1125 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1126 arg_str0("k", "key", "<hex>", "key specified as 6 hex bytes"),
1127 arg_int1("s", "sec", "<dec>", "sector number"),
1128 arg_lit0("v", "verbose", "verbose output"),
1131 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1132 uint8_t keytype
= MF_KEY_A
;
1133 if (arg_get_lit(ctx
, 1) && arg_get_lit(ctx
, 2)) {
1135 PrintAndLogEx(WARNING
, "Choose one single input key type");
1137 } else if (arg_get_lit(ctx
, 2)) {
1140 uint8_t prev_keytype
= keytype
;
1141 keytype
= arg_get_int_def(ctx
, 3, keytype
);
1142 if ((arg_get_lit(ctx
, 1) || arg_get_lit(ctx
, 2)) && (keytype
!= prev_keytype
)) {
1144 PrintAndLogEx(WARNING
, "Choose one single input key type");
1149 uint8_t key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1150 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
1152 int s
= arg_get_int_def(ctx
, 5, 0);
1153 bool verbose
= arg_get_lit(ctx
, 6);
1156 if (keylen
&& keylen
!= 6) {
1157 PrintAndLogEx(WARNING
, "Key must be 12 hex digits. Got %d", keylen
);
1161 if (s
>= MIFARE_4K_MAXSECTOR
) {
1162 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
1166 uint8_t sector
= (uint8_t)s
;
1167 uint16_t sc_size
= mfNumBlocksPerSector(sector
) * MFBLOCK_SIZE
;
1169 uint8_t *data
= calloc(sc_size
, sizeof(uint8_t));
1171 PrintAndLogEx(ERR
, "failed to allocate memory");
1175 int res
= mf_read_sector(sector
, keytype
, key
, data
);
1176 if (res
== PM3_SUCCESS
) {
1178 uint8_t blocks
= mfNumBlocksPerSector(sector
);
1179 uint8_t start
= mfFirstBlockOfSector(sector
);
1181 mf_print_sector_hdr(sector
);
1182 for (int i
= 0; i
< blocks
; i
++) {
1183 mf_print_block_one(start
+ i
, data
+ (i
* MFBLOCK_SIZE
), verbose
);
1187 decode_print_st(start
+ blocks
- 1, data
+ ((blocks
- 1) * MFBLOCK_SIZE
));
1191 PrintAndLogEx(NORMAL
, "");
1195 static int FastDumpWithEcFill(uint8_t numsectors
) {
1197 uint8_t dbg_curr
= DBG_NONE
;
1198 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
1203 if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) {
1208 mfc_eload_t payload
;
1209 payload
.sectorcnt
= numsectors
;
1210 payload
.keytype
= MF_KEY_A
;
1213 clearCommandBuffer();
1214 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
1216 PacketResponseNG resp
;
1217 bool res
= WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 2500);
1219 PrintAndLogEx(WARNING
, "command execution time out");
1220 return PM3_ETIMEOUT
;
1223 if (resp
.status
!= PM3_SUCCESS
) {
1224 PrintAndLogEx(FAILED
, "fast dump reported back failure w KEY A, swapping to KEY B");
1227 payload
.keytype
= MF_KEY_B
;
1229 clearCommandBuffer();
1230 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
1231 res
= WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 2500);
1233 PrintAndLogEx(WARNING
, "command execution time out");
1234 setDeviceDebugLevel(dbg_curr
, false);
1235 return PM3_ETIMEOUT
;
1238 if (resp
.status
!= PM3_SUCCESS
) {
1239 PrintAndLogEx(FAILED
, "fast dump reported back failure w KEY B");
1240 PrintAndLogEx(FAILED
, "Dump file is " _RED_("PARTIAL") " complete");
1244 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
1251 static int CmdHF14AMfDump(const char *Cmd
) {
1252 CLIParserContext
*ctx
;
1253 CLIParserInit(&ctx
, "hf mf dump",
1254 "Dump MIFARE Classic tag to file (bin/json)\n"
1255 "If no <name> given, UID will be used as filename",
1256 "hf mf dump --mini --> MIFARE Mini\n"
1257 "hf mf dump --1k --> MIFARE Classic 1k\n"
1258 "hf mf dump --2k --> MIFARE 2k\n"
1259 "hf mf dump --4k --> MIFARE 4k\n"
1260 "hf mf dump --keys hf-mf-066C8B78-key.bin --> MIFARE 1k with keys from specified file\n");
1262 void *argtable
[] = {
1264 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
1265 arg_str0("k", "keys", "<fn>", "filename of keys"),
1266 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1267 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
1268 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1269 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1270 arg_lit0(NULL
, "ns", "no save to file"),
1271 arg_lit0("v", "verbose", "verbose output"),
1274 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1277 char dataFilename
[FILE_PATH_SIZE
] = {0};
1278 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)dataFilename
, FILE_PATH_SIZE
, &datafnlen
);
1281 char keyFilename
[FILE_PATH_SIZE
] = {0};
1282 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
1284 bool m0
= arg_get_lit(ctx
, 3);
1285 bool m1
= arg_get_lit(ctx
, 4);
1286 bool m2
= arg_get_lit(ctx
, 5);
1287 bool m4
= arg_get_lit(ctx
, 6);
1288 bool nosave
= arg_get_lit(ctx
, 7);
1289 bool verbose
= arg_get_lit(ctx
, 8);
1292 uint64_t t1
= msclock();
1295 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1296 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1298 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
1302 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
1303 uint16_t bytes
= MIFARE_1K_MAX_BYTES
;
1304 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
1307 numSectors
= MIFARE_MINI_MAXSECTOR
;
1308 bytes
= MIFARE_MINI_MAX_BYTES
;
1309 block_cnt
= MIFARE_MINI_MAXBLOCK
;
1311 numSectors
= MIFARE_1K_MAXSECTOR
;
1312 bytes
= MIFARE_1K_MAX_BYTES
;
1313 block_cnt
= MIFARE_1K_MAXBLOCK
;
1315 numSectors
= MIFARE_2K_MAXSECTOR
;
1316 bytes
= MIFARE_2K_MAX_BYTES
;
1317 block_cnt
= MIFARE_2K_MAXBLOCK
;
1319 numSectors
= MIFARE_4K_MAXSECTOR
;
1320 bytes
= MIFARE_4K_MAX_BYTES
;
1321 block_cnt
= MIFARE_4K_MAXBLOCK
;
1323 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1328 iso14a_card_select_t card
;
1329 uint8_t *mem
= calloc(MIFARE_4K_MAX_BYTES
, sizeof(uint8_t));
1331 PrintAndLogEx(ERR
, "failed to allocate memory");
1334 int res
= mfc_read_tag(&card
, mem
, numSectors
, keyFilename
);
1335 if (res
!= PM3_SUCCESS
) {
1340 PrintAndLogEx(SUCCESS
, "time: %" PRIu64
" seconds\n", (msclock() - t1
) / 1000);
1342 mf_print_blocks(block_cnt
, mem
, verbose
);
1345 mf_print_keys(block_cnt
, mem
);
1346 mf_analyse_acl(block_cnt
, mem
);
1349 // Skip saving card data to file
1351 PrintAndLogEx(INFO
, "Called with no save option");
1357 if (strlen(dataFilename
) < 1) {
1358 char *fptr
= GenerateFilename("hf-mf-", "-dump");
1364 strcpy(dataFilename
, fptr
);
1368 pm3_save_mf_dump(dataFilename
, mem
, bytes
, jsfCardMemory
);
1373 static int CmdHF14AMfRestore(const char *Cmd
) {
1375 CLIParserContext
*ctx
;
1376 CLIParserInit(&ctx
, "hf mf restore",
1377 "Restore MIFARE Classic dump file to tag.\n"
1379 "The key file and dump file will program the card sector trailers.\n"
1380 "By default we authenticate to card with key 0xFFFFFFFFFFFF.\n"
1381 "If access rights in dump file is all zeros, it will be replaced with default values\n"
1383 "`--uid` param is used for filename templates `hf-mf-<uid>-dump.bin` and `hf-mf-<uid>-key.bin.\n"
1384 " if not specified, it will read the card uid instead.\n"
1385 " `--ka` param you can indicate that the key file should be used for authentication instead.\n"
1386 " if so we also try both B/A keys\n"
1387 "`--force` param is used to override warnings and allow bad ACL block writes.\n"
1388 " if not specified, it will skip blocks with bad ACL.\n",
1390 "hf mf restore --1k --uid 04010203\n"
1391 "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin\n"
1392 "hf mf restore --4k"
1395 void *argtable
[] = {
1397 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1398 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
1399 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1400 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1401 arg_str0("u", "uid", "<hex>", "uid, (4|7|10 hex bytes)"),
1402 arg_str0("f", "file", "<fn>", "specify a filename for dump file"),
1403 arg_str0("k", "kfn", "<fn>", "key filename"),
1404 arg_lit0(NULL
, "ka", "use specified keyfile to authenticate"),
1405 arg_lit0(NULL
, "force", "override warnings"),
1408 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1410 bool m0
= arg_get_lit(ctx
, 1);
1411 bool m1
= arg_get_lit(ctx
, 2);
1412 bool m2
= arg_get_lit(ctx
, 3);
1413 bool m4
= arg_get_lit(ctx
, 4);
1417 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
1420 char datafilename
[FILE_PATH_SIZE
] = {0};
1421 CLIParamStrToBuf(arg_get_str(ctx
, 6), (uint8_t *)datafilename
, FILE_PATH_SIZE
, &datafnlen
);
1424 char keyfilename
[FILE_PATH_SIZE
] = {0};
1425 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)keyfilename
, FILE_PATH_SIZE
, &keyfnlen
);
1427 bool use_keyfile_for_auth
= arg_get_lit(ctx
, 8);
1428 bool force
= arg_get_lit(ctx
, 9);
1433 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1434 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1436 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
1440 uint8_t sectors
= MIFARE_1K_MAXSECTOR
;
1443 sectors
= MIFARE_MINI_MAXSECTOR
;
1445 sectors
= MIFARE_1K_MAXSECTOR
;
1447 sectors
= MIFARE_2K_MAXSECTOR
;
1449 sectors
= MIFARE_4K_MAXSECTOR
;
1451 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
1455 // if user specified UID, use it in file templates
1458 if (keyfnlen
== 0) {
1459 snprintf(keyfilename
, FILE_PATH_SIZE
, "hf-mf-%s-key.bin", uid
);
1460 keyfnlen
= strlen(keyfilename
);
1463 if (datafnlen
== 0) {
1464 snprintf(datafilename
, FILE_PATH_SIZE
, "hf-mf-%s-dump.bin", uid
);
1465 datafnlen
= strlen(datafilename
);
1469 // try reading card uid and create filename
1470 if (keyfnlen
== 0) {
1471 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
1475 strncpy(keyfilename
, fptr
, sizeof(keyfilename
) - 1);
1480 size_t alen
= 0, blen
= 0;
1481 uint8_t *keyA
, *keyB
;
1482 if (loadFileBinaryKey(keyfilename
, "", (void **)&keyA
, (void **)&keyB
, &alen
, &blen
) != PM3_SUCCESS
) {
1486 PrintAndLogEx(INFO
, "Using key file `" _YELLOW_("%s") "`", keyfilename
);
1488 // try reading card uid and create filename
1489 if (datafnlen
== 0) {
1490 char *fptr
= GenerateFilename("hf-mf-", "-dump.bin");
1500 strcpy(datafilename
, fptr
);
1505 uint8_t *dump
= NULL
;
1506 size_t bytes_read
= 0;
1507 int res
= pm3_load_dump(datafilename
, (void **)&dump
, &bytes_read
, (MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
));
1508 if (res
!= PM3_SUCCESS
) {
1514 // default authentication key
1515 uint8_t default_key
[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1517 PrintAndLogEx(NORMAL
, "");
1518 PrintAndLogEx(INFO
, " blk | data | status");
1519 PrintAndLogEx(INFO
, "-----+-------------------------------------------------+----------------");
1521 // main loop for restoring.
1522 // a bit more complicated than needed
1523 // this is because of two things.
1524 // 1. we are setting keys from a key file or using the existing ones in the dump
1525 // 2. we need to authenticate against a card which might not have default keys.
1526 uint8_t *ref_dump
= dump
;
1527 for (uint8_t s
= 0; s
< sectors
; s
++) {
1528 for (uint8_t b
= 0; b
< mfNumBlocksPerSector(s
); b
++) {
1530 uint8_t bldata
[MFBLOCK_SIZE
] = {0x00};
1531 memcpy(bldata
, dump
, MFBLOCK_SIZE
);
1534 // if sector trailer
1535 if (mfIsSectorTrailerBasedOnBlocks(s
, b
)) {
1536 // keep the current keys on the card
1537 if (use_keyfile_for_auth
== false) {
1539 memcpy(bldata
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1542 memcpy(bldata
+ 10, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1545 // ensure access right isn't messed up.
1546 if (mfValidateAccessConditions(&bldata
[6]) == false) {
1547 PrintAndLogEx(WARNING
, "Invalid Access Conditions on sector %i, replacing with default values", s
);
1548 memcpy(bldata
+ 6, "\xFF\x07\x80\x69", 4);
1551 // Warn if ACL is strict read-only
1552 for (uint8_t foo
= 0; foo
< mfNumBlocksPerSector(s
); foo
++) {
1553 if (mfReadOnlyAccessConditions(foo
, &bldata
[6])) {
1554 PrintAndLogEx(WARNING
, "Strict ReadOnly Access Conditions on block " _YELLOW_("%u") " detected", foo
);
1556 // if --force isn't used, skip writing this block
1557 if (force
== false) {
1558 PrintAndLogEx(INFO
, "Skipping, use `" _YELLOW_("--force") "` to override and write this data");
1566 dump
+= MFBLOCK_SIZE
;
1567 bytes_read
-= MFBLOCK_SIZE
;
1574 memcpy(wdata
+ 10, bldata
, sizeof(bldata
));
1576 for (int8_t kt
= MF_KEY_B
; kt
> -1; kt
--) {
1577 if (use_keyfile_for_auth
) {
1579 if (kt
== MF_KEY_A
) {
1580 memcpy(wdata
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1582 memcpy(wdata
, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
1586 // use default key to authenticate for the write command
1587 memcpy(wdata
, default_key
, MIFARE_KEY_SIZE
);
1590 uint16_t blockno
= (mfFirstBlockOfSector(s
) + b
);
1592 clearCommandBuffer();
1593 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, kt
, 0, wdata
, sizeof(wdata
));
1594 PacketResponseNG resp
;
1595 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
1596 PrintAndLogEx(WARNING
, "command execution time out");
1600 int isOK
= resp
.oldarg
[0] & 0xff;
1602 // if success, skip to next block
1603 PrintAndLogEx(INFO
, " %3d | %s| ( " _GREEN_("ok") " )", blockno
, sprint_hex(bldata
, sizeof(bldata
)));
1606 // write somehow failed. Lets determine why.
1607 if (isOK
== PM3_ETEAROFF
) {
1608 PrintAndLogEx(INFO
, "Tear off triggered. Recommendation is not to use tear-off with restore command");
1612 PrintAndLogEx(INFO
, " %3d | %s| ( " _RED_("fail") " ) key " _YELLOW_("%c"),
1614 sprint_hex(bldata
, sizeof(bldata
)),
1615 (kt
== MF_KEY_A
) ? 'A' : 'B'
1617 } // end loop key types
1625 PrintAndLogEx(INFO
, "-----+-------------------------------------------------+----------------");
1626 PrintAndLogEx(NORMAL
, "");
1627 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf dump --ns") "` to verify");
1628 PrintAndLogEx(INFO
, "Done!");
1632 static int CmdHF14AMfNested(const char *Cmd
) { //TODO: single mode broken? can't find keys...
1633 CLIParserContext
*ctx
;
1634 CLIParserInit(&ctx
, "hf mf nested",
1635 "Execute Nested attack against MIFARE Classic card for key recovery",
1636 "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"
1637 "hf mf nested --mini --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
1638 "hf mf nested --1k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
1639 "hf mf nested --2k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
1640 "hf mf nested --4k --blk 0 -a -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k");
1642 void *argtable
[] = {
1644 arg_str0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
1645 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
1646 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
1647 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
1648 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
1649 arg_int0(NULL
, "blk", "<dec>", "Input block number"),
1650 arg_lit0("a", NULL
, "Input key specified is A key (default)"),
1651 arg_lit0("b", NULL
, "Input key specified is B key"),
1652 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
1653 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
1654 arg_lit0(NULL
, "ta", "Target A key (default)"),
1655 arg_lit0(NULL
, "tb", "Target B key"),
1656 arg_int0(NULL
, "tc", "<dec>", "Nested input key type is key A + offset (you must specify a single block as well!)"),
1657 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
1658 arg_lit0(NULL
, "dump", "Dump found keys to file"),
1659 arg_lit0(NULL
, "mem", "Use dictionary from flashmemory"),
1660 arg_lit0("i", NULL
, "Ignore static encrypted nonces"),
1663 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1666 uint8_t key
[6] = {0};
1667 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
1669 bool m0
= arg_get_lit(ctx
, 2);
1670 bool m1
= arg_get_lit(ctx
, 3);
1671 bool m2
= arg_get_lit(ctx
, 4);
1672 bool m4
= arg_get_lit(ctx
, 5);
1674 uint8_t blockNo
= arg_get_u32_def(ctx
, 6, 0);
1676 uint8_t keyType
= MF_KEY_A
;
1678 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
1680 PrintAndLogEx(WARNING
, "Choose one single input key type");
1682 } else if (arg_get_lit(ctx
, 8)) {
1685 uint8_t prev_keytype
= keyType
;
1686 keyType
= arg_get_int_def(ctx
, 9, keyType
);
1687 if ((arg_get_lit(ctx
, 7) || arg_get_lit(ctx
, 8)) && (keyType
!= prev_keytype
)) {
1689 PrintAndLogEx(WARNING
, "Choose one single input key type");
1693 int trgBlockNo
= arg_get_int_def(ctx
, 10, -1);
1695 uint8_t trgKeyType
= MF_KEY_A
;
1697 if (arg_get_lit(ctx
, 11) && arg_get_lit(ctx
, 12)) {
1699 PrintAndLogEx(WARNING
, "Choose one single target key type");
1701 } else if (arg_get_lit(ctx
, 12)) {
1702 trgKeyType
= MF_KEY_B
;
1704 uint8_t prev_trgkeytype
= trgKeyType
;
1705 trgKeyType
= arg_get_int_def(ctx
, 13, trgKeyType
);
1706 if ((arg_get_lit(ctx
, 11) || arg_get_lit(ctx
, 12)) && (trgKeyType
!= prev_trgkeytype
)) {
1708 PrintAndLogEx(WARNING
, "Choose one single target key type");
1711 bool transferToEml
= arg_get_lit(ctx
, 14);
1712 bool createDumpFile
= arg_get_lit(ctx
, 15);
1713 bool singleSector
= trgBlockNo
> -1;
1714 bool use_flashmemory
= arg_get_lit(ctx
, 16);
1715 bool ignore_static_encrypted
= arg_get_lit(ctx
, 17);
1720 if ((m0
+ m1
+ m2
+ m4
) > 1) {
1721 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
1725 uint8_t SectorsCnt
= 1;
1727 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1729 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1731 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
1733 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
1737 uint8_t MinSectorsCnt
= 0;
1738 // find a MIFARE type that can accommodate the provided block number
1739 uint8_t s
= MAX(mfSectorNum(trgBlockNo
), mfSectorNum(blockNo
));
1740 if (s
< MIFARE_MINI_MAXSECTOR
) {
1741 MinSectorsCnt
= MIFARE_MINI_MAXSECTOR
;
1742 } else if (s
< MIFARE_1K_MAXSECTOR
) {
1743 MinSectorsCnt
= MIFARE_1K_MAXSECTOR
;
1744 } else if (s
< MIFARE_2K_MAXSECTOR
) {
1745 MinSectorsCnt
= MIFARE_2K_MAXSECTOR
;
1746 } else if (s
< MIFARE_4K_MAXSECTOR
) {
1747 MinSectorsCnt
= MIFARE_4K_MAXSECTOR
;
1749 PrintAndLogEx(WARNING
, "Provided block out of possible MIFARE Type memory map");
1752 if (SectorsCnt
== 1) {
1753 SectorsCnt
= MinSectorsCnt
;
1754 } else if (SectorsCnt
< MinSectorsCnt
) {
1755 PrintAndLogEx(WARNING
, "Provided block out of provided MIFARE Type memory map");
1759 if (SectorsCnt
== 1) {
1760 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
1764 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
1768 sector_t
*e_sector
= NULL
;
1769 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
1772 // check if tag doesn't have static nonce
1773 if (detect_classic_static_nonce() == NONCE_STATIC
) {
1774 PrintAndLogEx(WARNING
, "Static nonce detected. Quitting...");
1775 PrintAndLogEx(INFO
, "\t Try use " _YELLOW_("`hf mf staticnested`"));
1776 return PM3_EOPABORTED
;
1779 // check if we can authenticate to sector
1780 if (mf_check_keys(blockNo
, keyType
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
1782 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo
, keyType
? 'B' : 'A');
1784 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockNo
, MIFARE_AUTH_KEYA
+ keyType
);
1786 return PM3_EOPABORTED
;
1790 int16_t isOK
= mf_nested(blockNo
, keyType
, key
, trgBlockNo
, trgKeyType
, keyBlock
, !ignore_static_encrypted
);
1793 PrintAndLogEx(ERR
, "command execution time out\n");
1795 case PM3_EOPABORTED
:
1796 PrintAndLogEx(WARNING
, "Button pressed. Aborted\n");
1799 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n");
1802 PrintAndLogEx(FAILED
, "No valid key found");
1804 case PM3_ESTATIC_NONCE
:
1805 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
1808 key64
= bytes_to_num(keyBlock
, 6);
1810 // transfer key to the emulator
1811 if (transferToEml
) {
1812 uint8_t sectortrailer
;
1814 if (trgBlockNo
< 32 * 4) { // 4 block sector
1815 sectortrailer
= trgBlockNo
| 0x03;
1816 } else { // 16 block sector
1817 sectortrailer
= trgBlockNo
| 0x0f;
1819 mf_eml_get_mem(keyBlock
, sectortrailer
, 1);
1821 if (trgKeyType
== MF_KEY_A
)
1822 num_to_bytes(key64
, 6, keyBlock
);
1824 num_to_bytes(key64
, 6, &keyBlock
[10]);
1826 mf_elm_set_mem(keyBlock
, sectortrailer
, 1);
1827 PrintAndLogEx(SUCCESS
, "Key transferred to emulator memory.");
1831 PrintAndLogEx(ERR
, "Unknown error\n");
1835 } else { // ------------------------------------ multiple sectors working
1836 uint64_t t1
= msclock();
1838 e_sector
= calloc(SectorsCnt
, sizeof(sector_t
));
1839 if (e_sector
== NULL
) return PM3_EMALLOC
;
1841 // add our known key
1842 e_sector
[mfSectorNum(blockNo
)].foundKey
[keyType
] = 1;
1843 e_sector
[mfSectorNum(blockNo
)].Key
[keyType
] = key64
;
1845 //test current key and additional standard keys first
1846 // add parameter key
1847 memcpy(keyBlock
+ (ARRAYLEN(g_mifare_default_keys
) * 6), key
, 6);
1849 for (int cnt
= 0; cnt
< ARRAYLEN(g_mifare_default_keys
); cnt
++) {
1850 num_to_bytes(g_mifare_default_keys
[cnt
], 6, (uint8_t *)(keyBlock
+ cnt
* 6));
1853 PrintAndLogEx(SUCCESS
, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt
);
1854 int res
= mf_check_keys_fast(SectorsCnt
, true, true, 1, ARRAYLEN(g_mifare_default_keys
) + 1, keyBlock
, e_sector
, use_flashmemory
, false);
1855 if (res
== PM3_SUCCESS
) {
1856 PrintAndLogEx(SUCCESS
, "Fast check found all keys");
1860 uint64_t t2
= msclock() - t1
;
1861 PrintAndLogEx(SUCCESS
, "Time to check " _YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys
), (float)t2
/ 1000.0);
1862 PrintAndLogEx(SUCCESS
, "enter nested key recovery");
1865 bool calibrate
= !ignore_static_encrypted
;
1867 for (trgKeyType
= MF_KEY_A
; trgKeyType
<= MF_KEY_B
; ++trgKeyType
) {
1868 for (uint8_t sectorNo
= 0; sectorNo
< SectorsCnt
; ++sectorNo
) {
1869 for (int i
= 0; i
< MIFARE_SECTOR_RETRY
; i
++) {
1871 if (e_sector
[sectorNo
].foundKey
[trgKeyType
]) continue;
1873 int16_t isOK
= mf_nested(blockNo
, keyType
, key
, mfFirstBlockOfSector(sectorNo
), trgKeyType
, keyBlock
, calibrate
);
1876 PrintAndLogEx(ERR
, "command execution time out\n");
1878 case PM3_EOPABORTED
:
1879 PrintAndLogEx(WARNING
, "button pressed. Aborted\n");
1882 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable)\n");
1888 case PM3_ESTATIC_NONCE
:
1889 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
1893 e_sector
[sectorNo
].foundKey
[trgKeyType
] = 1;
1894 e_sector
[sectorNo
].Key
[trgKeyType
] = bytes_to_num(keyBlock
, 6);
1896 mf_check_keys_fast(SectorsCnt
, true, true, 2, 1, keyBlock
, e_sector
, false, false);
1899 PrintAndLogEx(ERR
, "Unknown error\n");
1907 t1
= msclock() - t1
;
1908 PrintAndLogEx(SUCCESS
, "time in nested " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
1911 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
1912 PrintAndLogEx(INFO
, "trying to read key B...");
1913 for (int i
= 0; i
< SectorsCnt
; i
++) {
1914 // KEY A but not KEY B
1915 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
1917 uint8_t sectrail
= (mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
1919 PrintAndLogEx(SUCCESS
, "reading block %d", sectrail
);
1921 mf_readblock_t payload
;
1922 payload
.blockno
= sectrail
;
1923 payload
.keytype
= MF_KEY_A
;
1925 num_to_bytes(e_sector
[i
].Key
[0], 6, payload
.key
); // KEY A
1927 clearCommandBuffer();
1928 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
1930 PacketResponseNG resp
;
1931 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) continue;
1933 if (resp
.status
!= PM3_SUCCESS
) continue;
1935 uint8_t *data
= resp
.data
.asBytes
;
1936 key64
= bytes_to_num(data
+ 10, 6);
1938 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
1939 e_sector
[i
].foundKey
[1] = true;
1940 e_sector
[i
].Key
[1] = key64
;
1947 PrintAndLogEx(NORMAL
, "");
1948 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
1951 printKeyTable(SectorsCnt
, e_sector
);
1953 // transfer them to the emulator
1954 if (transferToEml
) {
1956 g_conn
.block_after_ACK
= true;
1957 for (int i
= 0; i
< SectorsCnt
; i
++) {
1958 mf_eml_get_mem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
1960 if (e_sector
[i
].foundKey
[0])
1961 num_to_bytes(e_sector
[i
].Key
[0], 6, keyBlock
);
1963 if (e_sector
[i
].foundKey
[1])
1964 num_to_bytes(e_sector
[i
].Key
[1], 6, &keyBlock
[10]);
1966 if (i
== SectorsCnt
- 1) {
1967 // Disable fast mode on last packet
1968 g_conn
.block_after_ACK
= false;
1970 mf_elm_set_mem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
1972 PrintAndLogEx(SUCCESS
, "keys transferred to emulator memory.");
1976 if (createDumpFile
) {
1977 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
1978 if (createMfcKeyDump(fptr
, SectorsCnt
, e_sector
) != PM3_SUCCESS
) {
1979 PrintAndLogEx(ERR
, "Failed to save keys to file");
1991 static int CmdHF14AMfNestedStatic(const char *Cmd
) {
1992 CLIParserContext
*ctx
;
1993 CLIParserInit(&ctx
, "hf mf staticnested",
1994 "Execute static nested attack against MIFARE Classic card with static nonce for key recovery.\n"
1995 "Supply a known key from one block to recover all keys",
1996 "hf mf staticnested --mini --blk 0 -a -k FFFFFFFFFFFF\n"
1997 "hf mf staticnested --1k --blk 0 -a -k FFFFFFFFFFFF\n"
1998 "hf mf staticnested --2k --blk 0 -a -k FFFFFFFFFFFF\n"
1999 "hf mf staticnested --4k --blk 0 -a -k FFFFFFFFFFFF\n");
2001 void *argtable
[] = {
2003 arg_str0("k", "key", "<hex>", "Known key (12 hex symbols)"),
2004 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
2005 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
2006 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
2007 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
2008 arg_int0(NULL
, "blk", "<dec>", "Input block number"),
2009 arg_lit0("a", NULL
, "Input key specified is keyA (def)"),
2010 arg_lit0("b", NULL
, "Input key specified is keyB"),
2011 arg_lit0("e", "emukeys", "Fill simulator keys from found keys"),
2012 arg_lit0(NULL
, "dumpkeys", "Dump found keys to file"),
2015 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2018 uint8_t key
[6] = {0};
2019 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
2021 bool m0
= arg_get_lit(ctx
, 2);
2022 bool m1
= arg_get_lit(ctx
, 3);
2023 bool m2
= arg_get_lit(ctx
, 4);
2024 bool m4
= arg_get_lit(ctx
, 5);
2026 uint8_t blockNo
= arg_get_u32_def(ctx
, 6, 0);
2028 uint8_t keyType
= MF_KEY_A
;
2030 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
2032 PrintAndLogEx(WARNING
, "Choose one single input key type");
2034 } else if (arg_get_lit(ctx
, 8)) {
2038 bool transferToEml
= arg_get_lit(ctx
, 9);
2039 bool createDumpFile
= arg_get_lit(ctx
, 10);
2043 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2044 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2048 uint8_t SectorsCnt
= 1;
2050 SectorsCnt
= MIFARE_MINI_MAXSECTOR
;
2052 SectorsCnt
= MIFARE_1K_MAXSECTOR
;
2054 SectorsCnt
= MIFARE_2K_MAXSECTOR
;
2056 SectorsCnt
= MIFARE_4K_MAXSECTOR
;
2058 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
2063 PrintAndLogEx(WARNING
, "Input key must include 12 HEX symbols");
2067 sector_t
*e_sector
= NULL
;
2069 uint8_t trgKeyType
= MF_KEY_A
;
2071 uint8_t keyBlock
[(ARRAYLEN(g_mifare_default_keys
) + 1) * 6];
2074 // check if tag have static nonce
2075 if (detect_classic_static_nonce() != NONCE_STATIC
) {
2076 PrintAndLogEx(WARNING
, "Normal nonce detected, or failed read of card. Quitting...");
2077 PrintAndLogEx(INFO
, "\t Try use " _YELLOW_("`hf mf nested`"));
2078 return PM3_EOPABORTED
;
2081 // check if we can authenticate to sector
2082 if (mf_check_keys(blockNo
, keyType
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
2084 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo
, keyType
? 'B' : 'A');
2086 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockNo
, MIFARE_AUTH_KEYA
+ keyType
);
2088 return PM3_EOPABORTED
;
2092 PrintAndLogEx(INFO
, "RDV4 with flashmemory supported detected.");
2095 uint64_t t1
= msclock();
2097 e_sector
= calloc(SectorsCnt
, sizeof(sector_t
));
2098 if (e_sector
== NULL
)
2101 // add our known key
2102 e_sector
[mfSectorNum(blockNo
)].foundKey
[keyType
] = 1;
2103 e_sector
[mfSectorNum(blockNo
)].Key
[keyType
] = key64
;
2105 //test current key and additional standard keys first
2106 // add parameter key
2107 memcpy(keyBlock
+ (ARRAYLEN(g_mifare_default_keys
) * 6), key
, 6);
2109 for (int cnt
= 0; cnt
< ARRAYLEN(g_mifare_default_keys
); cnt
++) {
2110 num_to_bytes(g_mifare_default_keys
[cnt
], 6, (uint8_t *)(keyBlock
+ cnt
* 6));
2113 PrintAndLogEx(SUCCESS
, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt
);
2114 int res
= mf_check_keys_fast(SectorsCnt
, true, true, 1, ARRAYLEN(g_mifare_default_keys
) + 1, keyBlock
, e_sector
, false, false);
2115 if (res
== PM3_SUCCESS
) {
2117 PrintAndLogEx(SUCCESS
, "Fast check found all keys");
2121 uint64_t t2
= msclock() - t1
;
2122 PrintAndLogEx(SUCCESS
, "Time to check "_YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys
), (float)t2
/ 1000.0);
2123 PrintAndLogEx(SUCCESS
, "enter static nested key recovery");
2126 for (trgKeyType
= MF_KEY_A
; trgKeyType
<= MF_KEY_B
; ++trgKeyType
) {
2127 for (uint8_t sectorNo
= 0; sectorNo
< SectorsCnt
; ++sectorNo
) {
2129 for (int i
= 0; i
< 1; i
++) {
2131 if (e_sector
[sectorNo
].foundKey
[trgKeyType
]) continue;
2133 int16_t isOK
= mf_static_nested(blockNo
, keyType
, key
, mfFirstBlockOfSector(sectorNo
), trgKeyType
, keyBlock
);
2136 PrintAndLogEx(ERR
, "command execution time out");
2138 case PM3_EOPABORTED
:
2139 PrintAndLogEx(WARNING
, "aborted via keyboard.");
2144 e_sector
[sectorNo
].foundKey
[trgKeyType
] = 1;
2145 e_sector
[sectorNo
].Key
[trgKeyType
] = bytes_to_num(keyBlock
, 6);
2147 // mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false);
2150 PrintAndLogEx(ERR
, "unknown error.\n");
2158 t1
= msclock() - t1
;
2159 PrintAndLogEx(SUCCESS
, "time in static nested " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
2162 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
2163 PrintAndLogEx(INFO
, "trying to read key B...");
2164 for (int i
= 0; i
< SectorsCnt
; i
++) {
2165 // KEY A but not KEY B
2166 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
2168 uint8_t sectrail
= (mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
2170 PrintAndLogEx(SUCCESS
, "reading block %d", sectrail
);
2172 mf_readblock_t payload
;
2173 payload
.blockno
= sectrail
;
2174 payload
.keytype
= MF_KEY_A
;
2176 num_to_bytes(e_sector
[i
].Key
[0], 6, payload
.key
); // KEY A
2178 clearCommandBuffer();
2179 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
2181 PacketResponseNG resp
;
2182 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500) == false) {
2186 if (resp
.status
!= PM3_SUCCESS
) continue;
2188 uint8_t *data
= resp
.data
.asBytes
;
2189 key64
= bytes_to_num(data
+ 10, 6);
2191 PrintAndLogEx(SUCCESS
, "data: %s", sprint_hex(data
+ 10, 6));
2192 e_sector
[i
].foundKey
[1] = true;
2193 e_sector
[i
].Key
[1] = key64
;
2200 PrintAndLogEx(NORMAL
, "");
2201 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
2204 printKeyTable(SectorsCnt
, e_sector
);
2206 // transfer them to the emulator
2207 if (transferToEml
) {
2209 g_conn
.block_after_ACK
= true;
2210 for (int i
= 0; i
< SectorsCnt
; i
++) {
2211 mf_eml_get_mem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
2213 if (e_sector
[i
].foundKey
[0])
2214 num_to_bytes(e_sector
[i
].Key
[0], 6, keyBlock
);
2216 if (e_sector
[i
].foundKey
[1])
2217 num_to_bytes(e_sector
[i
].Key
[1], 6, &keyBlock
[10]);
2219 if (i
== SectorsCnt
- 1) {
2220 // Disable fast mode on last packet
2221 g_conn
.block_after_ACK
= false;
2223 mf_elm_set_mem(keyBlock
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1);
2225 PrintAndLogEx(SUCCESS
, "keys transferred to emulator memory.");
2229 if (createDumpFile
) {
2230 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
2231 if (createMfcKeyDump(fptr
, SectorsCnt
, e_sector
) != PM3_SUCCESS
) {
2232 PrintAndLogEx(ERR
, "Failed to save keys to file");
2244 static int CmdHF14AMfNestedHard(const char *Cmd
) {
2246 CLIParserContext
*ctx
;
2247 CLIParserInit(&ctx
, "hf mf hardnested",
2248 "Nested attack for hardened MIFARE Classic cards.\n"
2249 "if card is EV1, command can detect and use known key see example below\n"
2251 "`--i<X>` set type of SIMD instructions. Without this flag programs autodetect it.\n"
2253 " hf mf hardnested -r --tk [known target key]\n"
2254 "Add the known target key to check if it is present in the remaining key space\n"
2255 " hf mf hardnested --blk 0 -a -k A0A1A2A3A4A5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
2257 "hf mf hardnested --tblk 4 --ta --> works for MFC EV1\n"
2258 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta\n"
2259 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -w\n"
2260 "hf mf hardnested --blk 0 -a -k FFFFFFFFFFFF --tblk 4 --ta -f nonces.bin -w -s\n"
2261 "hf mf hardnested -r\n"
2262 "hf mf hardnested -r --tk a0a1a2a3a4a5\n"
2263 "hf mf hardnested -t --tk a0a1a2a3a4a5\n"
2264 "hf mf hardnested --blk 0 -a -k a0a1a2a3a4a5 --tblk 4 --ta --tk FFFFFFFFFFFF\n"
2267 void *argtable
[] = {
2269 arg_str0("k", "key", "<hex>", "Key, 12 hex bytes"), // 1
2270 arg_int0(NULL
, "blk", "<dec>", "Input block number"), // 2
2271 arg_lit0("a", NULL
, "Input key A (def)"), // 3
2272 arg_lit0("b", NULL
, "Input key B"),
2273 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
2274 arg_lit0(NULL
, "ta", "Target key A"),
2275 arg_lit0(NULL
, "tb", "Target key B"),
2276 arg_str0(NULL
, "tk", "<hex>", "Target key, 12 hex bytes"), // 8
2277 arg_str0("u", "uid", "<hex>", "R/W `hf-mf-<UID>-nonces.bin` instead of default name"),
2278 arg_str0("f", "file", "<fn>", "R/W <name> instead of default name"),
2279 arg_lit0("r", "read", "Read `hf-mf-<UID>-nonces.bin` if tag present, otherwise `nonces.bin`, and start attack"),
2280 arg_lit0("s", "slow", "Slower acquisition (required by some non standard cards)"),
2281 arg_lit0("t", "tests", "Run tests"),
2282 arg_lit0("w", "wr", "Acquire nonces and UID, and write them to file `hf-mf-<UID>-nonces.bin`"),
2284 arg_lit0(NULL
, "in", "None (use CPU regular instruction set)"),
2285 #if defined(COMPILER_HAS_SIMD_X86)
2286 arg_lit0(NULL
, "im", "MMX"),
2287 arg_lit0(NULL
, "is", "SSE2"),
2288 arg_lit0(NULL
, "ia", "AVX"),
2289 arg_lit0(NULL
, "i2", "AVX2"),
2291 #if defined(COMPILER_HAS_SIMD_AVX512)
2292 arg_lit0(NULL
, "i5", "AVX512"),
2294 #if defined(COMPILER_HAS_SIMD_NEON)
2295 arg_lit0(NULL
, "ie", "NEON"),
2299 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
2302 uint8_t key
[6] = {0};
2303 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
2305 uint8_t blockno
= arg_get_u32_def(ctx
, 2, 0);
2307 uint8_t keytype
= MF_KEY_A
;
2308 if (arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) {
2310 PrintAndLogEx(WARNING
, "Choose one single input key type");
2312 } else if (arg_get_lit(ctx
, 4)) {
2316 uint8_t trg_blockno
= arg_get_u32_def(ctx
, 5, 0);
2318 uint8_t trg_keytype
= MF_KEY_A
;
2319 if (arg_get_lit(ctx
, 6) && arg_get_lit(ctx
, 7)) {
2321 PrintAndLogEx(WARNING
, "Choose one single target key type");
2323 } else if (arg_get_lit(ctx
, 7)) {
2324 trg_keytype
= MF_KEY_B
;
2328 uint8_t trg_key
[6] = {0};
2329 CLIGetHexWithReturn(ctx
, 8, trg_key
, &trg_keylen
);
2333 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)uid
, sizeof(uid
), &uidlen
);
2336 char filename
[FILE_PATH_SIZE
] = {0};
2337 CLIParamStrToBuf(arg_get_str(ctx
, 10), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2339 bool nonce_file_read
= arg_get_lit(ctx
, 11);
2340 bool slow
= arg_get_lit(ctx
, 12);
2341 bool tests
= arg_get_lit(ctx
, 13);
2342 bool nonce_file_write
= arg_get_lit(ctx
, 14);
2344 bool in
= arg_get_lit(ctx
, 15);
2345 #if defined(COMPILER_HAS_SIMD_X86)
2346 bool im
= arg_get_lit(ctx
, 16);
2347 bool is
= arg_get_lit(ctx
, 17);
2348 bool ia
= arg_get_lit(ctx
, 18);
2349 bool i2
= arg_get_lit(ctx
, 19);
2351 #if defined(COMPILER_HAS_SIMD_AVX512)
2352 bool i5
= arg_get_lit(ctx
, 20);
2354 #if defined(COMPILER_HAS_SIMD_NEON)
2355 bool ie
= arg_get_lit(ctx
, 16);
2359 // set SIM instructions
2360 SetSIMDInstr(SIMD_AUTO
);
2362 #if defined(COMPILER_HAS_SIMD_AVX512)
2364 SetSIMDInstr(SIMD_AVX512
);
2367 #if defined(COMPILER_HAS_SIMD_X86)
2369 SetSIMDInstr(SIMD_AVX2
);
2371 SetSIMDInstr(SIMD_AVX
);
2373 SetSIMDInstr(SIMD_SSE2
);
2375 SetSIMDInstr(SIMD_MMX
);
2378 #if defined(COMPILER_HAS_SIMD_NEON)
2380 SetSIMDInstr(SIMD_NEON
);
2384 SetSIMDInstr(SIMD_NONE
);
2387 bool known_target_key
= (trg_keylen
);
2389 if (nonce_file_read
) {
2390 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
2392 strncpy(filename
, "nonces.bin", FILE_PATH_SIZE
- 1);
2394 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
2398 if (nonce_file_write
) {
2399 char *fptr
= GenerateFilename("hf-mf-", "-nonces.bin");
2403 strncpy(filename
, fptr
, FILE_PATH_SIZE
- 1);
2408 snprintf(filename
, FILE_PATH_SIZE
, "hf-mf-%s-nonces.bin", uid
);
2411 if (g_session
.pm3_present
&& !tests
) {
2412 // detect MFC EV1 Signature
2413 if (detect_mfc_ev1_signature() && keylen
== 0) {
2414 PrintAndLogEx(INFO
, "MIFARE Classic EV1 card detected");
2417 memcpy(key
, g_mifare_signature_key_b
, sizeof(g_mifare_signature_key_b
));
2420 if (known_target_key
== false && nonce_file_read
== false) {
2421 // check if tag doesn't have static nonce
2422 if (detect_classic_static_nonce() == NONCE_STATIC
) {
2423 PrintAndLogEx(WARNING
, "Static nonce detected. Quitting...");
2424 PrintAndLogEx(HINT
, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
2425 return PM3_EOPABORTED
;
2429 // check if we can authenticate to sector
2430 if (mf_check_keys(blockno
, keytype
, true, 1, key
, &key64
) != PM3_SUCCESS
) {
2432 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%c", blockno
, keytype
? 'B' : 'A');
2434 PrintAndLogEx(WARNING
, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockno
, MIFARE_AUTH_KEYA
+ keytype
);
2436 return PM3_EWRONGANSWER
;
2441 PrintAndLogEx(INFO
, "Target block no " _YELLOW_("%3d") ", target key type: " _YELLOW_("%c") ", known target key: " _YELLOW_("%02x%02x%02x%02x%02x%02x%s"),
2443 (trg_keytype
== MF_KEY_B
) ? 'B' : 'A',
2444 trg_key
[0], trg_key
[1], trg_key
[2], trg_key
[3], trg_key
[4], trg_key
[5],
2445 known_target_key
? "" : " (not set)"
2447 PrintAndLogEx(INFO
, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"),
2448 nonce_file_write
? "write" : nonce_file_read
? "read" : "none",
2449 slow
? "Yes" : "No",
2452 uint64_t foundkey
= 0;
2453 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
);
2456 PrintAndLogEx(ERR
, "Error: No response from Proxmark3\n");
2458 case PM3_EOPABORTED
:
2459 PrintAndLogEx(WARNING
, "Button pressed. Aborted\n");
2461 case PM3_ESTATIC_NONCE
:
2462 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
2465 PrintAndLogEx(FAILED
, "\nFailed to recover a key...");
2472 if ((tests
== 0) && IfPm3Iso14443a()) {
2478 static int CmdHF14AMfAutoPWN(const char *Cmd
) {
2480 CLIParserContext
*ctx
;
2481 CLIParserInit(&ctx
, "hf mf autopwn",
2482 "This command automates the key recovery process on MIFARE Classic cards.\n"
2483 "It uses the fchk, chk, darkside, nested, hardnested and staticnested to recover keys.\n"
2484 "If all keys are found, it try dumping card content both to file and emulator memory.",
2486 "hf mf autopwn -s 0 -a -k FFFFFFFFFFFF --> target MFC 1K card, Sector 0 with known key A 'FFFFFFFFFFFF'\n"
2487 "hf mf autopwn --1k -f mfc_default_keys --> target MFC 1K card, default dictionary\n"
2488 "hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -f mfc_default_keys --> combo of the two above samples\n"
2489 "hf mf autopwn --1k -s 0 -a -k FFFFFFFFFFFF -k a0a1a2a3a4a5 --> multiple user supplied keys"
2492 void *argtable
[] = {
2494 arg_strx0("k", "key", "<hex>", "Known key, 12 hex bytes"),
2495 arg_int0("s", "sector", "<dec>", "Input sector number"),
2496 arg_lit0("a", NULL
, "Input key A (def)"),
2497 arg_lit0("b", NULL
, "Input key B"),
2498 arg_str0("f", "file", "<fn>", "filename of dictionary"),
2499 arg_lit0(NULL
, "slow", "Slower acquisition (required by some non standard cards)"),
2500 arg_lit0("l", "legacy", "legacy mode (use the slow `hf mf chk`)"),
2501 arg_lit0("v", "verbose", "verbose output"),
2503 arg_lit0(NULL
, "ns", "No save to file"),
2505 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
2506 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
2507 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
2508 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
2510 arg_lit0(NULL
, "in", "None (use CPU regular instruction set)"),
2511 #if defined(COMPILER_HAS_SIMD_X86)
2512 arg_lit0(NULL
, "im", "MMX"),
2513 arg_lit0(NULL
, "is", "SSE2"),
2514 arg_lit0(NULL
, "ia", "AVX"),
2515 arg_lit0(NULL
, "i2", "AVX2"),
2517 #if defined(COMPILER_HAS_SIMD_AVX512)
2518 arg_lit0(NULL
, "i5", "AVX512"),
2520 #if defined(COMPILER_HAS_SIMD_NEON)
2521 arg_lit0(NULL
, "ie", "NEON"),
2525 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
2527 int in_keys_len
= 0;
2528 uint8_t in_keys
[100 * MIFARE_KEY_SIZE
] = {0};
2529 CLIGetHexWithReturn(ctx
, 1, in_keys
, &in_keys_len
);
2531 uint8_t sectorno
= arg_get_u32_def(ctx
, 2, 0);
2533 uint8_t keytype
= MF_KEY_A
;
2534 if (arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) {
2536 PrintAndLogEx(WARNING
, "Choose one single input key type");
2538 } else if (arg_get_lit(ctx
, 4)) {
2543 char filename
[FILE_PATH_SIZE
] = {0};
2544 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
2546 bool slow
= arg_get_lit(ctx
, 6);
2547 bool legacy_mfchk
= arg_get_lit(ctx
, 7);
2548 bool verbose
= arg_get_lit(ctx
, 8);
2550 bool no_save
= arg_get_lit(ctx
, 9);
2552 bool m0
= arg_get_lit(ctx
, 10);
2553 bool m1
= arg_get_lit(ctx
, 11);
2554 bool m2
= arg_get_lit(ctx
, 12);
2555 bool m4
= arg_get_lit(ctx
, 13);
2557 bool in
= arg_get_lit(ctx
, 14);
2558 #if defined(COMPILER_HAS_SIMD_X86)
2559 bool im
= arg_get_lit(ctx
, 15);
2560 bool is
= arg_get_lit(ctx
, 16);
2561 bool ia
= arg_get_lit(ctx
, 17);
2562 bool i2
= arg_get_lit(ctx
, 18);
2564 #if defined(COMPILER_HAS_SIMD_AVX512)
2565 bool i5
= arg_get_lit(ctx
, 19);
2567 #if defined(COMPILER_HAS_SIMD_NEON)
2568 bool ie
= arg_get_lit(ctx
, 15);
2574 if ((m0
+ m1
+ m2
+ m4
) > 1) {
2575 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
2577 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
2581 uint8_t sector_cnt
= MIFARE_1K_MAXSECTOR
;
2582 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
2585 sector_cnt
= MIFARE_MINI_MAXSECTOR
;
2586 block_cnt
= MIFARE_MINI_MAXBLOCK
;
2588 sector_cnt
= MIFARE_1K_MAXSECTOR
;
2589 block_cnt
= MIFARE_1K_MAXBLOCK
;
2591 sector_cnt
= MIFARE_2K_MAXSECTOR
;
2592 block_cnt
= MIFARE_2K_MAXBLOCK
;
2594 sector_cnt
= MIFARE_4K_MAXSECTOR
;
2595 block_cnt
= MIFARE_4K_MAXBLOCK
;
2597 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
2602 // set SIM instructions
2603 SetSIMDInstr(SIMD_AUTO
);
2605 #if defined(COMPILER_HAS_SIMD_AVX512)
2607 SetSIMDInstr(SIMD_AVX512
);
2610 #if defined(COMPILER_HAS_SIMD_X86)
2612 SetSIMDInstr(SIMD_AVX2
);
2614 SetSIMDInstr(SIMD_AVX
);
2616 SetSIMDInstr(SIMD_SSE2
);
2618 SetSIMDInstr(SIMD_MMX
);
2621 #if defined(COMPILER_HAS_SIMD_NEON)
2623 SetSIMDInstr(SIMD_NEON
);
2627 SetSIMDInstr(SIMD_NONE
);
2630 // Nested and Hardnested parameter
2632 bool calibrate
= true;
2634 // Attack key storage variables
2635 uint8_t *keyBlock
= NULL
;
2636 uint32_t key_cnt
= 0;
2637 uint8_t tmp_key
[MIFARE_KEY_SIZE
] = {0};
2639 // Nested and Hardnested returned status
2640 uint64_t foundkey
= 0;
2641 int current_sector_i
= 0, current_key_type_i
= 0;
2643 // Dumping and transfere to simulater memory
2644 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
2648 int prng_type
= PM3_EUNDEF
;
2650 // ------------------------------
2652 uint64_t tagT
= GetHF14AMfU_Type();
2653 if (tagT
!= MFU_TT_UL_ERROR
) {
2654 PrintAndLogEx(ERR
, "Detected a MIFARE Ultralight/C/NTAG Compatible card.");
2655 PrintAndLogEx(ERR
, "This command targets " _YELLOW_("MIFARE Classic"));
2659 // Select card to get UID/UIDLEN/ATQA/SAK information
2660 clearCommandBuffer();
2661 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
2662 PacketResponseNG resp
;
2663 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
2664 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
2665 return PM3_ETIMEOUT
;
2668 uint64_t select_status
= resp
.oldarg
[0];
2669 if (select_status
== 0) {
2670 // iso14443a card select failed
2671 PrintAndLogEx(FAILED
, "No tag detected or other tag communication error");
2672 PrintAndLogEx(HINT
, "Hint: Try some distance or position of the card");
2673 return PM3_ECARDEXCHANGE
;
2677 iso14a_card_select_t card
;
2678 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
2680 bool known_key
= (in_keys_len
> 5);
2681 uint8_t key
[MIFARE_KEY_SIZE
] = {0};
2683 memcpy(key
, in_keys
, sizeof(key
));
2687 uint16_t key1_offset
= in_keys_len
;
2690 // iceman: todo, need to add all generated keys
2691 mfc_algo_mizip_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2692 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (0 * MIFARE_KEY_SIZE
));
2694 mfc_algo_di_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2695 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (1 * MIFARE_KEY_SIZE
));
2697 mfc_algo_sky_one(card
.uid
, 15, MF_KEY_A
, &key1
);
2698 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (2 * MIFARE_KEY_SIZE
));
2701 mfc_algo_saflok_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2702 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (3 * MIFARE_KEY_SIZE
));
2704 mfc_algo_touch_one(card
.uid
, 0, MF_KEY_A
, &key1
);
2705 num_to_bytes(key1
, MIFARE_KEY_SIZE
, in_keys
+ key1_offset
+ (4 * MIFARE_KEY_SIZE
));
2707 in_keys_len
+= (MIFARE_KEY_SIZE
* 5);
2709 // detect MFC EV1 Signature
2710 bool is_ev1
= detect_mfc_ev1_signature();
2712 // hidden sectors on MFC EV1
2716 // create/initialize key storage structure
2717 sector_t
*e_sector
= NULL
;
2718 size_t e_sector_cnt
= (sector_cnt
> sectorno
) ? sector_cnt
: sectorno
+ 1;
2719 if (initSectorTable(&e_sector
, e_sector_cnt
) != PM3_SUCCESS
) {
2724 PrintAndLogEx(INFO
, "MIFARE Classic EV1 card detected");
2726 // use found key if not supplied
2727 if (known_key
== false) {
2731 memcpy(key
, g_mifare_signature_key_b
, sizeof(g_mifare_signature_key_b
));
2735 // read uid to generate a filename for the key file
2736 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
2738 // check if tag doesn't have static nonce
2739 int has_staticnonce
= detect_classic_static_nonce();
2741 // card prng type (weak=1 / hard=0 / select/card comm error = negative value)
2742 if (has_staticnonce
== NONCE_NORMAL
) {
2743 prng_type
= detect_classic_prng();
2744 if (prng_type
< 0) {
2745 PrintAndLogEx(FAILED
, "\nNo tag detected or other tag communication error (%i)", prng_type
);
2754 PrintAndLogEx(INFO
, "======================= " _YELLOW_("SETTINGS") " =======================");
2755 PrintAndLogEx(INFO
, " card sectors .. " _YELLOW_("%d"), sector_cnt
);
2756 PrintAndLogEx(INFO
, " key supplied .. " _YELLOW_("%s"), known_key
? "True" : "False");
2757 PrintAndLogEx(INFO
, " known sector .. " _YELLOW_("%d"), sectorno
);
2758 PrintAndLogEx(INFO
, " keytype ....... " _YELLOW_("%c"), (keytype
== MF_KEY_B
) ? 'B' : 'A');
2759 PrintAndLogEx(INFO
, " known key ..... " _YELLOW_("%s"), sprint_hex_inrow(key
, sizeof(key
)));
2761 if (has_staticnonce
== NONCE_STATIC
)
2762 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("STATIC"));
2763 else if (has_staticnonce
== NONCE_NORMAL
)
2764 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("%s"), prng_type
? "WEAK" : "HARD");
2766 PrintAndLogEx(INFO
, " card PRNG ..... " _YELLOW_("Could not determine PRNG,") " " _RED_("read failed."));
2768 PrintAndLogEx(INFO
, " dictionary .... " _YELLOW_("%s"), strlen(filename
) ? filename
: "NONE");
2769 PrintAndLogEx(INFO
, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk
? "True" : "False");
2771 PrintAndLogEx(INFO
, "========================================================================");
2774 // check the user supplied key
2775 if (known_key
== false) {
2776 PrintAndLogEx(WARNING
, "no known key was supplied, key recovery might fail");
2780 uint64_t t1
= msclock();
2782 int ret
= mf_load_keys(&keyBlock
, &key_cnt
, in_keys
, in_keys_len
, filename
, fnlen
, true);
2783 if (ret
!= PM3_SUCCESS
) {
2788 int32_t res
= PM3_SUCCESS
;
2790 // Use the dictionary to find sector keys on the card
2791 if (verbose
) PrintAndLogEx(INFO
, "======================= " _YELLOW_("START DICTIONARY ATTACK") " =======================");
2794 PrintAndLogEx(INFO
, "." NOLF
);
2795 // Check all the sectors
2796 for (int i
= 0; i
< sector_cnt
; i
++) {
2797 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2798 // Check if the key is known
2799 if (e_sector
[i
].foundKey
[j
] == 0) {
2800 for (uint32_t k
= 0; k
< key_cnt
; k
++) {
2801 PrintAndLogEx(NORMAL
, "." NOLF
);
2804 if (mf_check_keys(mfFirstBlockOfSector(i
), j
, true, 1, (keyBlock
+ (MIFARE_KEY_SIZE
* k
)), &key64
) == PM3_SUCCESS
) {
2805 e_sector
[i
].Key
[j
] = bytes_to_num((keyBlock
+ (MIFARE_KEY_SIZE
* k
)), MIFARE_KEY_SIZE
);
2806 e_sector
[i
].foundKey
[j
] = 'D';
2813 PrintAndLogEx(NORMAL
, "");
2816 uint32_t chunksize
= key_cnt
> (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : key_cnt
;
2817 bool firstChunk
= true, lastChunk
= false;
2819 for (uint8_t strategy
= 1; strategy
< 3; strategy
++) {
2820 PrintAndLogEx(INFO
, "running strategy %u", strategy
);
2821 // main keychunk loop
2822 for (uint32_t i
= 0; i
< key_cnt
; i
+= chunksize
) {
2824 if (kbd_enter_pressed()) {
2825 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
2828 break; // Exit the loop
2830 uint32_t size
= ((key_cnt
- i
) > chunksize
) ? chunksize
: key_cnt
- i
;
2832 if (size
== key_cnt
- i
) {
2836 res
= mf_check_keys_fast(sector_cnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* MIFARE_KEY_SIZE
), e_sector
, false, verbose
);
2840 // all keys, aborted
2841 if (res
== PM3_SUCCESS
) {
2844 break; // Exit the loop
2846 } // end chunks of keys
2852 // Analyse the dictionary attack
2853 uint8_t num_found_keys
= 0;
2854 for (int i
= 0; i
< sector_cnt
; i
++) {
2855 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2856 if (e_sector
[i
].foundKey
[j
] != 1) {
2862 e_sector
[i
].foundKey
[j
] = 'D';
2863 num_to_bytes(e_sector
[i
].Key
[j
], MIFARE_KEY_SIZE
, tmp_key
);
2865 // Store valid credentials for the nested / hardnested attack if none exist
2866 if (known_key
== false) {
2867 num_to_bytes(e_sector
[i
].Key
[j
], MIFARE_KEY_SIZE
, key
);
2871 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
2873 (j
== MF_KEY_B
) ? 'B' : 'A',
2874 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2877 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2879 (j
== MF_KEY_B
) ? 'B' : 'A',
2880 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2886 if (num_found_keys
== sector_cnt
* 2) {
2890 // Check if at least one sector key was found
2891 if (known_key
== false) {
2893 // Check if the darkside attack can be used
2894 if (prng_type
&& has_staticnonce
!= NONCE_STATIC
) {
2896 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
2899 PrintAndLogEx(NORMAL
, "");
2901 isOK
= mf_dark_side(mfFirstBlockOfSector(sectorno
), MIFARE_AUTH_KEYA
+ keytype
, &key64
);
2903 if (isOK
!= PM3_SUCCESS
)
2904 goto noValidKeyFound
;
2906 PrintAndLogEx(SUCCESS
, "Found valid key [ " _GREEN_("%012" PRIx64
) " ]\n", key64
);
2909 num_to_bytes(key64
, MIFARE_KEY_SIZE
, key
);
2910 e_sector
[sectorno
].Key
[keytype
] = key64
;
2911 e_sector
[sectorno
].foundKey
[keytype
] = 'S';
2912 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%012" PRIx64
) " ] (used for nested / hardnested attack)",
2914 (keytype
== MF_KEY_B
) ? 'B' : 'A',
2920 PrintAndLogEx(FAILED
, "No usable key was found!");
2929 // Clear the needed variables
2930 num_to_bytes(0, MIFARE_KEY_SIZE
, tmp_key
);
2931 bool nested_failed
= false;
2933 // Iterate over each sector and key(A/B)
2934 for (current_sector_i
= 0; current_sector_i
< sector_cnt
; current_sector_i
++) {
2936 for (current_key_type_i
= MF_KEY_A
; current_key_type_i
<= MF_KEY_B
; current_key_type_i
++) {
2938 // If the key is already known, just skip it
2939 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
] == 0) {
2941 if (has_staticnonce
== NONCE_STATIC
)
2942 goto tryStaticnested
;
2944 // Try the found keys are reused
2945 if (bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
) != 0) {
2946 // <!> The fast check --> mfCheckKeys_fast(sector_cnt, true, true, 2, 1, tmp_key, e_sector, false, verbose);
2947 // <!> Returns false keys, so we just stick to the slower mfchk.
2948 for (int i
= 0; i
< sector_cnt
; i
++) {
2949 for (int j
= MF_KEY_A
; j
<= MF_KEY_B
; j
++) {
2950 // Check if the sector key is already broken
2951 if (e_sector
[i
].foundKey
[j
])
2954 // Check if the key works
2955 if (mf_check_keys(mfFirstBlockOfSector(i
), j
, true, 1, tmp_key
, &key64
) == PM3_SUCCESS
) {
2956 e_sector
[i
].Key
[j
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
2957 e_sector
[i
].foundKey
[j
] = 'R';
2958 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
2960 (j
== MF_KEY_B
) ? 'B' : 'A',
2961 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
2967 // Clear the last found key
2968 num_to_bytes(0, MIFARE_KEY_SIZE
, tmp_key
);
2970 if (current_key_type_i
== MF_KEY_B
) {
2971 if (e_sector
[current_sector_i
].foundKey
[0] && !e_sector
[current_sector_i
].foundKey
[1]) {
2973 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START READ B KEY ATTACK") " =======================");
2974 PrintAndLogEx(INFO
, "reading B key of sector %3d with key type %c",
2976 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
2978 uint8_t sectrail
= (mfFirstBlockOfSector(current_sector_i
) + mfNumBlocksPerSector(current_sector_i
) - 1);
2980 mf_readblock_t payload
;
2981 payload
.blockno
= sectrail
;
2982 payload
.keytype
= MF_KEY_A
;
2984 num_to_bytes(e_sector
[current_sector_i
].Key
[0], MIFARE_KEY_SIZE
, payload
.key
); // KEY A
2986 clearCommandBuffer();
2987 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
2989 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500) == false) goto skipReadBKey
;
2991 if (resp
.status
!= PM3_SUCCESS
) goto skipReadBKey
;
2993 uint8_t *data
= resp
.data
.asBytes
;
2994 key64
= bytes_to_num(data
+ 10, MIFARE_KEY_SIZE
);
2996 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'A';
2997 e_sector
[current_sector_i
].Key
[current_key_type_i
] = key64
;
2998 num_to_bytes(key64
, MIFARE_KEY_SIZE
, tmp_key
);
2999 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
3001 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3002 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
3006 PrintAndLogEx(WARNING
, "unknown B key: sector: %3d key type: %c",
3008 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A'
3010 PrintAndLogEx(INFO
, " -- reading the B key was not possible, maybe due to access rights?");
3018 // Use the nested / hardnested attack
3020 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
] == 0) {
3022 if (has_staticnonce
== NONCE_STATIC
)
3023 goto tryStaticnested
;
3025 if (prng_type
&& (nested_failed
== false)) {
3026 uint8_t retries
= 0;
3028 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START NESTED ATTACK") " =======================");
3029 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
3031 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
3034 isOK
= mf_nested(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, tmp_key
, calibrate
);
3037 case PM3_ETIMEOUT
: {
3038 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3.");
3043 case PM3_EOPABORTED
: {
3044 PrintAndLogEx(WARNING
, "\nButton pressed. Aborted.");
3050 PrintAndLogEx(FAILED
, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable).");
3051 PrintAndLogEx(FAILED
, "Nested attack failed --> try hardnested");
3057 // this can happen on some old cards, it's worth trying some more before switching to slower hardnested
3058 if (retries
++ < MIFARE_SECTOR_RETRY
) {
3059 PrintAndLogEx(FAILED
, "Nested attack failed, trying again (%i/%i)", retries
, MIFARE_SECTOR_RETRY
);
3062 PrintAndLogEx(FAILED
, "Nested attack failed, moving to hardnested");
3063 nested_failed
= true;
3068 case PM3_ESTATIC_NONCE
: {
3069 PrintAndLogEx(ERR
, "Error: Static encrypted nonce detected. Aborted\n");
3071 e_sector
[current_sector_i
].Key
[current_key_type_i
] = 0xffffffffffff;
3072 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = false;
3073 // Show the results to the user
3074 PrintAndLogEx(NORMAL
, "");
3075 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3076 printKeyTable(sector_cnt
, e_sector
);
3077 PrintAndLogEx(NORMAL
, "");
3084 e_sector
[current_sector_i
].Key
[current_key_type_i
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
3085 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'N';
3089 PrintAndLogEx(ERR
, "unknown Error.\n");
3097 tryHardnested
: // If the nested attack fails then we try the hardnested attack
3099 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START HARDNESTED ATTACK") " =======================");
3100 PrintAndLogEx(INFO
, "sector no %3d, target key type %c, Slow %s",
3102 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3103 slow
? "Yes" : "No");
3107 isOK
= mfnestedhard(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, NULL
, false, false, slow
, 0, &foundkey
, NULL
);
3109 if (isOK
!= PM3_SUCCESS
) {
3111 case PM3_ETIMEOUT
: {
3112 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
3115 case PM3_EOPABORTED
: {
3116 PrintAndLogEx(NORMAL
, "\nButton pressed, user aborted");
3119 case PM3_ESTATIC_NONCE
: {
3120 PrintAndLogEx(ERR
, "\nError: Static encrypted nonce detected. Aborted\n");
3122 e_sector
[current_sector_i
].Key
[current_key_type_i
] = 0xffffffffffff;
3123 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = false;
3125 // Show the results to the user
3126 PrintAndLogEx(NORMAL
, "");
3127 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3128 printKeyTable(sector_cnt
, e_sector
);
3129 PrintAndLogEx(NORMAL
, "");
3133 PrintAndLogEx(FAILED
, "\nFailed to recover a key...");
3145 // Copy the found key to the tmp_key variale (for the following print statement, and the mfCheckKeys above)
3146 num_to_bytes(foundkey
, MIFARE_KEY_SIZE
, tmp_key
);
3147 e_sector
[current_sector_i
].Key
[current_key_type_i
] = foundkey
;
3148 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'H';
3151 if (has_staticnonce
== NONCE_STATIC
) {
3154 PrintAndLogEx(INFO
, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
3155 PrintAndLogEx(INFO
, "sector no %3d, target key type %c",
3157 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A');
3160 isOK
= mf_static_nested(mfFirstBlockOfSector(sectorno
), keytype
, key
, mfFirstBlockOfSector(current_sector_i
), current_key_type_i
, tmp_key
);
3163 case PM3_ETIMEOUT
: {
3164 PrintAndLogEx(ERR
, "\nError: No response from Proxmark3");
3169 case PM3_EOPABORTED
: {
3170 PrintAndLogEx(WARNING
, "\nButton pressed, user aborted");
3176 e_sector
[current_sector_i
].Key
[current_key_type_i
] = bytes_to_num(tmp_key
, MIFARE_KEY_SIZE
);
3177 e_sector
[current_sector_i
].foundKey
[current_key_type_i
] = 'C';
3186 // Check if the key was found
3187 if (e_sector
[current_sector_i
].foundKey
[current_key_type_i
]) {
3188 PrintAndLogEx(SUCCESS
, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
3190 (current_key_type_i
== MF_KEY_B
) ? 'B' : 'A',
3191 sprint_hex_inrow(tmp_key
, sizeof(tmp_key
))
3201 // Show the results to the user
3202 PrintAndLogEx(NORMAL
, "");
3203 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3205 printKeyTable(sector_cnt
, e_sector
);
3207 if (no_save
== false) {
3210 PrintAndLogEx(NORMAL
, "");
3211 if (createMfcKeyDump(fptr
, sector_cnt
, e_sector
) != PM3_SUCCESS
) {
3212 PrintAndLogEx(ERR
, "Failed to save keys to file");
3216 // clear emulator mem
3217 clearCommandBuffer();
3218 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR
, NULL
, 0);
3220 PrintAndLogEx(INFO
, "transferring keys to simulator memory " NOLF
);
3222 bool transfer_status
= true;
3223 for (current_sector_i
= 0; current_sector_i
< sector_cnt
; current_sector_i
++) {
3224 mf_eml_get_mem(block
, current_sector_i
, 1);
3225 if (e_sector
[current_sector_i
].foundKey
[0])
3226 num_to_bytes(e_sector
[current_sector_i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3227 if (e_sector
[current_sector_i
].foundKey
[1])
3228 num_to_bytes(e_sector
[current_sector_i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3230 transfer_status
|= mf_elm_set_mem(block
, mfFirstBlockOfSector(current_sector_i
) + mfNumBlocksPerSector(current_sector_i
) - 1, 1);
3232 PrintAndLogEx(NORMAL
, "( %s )", (transfer_status
) ? _GREEN_("ok") : _RED_("fail"));
3234 PrintAndLogEx(INFO
, "dumping card content to emulator memory (Cmd Error: 04 can occur)");
3237 FastDumpWithEcFill(sector_cnt
);
3240 PrintAndLogEx(INFO
, "Called with no save option");
3241 PrintAndLogEx(NORMAL
, "");
3245 bytes
= block_cnt
* MFBLOCK_SIZE
;
3246 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
3248 PrintAndLogEx(ERR
, "Fail, cannot allocate memory");
3254 PrintAndLogEx(INFO
, "downloading card content from emulator memory");
3255 if (GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false) == false) {
3256 PrintAndLogEx(ERR
, "Fail, transfer from device time-out");
3260 return PM3_ETIMEOUT
;
3264 fptr
= GenerateFilename("hf-mf-", "-dump");
3272 strncpy(filename
, fptr
, sizeof(filename
) - 1);
3275 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
3279 // Generate and show statistics
3280 t1
= msclock() - t1
;
3281 PrintAndLogEx(INFO
, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1
/ 1000.0);
3287 static int CmdHF14AMfChk_fast(const char *Cmd
) {
3288 CLIParserContext
*ctx
;
3289 CLIParserInit(&ctx
, "hf mf fchk",
3290 "This is a improved checkkeys method speedwise. It checks MIFARE Classic tags sector keys against a dictionary file with keys",
3291 "hf mf fchk --mini -k FFFFFFFFFFFF --> Key recovery against MIFARE Mini\n"
3292 "hf mf fchk --1k -k FFFFFFFFFFFF --> Key recovery against MIFARE Classic 1k\n"
3293 "hf mf fchk --2k -k FFFFFFFFFFFF --> Key recovery against MIFARE 2k\n"
3294 "hf mf fchk --4k -k FFFFFFFFFFFF --> Key recovery against MIFARE 4k\n"
3295 "hf mf fchk --1k -f mfc_default_keys.dic --> Target 1K using default dictionary file\n"
3296 "hf mf fchk --1k --emu --> Target 1K, write keys to emulator memory\n"
3297 "hf mf fchk --1k --dump --> Target 1K, write keys to file\n"
3298 "hf mf fchk --1k --mem --> Target 1K, use dictionary from flash memory");
3300 void *argtable
[] = {
3302 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
3303 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3304 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3305 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3306 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3307 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3308 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3309 arg_lit0(NULL
, "mem", "Use dictionary from flashmemory"),
3310 arg_str0("f", "file", "<fn>", "filename of dictionary"),
3311 arg_int0(NULL
, "blk", "<dec>", "block number (single block recovery mode)"),
3312 arg_lit0("a", NULL
, "single block recovery key A"),
3313 arg_lit0("b", NULL
, "single block recovery key B"),
3314 arg_lit0(NULL
, "no-default", "Skip check default keys"),
3317 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3320 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0};
3321 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
3323 bool m0
= arg_get_lit(ctx
, 2);
3324 bool m1
= arg_get_lit(ctx
, 3);
3325 bool m2
= arg_get_lit(ctx
, 4);
3326 bool m4
= arg_get_lit(ctx
, 5);
3328 bool transferToEml
= arg_get_lit(ctx
, 6);
3329 bool createDumpFile
= arg_get_lit(ctx
, 7);
3330 bool use_flashmemory
= arg_get_lit(ctx
, 8);
3333 char filename
[FILE_PATH_SIZE
] = {0};
3334 CLIParamStrToBuf(arg_get_str(ctx
, 9), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3336 int blockn
= arg_get_int_def(ctx
, 10, -1);
3337 uint8_t keytype
= MF_KEY_A
;
3338 if (arg_get_lit(ctx
, 11) && arg_get_lit(ctx
, 12)) {
3340 PrintAndLogEx(WARNING
, "Choose one single input key type");
3342 } else if (arg_get_lit(ctx
, 12)) {
3345 bool load_default
= ! arg_get_lit(ctx
, 13);
3351 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3352 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3354 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3358 uint8_t sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3360 sectorsCnt
= MIFARE_MINI_MAXSECTOR
;
3362 sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3364 sectorsCnt
= MIFARE_2K_MAXSECTOR
;
3366 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
3368 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3372 uint8_t *keyBlock
= NULL
;
3373 uint32_t keycnt
= 0;
3374 int ret
= mf_load_keys(&keyBlock
, &keycnt
, key
, keylen
, filename
, fnlen
, load_default
);
3375 if (ret
!= PM3_SUCCESS
) {
3379 // create/initialize key storage structure
3380 sector_t
*e_sector
= NULL
;
3381 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
3386 uint32_t chunksize
= keycnt
> (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : keycnt
;
3387 bool firstChunk
= true, lastChunk
= false;
3392 uint64_t t1
= msclock();
3394 uint16_t singleSectorParams
= 0;
3396 singleSectorParams
= (blockn
& 0xFF) | keytype
<< 8 | 1 << 15;
3398 if (use_flashmemory
) {
3399 PrintAndLogEx(SUCCESS
, "Using dictionary in flash memory");
3400 mf_check_keys_fast_ex(sectorsCnt
, true, true, 1, 0, keyBlock
, e_sector
, use_flashmemory
, false, false, singleSectorParams
);
3403 // strategies. 1= deep first on sector 0 AB, 2= width first on all sectors
3404 for (uint8_t strategy
= 1; strategy
< 3; strategy
++) {
3405 PrintAndLogEx(INFO
, "Running strategy %u", strategy
);
3407 // main keychunk loop
3408 for (i
= 0; i
< keycnt
; i
+= chunksize
) {
3410 if (kbd_enter_pressed()) {
3411 PrintAndLogEx(NORMAL
, "");
3412 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
3413 // field is still ON if not on last chunk
3414 clearCommandBuffer();
3415 SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF
, NULL
, 0);
3416 // TODO: we're missing these cleanups on arm side, not sure if it's important...
3417 // set_tracing(false);
3419 // BigBuf_Clear_ext(false);
3422 PrintAndLogEx(INPLACE
, "Testing %5i/%5i %02.1f%%", i
, keycnt
, (float)i
* 100 / keycnt
);
3423 uint32_t size
= ((keycnt
- i
) > chunksize
) ? chunksize
: keycnt
- i
;
3426 if (size
== keycnt
- i
)
3429 int res
= mf_check_keys_fast_ex(sectorsCnt
, firstChunk
, lastChunk
, strategy
, size
, keyBlock
+ (i
* MIFARE_KEY_SIZE
), e_sector
, false, false, true, singleSectorParams
);
3433 // all keys, aborted
3434 if (res
== PM3_SUCCESS
|| res
== 2) {
3435 PrintAndLogEx(NORMAL
, "");
3438 } // end chunks of keys
3439 PrintAndLogEx(INPLACE
, "Testing %5i/%5i 100.00%%", keycnt
, keycnt
);
3440 PrintAndLogEx(NORMAL
, "");
3443 if (blockn
!= -1) break;
3447 t1
= msclock() - t1
;
3448 PrintAndLogEx(INFO
, "Time in checkkeys (fast) " _YELLOW_("%.1fs") "\n", (float)(t1
/ 1000.0));
3455 uint8_t found_keys
= 0;
3456 for (i
= 0; i
< sectorsCnt
; ++i
) {
3458 if (e_sector
[i
].foundKey
[0])
3461 if (e_sector
[i
].foundKey
[1])
3465 if (found_keys
== 0) {
3466 PrintAndLogEx(WARNING
, "No keys found");
3469 PrintAndLogEx(NORMAL
, "");
3470 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3472 printKeyTable(sectorsCnt
, e_sector
);
3474 if (use_flashmemory
&& found_keys
== (sectorsCnt
<< 1)) {
3475 PrintAndLogEx(SUCCESS
, "Card dumped as well. run " _YELLOW_("`%s %c`"),
3477 GetFormatFromSector(sectorsCnt
)
3481 if (transferToEml
) {
3483 g_conn
.block_after_ACK
= true;
3484 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3485 for (i
= 0; i
< sectorsCnt
; ++i
) {
3486 uint8_t b
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3487 mf_eml_get_mem(block
, b
, 1);
3489 if (e_sector
[i
].foundKey
[0])
3490 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3492 if (e_sector
[i
].foundKey
[1])
3493 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3495 if (i
== sectorsCnt
- 1) {
3496 // Disable fast mode on last packet
3497 g_conn
.block_after_ACK
= false;
3499 mf_elm_set_mem(block
, b
, 1);
3501 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
3503 if (found_keys
== (sectorsCnt
<< 1)) {
3504 FastDumpWithEcFill(sectorsCnt
);
3508 if (createDumpFile
) {
3510 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
3511 if (createMfcKeyDump(fptr
, sectorsCnt
, e_sector
) != PM3_SUCCESS
) {
3512 PrintAndLogEx(ERR
, "Failed to save keys to file");
3520 PrintAndLogEx(NORMAL
, "");
3524 static int CmdHF14AMfSmartBrute(const char *Cmd
) {
3525 CLIParserContext
*ctx
;
3526 CLIParserInit(&ctx
, "hf mf brute",
3527 "This is a smart bruteforce, exploiting common patterns, bugs and bad designs in key generators.",
3528 "hf mf brute --mini --> Key recovery against MIFARE Mini\n"
3529 "hf mf brute --1k --> Key recovery against MIFARE Classic 1k\n"
3530 "hf mf brute --2k --> Key recovery against MIFARE 2k\n"
3531 "hf mf brute --4k --> Key recovery against MIFARE 4k\n"
3532 "hf mf brute --1k --emu --> Target 1K, write keys to emulator memory\n"
3533 "hf mf brute --1k --dump --> Target 1K, write keys to file\n");
3535 void *argtable
[] = {
3537 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3538 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3539 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3540 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3541 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3542 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3545 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3548 bool m0
= arg_get_lit(ctx
, 2);
3549 bool m1
= arg_get_lit(ctx
, 3);
3550 bool m2
= arg_get_lit(ctx
, 4);
3551 bool m4
= arg_get_lit(ctx
, 5);
3553 bool transferToEml
= arg_get_lit(ctx
, 6);
3554 bool createDumpFile
= arg_get_lit(ctx
, 7);
3560 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3561 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3563 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
3567 uint8_t sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3569 sectorsCnt
= MIFARE_MINI_MAXSECTOR
;
3571 sectorsCnt
= MIFARE_1K_MAXSECTOR
;
3573 sectorsCnt
= MIFARE_2K_MAXSECTOR
;
3575 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
3577 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
3581 uint32_t chunksize
= 100 > (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) ? (PM3_CMD_DATA_SIZE
/ MIFARE_KEY_SIZE
) : 100;
3582 uint8_t *keyBlock
= calloc(MIFARE_KEY_SIZE
, chunksize
);
3584 if (keyBlock
== NULL
)
3587 // create/initialize key storage structure
3588 sector_t
*e_sector
= NULL
;
3589 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
3594 // initialize bruteforce engine
3595 generator_context_t bctx
;
3596 bf_generator_init(&bctx
, BF_MODE_SMART
, BF_KEY_SIZE_48
);
3599 int smart_mode_stage
= -1;
3600 uint64_t generator_key
;
3603 uint64_t t0
= msclock();
3604 uint64_t t1
= msclock();
3605 uint64_t keys_checked
= 0;
3606 uint64_t total_keys_checked
= 0;
3608 uint32_t keycnt
= 0;
3609 bool firstChunk
= true, lastChunk
= false;
3611 while (!lastChunk
) {
3614 // generate block of keys from generator
3615 memset(keyBlock
, 0, MIFARE_KEY_SIZE
* chunksize
);
3617 for (i
= 0; i
< chunksize
; i
++) {
3619 ret
= bf_generate(&bctx
);
3621 if (ret
== BF_GENERATOR_ERROR
) {
3622 PrintAndLogEx(ERR
, "Internal bruteforce generator error");
3627 } else if (ret
== BF_GENERATOR_END
) {
3632 } else if (ret
== BF_GENERATOR_NEXT
) {
3634 generator_key
= bf_get_key48(&bctx
);
3635 num_to_bytes(generator_key
, MIFARE_KEY_SIZE
, keyBlock
+ (i
* MIFARE_KEY_SIZE
));
3638 if (smart_mode_stage
!= bctx
.smart_mode_stage
) {
3640 smart_mode_stage
= bctx
.smart_mode_stage
;
3641 PrintAndLogEx(INFO
, "Running bruteforce stage %d", smart_mode_stage
);
3645 PrintAndLogEx(INFO
, "Current cracking speed (keys/s): %lu",
3646 keys_checked
/ ((msclock() - t1
) / 1000)
3656 int strategy
= 2; // width first on all sectors
3657 ret
= mf_check_keys_fast(sectorsCnt
, firstChunk
, lastChunk
, strategy
, keycnt
, keyBlock
, e_sector
, false, false);
3659 keys_checked
+= keycnt
;
3660 total_keys_checked
+= keycnt
;
3665 if (ret
== PM3_SUCCESS
|| ret
== 2)
3671 PrintAndLogEx(INFO
, "Time in brute mode: " _YELLOW_("%.1fs") "\n", (float)((msclock() - t0
) / 1000.0));
3672 PrintAndLogEx(INFO
, "Total keys checked: " _YELLOW_("%lu") "\n", total_keys_checked
);
3674 uint8_t found_keys
= 0;
3675 for (i
= 0; i
< sectorsCnt
; ++i
) {
3677 if (e_sector
[i
].foundKey
[0]) {
3681 if (e_sector
[i
].foundKey
[1]) {
3686 if (found_keys
== 0) {
3687 PrintAndLogEx(WARNING
, "No keys found");
3690 PrintAndLogEx(NORMAL
, "");
3691 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3693 printKeyTable(sectorsCnt
, e_sector
);
3695 if (transferToEml
) {
3697 g_conn
.block_after_ACK
= true;
3698 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3699 for (i
= 0; i
< sectorsCnt
; ++i
) {
3700 uint8_t b
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3701 mf_eml_get_mem(block
, b
, 1);
3703 if (e_sector
[i
].foundKey
[0])
3704 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3706 if (e_sector
[i
].foundKey
[1])
3707 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3709 if (i
== sectorsCnt
- 1) {
3710 // Disable fast mode on last packet
3711 g_conn
.block_after_ACK
= false;
3713 mf_elm_set_mem(block
, b
, 1);
3715 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
3717 if (found_keys
== (sectorsCnt
<< 1)) {
3718 FastDumpWithEcFill(sectorsCnt
);
3722 if (createDumpFile
) {
3724 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
3725 if (createMfcKeyDump(fptr
, sectorsCnt
, e_sector
) != PM3_SUCCESS
) {
3726 PrintAndLogEx(ERR
, "Failed to save keys to file");
3735 PrintAndLogEx(NORMAL
, "");
3739 static int CmdHF14AMfChk(const char *Cmd
) {
3740 CLIParserContext
*ctx
;
3741 CLIParserInit(&ctx
, "hf mf chk",
3742 "Check keys on MIFARE Classic card",
3743 "hf mf chk --mini -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Mini\n"
3744 "hf mf chk --1k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE Classic 1k\n"
3745 "hf mf chk --2k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 2k\n"
3746 "hf mf chk --4k -k FFFFFFFFFFFF --> Check all sectors, all keys against MIFARE 4k\n"
3747 "hf mf chk --1k --emu --> Check all sectors, all keys, 1K, and write to emulator memory\n"
3748 "hf mf chk --1k --dump --> Check all sectors, all keys, 1K, and write to file\n"
3749 "hf mf chk -a --tblk 0 -f mfc_default_keys.dic --> Check dictionary against block 0, key A");
3751 void *argtable
[] = {
3753 arg_strx0("k", "key", "<hex>", "Key specified as 12 hex symbols"),
3754 arg_int0(NULL
, "tblk", "<dec>", "Target block number"),
3755 arg_lit0("a", NULL
, "Target Key A"),
3756 arg_lit0("b", NULL
, "Target Key B"),
3757 arg_lit0("*", "all", "Target both key A & B (default)"),
3758 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
3759 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (default)"),
3760 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
3761 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
3762 arg_lit0(NULL
, "emu", "Fill simulator keys from found keys"),
3763 arg_lit0(NULL
, "dump", "Dump found keys to binary file"),
3764 arg_str0("f", "file", "<fn>", "Filename of dictionary"),
3765 arg_lit0(NULL
, "no-default", "Skip check default keys"),
3768 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
3771 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0};
3772 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
3774 int blockNo
= arg_get_int_def(ctx
, 2, -1);
3776 uint8_t keyType
= 2;
3778 if ((arg_get_lit(ctx
, 3) && arg_get_lit(ctx
, 4)) || arg_get_lit(ctx
, 5)) {
3780 } else if (arg_get_lit(ctx
, 3)) {
3782 } else if (arg_get_lit(ctx
, 4)) {
3786 bool m0
= arg_get_lit(ctx
, 6);
3787 bool m1
= arg_get_lit(ctx
, 7);
3788 bool m2
= arg_get_lit(ctx
, 8);
3789 bool m4
= arg_get_lit(ctx
, 9);
3791 bool transferToEml
= arg_get_lit(ctx
, 10);
3792 bool createDumpFile
= arg_get_lit(ctx
, 11);
3795 char filename
[FILE_PATH_SIZE
] = {0};
3796 CLIParamStrToBuf(arg_get_str(ctx
, 12), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
3797 bool load_default
= ! arg_get_lit(ctx
, 13);
3801 bool singleSector
= (blockNo
> -1);
3802 if (singleSector
== false) {
3803 // start from first trailer block
3808 if ((m0
+ m1
+ m2
+ m4
) > 1) {
3809 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
3813 size_t sectors_cnt
= 1;
3815 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
3817 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3819 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
3821 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
3826 // find a MIFARE type that can accommodate the provided block number
3827 size_t min_sectors_cnt
= 0;
3828 uint8_t s
= mfSectorNum(blockNo
);
3830 if (s
< MIFARE_MINI_MAXSECTOR
) {
3831 min_sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
3832 } else if (s
< MIFARE_1K_MAXSECTOR
) {
3833 min_sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3834 } else if (s
< MIFARE_2K_MAXSECTOR
) {
3835 min_sectors_cnt
= MIFARE_2K_MAXSECTOR
;
3836 } else if (s
< MIFARE_4K_MAXSECTOR
) {
3837 min_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
3839 PrintAndLogEx(WARNING
, "Provided block out of possible MIFARE Type memory map");
3843 if (sectors_cnt
== 1) {
3844 sectors_cnt
= min_sectors_cnt
;
3845 } else if (sectors_cnt
< min_sectors_cnt
) {
3846 PrintAndLogEx(WARNING
, "Provided block out of provided MIFARE Type memory map");
3851 if (sectors_cnt
== 1) {
3852 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
3855 uint8_t *keyBlock
= NULL
;
3856 uint32_t keycnt
= 0;
3857 int ret
= mf_load_keys(&keyBlock
, &keycnt
, key
, keylen
, filename
, fnlen
, load_default
);
3858 if (ret
!= PM3_SUCCESS
) {
3864 // create/initialize key storage structure
3865 sector_t
*e_sector
= NULL
;
3866 if (initSectorTable(&e_sector
, sectors_cnt
) != PM3_SUCCESS
) {
3871 uint8_t trgKeyType
= MF_KEY_A
;
3872 uint16_t max_keys
= keycnt
> KEYS_IN_BLOCK
? KEYS_IN_BLOCK
: keycnt
;
3874 PrintAndLogEx(INFO
, "Start check for keys...");
3875 PrintAndLogEx(INFO
, "." NOLF
);
3878 g_conn
.block_after_ACK
= true;
3880 // clear trace log by first check keys call only
3881 bool clearLog
= true;
3884 uint64_t t1
= msclock();
3887 for (trgKeyType
= (keyType
== 2) ? 0 : keyType
; trgKeyType
< 2; (keyType
== 2) ? (++trgKeyType
) : (trgKeyType
= 2)) {
3889 // loop sectors but block is used as to keep track of from which blocks to test
3891 for (int i
= mfSectorNum(b
); i
< sectors_cnt
; ++i
) {
3893 // skip already found keys.
3894 if (e_sector
[i
].foundKey
[trgKeyType
]) continue;
3896 for (uint32_t c
= 0; c
< keycnt
; c
+= max_keys
) {
3898 PrintAndLogEx(NORMAL
, "." NOLF
);
3901 if (kbd_enter_pressed()) {
3902 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
3906 uint32_t size
= keycnt
- c
> max_keys
? max_keys
: keycnt
- c
;
3908 if (mf_check_keys(b
, trgKeyType
, clearLog
, size
, &keyBlock
[MIFARE_KEY_SIZE
* c
], &key64
) == PM3_SUCCESS
) {
3909 e_sector
[i
].Key
[trgKeyType
] = key64
;
3910 e_sector
[i
].foundKey
[trgKeyType
] = true;
3919 b
< 127 ? (b
+= 4) : (b
+= 16);
3922 t1
= msclock() - t1
;
3923 PrintAndLogEx(INFO
, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1
/ 1000.0);
3925 // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
3926 if (keyType
!= MF_KEY_B
) {
3927 PrintAndLogEx(INFO
, "testing to read key B...");
3929 // loop sectors but block is used as to keep track of from which blocks to test
3931 for (int i
= mfSectorNum(b
); i
< sectors_cnt
; i
++) {
3933 // KEY A but not KEY B
3934 if (e_sector
[i
].foundKey
[0] && !e_sector
[i
].foundKey
[1]) {
3936 uint8_t sectrail
= mfSectorTrailerOfSector(i
);
3937 PrintAndLogEx(INFO
, "Sector: %u, First block: %u, Last block: %u, Num of blocks: %u", i
, mfFirstBlockOfSector(i
), sectrail
, mfNumBlocksPerSector(i
));
3938 PrintAndLogEx(INFO
, "Reading sector trailer");
3940 mf_readblock_t payload
;
3941 payload
.blockno
= sectrail
;
3942 payload
.keytype
= MF_KEY_A
;
3945 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, payload
.key
);
3947 clearCommandBuffer();
3948 SendCommandNG(CMD_HF_MIFARE_READBL
, (uint8_t *)&payload
, sizeof(mf_readblock_t
));
3950 PacketResponseNG resp
;
3951 if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL
, &resp
, 1500)) continue;
3953 if (resp
.status
!= PM3_SUCCESS
) continue;
3955 uint8_t *data
= resp
.data
.asBytes
;
3956 key64
= bytes_to_num(data
+ 10, MIFARE_KEY_SIZE
);
3958 PrintAndLogEx(NORMAL
, "Data:%s", sprint_hex(data
+ 10, MIFARE_KEY_SIZE
));
3959 e_sector
[i
].foundKey
[1] = 1;
3960 e_sector
[i
].Key
[1] = key64
;
3965 b
< 127 ? (b
+= 4) : (b
+= 16);
3970 PrintAndLogEx(NORMAL
, "");
3971 PrintAndLogEx(SUCCESS
, _GREEN_("found keys:"));
3974 // if (singleSector)
3975 // printKeyTableEx(1, e_sector, mfSectorNum(blockNo));
3977 printKeyTable(sectors_cnt
, e_sector
);
3979 if (transferToEml
) {
3981 g_conn
.block_after_ACK
= true;
3982 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
3983 for (int i
= 0; i
< sectors_cnt
; ++i
) {
3984 uint8_t blockno
= mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1;
3985 mf_eml_get_mem(block
, blockno
, 1);
3987 if (e_sector
[i
].foundKey
[0])
3988 num_to_bytes(e_sector
[i
].Key
[0], MIFARE_KEY_SIZE
, block
);
3990 if (e_sector
[i
].foundKey
[1])
3991 num_to_bytes(e_sector
[i
].Key
[1], MIFARE_KEY_SIZE
, block
+ 10);
3993 if (i
== sectors_cnt
- 1) {
3994 // Disable fast mode on last packet
3995 g_conn
.block_after_ACK
= false;
3997 mf_elm_set_mem(block
, blockno
, 1);
3999 PrintAndLogEx(SUCCESS
, "Found keys have been transferred to the emulator memory");
4002 if (createDumpFile
) {
4003 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
4004 if (createMfcKeyDump(fptr
, sectors_cnt
, e_sector
) != PM3_SUCCESS
) {
4005 PrintAndLogEx(ERR
, "Failed to save keys to file");
4013 // Disable fast mode and send a dummy command to make it effective
4014 g_conn
.block_after_ACK
= false;
4015 SendCommandNG(CMD_PING
, NULL
, 0);
4016 if (!WaitForResponseTimeout(CMD_PING
, NULL
, 1000)) {
4017 PrintAndLogEx(WARNING
, "command execution time out");
4018 return PM3_ETIMEOUT
;
4021 PrintAndLogEx(NORMAL
, "");
4025 void showSectorTable(sector_t
*k_sector
, size_t k_sectors_cnt
) {
4026 if (k_sector
!= NULL
) {
4027 printKeyTable(k_sectors_cnt
, k_sector
);
4032 void readerAttack(sector_t
*k_sector
, size_t k_sectors_cnt
, nonces_t data
, bool setEmulatorMem
, bool verbose
) {
4035 if (k_sector
== NULL
) {
4036 if (initSectorTable(&k_sector
, k_sectors_cnt
) != PM3_SUCCESS
) {
4043 if ((nonce_state
)data
.state
== SECOND
) {
4044 found
= mfkey32_moebius(&data
, &key
);
4045 } else if ((nonce_state
)data
.state
== NESTED
) {
4046 found
= mfkey32_nested(&data
, &key
);
4049 uint8_t sector
= data
.sector
;
4050 uint8_t keytype
= data
.keytype
;
4052 PrintAndLogEx(INFO
, "Reader is trying authenticate with: Key %s, sector %02d: [%012" PRIx64
"]"
4053 , (keytype
== MF_KEY_B
) ? "B" : "A"
4058 k_sector
[sector
].Key
[keytype
] = key
;
4059 k_sector
[sector
].foundKey
[keytype
] = true;
4061 //set emulator memory for keys
4062 if (setEmulatorMem
) {
4063 uint8_t memBlock
[16];
4064 mf_eml_get_mem(memBlock
, (sector
* 4) + 3, 1);
4065 if ((memBlock
[6] == 0) && (memBlock
[7] == 0) && (memBlock
[8] == 0)) {
4071 num_to_bytes(k_sector
[sector
].Key
[keytype
], 6, memBlock
+ ((keytype
== MF_KEY_B
) ? 10 : 0));
4072 //iceman, guessing this will not work so well for 4K tags.
4073 PrintAndLogEx(INFO
, "Setting Emulator Memory Block %02d: [%s]"
4075 , sprint_hex(memBlock
, sizeof(memBlock
))
4077 mf_elm_set_mem(memBlock
, (sector
* 4) + 3, 1);
4084 static int CmdHF14AMfSim(const char *Cmd
) {
4085 CLIParserContext
*ctx
;
4086 CLIParserInit(&ctx
, "hf mf sim",
4087 "Simulate MIFARE Classic family type based upon\n"
4088 "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n"
4089 "from emulator memory. See `hf mf eload` first.\n"
4090 "The UID from emulator memory will be used if not specified.",
4091 "hf mf sim --mini --> MIFARE Mini\n"
4092 "hf mf sim --1k --> MIFARE Classic 1k (default)\n"
4093 "hf mf sim --1k -u 0a0a0a0a --> MIFARE Classic 1k with 4b UID\n"
4094 "hf mf sim --1k -u 11223344556677 --> MIFARE Classic 1k with 7b UID\n"
4095 "hf mf sim --1k -u 11223344 -i -x --> Perform reader attack in interactive mode\n"
4096 "hf mf sim --2k --> MIFARE 2k\n"
4097 "hf mf sim --4k --> MIFARE 4k"
4098 "hf mf sim --1k -x -e --> Keep simulation running and populate with found reader keys\n"
4101 void *argtable
[] = {
4103 arg_str0("u", "uid", "<hex>", "<4|7|10> hex bytes UID"),
4104 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4105 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50"),
4106 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4107 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4108 arg_str0(NULL
, "atqa", "<hex>", "Provide explicit ATQA (2 bytes)"),
4109 arg_str0(NULL
, "sak", "<hex>", "Provide explicit SAK (1 bytes)"),
4110 arg_int0("n", "num", "<dec> ", "Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite"),
4111 arg_lit0("i", "interactive", "Console will not be returned until simulation finishes or is aborted"),
4112 arg_lit0("x", NULL
, "Performs the 'reader attack', nr/ar attack against a reader."),
4113 arg_lit0("y", NULL
, "Performs the nested 'reader attack'. This requires preloading nt & nt_enc in emulator memory. Implies -x."),
4114 arg_lit0("e", "emukeys", "Fill simulator keys from found keys. Requires -x or -y. Implies -i. Simulation will restart automatically."),
4115 // If access bits show that key B is Readable, any subsequent memory access should be refused.
4116 arg_lit0(NULL
, "allowkeyb", "Allow key B even if readable"),
4117 arg_lit0("v", "verbose", "Verbose output"),
4118 arg_lit0(NULL
, "cve", "Trigger CVE 2021_0430"),
4121 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4126 uint8_t uid
[10] = {0};
4127 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
4130 FLAG_SET_UID_IN_DATA(flags
, uidlen
);
4131 if (IS_FLAG_UID_IN_EMUL(flags
)) {
4132 PrintAndLogEx(WARNING
, "Invalid parameter for UID");
4138 bool m0
= arg_get_lit(ctx
, 2);
4139 bool m1
= arg_get_lit(ctx
, 3);
4140 bool m2
= arg_get_lit(ctx
, 4);
4141 bool m4
= arg_get_lit(ctx
, 5);
4144 uint8_t atqa
[2] = {0};
4145 CLIGetHexWithReturn(ctx
, 6, atqa
, &atqalen
);
4148 uint8_t sak
[1] = {0};
4149 CLIGetHexWithReturn(ctx
, 7, sak
, &saklen
);
4151 uint8_t exitAfterNReads
= arg_get_u32_def(ctx
, 8, 0);
4153 if (arg_get_lit(ctx
, 9)) {
4154 flags
|= FLAG_INTERACTIVE
;
4157 if (arg_get_lit(ctx
, 10)) {
4158 flags
|= FLAG_NR_AR_ATTACK
;
4161 if (arg_get_lit(ctx
, 11)) {
4162 flags
|= FLAG_NESTED_AUTH_ATTACK
;
4165 bool setEmulatorMem
= arg_get_lit(ctx
, 12);
4167 if (arg_get_lit(ctx
, 13)) {
4168 flags
|= FLAG_MF_USE_READ_KEYB
;
4171 bool verbose
= arg_get_lit(ctx
, 14);
4173 if (arg_get_lit(ctx
, 15)) {
4174 flags
|= FLAG_CVE21_0430
;
4181 PrintAndLogEx(WARNING
, "Wrong ATQA length");
4184 flags
|= FLAG_ATQA_IN_DATA
;
4189 PrintAndLogEx(WARNING
, "Wrong SAK length");
4192 flags
|= FLAG_SAK_IN_DATA
;
4195 size_t k_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4196 char csize
[13] = { 0 };
4198 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4199 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4204 FLAG_SET_MF_SIZE(flags
, MIFARE_MINI_MAX_BYTES
);
4205 snprintf(csize
, sizeof(csize
), "MINI");
4206 k_sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
4208 FLAG_SET_MF_SIZE(flags
, MIFARE_1K_MAX_BYTES
);
4209 snprintf(csize
, sizeof(csize
), "1K");
4210 k_sectors_cnt
= MIFARE_1K_MAXSECTOR
;
4212 FLAG_SET_MF_SIZE(flags
, MIFARE_2K_MAX_BYTES
);
4213 snprintf(csize
, sizeof(csize
), "2K with RATS");
4214 k_sectors_cnt
= MIFARE_2K_MAXSECTOR
;
4216 FLAG_SET_MF_SIZE(flags
, MIFARE_4K_MAX_BYTES
);
4217 snprintf(csize
, sizeof(csize
), "4K");
4218 k_sectors_cnt
= MIFARE_4K_MAXSECTOR
;
4220 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4224 if ((flags
& FLAG_NESTED_AUTH_ATTACK
) == FLAG_NESTED_AUTH_ATTACK
) {
4225 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
) {
4226 PrintAndLogEx(INFO
, "Note: option -y implies -x");
4227 flags
|= FLAG_NR_AR_ATTACK
;
4231 if (setEmulatorMem
) {
4232 if ((flags
& FLAG_INTERACTIVE
) != FLAG_INTERACTIVE
) {
4233 PrintAndLogEx(INFO
, "Note: option -e implies -i");
4234 flags
|= FLAG_INTERACTIVE
;
4236 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
) {
4237 PrintAndLogEx(WARNING
, "Option -e requires -x or -y");
4242 PrintAndLogEx(INFO
, _YELLOW_("MIFARE %s") " | %i bytes UID " _YELLOW_("%s") ""
4245 , (uidlen
== 0) ? "n/a" : sprint_hex(uid
, uidlen
)
4248 PrintAndLogEx(INFO
, "Options [ numreads: %d, flags: 0x%04x ]"
4260 payload
.flags
= flags
;
4261 payload
.exitAfter
= exitAfterNReads
;
4262 memcpy(payload
.uid
, uid
, uidlen
);
4263 payload
.atqa
= (atqa
[1] << 8) | atqa
[0];
4264 payload
.sak
= sak
[0];
4266 clearCommandBuffer();
4268 if (flags
& FLAG_INTERACTIVE
) {
4269 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " or a key to abort simulation");
4271 PrintAndLogEx(INFO
, "Press " _GREEN_("pm3 button") " or send another cmd to abort simulation");
4276 SendCommandNG(CMD_HF_MIFARE_SIMULATE
, (uint8_t *)&payload
, sizeof(payload
));
4277 if (flags
& FLAG_INTERACTIVE
) {
4278 PacketResponseNG resp
;
4279 sector_t
*k_sector
= NULL
;
4281 bool keypress
= kbd_enter_pressed();
4282 while (keypress
== false) {
4284 if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE
, &resp
, 1500) == 0) {
4285 keypress
= kbd_enter_pressed();
4289 if (resp
.status
!= PM3_SUCCESS
)
4292 if ((flags
& FLAG_NR_AR_ATTACK
) != FLAG_NR_AR_ATTACK
)
4295 const nonces_t
*data
= (nonces_t
*)resp
.data
.asBytes
;
4296 readerAttack(k_sector
, k_sectors_cnt
, data
[0], setEmulatorMem
, verbose
);
4297 if (setEmulatorMem
) {
4303 if ((flags
& FLAG_NR_AR_ATTACK
) == FLAG_NR_AR_ATTACK
) {
4304 // inform device to break the sim loop since client has exited
4305 PrintAndLogEx(INFO
, "Key pressed, please wait a few seconds for the pm3 to stop...");
4306 SendCommandNG(CMD_BREAK_LOOP
, NULL
, 0);
4316 static int CmdHF14AMfKeyBrute(const char *Cmd) {
4318 uint8_t blockNo = 0, keytype = MF_KEY_A;
4319 uint8_t key[6] = {0, 0, 0, 0, 0, 0};
4320 uint64_t foundkey = 0;
4322 char cmdp = tolower(param_getchar(Cmd, 0));
4323 if (cmdp == 'h') return usage_hf14_keybrute();
4326 blockNo = param_get8(Cmd, 0);
4329 cmdp = tolower(param_getchar(Cmd, 1));
4330 if (cmdp == 'b') keytype = MF_KEY_B;
4334 if (param_gethex_ex(Cmd, 2, key, &keylen) && (keylen != 12)) {
4335 return usage_hf14_keybrute();
4338 uint64_t t1 = msclock();
4340 if (mfKeyBrute(blockNo, keytype, key, &foundkey))
4341 PrintAndLogEx(SUCCESS, "found valid key: %012" PRIx64 " \n", foundkey);
4343 PrintAndLogEx(FAILED, "key not found");
4345 t1 = msclock() - t1;
4346 PrintAndLogEx(SUCCESS, "\ntime in keybrute " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
4351 void printKeyTable(size_t sectorscnt
, sector_t
*e_sector
) {
4352 printKeyTableEx(sectorscnt
, e_sector
, 0);
4355 void printKeyTableEx(size_t sectorscnt
, sector_t
*e_sector
, uint8_t start_sector
) {
4356 char strA
[26 + 1] = {0};
4357 char strB
[26 + 1] = {0};
4358 char resA
[20 + 1] = {0};
4359 char resB
[20 + 1] = {0};
4361 uint64_t ndef_key
= 0xD3F7D3F7D3F7;
4362 bool has_ndef_key
= false;
4363 bool extended_legend
= false;
4365 PrintAndLogEx(NORMAL
, "");
4366 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4367 PrintAndLogEx(SUCCESS
, " Sec | Blk | key A |res| key B |res");
4368 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4370 for (size_t i
= 0; i
< sectorscnt
; i
++) {
4372 if ((e_sector
[i
].foundKey
[0] > 1) || (e_sector
[i
].foundKey
[1] > 1)) {
4373 extended_legend
= true;
4376 if (e_sector
[i
].Key
[0] == ndef_key
|| e_sector
[i
].Key
[1] == ndef_key
) {
4377 has_ndef_key
= true;
4380 if (e_sector
[i
].foundKey
[0]) {
4381 snprintf(strA
, sizeof(strA
), _GREEN_("%012" PRIX64
), e_sector
[i
].Key
[0]);
4382 if (extended_legend
) {
4383 snprintf(resA
, sizeof(resA
), _BRIGHT_GREEN_("%c"), e_sector
[i
].foundKey
[0]);
4385 snprintf(resA
, sizeof(resA
), _BRIGHT_GREEN_("%d"), e_sector
[i
].foundKey
[0]);
4388 snprintf(strA
, sizeof(strA
), _RED_("%s"), "------------");
4389 snprintf(resA
, sizeof(resA
), _RED_("0"));
4392 if (e_sector
[i
].foundKey
[1]) {
4393 snprintf(strB
, sizeof(strB
), _GREEN_("%012" PRIX64
), e_sector
[i
].Key
[1]);
4394 if (extended_legend
) {
4395 snprintf(resB
, sizeof(resB
), _BRIGHT_GREEN_("%c"), e_sector
[i
].foundKey
[1]);
4397 snprintf(resB
, sizeof(resB
), _BRIGHT_GREEN_("%d"), e_sector
[i
].foundKey
[1]);
4400 snprintf(strB
, sizeof(strB
), _RED_("%s"), "------------");
4401 snprintf(resB
, sizeof(resB
), _RED_("0"));
4404 // keep track if we use start_sector or i
4405 // show one sector or all.
4406 uint8_t s
= start_sector
;
4407 if (start_sector
== 0) {
4411 char extra
[24] = {0x00};
4412 if (sectorscnt
== 18 && i
> 15) {
4413 strcat(extra
, "( " _MAGENTA_("*") " )");
4416 PrintAndLogEx(SUCCESS
, " " _YELLOW_("%03d") " | %03d | %s | %s | %s | %s %s"
4418 , mfSectorTrailerOfSector(s
)
4425 PrintAndLogEx(SUCCESS
, "-----+-----+--------------+---+--------------+----");
4427 if (extended_legend
) {
4428 PrintAndLogEx(INFO
, "( "
4429 _YELLOW_("D") ":Dictionary / "
4430 _YELLOW_("S") ":darkSide / "
4431 _YELLOW_("U") ":User / "
4432 _YELLOW_("R") ":Reused / "
4433 _YELLOW_("N") ":Nested / "
4434 _YELLOW_("H") ":Hardnested / "
4435 _YELLOW_("C") ":statiCnested / "
4436 _YELLOW_("A") ":keyA "
4439 if (sectorscnt
== 18) {
4440 PrintAndLogEx(INFO
, "( " _MAGENTA_("*") " ) These sectors used for signature. Lays outside of user memory");
4444 PrintAndLogEx(SUCCESS
, "( " _RED_("0") ":Failed / " _GREEN_("1") ":Success )");
4448 if (e_sector
[MF_MAD1_SECTOR
].foundKey
[0] && e_sector
[MF_MAD1_SECTOR
].Key
[0] == 0xA0A1A2A3A4A5) {
4449 PrintAndLogEx(HINT
, "MAD key detected. Try " _YELLOW_("`hf mf mad`") " for more details");
4453 PrintAndLogEx(HINT
, "NDEF key detected. Try " _YELLOW_("`hf mf ndefread`") " for more details");
4455 PrintAndLogEx(NORMAL
, "");
4459 // EMULATOR COMMANDS
4460 static int CmdHF14AMfEGetBlk(const char *Cmd
) {
4461 CLIParserContext
*ctx
;
4462 CLIParserInit(&ctx
, "hf mf egetblk",
4463 "Get emulator memory block",
4464 "hf mf egetblk --blk 0 -> get block 0 (manufacturer)\n"
4465 "hf mf egetblk --blk 3 -v -> get block 3, decode sector trailer\n"
4467 void *argtable
[] = {
4469 arg_int1("b", "blk", "<dec>", "block number"),
4470 arg_lit0("v", "verbose", "verbose output"),
4473 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4474 int b
= arg_get_int_def(ctx
, 1, 0);
4475 bool verbose
= arg_get_lit(ctx
, 2);
4481 uint8_t blockno
= (uint8_t)b
;
4483 uint8_t data
[16] = {0x00};
4484 if (mf_eml_get_mem(data
, blockno
, 1) == PM3_SUCCESS
) {
4486 uint8_t sector
= mfSectorNum(blockno
);
4487 mf_print_sector_hdr(sector
);
4488 mf_print_block_one(blockno
, data
, verbose
);
4491 decode_print_st(blockno
, data
);
4493 PrintAndLogEx(NORMAL
, "");
4498 static int CmdHF14AMfEGetSc(const char *Cmd
) {
4499 CLIParserContext
*ctx
;
4500 CLIParserInit(&ctx
, "hf mf egetsc",
4501 "Get emulator memory sector",
4504 void *argtable
[] = {
4506 arg_int1("s", "sec", "<dec>", "sector number"),
4507 arg_lit0("v", "verbose", "verbose output"),
4510 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4511 int s
= arg_get_int_def(ctx
, 1, 0);
4512 bool verbose
= arg_get_lit(ctx
, 2);
4515 if (s
>= MIFARE_4K_MAXSECTOR
) {
4516 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
4520 uint8_t sector
= (uint8_t)s
;
4521 mf_print_sector_hdr(sector
);
4523 uint8_t blocks
= mfNumBlocksPerSector(sector
);
4524 uint8_t start
= mfFirstBlockOfSector(sector
);
4526 uint8_t data
[16] = {0};
4527 for (int i
= 0; i
< blocks
; i
++) {
4528 int res
= mf_eml_get_mem(data
, start
+ i
, 1);
4529 if (res
== PM3_SUCCESS
) {
4530 mf_print_block_one(start
+ i
, data
, verbose
);
4534 decode_print_st(start
+ blocks
- 1, data
);
4536 PrintAndLogEx(NORMAL
, "");
4541 static int CmdHF14AMfEClear(const char *Cmd
) {
4542 CLIParserContext
*ctx
;
4543 CLIParserInit(&ctx
, "hf mf eclr",
4544 "It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF",
4547 void *argtable
[] = {
4551 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4553 clearCommandBuffer();
4554 SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR
, NULL
, 0);
4558 static int CmdHF14AMfESet(const char *Cmd
) {
4560 CLIParserContext
*ctx
;
4561 CLIParserInit(&ctx
, "hf mf esetblk",
4562 "Set emulator memory block",
4563 "hf mf esetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
4565 void *argtable
[] = {
4567 arg_int1("b", "blk", "<dec>", "block number"),
4568 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
4571 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4573 int b
= arg_get_int_def(ctx
, 1, 0);
4575 uint8_t data
[16] = {0x00};
4577 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), data
, sizeof(data
), &datalen
);
4580 PrintAndLogEx(FAILED
, "Error parsing bytes");
4588 if (datalen
!= sizeof(data
)) {
4589 PrintAndLogEx(WARNING
, "block data must include 16 HEX bytes. Got %i", datalen
);
4594 return mf_elm_set_mem(data
, b
, 1);
4597 int CmdHF14AMfELoad(const char *Cmd
) {
4599 CLIParserContext
*ctx
;
4600 CLIParserInit(&ctx
, "hf mf eload",
4601 "Load emulator memory with data from (bin/eml/json) dump file",
4602 "hf mf eload -f hf-mf-01020304.bin\n"
4603 "hf mf eload --4k -f hf-mf-01020304.eml\n"
4605 void *argtable
[] = {
4607 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
4608 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4609 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4610 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4611 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4612 arg_lit0(NULL
, "ul", "MIFARE Ultralight family"),
4613 arg_lit0("m", "mem", "use RDV4 spiffs"),
4614 arg_int0("q", "qty", "<dec>", "manually set number of blocks (overrides)"),
4615 arg_lit0("v", "verbose", "verbose output"),
4618 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
4621 char filename
[FILE_PATH_SIZE
];
4622 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
4624 bool m0
= arg_get_lit(ctx
, 2);
4625 bool m1
= arg_get_lit(ctx
, 3);
4626 bool m2
= arg_get_lit(ctx
, 4);
4627 bool m4
= arg_get_lit(ctx
, 5);
4628 bool mu
= arg_get_lit(ctx
, 6);
4630 bool use_spiffs
= arg_get_lit(ctx
, 7);
4631 int numblks
= arg_get_int_def(ctx
, 8, -1);
4632 bool verbose
= arg_get_lit(ctx
, 9);
4636 if ((m0
+ m1
+ m2
+ m4
+ mu
) > 1) {
4637 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4639 } else if ((m0
+ m1
+ m2
+ m4
+ mu
) == 0) {
4643 uint8_t block_width
= 16;
4644 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4645 uint8_t hdr_len
= 0;
4648 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4650 block_cnt
= MIFARE_1K_MAXBLOCK
;
4652 block_cnt
= MIFARE_2K_MAXBLOCK
;
4654 block_cnt
= MIFARE_4K_MAXBLOCK
;
4656 block_cnt
= MFU_MAX_BLOCKS
;
4657 block_width
= MFU_BLOCK_SIZE
;
4658 hdr_len
= MFU_DUMP_PREFIX_LENGTH
;
4660 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4664 PrintAndLogEx(INFO
, "Upload " _YELLOW_("%u") " blocks " _YELLOW_("%u") " bytes", block_cnt
, block_cnt
* block_width
);
4667 block_cnt
= MIN(numblks
, block_cnt
);
4668 PrintAndLogEx(INFO
, "overriding number of blocks, will use " _YELLOW_("%u") " blocks " _YELLOW_("%u") " bytes", block_cnt
, block_cnt
* block_width
);
4671 // ICEMAN: bug. if device has been using ICLASS commands,
4672 // the device needs to load the HF fpga image. It takes 1.5 second.
4673 set_fpga_mode(FPGA_BITSTREAM_HF
);
4676 if (use_spiffs
&& IfPm3Flash() == false) {
4677 PrintAndLogEx(WARNING
, "Device not compiled to support spiffs");
4684 PrintAndLogEx(WARNING
, "filename too long for spiffs, expected 32, got %u", fnlen
);
4688 clearCommandBuffer();
4689 SendCommandNG(CMD_SPIFFS_ELOAD
, (uint8_t *)filename
, fnlen
);
4690 PacketResponseNG resp
;
4691 if (WaitForResponseTimeout(CMD_SPIFFS_ELOAD
, &resp
, 2000) == false) {
4692 PrintAndLogEx(WARNING
, "timeout while waiting for reply.");
4693 return PM3_ETIMEOUT
;
4696 if (resp
.status
!= PM3_SUCCESS
) {
4697 PrintAndLogEx(FAILED
, "Loading file from spiffs to emulator memory failed");
4701 PrintAndLogEx(SUCCESS
, "File transfered from spiffs to device emulator memory");
4705 uint8_t *data
= NULL
;
4706 size_t bytes_read
= 0;
4707 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (block_width
* block_cnt
+ hdr_len
));
4708 if (res
!= PM3_SUCCESS
) {
4712 // 64 or 256 blocks.
4713 if ((bytes_read
% block_width
) != 0) {
4714 PrintAndLogEx(FAILED
, "File content error. Size doesn't match blockwidth ");
4719 // convert plain or old mfu format to new format
4720 if (block_width
== MFU_BLOCK_SIZE
) {
4721 res
= convert_mfu_dump_format(&data
, &bytes_read
, true);
4722 if (res
!= PM3_SUCCESS
) {
4723 PrintAndLogEx(FAILED
, "Failed convert on load to new Ultralight/NTAG format");
4729 mfu_dump_t
*mfu_dump
= (mfu_dump_t
*)data
;
4730 mfu_print_dump(mfu_dump
, mfu_dump
->pages
+ 1, 0, false);
4733 // update expected blocks to match converted data.
4734 block_cnt
= bytes_read
/ MFU_BLOCK_SIZE
;
4735 PrintAndLogEx(INFO
, "MIFARE Ultralight override, will use %d blocks ( %u bytes )", block_cnt
, block_cnt
* block_width
);
4738 PrintAndLogEx(INFO
, "Uploading to emulator memory");
4739 PrintAndLogEx(INFO
, "." NOLF
);
4742 g_conn
.block_after_ACK
= true;
4747 // 12 is the size of the struct the fct mf_eml_set_mem_xt uses to transfer to device
4748 uint16_t max_avail_blocks
= ((PM3_CMD_DATA_SIZE
- 12) / block_width
) * block_width
;
4750 while (bytes_read
&& cnt
< block_cnt
) {
4751 if (bytes_read
== block_width
) {
4752 // Disable fast mode on last packet
4753 g_conn
.block_after_ACK
= false;
4756 uint16_t chunk_size
= MIN(max_avail_blocks
, bytes_read
);
4757 uint16_t blocks_to_send
= chunk_size
/ block_width
;
4759 if (mf_eml_set_mem_xt(data
+ offset
, cnt
, blocks_to_send
, block_width
) != PM3_SUCCESS
) {
4760 PrintAndLogEx(FAILED
, "Can't set emulator mem at block: %3d", cnt
);
4764 cnt
+= blocks_to_send
;
4765 offset
+= chunk_size
;
4766 bytes_read
-= chunk_size
;
4767 PrintAndLogEx(NORMAL
, "." NOLF
);
4771 PrintAndLogEx(NORMAL
, "");
4773 if (block_width
== MFU_BLOCK_SIZE
) {
4774 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mfu sim -h`"));
4776 if ((cnt
!= block_cnt
)) {
4777 PrintAndLogEx(WARNING
, "Warning, Ultralight/Ntag file content, Loaded %d blocks of expected %d blocks into emulator memory", cnt
, block_cnt
);
4781 PrintAndLogEx(HINT
, "You are ready to simulate. See " _YELLOW_("`hf mf sim -h`"));
4783 if ((cnt
!= block_cnt
)) {
4784 PrintAndLogEx(WARNING
, "Error, file content, Only loaded %d blocks, must be %d blocks into emulator memory", cnt
, block_cnt
);
4787 PrintAndLogEx(INFO
, "Done!");
4792 static int CmdHF14AMfESave(const char *Cmd
) {
4794 CLIParserContext
*ctx
;
4795 CLIParserInit(&ctx
, "hf mf esave",
4796 "Save emulator memory to file (bin/json) ",
4798 "hf mf esave --4k\n"
4799 "hf mf esave --4k -f hf-mf-01020304.eml"
4801 void *argtable
[] = {
4803 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
4804 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4805 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4806 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4807 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4810 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4813 char filename
[FILE_PATH_SIZE
];
4814 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
4816 bool m0
= arg_get_lit(ctx
, 2);
4817 bool m1
= arg_get_lit(ctx
, 3);
4818 bool m2
= arg_get_lit(ctx
, 4);
4819 bool m4
= arg_get_lit(ctx
, 5);
4823 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4824 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4826 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4830 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4833 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4835 block_cnt
= MIFARE_1K_MAXBLOCK
;
4837 block_cnt
= MIFARE_2K_MAXBLOCK
;
4839 block_cnt
= MIFARE_4K_MAXBLOCK
;
4842 int bytes
= block_cnt
* MFBLOCK_SIZE
;
4845 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4847 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
4850 memset(dump
, 0, bytes
);
4852 PrintAndLogEx(INFO
, "downloading %u bytes from emulator memory", bytes
);
4853 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
4854 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
4856 return PM3_ETIMEOUT
;
4859 // user supplied filename?
4861 char *fptr
= filename
;
4862 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
4863 FillFileNameByUID(fptr
, dump
, "-dump", 4);
4866 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
4871 static int CmdHF14AMfEView(const char *Cmd
) {
4873 CLIParserContext
*ctx
;
4874 CLIParserInit(&ctx
, "hf mf eview",
4875 "It displays emulator memory",
4879 void *argtable
[] = {
4881 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4882 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4883 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4884 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4885 arg_lit0("v", "verbose", "verbose output"),
4886 arg_lit0(NULL
, "sk", "Save extracted keys to binary file"),
4889 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4890 bool m0
= arg_get_lit(ctx
, 1);
4891 bool m1
= arg_get_lit(ctx
, 2);
4892 bool m2
= arg_get_lit(ctx
, 3);
4893 bool m4
= arg_get_lit(ctx
, 4);
4894 bool verbose
= arg_get_lit(ctx
, 5);
4895 bool save_keys
= arg_get_lit(ctx
, 6);
4899 if ((m0
+ m1
+ m2
+ m4
) > 1) {
4900 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
4902 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
4906 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
4909 block_cnt
= MIFARE_MINI_MAXBLOCK
;
4911 block_cnt
= MIFARE_1K_MAXBLOCK
;
4913 block_cnt
= MIFARE_2K_MAXBLOCK
;
4915 block_cnt
= MIFARE_4K_MAXBLOCK
;
4917 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
4921 int bytes
= block_cnt
* MFBLOCK_SIZE
;
4923 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
4925 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
4929 PrintAndLogEx(INFO
, "downloading emulator memory");
4930 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
4931 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
4933 return PM3_ETIMEOUT
;
4936 mf_print_blocks(block_cnt
, dump
, verbose
);
4939 mf_print_keys(block_cnt
, dump
);
4943 mf_save_keys_from_arr(block_cnt
, dump
);
4950 static int CmdHF14AMfECFill(const char *Cmd
) {
4952 CLIParserContext
*ctx
;
4953 CLIParserInit(&ctx
, "hf mf ecfill",
4954 "Dump card and transfer the data to emulator memory.\n"
4955 "Keys must be in the emulator memory",
4956 "hf mf ecfill --> use key type A\n"
4957 "hf mf ecfill --4k -b --> target 4K card with key type B"
4959 void *argtable
[] = {
4961 arg_lit0("a", NULL
, "input key type is key A(def)"),
4962 arg_lit0("b", NULL
, "input key type is key B"),
4963 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
4964 arg_str0("k", "key", "<hex>", "key, 6 hex bytes, only for option -c"),
4965 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
4966 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
4967 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
4968 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
4971 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
4972 uint8_t keytype
= MF_KEY_A
;
4973 if (arg_get_lit(ctx
, 1) && arg_get_lit(ctx
, 2)) {
4975 PrintAndLogEx(WARNING
, "Choose one single input key type");
4977 } else if (arg_get_lit(ctx
, 2)) {
4980 uint8_t prev_keytype
= keytype
;
4981 keytype
= arg_get_int_def(ctx
, 3, keytype
);
4982 if ((arg_get_lit(ctx
, 1) || arg_get_lit(ctx
, 2)) && (keytype
!= prev_keytype
)) {
4984 PrintAndLogEx(WARNING
, "Choose one single input key type");
4988 uint8_t key
[6] = {0};
4989 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
4990 if ((keytype
> MF_KEY_B
) && (keylen
!= 6)) {
4991 PrintAndLogEx(WARNING
, "Missing key");
4994 if ((keytype
<= MF_KEY_B
) && (keylen
> 0)) {
4995 PrintAndLogEx(WARNING
, "Ignoring provided key");
4998 bool m0
= arg_get_lit(ctx
, 5);
4999 bool m1
= arg_get_lit(ctx
, 6);
5000 bool m2
= arg_get_lit(ctx
, 7);
5001 bool m4
= arg_get_lit(ctx
, 8);
5005 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5006 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5008 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5012 uint8_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5015 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
5017 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5019 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
5021 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
5023 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5027 mfc_eload_t payload
= {
5028 .sectorcnt
= sectors_cnt
,
5031 memcpy(payload
.key
, key
, sizeof(payload
.key
));
5033 clearCommandBuffer();
5034 uint64_t t1
= msclock();
5035 SendCommandNG(CMD_HF_MIFARE_EML_LOAD
, (uint8_t *)&payload
, sizeof(payload
));
5037 PacketResponseNG resp
;
5038 if (WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD
, &resp
, 1500) == false) {
5039 PrintAndLogEx(WARNING
, "command execution time out");
5040 return PM3_ETIMEOUT
;
5042 t1
= msclock() - t1
;
5044 if (resp
.status
== PM3_SUCCESS
)
5045 PrintAndLogEx(SUCCESS
, "Fill ( " _GREEN_("ok") " ) in " _YELLOW_("%" PRIu64
) " ms", t1
);
5047 PrintAndLogEx(FAILED
, "Fill ( " _RED_("fail") " )");
5052 static int CmdHF14AMfEKeyPrn(const char *Cmd
) {
5054 CLIParserContext
*ctx
;
5055 CLIParserInit(&ctx
, "hf mf ekeyprn",
5056 "Download and print the keys from emulator memory",
5057 "hf mf ekeyprn --1k --> print MFC 1K keyset\n"
5058 "hf mf ekeyprn -w --> write keys to binary file"
5060 void *argtable
[] = {
5062 arg_lit0("w", "write", "write keys to binary file `hf-mf-<UID>-key.bin`"),
5063 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5064 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5065 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5066 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5069 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5071 bool create_dumpfile
= arg_get_lit(ctx
, 1);
5072 bool m0
= arg_get_lit(ctx
, 2);
5073 bool m1
= arg_get_lit(ctx
, 3);
5074 bool m2
= arg_get_lit(ctx
, 4);
5075 bool m4
= arg_get_lit(ctx
, 5);
5079 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5080 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5082 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5086 size_t sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5089 sectors_cnt
= MIFARE_MINI_MAXSECTOR
;
5091 sectors_cnt
= MIFARE_1K_MAXSECTOR
;
5093 sectors_cnt
= MIFARE_2K_MAXSECTOR
;
5095 sectors_cnt
= MIFARE_4K_MAXSECTOR
;
5097 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5101 // create/initialize key storage structure
5102 sector_t
*e_sector
= NULL
;
5103 if (initSectorTable(&e_sector
, sectors_cnt
) != PM3_SUCCESS
) {
5107 // read UID from EMUL
5109 if (mf_eml_get_mem(data
, 0, 1) != PM3_SUCCESS
) {
5110 PrintAndLogEx(WARNING
, "error get block 0");
5115 // assuming 4byte UID.
5117 memcpy(uid
, data
, sizeof(uid
));
5119 // download keys from EMUL
5120 for (int i
= 0; i
< sectors_cnt
; i
++) {
5122 if (mf_eml_get_mem(data
, mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1, 1) != PM3_SUCCESS
) {
5123 PrintAndLogEx(WARNING
, "error get block %d", mfFirstBlockOfSector(i
) + mfNumBlocksPerSector(i
) - 1);
5124 e_sector
[i
].foundKey
[0] = false;
5125 e_sector
[i
].foundKey
[1] = false;
5127 e_sector
[i
].foundKey
[0] = true;
5128 e_sector
[i
].Key
[0] = bytes_to_num(data
, 6);
5129 e_sector
[i
].foundKey
[1] = true;
5130 e_sector
[i
].Key
[1] = bytes_to_num(data
+ 10, 6);
5135 printKeyTable(sectors_cnt
, e_sector
);
5138 if (create_dumpfile
) {
5140 char filename
[FILE_PATH_SIZE
] = {0};
5141 char *fptr
= filename
;
5142 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
5143 FillFileNameByUID(fptr
+ strlen(fptr
), uid
, "-key", sizeof(uid
));
5144 createMfcKeyDump(filename
, sectors_cnt
, e_sector
);
5151 // CHINESE MAGIC COMMANDS
5152 static int CmdHF14AMfCSetUID(const char *Cmd
) {
5154 CLIParserContext
*ctx
;
5155 CLIParserInit(&ctx
, "hf mf csetuid",
5156 "Set UID, ATQA, and SAK for magic gen1a card",
5157 "hf mf csetuid -u 01020304\n"
5158 "hf mf csetuid -w -u 01020304 --atqa 0004 --sak 08"
5160 void *argtable
[] = {
5162 arg_lit0("w", "wipe", "wipes card with backdoor cmd`"),
5163 arg_str0("u", "uid", "<hex>", "UID, 4/7 hex bytes"),
5164 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
5165 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
5166 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5169 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5171 uint8_t wipe_card
= arg_get_lit(ctx
, 1);
5174 uint8_t uid
[7] = {0x00};
5175 CLIGetHexWithReturn(ctx
, 2, uid
, &uidlen
);
5178 uint8_t atqa
[2] = {0x00};
5179 CLIGetHexWithReturn(ctx
, 3, atqa
, &alen
);
5182 uint8_t sak
[1] = {0x00};
5183 CLIGetHexWithReturn(ctx
, 4, sak
, &slen
);
5184 uint8_t gdm
= arg_get_lit(ctx
, 5);
5188 if (uidlen
!= 4 && uidlen
!= 7) {
5189 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
5192 if (alen
&& alen
!= 2) {
5193 PrintAndLogEx(FAILED
, "ATQA must be 2 hex bytes. Got %d", alen
);
5196 if (slen
&& slen
!= 1) {
5197 PrintAndLogEx(FAILED
, "SAK must be 1 hex byte. Got %d", slen
);
5201 uint8_t old_uid
[7] = {0};
5202 uint8_t verify_uid
[7] = {0};
5204 int res
= mf_chinese_set_uid(
5207 (alen
) ? atqa
: NULL
,
5208 (slen
) ? sak
: NULL
,
5216 PrintAndLogEx(ERR
, "Can't set UID. error %d", res
);
5220 res
= memcmp(uid
, verify_uid
, uidlen
);
5222 PrintAndLogEx(SUCCESS
, "Old UID... %s", sprint_hex(old_uid
, uidlen
));
5223 PrintAndLogEx(SUCCESS
, "New UID... %s ( %s )",
5224 sprint_hex(verify_uid
, uidlen
),
5225 (res
== 0) ? _GREEN_("verified") : _RED_("fail")
5230 static int CmdHF14AMfCWipe(const char *cmd
) {
5231 CLIParserContext
*ctx
;
5232 CLIParserInit(&ctx
, "hf mf cwipe",
5233 "Wipe gen1 magic chinese card.\n"
5234 "Set UID / ATQA / SAK / Data / Keys / Access to default values",
5236 "hf mf cwipe -u 09080706 -a 0004 -s 18 --> set UID, ATQA and SAK and wipe card");
5238 void *argtable
[] = {
5240 arg_str0("u", "uid", "<hex>", "UID, 4 hex bytes"),
5241 arg_str0("a", "atqa", "<hex>", "ATQA, 2 hex bytes"),
5242 arg_str0("s", "sak", "<hex>", "SAK, 1 hex byte"),
5243 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5246 CLIExecWithReturn(ctx
, cmd
, argtable
, true);
5249 uint8_t uid
[8] = {0x00};
5250 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
5253 uint8_t atqa
[2] = {0x00};
5254 CLIGetHexWithReturn(ctx
, 2, atqa
, &alen
);
5257 uint8_t sak
[1] = {0x00};
5258 CLIGetHexWithReturn(ctx
, 3, sak
, &slen
);
5259 uint8_t gdm
= arg_get_lit(ctx
, 4);
5262 if (uidlen
&& uidlen
!= 4) {
5263 PrintAndLogEx(ERR
, "UID length must be 4 bytes, got %d", uidlen
);
5266 if (alen
&& alen
!= 2) {
5267 PrintAndLogEx(ERR
, "ATQA length must be 2 bytes, got %d", alen
);
5270 if (slen
&& slen
!= 1) {
5271 PrintAndLogEx(ERR
, "SAK length must be 1 byte, got %d", slen
);
5275 int res
= mf_chinese_wipe((uidlen
) ? uid
: NULL
, (alen
) ? atqa
: NULL
, (slen
) ? sak
: NULL
, gdm
);
5277 PrintAndLogEx(ERR
, "Can't wipe card. error %d", res
);
5281 PrintAndLogEx(SUCCESS
, "Card wiped successfully");
5285 static int CmdHF14AMfCSetBlk(const char *Cmd
) {
5287 CLIParserContext
*ctx
;
5288 CLIParserInit(&ctx
, "hf mf csetblk",
5289 "Set block data on a magic gen1a card",
5290 "hf mf csetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
5292 void *argtable
[] = {
5294 arg_int1("b", "blk", "<dec>", "block number"),
5295 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
5296 arg_lit0("w", "wipe", "wipes card with backdoor cmd before writing"),
5297 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5300 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5302 int b
= arg_get_int_def(ctx
, 1, -1);
5304 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
5306 CLIGetHexWithReturn(ctx
, 2, data
, &datalen
);
5308 uint8_t wipe_card
= arg_get_lit(ctx
, 3);
5309 uint8_t gdm
= arg_get_lit(ctx
, 4);
5312 if (b
< 0 || b
>= MIFARE_1K_MAXBLOCK
) {
5313 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
5317 if (datalen
!= MFBLOCK_SIZE
) {
5318 PrintAndLogEx(FAILED
, "expected 16 bytes data, got %i", datalen
);
5322 uint8_t params
= MAGIC_SINGLE
;
5324 params
|= MAGIC_GDM_ALT_WUPC
;
5326 params
|= MAGIC_WUPC
;
5330 params
|= MAGIC_WIPE
;
5333 PrintAndLogEx(INFO
, "Writing block number:%2d data:%s", b
, sprint_hex_inrow(data
, sizeof(data
)));
5335 int res
= mf_chinese_set_block(b
, data
, NULL
, params
);
5337 PrintAndLogEx(ERR
, "Can't write block. error=%d", res
);
5343 static int CmdHF14AMfCLoad(const char *Cmd
) {
5345 CLIParserContext
*ctx
;
5346 CLIParserInit(&ctx
, "hf mf cload",
5347 "Load magic gen1a card with data from (bin/eml/json) dump file\n"
5348 "or from emulator memory.",
5349 "hf mf cload --emu\n"
5350 "hf mf cload -f hf-mf-01020304.eml\n"
5352 void *argtable
[] = {
5354 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
5355 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5356 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5357 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5358 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5359 arg_lit0(NULL
, "emu", "from emulator memory"),
5360 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5363 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5366 char filename
[FILE_PATH_SIZE
] = {0};
5367 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5369 bool m0
= arg_get_lit(ctx
, 2);
5370 bool m1
= arg_get_lit(ctx
, 3);
5371 bool m2
= arg_get_lit(ctx
, 4);
5372 bool m4
= arg_get_lit(ctx
, 5);
5373 bool fill_from_emulator
= arg_get_lit(ctx
, 6);
5374 bool gdm
= arg_get_lit(ctx
, 7);
5378 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5379 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5381 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5386 memset(s
, 0, sizeof(s
));
5387 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5389 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5390 strncpy(s
, "Mini", 5);
5392 block_cnt
= MIFARE_1K_MAXBLOCK
;
5393 strncpy(s
, "1K", 3);
5395 block_cnt
= MIFARE_2K_MAXBLOCK
;
5396 strncpy(s
, "2K", 3);
5398 block_cnt
= MIFARE_4K_MAXBLOCK
;
5399 strncpy(s
, "4K", 3);
5401 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5406 if (fill_from_emulator
) {
5408 PrintAndLogEx(INFO
, "Start upload from emulator memory");
5409 PrintAndLogEx(INFO
, "." NOLF
);
5411 for (int b
= 0; b
< block_cnt
; b
++) {
5413 uint8_t buf8
[MFBLOCK_SIZE
] = {0x00};
5415 // read from emul memory
5416 if (mf_eml_get_mem(buf8
, b
, 1)) {
5417 PrintAndLogEx(WARNING
, "Can't read from emul block: %d", b
);
5421 // switch on field and send magic sequence
5423 flags
= MAGIC_INIT
| (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
);
5431 // Done. Magic Halt and switch off field.
5432 if (b
== (block_cnt
- 1)) {
5433 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5437 if (mf_chinese_set_block(b
, buf8
, NULL
, flags
)) {
5438 PrintAndLogEx(WARNING
, "Can't set magic card block: %d", b
);
5441 PrintAndLogEx(NORMAL
, "." NOLF
);
5444 PrintAndLogEx(NORMAL
, "");
5449 uint8_t *data
= NULL
;
5450 size_t bytes_read
= 0;
5451 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (MFBLOCK_SIZE
* block_cnt
));
5452 if (res
!= PM3_SUCCESS
) {
5456 if (bytes_read
!= (block_cnt
* MFBLOCK_SIZE
)) {
5457 PrintAndLogEx(ERR
, "File content error. Read %zu bytes", bytes_read
);
5462 PrintAndLogEx(INFO
, "Copying to magic gen1a card");
5463 PrintAndLogEx(INFO
, "." NOLF
);
5467 while (bytes_read
) {
5469 // switch on field and send magic sequence
5471 flags
= MAGIC_INIT
| (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
);
5480 if (blockno
== (block_cnt
- 1)) {
5481 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5484 if (mf_chinese_set_block(blockno
, data
+ (MFBLOCK_SIZE
* blockno
), NULL
, flags
)) {
5485 PrintAndLogEx(WARNING
, "Can't set magic card block: %d", blockno
);
5490 bytes_read
-= MFBLOCK_SIZE
;
5492 PrintAndLogEx(NORMAL
, "." NOLF
);
5497 if (blockno
>= block_cnt
) break;
5499 PrintAndLogEx(NORMAL
, "\n");
5503 // confirm number written blocks. Must be 20, 64 or 256 blocks
5504 if (blockno
!= block_cnt
) {
5505 PrintAndLogEx(ERR
, "File content error. There must be %d blocks", block_cnt
);
5509 PrintAndLogEx(SUCCESS
, "Card loaded " _YELLOW_("%d") " blocks from file", block_cnt
);
5510 PrintAndLogEx(INFO
, "Done!");
5514 static int CmdHF14AMfCGetBlk(const char *Cmd
) {
5515 CLIParserContext
*ctx
;
5516 CLIParserInit(&ctx
, "hf mf cgetblk",
5517 "Get block data from magic Chinese card.\n"
5518 "Only works with magic gen1a cards",
5519 "hf mf cgetblk --blk 0 --> get block 0 (manufacturer)\n"
5520 "hf mf cgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
5522 void *argtable
[] = {
5524 arg_int1("b", "blk", "<dec>", "block number"),
5525 arg_lit0("v", "verbose", "verbose output"),
5526 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5529 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5530 int b
= arg_get_int_def(ctx
, 1, 0);
5531 bool verbose
= arg_get_lit(ctx
, 2);
5532 bool gdm
= arg_get_lit(ctx
, 3);
5539 uint8_t blockno
= (uint8_t)b
;
5540 uint8_t data
[16] = {0};
5541 int res
= mf_chinese_get_block(blockno
, data
, MAGIC_SINGLE
| (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
));
5543 PrintAndLogEx(ERR
, "Can't read block. error=%d", res
);
5547 uint8_t sector
= mfSectorNum(blockno
);
5548 mf_print_sector_hdr(sector
);
5549 mf_print_block_one(blockno
, data
, verbose
);
5552 decode_print_st(blockno
, data
);
5554 PrintAndLogEx(NORMAL
, "");
5559 static int CmdHF14AMfCGetSc(const char *Cmd
) {
5560 CLIParserContext
*ctx
;
5561 CLIParserInit(&ctx
, "hf mf cgetsc",
5562 "Get sector data from magic Chinese card.\n"
5563 "Only works with magic gen1a cards",
5566 void *argtable
[] = {
5568 arg_int1("s", "sec", "<dec>", "sector number"),
5569 arg_lit0("v", "verbose", "verbose output"),
5570 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5573 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5574 int s
= arg_get_int_def(ctx
, 1, 0);
5575 bool verbose
= arg_get_lit(ctx
, 2);
5576 bool gdm
= arg_get_lit(ctx
, 3);
5579 if (s
>= MIFARE_4K_MAXSECTOR
) {
5580 PrintAndLogEx(WARNING
, "Sector number must be less then 40");
5584 uint8_t sector
= (uint8_t)s
;
5585 mf_print_sector_hdr(sector
);
5588 uint8_t start
= sector
* 4;
5591 start
= 128 + (sector
- 32) * 16;
5594 int flags
= MAGIC_INIT
+ (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
);
5595 uint8_t data
[16] = {0};
5596 for (int i
= 0; i
< blocks
; i
++) {
5597 if (i
== 1) flags
= 0;
5598 if (i
== blocks
- 1) flags
= MAGIC_HALT
+ MAGIC_OFF
;
5600 int res
= mf_chinese_get_block(start
+ i
, data
, flags
);
5602 PrintAndLogEx(ERR
, "Can't read block. %d error=%d", start
+ i
, res
);
5605 mf_print_block_one(start
+ i
, data
, verbose
);
5608 decode_print_st(start
+ blocks
- 1, data
);
5610 PrintAndLogEx(NORMAL
, "");
5615 static int CmdHF14AMfCSave(const char *Cmd
) {
5616 CLIParserContext
*ctx
;
5617 CLIParserInit(&ctx
, "hf mf csave",
5618 "Save magic gen1a card memory to file (bin/json)"
5619 "or into emulator memory",
5623 void *argtable
[] = {
5625 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
5626 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5627 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5628 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5629 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5630 arg_lit0(NULL
, "emu", "to emulator memory"),
5631 arg_lit0(NULL
, "gdm", "to emulator memory"),
5634 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5637 char filename
[FILE_PATH_SIZE
];
5638 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
5640 bool m0
= arg_get_lit(ctx
, 2);
5641 bool m1
= arg_get_lit(ctx
, 3);
5642 bool m2
= arg_get_lit(ctx
, 4);
5643 bool m4
= arg_get_lit(ctx
, 5);
5644 bool fill_emulator
= arg_get_lit(ctx
, 6);
5645 bool gdm
= arg_get_lit(ctx
, 7);
5649 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5650 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5652 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5657 memset(s
, 0, sizeof(s
));
5658 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5660 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5661 strncpy(s
, "Mini", 5);
5663 block_cnt
= MIFARE_1K_MAXBLOCK
;
5664 strncpy(s
, "1K", 3);
5666 block_cnt
= MIFARE_2K_MAXBLOCK
;
5667 strncpy(s
, "2K", 3);
5669 block_cnt
= MIFARE_4K_MAXBLOCK
;
5670 strncpy(s
, "4K", 3);
5672 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5676 PrintAndLogEx(SUCCESS
, "Dumping magic Gen1a MIFARE Classic " _GREEN_("%s") " card memory", s
);
5677 PrintAndLogEx(INFO
, "." NOLF
);
5679 // Select card to get UID/UIDLEN information
5680 clearCommandBuffer();
5681 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
5682 PacketResponseNG resp
;
5683 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
5684 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
5685 return PM3_ETIMEOUT
;
5692 3: proprietary Anticollision
5694 uint64_t select_status
= resp
.oldarg
[0];
5695 if (select_status
== 0) {
5696 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
5701 iso14a_card_select_t card
;
5702 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
5705 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
5706 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
5708 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5712 // switch on field and send magic sequence
5713 uint8_t flags
= MAGIC_INIT
+ (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
);
5714 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
5721 if (i
== block_cnt
- 1) {
5722 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5725 if (mf_chinese_get_block(i
, dump
+ (i
* MFBLOCK_SIZE
), flags
)) {
5726 PrintAndLogEx(WARNING
, "Can't get magic card block: %d", i
);
5727 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
5731 PrintAndLogEx(NORMAL
, "." NOLF
);
5734 PrintAndLogEx(NORMAL
, "");
5736 if (fill_emulator
) {
5737 PrintAndLogEx(INFO
, "uploading to emulator memory");
5738 PrintAndLogEx(INFO
, "." NOLF
);
5740 g_conn
.block_after_ACK
= true;
5741 for (int i
= 0; i
< block_cnt
; i
+= 5) {
5742 if (i
== block_cnt
- 1) {
5743 // Disable fast mode on last packet
5744 g_conn
.block_after_ACK
= false;
5746 if (mf_elm_set_mem(dump
+ (i
* MFBLOCK_SIZE
), i
, 5) != PM3_SUCCESS
) {
5747 PrintAndLogEx(WARNING
, "Can't set emul block: " _YELLOW_("%d"), i
);
5750 PrintAndLogEx(NORMAL
, "");
5751 PrintAndLogEx(INFO
, "" NOLF
) ;
5753 PrintAndLogEx(NORMAL
, "." NOLF
);
5756 PrintAndLogEx(NORMAL
, "");
5757 PrintAndLogEx(SUCCESS
, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes
);
5760 // user supplied filename?
5762 char *fptr
= filename
;
5763 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
5764 FillFileNameByUID(fptr
, card
.uid
, "-dump", card
.uidlen
);
5767 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
5772 static int CmdHF14AMfCView(const char *Cmd
) {
5774 CLIParserContext
*ctx
;
5775 CLIParserInit(&ctx
, "hf mf cview",
5776 "View `magic gen1a` card memory",
5780 void *argtable
[] = {
5782 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
5783 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
5784 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
5785 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
5786 arg_lit0("v", "verbose", "verbose output"),
5787 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
5790 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5791 bool m0
= arg_get_lit(ctx
, 1);
5792 bool m1
= arg_get_lit(ctx
, 2);
5793 bool m2
= arg_get_lit(ctx
, 3);
5794 bool m4
= arg_get_lit(ctx
, 4);
5795 bool verbose
= arg_get_lit(ctx
, 5);
5796 bool gdm
= arg_get_lit(ctx
, 6);
5800 if ((m0
+ m1
+ m2
+ m4
) > 1) {
5801 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
5803 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
5808 memset(s
, 0, sizeof(s
));
5809 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
5811 block_cnt
= MIFARE_MINI_MAXBLOCK
;
5812 strncpy(s
, "Mini", 5);
5814 block_cnt
= MIFARE_1K_MAXBLOCK
;
5815 strncpy(s
, "1K", 3);
5817 block_cnt
= MIFARE_2K_MAXBLOCK
;
5818 strncpy(s
, "2K", 3);
5820 block_cnt
= MIFARE_4K_MAXBLOCK
;
5821 strncpy(s
, "4K", 3);
5823 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
5826 PrintAndLogEx(SUCCESS
, "View magic Gen1a MIFARE Classic " _GREEN_("%s"), s
);
5827 PrintAndLogEx(INFO
, "." NOLF
);
5829 // Select card to get UID/UIDLEN information
5830 clearCommandBuffer();
5831 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
5832 PacketResponseNG resp
;
5833 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
5834 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
5835 return PM3_ETIMEOUT
;
5842 3: proprietary Anticollision
5844 uint64_t select_status
= resp
.oldarg
[0];
5846 if (select_status
== 0) {
5847 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
5848 return PM3_ERFTRANS
;
5851 iso14a_card_select_t card
;
5852 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
5855 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
5856 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
5858 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
5862 // switch on field and send magic sequence
5863 uint8_t flags
= MAGIC_INIT
+ (gdm
? MAGIC_GDM_ALT_WUPC
: MAGIC_WUPC
);
5864 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
5870 if (i
== block_cnt
- 1) {
5871 flags
= MAGIC_HALT
+ MAGIC_OFF
;
5874 if (mf_chinese_get_block(i
, dump
+ (i
* MFBLOCK_SIZE
), flags
)) {
5875 PrintAndLogEx(WARNING
, "Can't get magic card block: " _YELLOW_("%u"), i
);
5876 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
5880 PrintAndLogEx(NORMAL
, "." NOLF
);
5884 PrintAndLogEx(NORMAL
, "");
5885 mf_print_blocks(block_cnt
, dump
, verbose
);
5888 mf_print_keys(block_cnt
, dump
);
5895 //needs nt, ar, at, Data to decrypt
5896 static int CmdHf14AMfDecryptBytes(const char *Cmd
) {
5897 CLIParserContext
*ctx
;
5898 CLIParserInit(&ctx
, "hf mf decrypt",
5899 "Decrypt Crypto-1 encrypted bytes given some known state of crypto. See tracelog to gather needed values",
5900 "hf mf decrypt --nt b830049b --ar 9248314a --at 9280e203 -d 41e586f9\n"
5901 " -> 41e586f9 becomes 3003999a\n"
5902 " -> which annotates 30 03 [99 9a] read block 3 [crc]"
5904 void *argtable
[] = {
5906 arg_str1(NULL
, "nt", "<hex>", "tag nonce"),
5907 arg_str1(NULL
, "ar", "<hex>", "ar_enc, encrypted reader response"),
5908 arg_str1(NULL
, "at", "<hex>", "at_enc, encrypted tag response"),
5909 arg_str1("d", "data", "<hex>", "encrypted data, taken directly after at_enc and forward"),
5912 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
5915 int res
= arg_get_u32_hexstr_def(ctx
, 1, 0, &nt
);
5918 PrintAndLogEx(WARNING
, "check `nt` parameter");
5922 uint32_t ar_enc
= 0;
5923 res
= arg_get_u32_hexstr_def(ctx
, 2, 0, &ar_enc
);
5926 PrintAndLogEx(WARNING
, "check `ar` parameter");
5930 uint32_t at_enc
= 0;
5931 res
= arg_get_u32_hexstr_def(ctx
, 3, 0, &at_enc
);
5934 PrintAndLogEx(WARNING
, "check `at` parameter");
5939 uint8_t data
[512] = {0x00};
5940 CLIGetHexWithReturn(ctx
, 4, data
, &datalen
);
5943 PrintAndLogEx(INFO
, "nt....... %08X", nt
);
5944 PrintAndLogEx(INFO
, "ar enc... %08X", ar_enc
);
5945 PrintAndLogEx(INFO
, "at enc... %08X", at_enc
);
5947 return try_decrypt_word(nt
, ar_enc
, at_enc
, data
, datalen
);
5950 static int CmdHf14AMfSetMod(const char *Cmd
) {
5952 CLIParserContext
*ctx
;
5953 CLIParserInit(&ctx
, "hf mf setmod",
5954 "Sets the load modulation strength of a MIFARE Classic EV1 card",
5955 "hf mf setmod -k ffffffffffff -0"
5957 void *argtable
[] = {
5959 arg_lit0("0", NULL
, "normal modulation"),
5960 arg_lit0("1", NULL
, "strong modulation (def)"),
5961 arg_str0("k", "key", "<hex>", "key A, Sector 0, 6 hex bytes"),
5964 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
5965 bool m0
= arg_get_lit(ctx
, 1);
5966 bool m1
= arg_get_lit(ctx
, 2);
5969 uint8_t key
[6] = {0};
5970 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
5974 PrintAndLogEx(WARNING
, "please select one modulation");
5978 uint8_t data
[7] = {0};
5979 memcpy(data
+ 1, key
, 6);
5987 clearCommandBuffer();
5988 SendCommandNG(CMD_HF_MIFARE_SETMOD
, data
, sizeof(data
));
5989 PacketResponseNG resp
;
5990 if (WaitForResponseTimeout(CMD_HF_MIFARE_SETMOD
, &resp
, 1500) == false) {
5991 PrintAndLogEx(WARNING
, "command execution time out");
5992 return PM3_ETIMEOUT
;
5995 if (resp
.status
== PM3_SUCCESS
)
5996 PrintAndLogEx(SUCCESS
, "Change ( " _GREEN_("ok") " )");
5998 PrintAndLogEx(FAILED
, "Change ( " _RED_("fail") " )");
6003 // MIFARE NACK bug detection
6004 static int CmdHf14AMfNack(const char *Cmd
) {
6005 CLIParserContext
*ctx
;
6006 CLIParserInit(&ctx
, "hf mf nack",
6007 "Test a MIFARE Classic based card for the NACK bug",
6010 void *argtable
[] = {
6012 arg_lit0("v", "verbose", "verbose output`"),
6015 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6016 bool verbose
= arg_get_lit(ctx
, 1);
6020 PrintAndLogEx(INFO
, "Started testing card for NACK bug. Press Enter to abort");
6022 detect_classic_nackbug(verbose
);
6027 static int CmdHF14AMfice(const char *Cmd) {
6028 CLIParserContext *ctx;
6029 CLIParserInit(&ctx, "hf mf ice",
6030 "Collect MIFARE Classic nonces to file",
6032 "hf mf ice -f nonces.bin");
6034 void *argtable[] = {
6036 arg_str0("f", "file", "<fn>", "filename of nonce dump"),
6037 arg_u64_0(NULL, "limit", "<dec>", "nonces to be collected"),
6040 CLIExecWithReturn(ctx, Cmd, argtable, true);
6043 char filename[FILE_PATH_SIZE] = {0};
6044 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
6046 uint32_t limit = arg_get_u32_def(ctx, 2, 50000);
6053 if (filename[0] == '\0') {
6054 fptr = GenerateFilename("hf-mf-", "-nonces.bin");
6057 strncpy(filename, fptr, sizeof(filename) - 1);
6061 uint8_t blockNo = 0;
6062 uint8_t keyType = MF_KEY_A;
6063 uint8_t trgBlockNo = 0;
6064 uint8_t trgKeyType = MF_KEY_B;
6066 bool initialize = true;
6067 bool acquisition_completed = false;
6068 uint32_t total_num_nonces = 0;
6069 PacketResponseNG resp;
6071 uint32_t part_limit = 3000;
6073 PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit);
6075 FILE *fnonces = NULL;
6076 if ((fnonces = fopen(filename, "wb")) == NULL) {
6077 PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), filename);
6081 clearCommandBuffer();
6083 uint64_t t1 = msclock();
6086 if (kbd_enter_pressed()) {
6087 PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
6092 flags |= initialize ? 0x0001 : 0;
6093 flags |= slow ? 0x0002 : 0;
6094 clearCommandBuffer();
6095 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0);
6097 if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out;
6098 if (resp.oldarg[0]) goto out;
6100 uint32_t items = resp.oldarg[2];
6101 fwrite(resp.data.asBytes, 1, items * 4, fnonces);
6104 total_num_nonces += items;
6105 if (total_num_nonces > part_limit) {
6106 PrintAndLogEx(INFO, "Total nonces %u\n", total_num_nonces);
6110 acquisition_completed = (total_num_nonces > limit);
6114 } while (!acquisition_completed);
6117 PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000);
6124 clearCommandBuffer();
6125 SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, NULL, 0);
6130 static int CmdHF14AMfAuth4(const char *Cmd
) {
6131 uint8_t keyn
[20] = {0};
6133 uint8_t key
[16] = {0};
6136 CLIParserContext
*ctx
;
6137 CLIParserInit(&ctx
, "hf mf auth4",
6138 "Executes AES authentication command in ISO14443-4",
6139 "hf mf auth4 -n 4000 -k 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
6140 "hf mf auth4 -n 9003 -k FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n");
6142 void *argtable
[] = {
6144 arg_str1("n", NULL
, "<hex>", "key num, 2 hex bytes"),
6145 arg_str1("k", "key", "<hex>", "key, 16 hex bytes"),
6148 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6149 CLIGetHexWithReturn(ctx
, 1, keyn
, &keynlen
);
6150 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
6154 PrintAndLogEx(ERR
, "Key number must be 2 bytes. Got... %d", keynlen
);
6159 PrintAndLogEx(ERR
, "Key must be 16 bytes. Got... %d", keylen
);
6163 return MifareAuth4(NULL
, keyn
, key
, true, false, true, true, false);
6166 // https://www.nxp.com/docs/en/application-note/AN10787.pdf
6167 static int CmdHF14AMfMAD(const char *Cmd
) {
6169 CLIParserContext
*ctx
;
6170 CLIParserInit(&ctx
, "hf mf mad",
6171 "Checks and prints MIFARE Application Directory (MAD)",
6172 "hf mf mad -> shows MAD if exists\n"
6173 "hf mf mad --aid e103 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"
6174 "hf mf mad --dch -k ffffffffffff -> decode CardHolder information\n");
6176 void *argtable
[] = {
6178 arg_lit0("v", "verbose", "verbose output"),
6179 arg_str0(NULL
, "aid", "<hex>", "print all sectors with specified aid"),
6180 arg_str0("k", "key", "<hex>", "key for printing sectors"),
6181 arg_lit0("b", "keyb", "use key B for access printing sectors (by default: key A)"),
6182 arg_lit0(NULL
, "be", "(optional, BigEndian)"),
6183 arg_lit0(NULL
, "dch", "decode Card Holder information"),
6184 arg_str0("f", "file", "<fn>", "load dump file and decode MAD"),
6185 arg_lit0(NULL
, "force", "force decode (skip key check)"),
6188 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6189 bool verbose
= arg_get_lit(ctx
, 1);
6190 uint8_t aid
[2] = {0};
6192 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
6193 uint8_t userkey
[6] = {0};
6195 CLIGetHexWithReturn(ctx
, 3, userkey
, &keylen
);
6196 bool keyB
= arg_get_lit(ctx
, 4);
6197 bool swapmad
= arg_get_lit(ctx
, 5);
6198 bool decodeholder
= arg_get_lit(ctx
, 6);
6199 bool force
= arg_get_lit(ctx
, 8);
6202 char filename
[FILE_PATH_SIZE
] = {0};
6203 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6209 uint8_t *dump
= NULL
;
6210 size_t bytes_read
= 0;
6211 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, MIFARE_4K_MAX_BYTES
);
6212 if (res
!= PM3_SUCCESS
) {
6216 uint16_t block_cnt
= MIN(MIFARE_1K_MAXBLOCK
, (bytes_read
/ MFBLOCK_SIZE
));
6217 if (bytes_read
== MIFARE_MINI_MAX_BYTES
)
6218 block_cnt
= MIFARE_MINI_MAXBLOCK
;
6219 else if (bytes_read
== MIFARE_2K_MAX_BYTES
)
6220 block_cnt
= MIFARE_2K_MAXBLOCK
;
6221 else if (bytes_read
== MIFARE_4K_MAX_BYTES
)
6222 block_cnt
= MIFARE_4K_MAXBLOCK
;
6225 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
6229 if ((HasMADKey(dump
) == false) && (force
== false)) {
6230 PrintAndLogEx(FAILED
, "No MAD key was detected in the dump file");
6236 bool haveMAD2
= false;
6237 MAD1DecodeAndPrint(dump
, swapmad
, verbose
, &haveMAD2
);
6239 int sector
= DetectHID(dump
, 0x484d);
6243 PrintAndLogEx(INFO
, "");
6244 PrintAndLogEx(INFO
, _CYAN_("HID PACS detected"));
6246 uint8_t pacs_sector
[MFBLOCK_SIZE
* 3] = {0};
6247 memcpy(pacs_sector
, dump
+ (sector
* 4 * 16), sizeof(pacs_sector
));
6249 if (pacs_sector
[16] == 0x02) {
6251 PrintAndLogEx(SUCCESS
, "Raw...... " _GREEN_("%s"), sprint_hex_inrow(pacs_sector
+ 24, 8));
6253 //todo: remove preamble/sentinel
6254 uint32_t top
= 0, mid
= 0, bot
= 0;
6255 char hexstr
[16 + 1] = {0};
6256 hex_to_buffer((uint8_t *)hexstr
, pacs_sector
+ 24, 8, sizeof(hexstr
) - 1, 0, 0, true);
6257 hexstring_to_u96(&top
, &mid
, &bot
, hexstr
);
6259 char binstr
[64 + 1];
6260 hextobinstring(binstr
, hexstr
);
6261 char *pbin
= binstr
;
6262 while (strlen(pbin
) && *(++pbin
) == '0');
6264 PrintAndLogEx(SUCCESS
, "Binary... " _GREEN_("%s"), pbin
);
6266 PrintAndLogEx(INFO
, "Wiegand decode");
6267 wiegand_message_t packed
= initialize_message_object(top
, mid
, bot
, 0);
6268 HIDTryUnpack(&packed
);
6272 sector
= DetectHID(dump
, 0x4910);
6275 PrintAndLogEx(INFO
, "");
6276 PrintAndLogEx(INFO
, _CYAN_("VIGIK PACS detected"));
6280 MAD2DecodeAndPrint(dump
+ (MIFARE_1K_MAXBLOCK
* MF_MAD2_SECTOR
), swapmad
, verbose
);
6283 if (aidlen
== 2 || decodeholder
) {
6284 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6286 if (MADDecode(dump
, dump
+ (0x10 * MIFARE_1K_MAXBLOCK
), mad
, &madlen
, swapmad
)) {
6287 PrintAndLogEx(ERR
, "can't decode MAD");
6292 uint16_t aaid
= 0x0004;
6294 aaid
= (aid
[0] << 8) + aid
[1];
6297 PrintAndLogEx(NORMAL
, "");
6298 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
6300 MADCardHolderInfoDecode(dump
, bytes_read
, verbose
);
6306 if (g_session
.pm3_present
== false)
6310 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6311 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6313 bool got_first
= true;
6314 if (mf_read_sector(MF_MAD1_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifare_mad_key
, sector0
) != PM3_SUCCESS
) {
6315 PrintAndLogEx(WARNING
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
6318 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6321 // User supplied key
6322 if (got_first
== false && keylen
== 6) {
6323 PrintAndLogEx(INFO
, "Trying user specified key...");
6324 if (mf_read_sector(MF_MAD1_SECTOR
, MF_KEY_A
, userkey
, sector0
) != PM3_SUCCESS
) {
6325 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or the custom key is wrong");
6327 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6332 // Both default and user supplied key failed
6333 if (got_first
== false) {
6338 if (mf_read_sector(MF_MAD2_SECTOR
, MF_KEY_A
, (uint8_t *)g_mifare_mad_key
, sector10
) != PM3_SUCCESS
) {
6340 PrintAndLogEx(ERR
, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys");
6344 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6347 // User supplied key
6348 if (got_first
== false && keylen
== 6) {
6349 PrintAndLogEx(INFO
, "Trying user specified key...");
6350 if (mf_read_sector(MF_MAD2_SECTOR
, MF_KEY_A
, userkey
, sector10
) != PM3_SUCCESS
) {
6352 PrintAndLogEx(ERR
, "error, read sector 10. card doesn't have MAD 2 or the custom key is wrong");
6355 PrintAndLogEx(INFO
, "Authentication ( " _GREEN_("ok") " )");
6361 bool haveMAD2
= false;
6362 MAD1DecodeAndPrint(sector0
, swapmad
, verbose
, &haveMAD2
);
6365 MAD2DecodeAndPrint(sector10
, swapmad
, verbose
);
6368 if (aidlen
== 2 || decodeholder
) {
6369 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6371 if (MADDecode(sector0
, sector10
, mad
, &madlen
, swapmad
)) {
6372 PrintAndLogEx(ERR
, "can't decode MAD");
6376 // copy default NDEF key
6377 uint8_t akey
[6] = {0};
6378 memcpy(akey
, g_mifare_ndef_key
, 6);
6380 // user specified key
6382 memcpy(akey
, userkey
, sizeof(akey
));
6385 uint16_t aaid
= 0x0004;
6388 aaid
= (aid
[0] << 8) + aid
[1];
6390 PrintAndLogEx(NORMAL
, "");
6391 PrintAndLogEx(INFO
, "-------------- " _CYAN_("AID 0x%04x") " ---------------", aaid
);
6393 for (int i
= 0; i
< madlen
; i
++) {
6394 if (aaid
== mad
[i
]) {
6395 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6396 if (mf_read_sector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
)) {
6397 PrintAndLogEx(NORMAL
, "");
6398 PrintAndLogEx(ERR
, "error, read sector %d", i
+ 1);
6402 for (int j
= 0; j
< (verbose
? 4 : 3); j
++)
6403 PrintAndLogEx(NORMAL
, " [%03d] %s", (i
+ 1) * 4 + j
, sprint_hex(&vsector
[j
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6410 PrintAndLogEx(NORMAL
, "");
6411 PrintAndLogEx(INFO
, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid
);
6413 uint8_t data
[MIFARE_4K_MAX_BYTES
] = {0};
6416 for (int i
= 0; i
< madlen
; i
++) {
6417 if (aaid
== mad
[i
]) {
6419 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6420 if (mf_read_sector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, akey
, vsector
)) {
6421 PrintAndLogEx(NORMAL
, "");
6422 PrintAndLogEx(ERR
, "error, read sector %d", i
+ 1);
6426 // skip ST block hence only 3 blocks copy
6427 memcpy(&data
[datalen
], vsector
, MFBLOCK_SIZE
* 3);
6428 datalen
+= MFBLOCK_SIZE
* 3;
6433 PrintAndLogEx(WARNING
, "no Card Holder Info data");
6436 MADCardHolderInfoDecode(data
, datalen
, verbose
);
6441 PrintAndLogEx(NORMAL
, "");
6442 PrintAndLogEx(INFO
, "------------ " _CYAN_("MAD v1 sector raw") " -------------");
6443 for (int i
= 0; i
< 4; i
++) {
6444 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex(§or0
[i
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6447 PrintAndLogEx(NORMAL
, "");
6448 PrintAndLogEx(INFO
, "------------ " _CYAN_("MAD v2 sector raw") " -------------");
6449 for (int i
= 0; i
< 4; i
++) {
6450 PrintAndLogEx(INFO
, "[%d] %s", i
, sprint_hex(§or10
[i
* MFBLOCK_SIZE
], MFBLOCK_SIZE
));
6457 int CmdHFMFNDEFRead(const char *Cmd
) {
6459 CLIParserContext
*ctx
;
6460 CLIParserInit(&ctx
, "hf mf ndefread",
6461 "Prints NFC Data Exchange Format (NDEF)",
6462 "hf mf ndefread -> shows NDEF parsed data\n"
6463 "hf mf ndefread -vv -> shows NDEF parsed and raw data\n"
6464 "hf mf ndefread --aid e103 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"
6465 "hf mf ndefread -f myfilename -> save raw NDEF to file"
6468 void *argtable
[] = {
6470 arg_litn("v", "verbose", 0, 2, "Verbose output"),
6471 arg_str0(NULL
, "aid", "<aid>", "replace default aid for NDEF"),
6472 arg_str0("k", "key", "<key>", "replace default key for NDEF"),
6473 arg_lit0("b", "keyb", "use key B for access sectors (by default: key A)"),
6474 arg_str0("f", "file", "<fn>", "save raw NDEF to file"),
6477 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6479 bool verbose
= arg_get_lit(ctx
, 1);
6480 bool verbose2
= arg_get_lit(ctx
, 1) > 1;
6481 uint8_t aid
[2] = {0};
6484 CLIGetHexWithReturn(ctx
, 2, aid
, &aidlen
);
6485 uint8_t key
[6] = {0};
6488 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
6489 bool keyB
= arg_get_lit(ctx
, 4);
6492 char filename
[FILE_PATH_SIZE
] = {0};
6493 CLIParamStrToBuf(arg_get_str(ctx
, 5), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6497 uint16_t ndef_aid
= NDEF_MFC_AID
;
6499 ndef_aid
= (aid
[0] << 8) + aid
[1];
6502 uint8_t ndefkey
[6] = {0};
6503 memcpy(ndefkey
, g_mifare_ndef_key
, 6);
6505 memcpy(ndefkey
, key
, 6);
6508 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6509 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6510 uint8_t data
[4096] = {0};
6514 PrintAndLogEx(INFO
, "reading MAD v1 sector");
6517 if (mf_read_sector(MF_MAD1_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector0
)) {
6518 PrintAndLogEx(ERR
, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys");
6519 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
6524 PrintAndLogEx(INFO
, "reading MAD v2 sector");
6527 if (mf_read_sector(MF_MAD2_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector10
)) {
6529 PrintAndLogEx(ERR
, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys");
6530 PrintAndLogEx(INFO
, "Skipping MAD 2");
6534 bool haveMAD2
= false;
6535 int res
= MADCheck(sector0
, sector10
, verbose
, &haveMAD2
);
6536 if (res
!= PM3_SUCCESS
) {
6537 PrintAndLogEx(ERR
, "MAD error %d", res
);
6541 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6543 res
= MADDecode(sector0
, sector10
, mad
, &madlen
, false);
6544 if (res
!= PM3_SUCCESS
) {
6545 PrintAndLogEx(ERR
, "can't decode MAD");
6549 PrintAndLogEx(INFO
, "reading data from tag");
6550 for (int i
= 0; i
< madlen
; i
++) {
6551 if (ndef_aid
== mad
[i
]) {
6552 uint8_t vsector
[MFBLOCK_SIZE
* 4] = {0};
6553 if (mf_read_sector(i
+ 1, keyB
? MF_KEY_B
: MF_KEY_A
, ndefkey
, vsector
)) {
6554 PrintAndLogEx(ERR
, "error, reading sector %d ", i
+ 1);
6558 memcpy(&data
[datalen
], vsector
, MFBLOCK_SIZE
* 3);
6559 datalen
+= MFBLOCK_SIZE
* 3;
6561 PrintAndLogEx(INPLACE
, "%d", i
);
6564 PrintAndLogEx(NORMAL
, "");
6567 PrintAndLogEx(WARNING
, "no NDEF data");
6572 PrintAndLogEx(NORMAL
, "");
6573 PrintAndLogEx(INFO
, "--- " _CYAN_("MFC NDEF raw") " ----------------");
6574 print_buffer(data
, datalen
, 1);
6577 res
= NDEFDecodeAndPrint(data
, datalen
, verbose
);
6578 if (res
!= PM3_SUCCESS
) {
6579 PrintAndLogEx(INFO
, "Trying to parse NDEF records w/o NDEF header");
6580 res
= NDEFRecordsDecodeAndPrint(data
, datalen
, verbose
);
6583 // if given a filename, save it
6585 // get total NDEF length before save. If fails, we save it all
6587 if (NDEFGetTotalLength(data
, datalen
, &n
) != PM3_SUCCESS
) {
6591 pm3_save_dump(filename
, data
, n
, jsfNDEF
);
6594 if (verbose
== false) {
6595 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -v`") " for more details");
6597 if (verbose2
== false) {
6598 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -vv`") " for more details");
6604 // https://www.nxp.com/docs/en/application-note/AN1305.pdf
6605 int CmdHFMFNDEFFormat(const char *Cmd
) {
6607 CLIParserContext
*ctx
;
6608 CLIParserInit(&ctx
, "hf mf ndefformat",
6609 "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF)\n"
6610 "If no <name> given, UID will be used as filename. \n"
6611 "It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
6613 "If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
6614 "hf mf ndefformat\n"
6615 // "hf mf ndefformat --mini --> MIFARE Mini\n"
6616 "hf mf ndefformat --1k --> MIFARE Classic 1k\n"
6617 // "hf mf ndefformat --2k --> MIFARE 2k\n"
6618 // "hf mf ndefformat --4k --> MIFARE 4k\n"
6619 "hf mf ndefformat --keys hf-mf-01020304-key.bin --> MIFARE 1k with keys from specified file\n"
6622 void *argtable
[] = {
6624 arg_str0("k", "keys", "<fn>", "filename of keys"),
6625 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
6626 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
6627 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
6628 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
6631 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
6634 char keyFilename
[FILE_PATH_SIZE
] = {0};
6635 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
6637 bool m0
= arg_get_lit(ctx
, 2);
6638 bool m1
= arg_get_lit(ctx
, 3);
6639 bool m2
= arg_get_lit(ctx
, 4);
6640 bool m4
= arg_get_lit(ctx
, 5);
6645 if ((m0
+ m1
+ m2
+ m4
) > 1) {
6646 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
6648 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
6652 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
6655 numSectors
= MIFARE_MINI_MAXSECTOR
;
6657 numSectors
= MIFARE_1K_MAXSECTOR
;
6659 numSectors
= MIFARE_2K_MAXSECTOR
;
6661 numSectors
= MIFARE_4K_MAXSECTOR
;
6663 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
6668 if (g_session
.pm3_present
== false)
6671 // Select card to get UID/UIDLEN/ATQA/SAK information
6672 clearCommandBuffer();
6673 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
6674 PacketResponseNG resp
;
6675 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
6676 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
6677 return PM3_ETIMEOUT
;
6680 uint64_t select_status
= resp
.oldarg
[0];
6681 if (select_status
== 0) {
6682 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
6689 // init keys to default key
6690 uint8_t keyA
[MIFARE_4K_MAXSECTOR
][MIFARE_KEY_SIZE
];
6691 uint8_t keyB
[MIFARE_4K_MAXSECTOR
][MIFARE_KEY_SIZE
];
6693 for (uint8_t i
= 0; i
< MIFARE_4K_MAXSECTOR
; i
++) {
6694 memcpy(keyA
[i
], g_mifare_default_key
, sizeof(g_mifare_default_key
));
6695 memcpy(keyB
[i
], g_mifare_default_key
, sizeof(g_mifare_default_key
));
6698 // test if MAD key is used
6701 // check if we can authenticate to sector
6702 if (mf_check_keys(0, MF_KEY_A
, true, 1, (uint8_t *)g_mifare_mad_key
, &key64
) == PM3_SUCCESS
) {
6704 // if used, assume KEY A is MAD/NDEF set.
6705 memcpy(keyA
[0], g_mifare_mad_key
, sizeof(g_mifare_mad_key
));
6706 memcpy(keyB
[0], g_mifare_mad_key_b
, sizeof(g_mifare_mad_key_b
));
6707 for (uint8_t i
= 1; i
< MIFARE_4K_MAXSECTOR
; i
++) {
6708 memcpy(keyA
[i
], g_mifare_ndef_key
, sizeof(g_mifare_ndef_key
));
6712 // Do we have a keyfile based from UID?
6713 if (keyfnlen
== 0) {
6714 char *fptr
= GenerateFilename("hf-mf-", "-key.bin");
6716 strncpy(keyFilename
, fptr
, sizeof(keyFilename
) - 1);
6722 // load key file if exist
6723 if (strlen(keyFilename
)) {
6725 size_t alen
= 0, blen
= 0;
6726 uint8_t *tmpA
, *tmpB
;
6727 if (loadFileBinaryKey(keyFilename
, "", (void **)&tmpA
, (void **)&tmpB
, &alen
, &blen
) != PM3_SUCCESS
) {
6731 PrintAndLogEx(INFO
, "Using `" _YELLOW_("%s") "`", keyFilename
);
6733 for (int i
= 0; i
< numSectors
; i
++) {
6734 memcpy(keyA
[i
], tmpA
+ (i
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
6735 memcpy(keyB
[i
], tmpB
+ (i
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
6744 uint8_t firstblocks
[8][16] = {
6745 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6746 { 0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1 },
6747 { 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1 },
6748 { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A },
6749 { 0x03, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6750 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6751 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
6752 { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
6756 for (int i
= 0; i
< numSectors
; i
++) {
6757 for (int j
= 0; j
< mfNumBlocksPerSector(j
); j
++) {
6759 uint8_t b
= (mfFirstBlockOfSector(i
) + j
);
6760 uint8_t block
[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
6772 memcpy(block
, firstblocks
[b
], MFBLOCK_SIZE
);
6775 if (mfIsSectorTrailerBasedOnBlocks(i
, j
)) {
6777 memcpy(block
, firstblocks
[7], MFBLOCK_SIZE
);
6783 // write to card, try B key first
6784 if (mf_write_block(b
, MF_KEY_B
, keyB
[i
], block
) != PM3_SUCCESS
) {
6786 if (mf_write_block(b
, MF_KEY_A
, keyA
[i
], block
) != PM3_SUCCESS
) {
6790 PrintAndLogEx(INPLACE
, "Formatting block %u", b
);
6794 PrintAndLogEx(NORMAL
, "");
6798 int CmdHFMFNDEFWrite(const char *Cmd
) {
6800 CLIParserContext
*ctx
;
6801 CLIParserInit(&ctx
, "hf mf ndefwrite",
6802 "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
6803 "hf mf ndefwrite -d 0300FE -> write empty record to tag\n"
6804 "hf mf ndefwrite -f myfilename\n"
6805 "hf mf ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
6808 void *argtable
[] = {
6810 arg_str0("d", NULL
, "<hex>", "raw NDEF hex bytes"),
6811 arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
6812 arg_lit0("p", NULL
, "fix NDEF record headers / terminator block if missing"),
6813 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
6814 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
6815 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
6816 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
6817 arg_lit0("v", "verbose", "verbose output"),
6820 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
6822 uint8_t raw
[4096] = {0};
6824 CLIGetHexWithReturn(ctx
, 1, raw
, &rawlen
);
6827 char filename
[FILE_PATH_SIZE
] = {0};
6828 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
6830 bool fix_msg
= arg_get_lit(ctx
, 3);
6832 bool m0
= arg_get_lit(ctx
, 4);
6833 bool m1
= arg_get_lit(ctx
, 5);
6834 bool m2
= arg_get_lit(ctx
, 6);
6835 bool m4
= arg_get_lit(ctx
, 7);
6836 bool verbose
= arg_get_lit(ctx
, 8);
6841 if ((m0
+ m1
+ m2
+ m4
) > 1) {
6842 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
6844 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
6848 uint8_t numSectors
= MIFARE_1K_MAXSECTOR
;
6851 numSectors
= MIFARE_MINI_MAXSECTOR
;
6853 numSectors
= MIFARE_1K_MAXSECTOR
;
6855 numSectors
= MIFARE_2K_MAXSECTOR
;
6857 numSectors
= MIFARE_4K_MAXSECTOR
;
6859 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
6864 PrintAndLogEx(INFO
, "Number of sectors selected: %u", numSectors
);
6867 if (g_session
.pm3_present
== false) {
6868 PrintAndLogEx(FAILED
, "No Proxmark3 device present");
6872 if ((rawlen
&& fnlen
) || (rawlen
== 0 && fnlen
== 0)) {
6873 PrintAndLogEx(WARNING
, "Please specify either raw hex or filename");
6877 // test if MAD key is used
6880 // check if we can authenticate to sector
6881 int res
= mf_check_keys(0, MF_KEY_A
, true, 1, (uint8_t *)g_mifare_mad_key
, &key64
);
6882 if (res
!= PM3_SUCCESS
) {
6883 PrintAndLogEx(FAILED
, "Sector 0 failed to authenticate with MAD default key");
6884 PrintAndLogEx(HINT
, "Verify that the tag NDEF formatted");
6888 // NDEF for MIFARE CLASSIC has different memory size available.
6890 int32_t bytes
= rawlen
;
6894 uint8_t *dump
= NULL
;
6895 size_t bytes_read
= 0;
6896 res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, sizeof(raw
));
6897 if (res
!= PM3_SUCCESS
) {
6900 memcpy(raw
, dump
, bytes_read
);
6905 // Has raw bytes ndef message header?bytes
6915 if (fix_msg
== false) {
6916 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a proper header, continuing...");
6918 if (bytes
+ 2 > sizeof(raw
)) {
6919 PrintAndLogEx(WARNING
, "no room for header, exiting...");
6922 uint8_t tmp_raw
[4096];
6923 memcpy(tmp_raw
, raw
, sizeof(tmp_raw
));
6926 memcpy(raw
+ 2, tmp_raw
, sizeof(raw
) - 2);
6928 PrintAndLogEx(SUCCESS
, "Added generic message header (0x03)");
6933 // Has raw bytes ndef a terminator block?
6934 if (raw
[bytes
- 1] != 0xFE) {
6935 if (fix_msg
== false) {
6936 PrintAndLogEx(WARNING
, "raw NDEF message doesn't have a terminator block, continuing...");
6939 if (bytes
+ 1 > sizeof(raw
)) {
6940 PrintAndLogEx(WARNING
, "no room for terminator block, exiting...");
6945 PrintAndLogEx(SUCCESS
, "Added terminator block (0xFE)");
6950 PrintAndLogEx(INFO
, "Num of Bytes... %u", bytes
);
6951 print_buffer(raw
, bytes
, 0);
6954 // read MAD Sector 0, block1,2
6955 uint8_t sector0
[MFBLOCK_SIZE
* 4] = {0};
6956 if (mf_read_sector(MF_MAD1_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector0
)) {
6957 PrintAndLogEx(ERR
, "error, reading sector 0. 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");
6962 // read MAD Sector 10, block1,2
6963 uint8_t sector10
[MFBLOCK_SIZE
* 4] = {0};
6965 if (mf_read_sector(MF_MAD2_SECTOR
, MF_KEY_A
, g_mifare_mad_key
, sector10
)) {
6966 PrintAndLogEx(ERR
, "error, reading sector 10. Card doesn't have MAD or doesn't have MAD on default keys");
6967 PrintAndLogEx(HINT
, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key");
6973 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
6975 res
= MADDecode(sector0
, sector10
, mad
, &madlen
, false);
6976 if (res
!= PM3_SUCCESS
) {
6977 PrintAndLogEx(ERR
, "can't decode MAD");
6981 // how much memory do I have available ?
6982 // Skip sector 0 since its used for MAD
6983 uint8_t freemem
[MIFARE_4K_MAXSECTOR
] = {0};
6985 uint8_t block_no
= 0;
6986 for (uint8_t i
= 1; i
< (madlen
& 0xFF); i
++) {
6988 freemem
[i
] = (mad
[i
] == NDEF_MFC_AID
);
6992 if (block_no
== 0) {
6993 block_no
= mfFirstBlockOfSector(i
);
6997 PrintAndLogEx(INFO
, "Sector %u is NDEF formatted", i
);
6999 sum
+= (MFBLOCK_SIZE
* 3);
7004 PrintAndLogEx(INFO
, "Total avail ndef mem... %u", sum
);
7005 PrintAndLogEx(INFO
, "First block............ %u", block_no
);
7009 PrintAndLogEx(WARNING
, "Raw NDEF message is larger than available NDEF formatted memory");
7013 // main loop - write blocks
7014 uint8_t *ptr_raw
= raw
;
7017 uint8_t block
[MFBLOCK_SIZE
] = { 0x00 };
7019 if (bytes
< MFBLOCK_SIZE
) {
7020 memcpy(block
, ptr_raw
, bytes
);
7022 memcpy(block
, ptr_raw
, MFBLOCK_SIZE
);
7023 ptr_raw
+= MFBLOCK_SIZE
;
7026 // write to card, try B key first
7027 if (mf_write_block(block_no
, MF_KEY_B
, g_mifare_default_key
, block
) != PM3_SUCCESS
) {
7031 if (mf_write_block(block_no
, MF_KEY_A
, g_mifare_ndef_key
, block
) != PM3_SUCCESS
) {
7036 PrintAndLogEx(INPLACE
, "%u", block_no
);
7038 // find next available block
7041 if (mfIsSectorTrailer(block_no
)) {
7043 // skip sectors which isn't ndef formatted
7044 while (freemem
[mfSectorNum(block_no
)] == 0) {
7049 bytes
-= MFBLOCK_SIZE
;
7052 PrintAndLogEx(NORMAL
, "");
7056 static int CmdHFMFPersonalize(const char *Cmd
) {
7057 CLIParserContext
*ctx
;
7058 CLIParserInit(&ctx
, "hf mf personalize",
7059 "Personalize the UID of a MIFARE Classic EV1 card. This is only possible \n"
7060 "if it is a 7Byte UID card and if it is not already personalized.",
7061 "hf mf personalize --f0 -> double size UID\n"
7062 "hf mf personalize --f1 -> double size UID, optional usage of selection process shortcut\n"
7063 "hf mf personalize --f2 -> single size random ID\n"
7064 "hf mf personalize --f3 -> single size NUID\n"
7065 "hf mf personalize -b -k B0B1B2B3B4B5 --f3 -> use key B = 0xB0B1B2B3B4B5"
7068 void *argtable
[] = {
7070 arg_lit0("a", NULL
, "use key A to authenticate sector 0 (def)"),
7071 arg_lit0("b", NULL
, "use key B to authenticate sector 0"),
7072 arg_str0("k", "key", "<hex>", "key (def FFFFFFFFFFFF)"),
7073 arg_lit0(NULL
, "f0", "UIDFO, double size UID"),
7074 arg_lit0(NULL
, "f1", "UIDF1, double size UID, optional usage of selection process shortcut"),
7075 arg_lit0(NULL
, "f2", "UIDF2, single size random ID"),
7076 arg_lit0(NULL
, "f3", "UIDF3, single size NUID"),
7079 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7081 bool use_a
= arg_get_lit(ctx
, 1);
7082 bool use_b
= arg_get_lit(ctx
, 2);
7084 if (use_a
+ use_b
> 1) {
7085 PrintAndLogEx(ERR
, "error, use only one key type");
7090 uint8_t keytype
= 0;
7095 uint8_t key
[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
7097 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 3), key
, 6, &key_len
);
7098 if (res
|| (!res
&& key_len
&& key_len
!= 6)) {
7099 PrintAndLogEx(ERR
, "ERROR: not a valid key. Key must be 12 hex digits");
7104 bool f0
= arg_get_lit(ctx
, 4);
7105 bool f1
= arg_get_lit(ctx
, 5);
7106 bool f2
= arg_get_lit(ctx
, 6);
7107 bool f3
= arg_get_lit(ctx
, 7);
7110 uint8_t tmp
= f0
+ f1
+ f2
+ f3
;
7112 PrintAndLogEx(WARNING
, "select only one key type");
7116 PrintAndLogEx(WARNING
, "select one key type");
7120 uint8_t pers_option
= MIFARE_EV1_UIDF3
;
7122 pers_option
= MIFARE_EV1_UIDF0
;
7124 pers_option
= MIFARE_EV1_UIDF1
;
7126 pers_option
= MIFARE_EV1_UIDF2
;
7133 uint8_t pers_option
;
7136 payload
.keytype
= keytype
;
7137 payload
.pers_option
= pers_option
;
7138 memcpy(payload
.key
, key
, sizeof(payload
.key
));
7140 clearCommandBuffer();
7141 SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID
, (uint8_t *)&payload
, sizeof(payload
));
7142 PacketResponseNG resp
;
7143 if (WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID
, &resp
, 2500) == false) {
7144 return PM3_ETIMEOUT
;
7147 if (resp
.status
== PM3_SUCCESS
) {
7148 PrintAndLogEx(SUCCESS
, "Personalization ( %s )", _GREEN_("ok"));
7150 PrintAndLogEx(FAILED
, "Personalization ( %s )", _RED_("fail"));
7155 static int CmdHF14AMfList(const char *Cmd
) {
7156 return CmdTraceListAlias(Cmd
, "hf mf", "mf -c");
7159 static int CmdHf14AGen3UID(const char *Cmd
) {
7160 CLIParserContext
*ctx
;
7161 CLIParserInit(&ctx
, "hf mf gen3uid",
7162 "Set UID for magic Gen3 card _without_ changes to manufacturer block 0",
7163 "hf mf gen3uid --uid 01020304 --> set 4 byte uid\n"
7164 "hf mf gen3uid --uid 01020304050607 --> set 7 byte uid"
7166 void *argtable
[] = {
7168 arg_str0("u", "uid", "<hex>", "UID 4/7 hex bytes"),
7171 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7173 uint8_t uid
[7] = {0};
7175 CLIGetHexWithReturn(ctx
, 1, uid
, &uidlen
);
7179 if (uidlen
!= 4 && uidlen
!= 7) {
7180 PrintAndLogEx(FAILED
, "UID must be 4 or 7 hex bytes. Got %d", uidlen
);
7184 uint8_t old_uid
[10] = {0};
7186 int res
= mf_chinese_gen_3_uid(uid
, uidlen
, old_uid
);
7187 if (res
!= PM3_SUCCESS
) {
7188 PrintAndLogEx(ERR
, "Can't set UID");
7189 PrintAndLogEx(HINT
, "Are you sure your card is a Gen3 ?");
7193 PrintAndLogEx(SUCCESS
, "Old UID... %s", sprint_hex(old_uid
, uidlen
));
7194 PrintAndLogEx(SUCCESS
, "New UID... %s", sprint_hex(uid
, uidlen
));
7198 static int CmdHf14AGen3Block(const char *Cmd
) {
7199 CLIParserContext
*ctx
;
7200 CLIParserInit(&ctx
, "hf mf gen3blk",
7201 "Overwrite full manufacturer block for magic Gen3 card\n"
7202 " - You can specify part of manufacturer block as\n"
7203 " 4/7-bytes for UID change only\n"
7205 "NOTE: BCC, SAK, ATQA will be calculated automatically"
7207 "hf mf gen3blk --> print current data\n"
7208 "hf mf gen3blk -d 01020304 --> set 4 byte uid\n"
7209 "hf mf gen3blk -d 01020304050607 --> set 7 byte uid \n"
7210 "hf mf gen3blk -d 01020304FFFFFFFF0102030405060708"
7213 void *argtable
[] = {
7215 arg_str0("d", "data", "<hex>", "manufacturer block data up to 16 hex bytes"),
7218 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7220 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
7222 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
7225 uint8_t new_block
[MFBLOCK_SIZE
] = {0x00};
7226 int res
= mf_chinese_gen_3_block(data
, datalen
, new_block
);
7228 PrintAndLogEx(ERR
, "Can't change manufacturer block data. error %d", res
);
7232 PrintAndLogEx(SUCCESS
, "Current block... %s", sprint_hex_inrow(new_block
, sizeof(new_block
)));
7236 static int CmdHf14AGen3Freeze(const char *Cmd
) {
7237 CLIParserContext
*ctx
;
7238 CLIParserInit(&ctx
, "hf mf gen3freeze",
7239 "Perma lock further UID changes. No more UID changes available after operation completed\n"
7240 "\nNote: operation is " _RED_("! irreversible !"),
7242 "hf mf gen3freeze -y"
7244 void *argtable
[] = {
7246 arg_lit1("y", "yes", "confirm UID lock operation"),
7249 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
7250 bool confirm
= arg_get_lit(ctx
, 1);
7252 if (confirm
== false) {
7253 PrintAndLogEx(INFO
, "please confirm that you want to perma lock the card");
7257 int res
= mf_chinese_gen_3_freeze();
7258 if (res
!= PM3_SUCCESS
) {
7259 PrintAndLogEx(ERR
, "Can't lock UID changes. error %d", res
);
7261 PrintAndLogEx(SUCCESS
, "MFC Gen3 UID card is now perma-locked");
7266 #define FURUI_MAX_TRACES 8
7267 static int mfc_furui_recovery(uint8_t items
, uint8_t tracedata
[FURUI_MAX_TRACES
][18]) {
7268 // recover key from collected traces
7270 for (uint8_t i
= 0; i
< items
; i
++) {
7274 data
.cuid
= bytes_to_num(tracedata
[i
], 4);
7275 data
.nonce
= bytes_to_num(tracedata
[i
] + 6, 4);
7276 data
.nr
= bytes_to_num(tracedata
[i
] + 10, 4);
7277 data
.ar
= bytes_to_num(tracedata
[i
] + 14, 4);
7281 for (uint8_t j
= i
+ 1; j
< items
; j
++) {
7283 uint8_t *p
= tracedata
[j
];
7284 PrintAndLogEx(INFO
, "%u... %s", i
, sprint_hex_inrow(p
, 18));
7286 // since data stored as block number but its the same key for all blocks in one sector
7287 // we compare with sector number here
7288 uint8_t s
= mfSectorNum(tracedata
[i
][4]);
7289 if (mfSectorNum(p
[4]) == s
) {
7291 data
.nonce2
= bytes_to_num(p
+ 6, 4);
7292 data
.nr2
= bytes_to_num(p
+ 10, 4);
7293 data
.ar2
= bytes_to_num(p
+ 14, 4);
7295 data
.keytype
= tracedata
[i
][5];
7298 uint64_t key64
= -1;
7299 if (mfkey32_moebius(&data
, &key64
)) {
7300 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64
) " ]",
7301 sprint_hex_inrow(tracedata
[i
], 4),
7303 (data
.keytype
== 0x60) ? 'A' : 'B',
7314 static int mfc_supercard_gen2_recovery(uint8_t items
, uint8_t tracedata
[FURUI_MAX_TRACES
][18]) {
7315 for (uint8_t i
= 0; i
< items
; i
++) {
7316 uint8_t *tmp
= tracedata
[i
];
7319 uint16_t NT0
= (tmp
[6] << 8) | tmp
[7];
7322 data
.cuid
= bytes_to_num(tmp
, 4);
7323 data
.nonce
= prng_successor(NT0
, 31);
7324 data
.nr
= bytes_to_num(tmp
+ 8, 4);
7325 data
.ar
= bytes_to_num(tmp
+ 12, 4);
7329 for (uint8_t j
= i
+ 1; j
< items
; j
++) {
7330 uint8_t *p
= tracedata
[j
];
7332 // since data stored as block number but its the same key for all blocks in one sector
7333 // we compare with sector number here
7334 uint8_t s
= mfSectorNum(tmp
[5]);
7335 if (mfSectorNum(p
[5]) == s
) {
7337 NT0
= (p
[6] << 8) | p
[7];
7339 data
.nonce2
= prng_successor(NT0
, 31);
7340 data
.nr2
= bytes_to_num(p
+ 8, 4);
7341 data
.ar2
= bytes_to_num(p
+ 12, 4);
7343 data
.keytype
= tmp
[4];
7346 uint64_t key64
= -1;
7347 if (mfkey32_moebius(&data
, &key64
)) {
7348 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64
) " ]",
7349 sprint_hex_inrow(tmp
, 4),
7351 (data
.keytype
== 0x60) ? 'A' : 'B',
7362 static int CmdHf14AMfSuperCard(const char *Cmd
) {
7363 CLIParserContext
*ctx
;
7364 CLIParserInit(&ctx
, "hf mf supercard",
7365 "Extract info from a `super card`",
7366 "hf mf supercard -> recover key\n"
7367 "hf mf supercard -r -> reset card\n"
7368 "hf mf supercard -u 11223344 -> change UID\n");
7370 void *argtable
[] = {
7372 arg_lit0("r", "reset", "Reset card"),
7373 arg_str0("u", "uid", "<hex>", "New UID (4 hex bytes)"),
7374 arg_lit0(NULL
, "furui", "Furui detection card"),
7377 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7378 bool reset_card
= arg_get_lit(ctx
, 1);
7381 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), uid
, sizeof(uid
), &uidlen
);
7382 bool is_furui
= arg_get_lit(ctx
, 3);
7387 if (res
|| (!res
&& uidlen
&& uidlen
!= sizeof(uid
))) {
7388 PrintAndLogEx(ERR
, "UID must include 4 hex bytes");
7392 uint8_t tracedata
[FURUI_MAX_TRACES
][18];
7397 // no reset on super card FURUI
7398 if (uidlen
|| reset_card
) {
7399 PrintAndLogEx(FAILED
, "Not supported on this card");
7405 for (i
= 0; i
< FURUI_MAX_TRACES
; i
++) {
7407 uint8_t data
[] = {0xAA, 0xA8, 0x00, i
};
7408 uint32_t flags
= ISO14A_CONNECT
| ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_RATS
;
7409 clearCommandBuffer();
7410 SendCommandMIX(CMD_HF_ISO14443A_READER
, flags
, sizeof(data
), 0, data
, sizeof(data
));
7411 if (WaitForResponseTimeout(CMD_ACK
, NULL
, 1500) == false) {
7415 PacketResponseNG resp
;
7416 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
7420 uint16_t len
= resp
.oldarg
[0] & 0xFFFF;
7422 break; // Not trace data
7425 PrintAndLogEx(DEBUG
, ">>> %s", sprint_hex_inrow(resp
.data
.asBytes
, len
));
7426 memcpy(&tracedata
[i
], resp
.data
.asBytes
, len
- 2);
7429 return mfc_furui_recovery(i
, tracedata
);
7432 #define SUPER_MAX_TRACES 7
7434 // read 7 traces from super card generation 1,2
7436 for (i
= 0; i
< SUPER_MAX_TRACES
; i
++) {
7438 uint8_t data
[] = {0x30, i
};
7439 uint32_t flags
= ISO14A_CONNECT
| ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_RATS
;
7440 clearCommandBuffer();
7441 SendCommandMIX(CMD_HF_ISO14443A_READER
, flags
, sizeof(data
), 0, data
, sizeof(data
));
7442 if (WaitForResponseTimeout(CMD_ACK
, NULL
, 1500) == false) {
7446 PacketResponseNG resp
;
7447 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
7451 uint16_t len
= resp
.oldarg
[0] & 0xFFFF;
7453 break; // Not trace data
7456 PrintAndLogEx(DEBUG
, ">>> %s", sprint_hex_inrow(resp
.data
.asBytes
, len
));
7457 memcpy(&tracedata
[i
], resp
.data
.asBytes
, len
- 2);
7460 // Super card generation 2
7461 if (i
== SUPER_MAX_TRACES
) {
7463 // no reset on super card generation 2.
7464 if (uidlen
|| reset_card
) {
7465 PrintAndLogEx(FAILED
, "Not supported on this card");
7469 // recover key from collected traces
7470 return mfc_supercard_gen2_recovery(i
, tracedata
);
7473 // Super card generation 1
7479 bool activate_field
= true;
7480 bool keep_field_on
= true;
7482 // change UID on a super card generation 1
7484 keep_field_on
= false;
7485 uint8_t response
[6];
7488 // --------------- CHANGE UID ----------------
7489 uint8_t aCHANGE
[] = {0x00, 0xa6, 0xa0, 0x00, 0x05, 0xff, 0xff, 0xff, 0xff, 0x00};
7490 memcpy(aCHANGE
+ 5, uid
, uidlen
);
7491 res
= ExchangeAPDU14a(
7492 aCHANGE
, sizeof(aCHANGE
),
7495 response
, sizeof(response
),
7499 if (res
!= PM3_SUCCESS
) {
7500 PrintAndLogEx(FAILED
, "Super card UID change [ " _RED_("fail") " ]");
7505 PrintAndLogEx(SUCCESS
, "Super card UID change ( " _GREEN_("ok") " )");
7509 // reset a super card generation 1
7511 keep_field_on
= false;
7512 uint8_t response
[6];
7515 // --------------- RESET CARD ----------------
7516 uint8_t aRESET
[] = {0x00, 0xa6, 0xc0, 0x00};
7517 res
= ExchangeAPDU14a(
7518 aRESET
, sizeof(aRESET
),
7521 response
, sizeof(response
),
7525 if (res
!= PM3_SUCCESS
) {
7526 PrintAndLogEx(FAILED
, "Super card reset [ " _RED_("fail") " ]");
7530 PrintAndLogEx(SUCCESS
, "Super card reset ( " _GREEN_("ok") " )");
7534 uint8_t responseA
[22];
7535 uint8_t responseB
[22];
7539 // --------------- First ----------------
7540 uint8_t aFIRST
[] = {0x00, 0xa6, 0xb0, 0x00, 0x10};
7541 res
= ExchangeAPDU14a(aFIRST
, sizeof(aFIRST
), activate_field
, keep_field_on
, responseA
, sizeof(responseA
), &respAlen
);
7542 if (res
!= PM3_SUCCESS
) {
7547 // --------------- Second ----------------
7548 activate_field
= false;
7549 keep_field_on
= false;
7551 uint8_t aSECOND
[] = {0x00, 0xa6, 0xb0, 0x01, 0x10};
7552 res
= ExchangeAPDU14a(aSECOND
, sizeof(aSECOND
), activate_field
, keep_field_on
, responseB
, sizeof(responseB
), &respBlen
);
7553 if (res
!= PM3_SUCCESS
) {
7558 uint8_t outA
[16] = {0};
7559 uint8_t outB
[16] = {0};
7561 uint8_t key
[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
7562 for (i
= 0; i
< 16; i
+= 8) {
7563 des_decrypt(outA
+ i
, responseA
+ i
, key
);
7564 des_decrypt(outB
+ i
, responseB
+ i
, key
);
7567 PrintAndLogEx(DEBUG
, " in : %s", sprint_hex_inrow(responseA
, respAlen
));
7568 PrintAndLogEx(DEBUG
, "out : %s", sprint_hex_inrow(outA
, sizeof(outA
)));
7569 PrintAndLogEx(DEBUG
, " in : %s", sprint_hex_inrow(responseB
, respAlen
));
7570 PrintAndLogEx(DEBUG
, "out : %s", sprint_hex_inrow(outB
, sizeof(outB
)));
7572 if (memcmp(outA
, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
7573 PrintAndLogEx(INFO
, "No trace recorded");
7578 if (memcmp(outB
, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) {
7579 PrintAndLogEx(INFO
, "Only one trace recorded");
7586 uint16_t NT0
= (outA
[6] << 8) | outA
[7];
7587 data
.cuid
= bytes_to_num(outA
, 4);
7588 data
.nonce
= prng_successor(NT0
, 31);
7589 data
.nr
= bytes_to_num(outA
+ 8, 4);
7590 data
.ar
= bytes_to_num(outA
+ 12, 4);
7594 NT0
= (outB
[6] << 8) | outB
[7];
7595 data
.nonce2
= prng_successor(NT0
, 31);
7596 data
.nr2
= bytes_to_num(outB
+ 8, 4);
7597 data
.ar2
= bytes_to_num(outB
+ 12, 4);
7598 data
.sector
= mfSectorNum(outA
[5]);
7599 data
.keytype
= outA
[4];
7602 PrintAndLogEx(DEBUG
, "A Sector %02x", data
.sector
);
7603 PrintAndLogEx(DEBUG
, "A NT %08x", data
.nonce
);
7604 PrintAndLogEx(DEBUG
, "A NR %08x", data
.nr
);
7605 PrintAndLogEx(DEBUG
, "A AR %08x", data
.ar
);
7606 PrintAndLogEx(DEBUG
, "");
7607 PrintAndLogEx(DEBUG
, "B NT %08x", data
.nonce2
);
7608 PrintAndLogEx(DEBUG
, "B NR %08x", data
.nr2
);
7609 PrintAndLogEx(DEBUG
, "B AR %08x", data
.ar2
);
7611 uint64_t key64
= -1;
7612 if (mfkey32_moebius(&data
, &key64
)) {
7613 PrintAndLogEx(SUCCESS
, "UID: %s Sector %02x key %c [ " _GREEN_("%012" PRIX64
) " ]",
7614 sprint_hex_inrow(outA
, 4),
7616 (data
.keytype
== 0x60) ? 'A' : 'B',
7620 PrintAndLogEx(FAILED
, "failed to recover any key");
7625 static int CmdHF14AMfWipe(const char *Cmd
) {
7626 CLIParserContext
*ctx
;
7627 CLIParserInit(&ctx
, "hf mf wipe",
7628 "Wipe card to zeros and default keys/acc. This command takes a key file to wipe card\n"
7629 "Will use UID from card to generate keyfile name if not specified.\n"
7630 "New A/B keys..... FF FF FF FF FF FF\n"
7631 "New acc rights... FF 07 80\n"
7632 "New GPB.......... 69",
7633 "hf mf wipe --> reads card uid to generate file name\n"
7634 "hf mf wipe --gen2 --> force write to S0, B0 manufacture block\n"
7635 "hf mf wipe -f mykey.bin --> use mykey.bin\n"
7637 void *argtable
[] = {
7639 arg_str0("f", "file", "<fn>", "key filename"),
7640 arg_lit0(NULL
, "gen2", "force write to Sector 0, block 0 (GEN2)"),
7643 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
7646 char keyFilename
[FILE_PATH_SIZE
] = {0};
7647 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)keyFilename
, FILE_PATH_SIZE
, &keyfnlen
);
7649 bool gen2
= arg_get_lit(ctx
, 2);
7653 if (keyfnlen
== 0) {
7654 fptr
= GenerateFilename("hf-mf-", "-key.bin");
7658 strncpy(keyFilename
, fptr
, sizeof(keyFilename
) - 1);
7664 if (loadFile_safeEx(keyFilename
, ".bin", (void **)&keys
, (size_t *)&keyslen
, false) != PM3_SUCCESS
) {
7665 PrintAndLogEx(FAILED
, "failed to load key file");
7669 uint8_t keyA
[MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
];
7670 uint8_t keyB
[MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
];
7671 uint8_t num_sectors
= 0;
7673 uint8_t mf
[MFBLOCK_SIZE
];
7675 case (MIFARE_MINI_MAX_KEY_SIZE
): {
7676 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic Mini 320b");
7677 memcpy(keyA
, keys
, (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
));
7678 memcpy(keyB
, keys
+ (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_MINI_MAXSECTOR
* MIFARE_KEY_SIZE
));
7679 num_sectors
= NumOfSectors('0');
7680 memcpy(mf
, "\x11\x22\x33\x44\x44\x09\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7683 case (MIFARE_1K_EV1_MAX_KEY_SIZE
): {
7684 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 1K Ev1");
7685 memcpy(keyA
, keys
, (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
));
7686 memcpy(keyB
, keys
+ (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_1K_EV1_MAXSECTOR
* MIFARE_KEY_SIZE
));
7687 num_sectors
= NumOfSectors('1');
7688 memcpy(mf
, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7691 case (MIFARE_1K_MAX_KEY_SIZE
): {
7692 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 1K");
7693 memcpy(keyA
, keys
, (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7694 memcpy(keyB
, keys
+ (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_1K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7695 num_sectors
= NumOfSectors('1');
7697 memcpy(mf
, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7700 case (MIFARE_4K_MAX_KEY_SIZE
): {
7701 PrintAndLogEx(INFO
, "Loaded keys matching MIFARE Classic 4K");
7702 memcpy(keyA
, keys
, (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7703 memcpy(keyB
, keys
+ (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
), (MIFARE_4K_MAXSECTOR
* MIFARE_KEY_SIZE
));
7704 num_sectors
= NumOfSectors('4');
7705 memcpy(mf
, "\x11\x22\x33\x44\x44\x18\x02\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE
);
7709 PrintAndLogEx(INFO
, "wrong key file size. got %zu", keyslen
);
7715 PrintAndLogEx(INFO
, "Forcing overwrite of sector 0 / block 0 ");
7717 PrintAndLogEx(INFO
, "Skipping sector 0 / block 0");
7719 PrintAndLogEx(NORMAL
, "");
7721 uint8_t zeros
[MFBLOCK_SIZE
] = {0};
7722 memset(zeros
, 0x00, sizeof(zeros
));
7723 uint8_t st
[MFBLOCK_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
7725 PrintAndLogEx(INFO
, " blk | ");
7726 PrintAndLogEx(INFO
, "-----+------------------------------------------------------------");
7727 // time to wipe card
7728 for (uint8_t s
= 0; s
< num_sectors
; s
++) {
7730 for (uint8_t b
= 0; b
< mfNumBlocksPerSector(s
); b
++) {
7732 if (kbd_enter_pressed()) {
7733 PrintAndLogEx(WARNING
, "\naborted via keyboard!\n");
7737 // Skip write to manufacture block if not enforced
7738 if (s
== 0 && b
== 0 && gen2
== false) {
7743 memset(data
, 0, sizeof(data
));
7744 if (mfIsSectorTrailerBasedOnBlocks(s
, b
)) {
7745 memcpy(data
+ 10, st
, sizeof(st
));
7747 memcpy(data
+ 10, zeros
, sizeof(zeros
));
7750 // add correct manufacture block if UID Gen2
7751 if (s
== 0 && b
== 0 && gen2
) {
7752 memcpy(data
+ 10, mf
, sizeof(mf
));
7755 // try both A/B keys, start with B key first
7756 for (int8_t kt
= MF_KEY_B
; kt
> -1; kt
--) {
7759 memcpy(data
, keyA
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
7761 memcpy(data
, keyB
+ (s
* MIFARE_KEY_SIZE
), MIFARE_KEY_SIZE
);
7763 PrintAndLogEx(INFO
, " %3d | %s" NOLF
, mfFirstBlockOfSector(s
) + b
, sprint_hex(data
+ 10, MFBLOCK_SIZE
));
7764 clearCommandBuffer();
7765 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, mfFirstBlockOfSector(s
) + b
, kt
, 0, data
, sizeof(data
));
7766 PacketResponseNG resp
;
7767 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500)) {
7768 int8_t isOK
= resp
.oldarg
[0];
7770 PrintAndLogEx(NORMAL
, "- key %c ( " _GREEN_("ok") " )", (kt
== MF_KEY_A
) ? 'A' : 'B');
7773 PrintAndLogEx(NORMAL
, "- key %c ( " _RED_("fail") " )", (kt
== MF_KEY_A
) ? 'A' : 'B');
7776 PrintAndLogEx(WARNING
, "command execution time out");
7782 PrintAndLogEx(INFO
, "-----+------------------------------------------------------------");
7783 PrintAndLogEx(NORMAL
, "");
7784 PrintAndLogEx(INFO
, "Done!");
7790 static int CmdHF14AMfView(const char *Cmd
) {
7792 CLIParserContext
*ctx
;
7793 CLIParserInit(&ctx
, "hf mf view",
7794 "Print a MIFARE Classic dump file (bin/eml/json)",
7795 "hf mf view -f hf-mf-01020304-dump.bin"
7797 void *argtable
[] = {
7799 arg_str1("f", "file", "<fn>", "Specify a filename for dump file"),
7800 arg_lit0("v", "verbose", "verbose output"),
7801 arg_lit0(NULL
, "sk", "Save extracted keys to binary file"),
7804 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
7806 char filename
[FILE_PATH_SIZE
];
7807 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
7808 bool verbose
= arg_get_lit(ctx
, 2);
7809 bool save_keys
= arg_get_lit(ctx
, 3);
7813 uint8_t *dump
= NULL
;
7814 size_t bytes_read
= 0;
7815 int res
= pm3_load_dump(filename
, (void **)&dump
, &bytes_read
, MIFARE_4K_MAX_BYTES
);
7816 if (res
!= PM3_SUCCESS
) {
7820 uint16_t block_cnt
= MIN(MIFARE_1K_MAXBLOCK
, (bytes_read
/ MFBLOCK_SIZE
));
7821 if (bytes_read
== MIFARE_MINI_MAX_BYTES
)
7822 block_cnt
= MIFARE_MINI_MAXBLOCK
;
7823 else if (bytes_read
== MIFARE_2K_MAX_BYTES
)
7824 block_cnt
= MIFARE_2K_MAXBLOCK
;
7825 else if (bytes_read
== MIFARE_4K_MAX_BYTES
)
7826 block_cnt
= MIFARE_4K_MAXBLOCK
;
7829 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
7832 mf_print_blocks(block_cnt
, dump
, verbose
);
7835 mf_print_keys(block_cnt
, dump
);
7836 mf_analyse_acl(block_cnt
, dump
);
7840 mf_save_keys_from_arr(block_cnt
, dump
);
7843 int sector
= DetectHID(dump
, 0x4910);
7846 PrintAndLogEx(INFO
, "");
7847 PrintAndLogEx(INFO
, _CYAN_("VIGIK PACS detected"));
7850 uint16_t mad
[7 + 8 + 8 + 8 + 8] = {0};
7852 res
= MADDecode(dump
, NULL
, mad
, &madlen
, false);
7853 if (res
!= PM3_SUCCESS
) {
7854 PrintAndLogEx(ERR
, "can't decode MAD");
7858 typedef union UDATA
{
7864 d
.bytes
= calloc(bytes_read
, sizeof(uint8_t));
7865 if (d
.bytes
== NULL
) {
7870 // vigik struture sector 0
7871 uint8_t *pdump
= dump
;
7873 memcpy(d
.bytes
+ dlen
, pdump
, MFBLOCK_SIZE
* 3);
7874 dlen
+= MFBLOCK_SIZE
* 3;
7875 pdump
+= (MFBLOCK_SIZE
* 4); // skip sectortrailer
7877 // extract memory from MAD sectors
7878 for (int i
= 0; i
<= madlen
; i
++) {
7879 if (0x4910 == mad
[i
] || 0x4916 == mad
[i
]) {
7880 memcpy(d
.bytes
+ dlen
, pdump
, MFBLOCK_SIZE
* 3);
7881 dlen
+= MFBLOCK_SIZE
* 3;
7884 pdump
+= (MFBLOCK_SIZE
* 4); // skip sectortrailer
7887 // convert_mfc_2_arr(pdump, bytes_read, d, &dlen);
7888 vigik_annotate(d
.vigik
);
7896 static int parse_gtu_cfg(uint8_t *d
, size_t n
) {
7898 PrintAndLogEx(NORMAL
, "");
7899 PrintAndLogEx(INFO
, "---------- " _CYAN_("GTU Gen4 Configuration") " -------------------------------------");
7900 if (n
!= 30 && n
!= 32) {
7901 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
, n
));
7902 PrintAndLogEx(INFO
, "%zu bytes", n
);
7903 PrintAndLogEx(WARNING
, "Unknown config format");
7907 PrintAndLogEx(INFO
, _YELLOW_("%s"), sprint_hex_inrow(d
, n
));
7908 PrintAndLogEx(INFO
, "%zu bytes", n
);
7909 PrintAndLogEx(INFO
, "");
7910 PrintAndLogEx(INFO
, _CYAN_("Config 1 - UID & modes"));
7911 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
, 8));
7912 PrintAndLogEx(INFO
, "%02X.............. " NOLF
, d
[0]);
7913 bool is_ul_enabled
= (d
[0] == 1);
7916 PrintAndLogEx(NORMAL
, "MIFARE Classic mode");
7919 PrintAndLogEx(NORMAL
, "MIFARE Ultralight/NTAG mode");
7922 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7926 PrintAndLogEx(INFO
, "..%02X............ UID " NOLF
, d
[1]);
7930 PrintAndLogEx(NORMAL
, _GREEN_("4") " byte");
7933 PrintAndLogEx(NORMAL
, _GREEN_("7") " byte");
7936 PrintAndLogEx(NORMAL
, _GREEN_("10") " byte");
7939 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7943 PrintAndLogEx(INFO
, "...." _YELLOW_("%s") ".... " _YELLOW_("Password"), sprint_hex_inrow(&d
[2], 4));
7944 PrintAndLogEx(INFO
, "............%02X.. GTU mode " NOLF
, d
[6]);
7947 PrintAndLogEx(NORMAL
, _GREEN_("pre-write") " - shadow data can be written");
7950 PrintAndLogEx(NORMAL
, _GREEN_("restore mode"));
7953 PrintAndLogEx(NORMAL
, "disabled");
7956 PrintAndLogEx(NORMAL
, "disabled, high speed R/W mode for Ultralight ?");
7959 PrintAndLogEx(NORMAL
, _RED_("unknown"));
7963 uint8_t atslen
= d
[7];
7965 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _YELLOW_("zero"));
7966 } else if (atslen
<= 16) {
7967 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _GREEN_("ok"));
7969 PrintAndLogEx(INFO
, ".............. ATS length %u bytes ( %s )", atslen
, _RED_("fail"));
7973 PrintAndLogEx(INFO
, "");
7975 // ATS seems to have 16 bytes reserved
7976 PrintAndLogEx(INFO
, _CYAN_("Config 2 - ATS"));
7977 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
+ 8, 16));
7979 PrintAndLogEx(INFO
, "%s.............. ATS ( %d bytes )", sprint_hex_inrow(&d
[8], d
[7]), d
[7]);
7980 PrintAndLogEx(INFO
, "..................%s Reserved for ATS", sprint_hex_inrow(d
+ 8 + d
[7], 16 - d
[7]));
7982 PrintAndLogEx(INFO
, "%s.............. %u Reserved for ATS", sprint_hex_inrow(&d
[8], 16), 16);
7985 PrintAndLogEx(INFO
, "");
7986 PrintAndLogEx(INFO
, _CYAN_("Config 3 - Limits"));
7987 PrintAndLogEx(INFO
, "%s", sprint_hex_inrow(d
+ 24, (n
- 24)));
7988 PrintAndLogEx(INFO
, "%02X%02X............ ATQA", d
[24], d
[25]);
7989 PrintAndLogEx(INFO
, "....%02X.......... SAK", d
[26]);
7990 PrintAndLogEx(INFO
, "......%02X........ " NOLF
, d
[27]);
7993 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight EV1") : "Ultralight Ev1");
7996 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("NTAG") : "NTAG");
7999 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight C") : "Ultralight C");
8002 PrintAndLogEx(NORMAL
, "%s", (is_ul_enabled
) ? _GREEN_("Ultralight") : "Ultralight");
8005 PrintAndLogEx(NORMAL
, _RED_("unknown"));
8009 PrintAndLogEx(INFO
, "........%02X...... Max R/W sectors", d
[28]);
8010 PrintAndLogEx(INFO
, "..........%02X.... " NOLF
, d
[29]);
8013 PrintAndLogEx(NORMAL
, _GREEN_("CUID enabled"));
8016 PrintAndLogEx(NORMAL
, "CUID disabled");
8019 PrintAndLogEx(NORMAL
, "Default value. Same behaviour as 00?");
8022 PrintAndLogEx(NORMAL
, _RED_("unknown"));
8025 PrintAndLogEx(INFO
, "............%s unknown", sprint_hex_inrow(d
+ 30, n
- 30));
8026 PrintAndLogEx(INFO
, "");
8030 // info about Gen4 GTU card
8031 static int CmdHF14AGen4Info(const char *cmd
) {
8032 CLIParserContext
*ctx
;
8033 CLIParserInit(&ctx
, "hf mf ginfo",
8034 "Read info about magic gen4 GTU card.",
8035 "hf mf ginfo --> get info with default password 00000000\n"
8036 "hf mf ginfo --pwd 01020304 --> get info with password\n"
8037 "hf mf ginfo -d 00000000000002090978009102BDAC19131011121314151604001800FF0002FD -v --> decode config block"
8039 void *argtable
[] = {
8041 arg_lit0("v", "verbose", "verbose output"),
8042 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8043 arg_str0("d", "data", "<hex>", "config bytes 32 bytes"),
8046 CLIExecWithReturn(ctx
, cmd
, argtable
, true);
8047 bool verbose
= arg_get_lit(ctx
, 1);
8050 uint8_t pwd
[4] = {0};
8051 CLIGetHexWithReturn(ctx
, 2, pwd
, &pwd_len
);
8054 uint8_t data
[32] = {0};
8055 CLIGetHexWithReturn(ctx
, 3, data
, &dlen
);
8058 if (pwd_len
!= 0 && pwd_len
!= 4) {
8059 PrintAndLogEx(FAILED
, "Password must be 4 bytes length, got " _YELLOW_("%u"), pwd_len
);
8063 uint8_t resp
[40] = {0};
8068 res
= mfG4GetConfig(pwd
, resp
, &resplen
, verbose
);
8069 if (res
!= PM3_SUCCESS
|| resplen
== 0) {
8070 if (res
== PM3_ETIMEOUT
)
8071 PrintAndLogEx(ERR
, "No card in the field or card command timeout.");
8073 PrintAndLogEx(ERR
, "Error get config. Maybe not a Gen4 card?. error=%d rlen=%zu", res
, resplen
);
8077 memcpy(resp
, data
, dlen
);
8081 parse_gtu_cfg(resp
, resplen
);
8083 uint8_t uid_len
= resp
[1];
8085 res
= mfG4GetFactoryTest(pwd
, resp
, &resplen
, false);
8086 if (res
== PM3_SUCCESS
&& resplen
> 2) {
8087 PrintAndLogEx(INFO
, "");
8088 PrintAndLogEx(INFO
, _CYAN_("Factory test"));
8090 PrintAndLogEx(INFO
, "Raw......... %s", sprint_hex_inrow(resp
, resplen
));
8093 if (memcmp(resp
+ resplen
- 2, "\x66\x66", 2) == 0) {
8094 PrintAndLogEx(INFO
, "Card type... Generic");
8096 } else if (memcmp(resp
+ resplen
- 2, "\x02\xAA", 2) == 0) {
8097 PrintAndLogEx(INFO
, "Card type... " _RED_("Limited functionality"));
8099 } else if (memcmp(resp
+ resplen
- 2, "\x03\xA0", 2) == 0) {
8100 PrintAndLogEx(INFO
, "Card type... Old card version");
8102 } else if (memcmp(resp
+ resplen
- 2, "\x06\xA0", 2) == 0) {
8103 PrintAndLogEx(INFO
, "Card type... " _GREEN_("New card version"));
8106 PrintAndLogEx(INFO
, "Card type... " _RED_("unknown %02X%02X"), resp
[resplen
- 2], resp
[resplen
- 1]);
8111 res
= mfG4GetBlock(pwd
, 0, resp
, MAGIC_INIT
| MAGIC_OFF
);
8112 if (res
== PM3_SUCCESS
) {
8113 PrintAndLogEx(INFO
, "");
8114 PrintAndLogEx(INFO
, _CYAN_("Block 0 test"));
8115 PrintAndLogEx(INFO
, "Block 0..... %s", sprint_hex_inrow(resp
, 16));
8119 PrintAndLogEx(INFO
, "UID [4]..... %s", sprint_hex_inrow(resp
, 4));
8122 PrintAndLogEx(INFO
, "UID [7]..... %s", sprint_hex_inrow(resp
, 7));
8125 PrintAndLogEx(INFO
, "UID [10..... %s", sprint_hex_inrow(resp
, 10));
8132 PrintAndLogEx(NORMAL
, "");
8136 // Read block from Gen4 GTU card
8137 static int CmdHF14AGen4GetBlk(const char *cmd
) {
8138 CLIParserContext
*ctx
;
8139 CLIParserInit(&ctx
, "hf mf ggetblk",
8140 "Get block data from magic gen4 GTU card.",
8141 "hf mf ggetblk --blk 0 --> get block 0 (manufacturer)\n"
8142 "hf mf ggetblk --blk 3 -v --> get block 3, decode sector trailer\n"
8144 void *argtable
[] = {
8146 arg_int1("b", "blk", "<dec>", "block number"),
8147 arg_lit0("v", "verbose", "verbose output"),
8148 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8151 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8152 int b
= arg_get_int_def(ctx
, 1, 0);
8153 bool verbose
= arg_get_lit(ctx
, 2);
8156 uint8_t pwd
[4] = {0};
8157 CLIGetHexWithReturn(ctx
, 3, pwd
, &pwd_len
);
8161 if (b
> MIFARE_4K_MAXBLOCK
) {
8165 if (pwd_len
!= 4 && pwd_len
!= 0) {
8166 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8170 uint8_t blockno
= (uint8_t)b
;
8171 uint8_t data
[16] = {0};
8173 PrintAndLogEx(NORMAL
, "Block: %x", blockno
) ;
8175 int res
= mfG4GetBlock(pwd
, blockno
, data
, MAGIC_INIT
| MAGIC_OFF
);
8177 PrintAndLogEx(ERR
, "Can't read block. error=%d", res
);
8181 uint8_t sector
= mfSectorNum(blockno
);
8182 mf_print_sector_hdr(sector
);
8183 mf_print_block_one(blockno
, data
, verbose
);
8186 decode_print_st(blockno
, data
);
8188 PrintAndLogEx(NORMAL
, "");
8194 // Load dump to Gen4 GTU card
8195 static int CmdHF14AGen4Load(const char *cmd
) {
8197 CLIParserContext
*ctx
;
8198 CLIParserInit(&ctx
, "hf mf gload",
8199 "Load magic gen4 gtu card with data from (bin/eml/json) dump file\n"
8200 "or from emulator memory.",
8201 "hf mf gload --emu\n"
8202 "hf mf gload -f hf-mf-01020304.eml\n"
8203 "hf mf gload -p AABBCCDD --4k -v -f hf-mf-01020304-dump.bin\n"
8205 "Card must be configured beforehand with `script run hf_mf_ultimatecard`.\n"
8206 "Blocks are 16 bytes long."
8208 void *argtable
[] = {
8210 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8211 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8212 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8213 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8214 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8215 arg_lit0("v", "verbose", "verbose output"),
8216 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
8217 arg_lit0(NULL
, "emu", "from emulator memory"),
8218 arg_int0(NULL
, "start", "<dec>", "index of block to start writing (default 0)"),
8219 arg_int0(NULL
, "end", "<dec>", "index of block to end writing (default last block)"),
8223 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8224 bool m0
= arg_get_lit(ctx
, 1);
8225 bool m1
= arg_get_lit(ctx
, 2);
8226 bool m2
= arg_get_lit(ctx
, 3);
8227 bool m4
= arg_get_lit(ctx
, 4);
8230 uint8_t pwd
[4] = {0};
8231 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8233 bool verbose
= arg_get_lit(ctx
, 6);
8236 char filename
[FILE_PATH_SIZE
] = {0};
8237 CLIParamStrToBuf(arg_get_str(ctx
, 7), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
8239 bool fill_from_emulator
= arg_get_lit(ctx
, 8);
8241 int start
= arg_get_int_def(ctx
, 9, 0);
8242 int end
= arg_get_int_def(ctx
, 10, -1);
8247 if (pwd_len
!= 4 && pwd_len
!= 0) {
8248 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8252 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8253 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8255 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8260 memset(s
, 0, sizeof(s
));
8261 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8263 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8264 strncpy(s
, "Mini", 5);
8266 block_cnt
= MIFARE_1K_MAXBLOCK
;
8267 strncpy(s
, "1K", 3);
8269 block_cnt
= MIFARE_2K_MAXBLOCK
;
8270 strncpy(s
, "2K", 3);
8272 block_cnt
= MIFARE_4K_MAXBLOCK
;
8273 strncpy(s
, "4K", 3);
8275 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8279 if (fill_from_emulator
&& (fnlen
!= 0)) {
8280 PrintAndLogEx(WARNING
, "Please specify file or emulator memory, but not both");
8284 if (!fill_from_emulator
&& (fnlen
== 0)) {
8285 PrintAndLogEx(WARNING
, "Please specify file or emulator memory");
8290 end
= block_cnt
- 1;
8293 if (start
< 0 || end
< 0) {
8294 PrintAndLogEx(WARNING
, "start and end must be positive integers");
8295 return PM3_EINVARG
;
8299 PrintAndLogEx(WARNING
, "start cannot be more than end");
8300 return PM3_EINVARG
;
8303 if (start
>= block_cnt
) {
8304 PrintAndLogEx(WARNING
, "Last block for Mifare %s is %d. Start is too high.", s
, block_cnt
- 1) ;
8305 return PM3_EINVARG
;
8308 if (end
>= block_cnt
) {
8309 PrintAndLogEx(WARNING
, "Last block for Mifare %s is %d. End is too high.", s
, block_cnt
- 1) ;
8310 return PM3_EINVARG
;
8313 uint8_t *data
= NULL
;
8314 size_t bytes_read
= 0;
8316 if (fill_from_emulator
) {
8317 data
= calloc(block_cnt
* MFBLOCK_SIZE
, sizeof(uint8_t));
8319 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8323 PrintAndLogEx(INFO
, "downloading emulator memory");
8324 if (GetFromDevice(BIG_BUF_EML
, data
, block_cnt
* MFBLOCK_SIZE
, 0, NULL
, 0, NULL
, 2500, false) == false) {
8325 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
8327 return PM3_ETIMEOUT
;
8332 int res
= pm3_load_dump(filename
, (void **)&data
, &bytes_read
, (MFBLOCK_SIZE
* MIFARE_4K_MAXBLOCK
));
8333 if (res
!= PM3_SUCCESS
) {
8337 // check file size corresponds to card size.
8338 if (bytes_read
!= (block_cnt
* MFBLOCK_SIZE
)) {
8339 PrintAndLogEx(ERR
, "File content error. Read %zu bytes, expected %i", bytes_read
, block_cnt
* MFBLOCK_SIZE
);
8340 if (data
!= NULL
) free(data
);
8347 PrintAndLogEx(INFO
, "File: " _YELLOW_("%s"), filename
);
8348 PrintAndLogEx(INFO
, "File size %zu bytes, file blocks %d (0x%x)", bytes_read
, block_cnt
, block_cnt
);
8350 PrintAndLogEx(INFO
, "Read %d blocks from emulator memory", block_cnt
);
8354 PrintAndLogEx(INFO
, "Copying to magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s
);
8355 PrintAndLogEx(INFO
, "Starting block: %d. Ending block: %d.", start
, end
);
8358 for (uint16_t blockno
= start
; blockno
<= end
; blockno
++) {
8360 // 4k writes can be long, so we split status each 64 block boundary.
8361 if (blockno
% 64 == 0 || blockno
== start
) {
8362 PrintAndLogEx(NORMAL
, "");
8363 PrintAndLogEx(INFO
, "" NOLF
) ;
8365 PrintAndLogEx(NORMAL
, "." NOLF
);
8370 if (blockno
== start
) flags
|= MAGIC_INIT
;
8371 if (blockno
== end
) flags
|= MAGIC_OFF
;
8373 int res
= mfG4SetBlock(pwd
, blockno
, data
+ (blockno
* MFBLOCK_SIZE
), flags
);
8374 if (res
!= PM3_SUCCESS
) {
8375 PrintAndLogEx(WARNING
, "Can't set magic card block: %d. error=%d", blockno
, res
);
8376 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8381 PrintAndLogEx(NORMAL
, "\n");
8383 if (data
!= NULL
) free(data
);
8385 PrintAndLogEx(SUCCESS
, "Card loaded " _YELLOW_("%d") " blocks from %s", end
- start
+ 1,
8386 (fill_from_emulator
? "emulator memory" : "file"));
8387 PrintAndLogEx(INFO
, "Done!");
8391 // Write block to Gen4 GTU card
8392 static int CmdHF14AGen4SetBlk(const char *cmd
) {
8393 CLIParserContext
*ctx
;
8394 CLIParserInit(&ctx
, "hf mf gsetblk",
8395 "Set block data on a magic gen4 GTU card",
8396 "hf mf gsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
8398 void *argtable
[] = {
8400 arg_int1("b", "blk", "<dec>", "block number"),
8401 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8402 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8405 CLIExecWithReturn(ctx
, cmd
, argtable
, false);
8407 int b
= arg_get_int_def(ctx
, 1, -1);
8409 uint8_t data
[MFBLOCK_SIZE
] = {0x00};
8411 CLIGetHexWithReturn(ctx
, 2, data
, &datalen
);
8414 uint8_t pwd
[4] = {0};
8415 CLIGetHexWithReturn(ctx
, 3, pwd
, &pwd_len
);
8420 if (pwd_len
!= 4 && pwd_len
!= 0) {
8421 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8427 if (b
< 0 || b
>= MIFARE_4K_MAXBLOCK
) {
8428 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
8432 if (datalen
!= MFBLOCK_SIZE
) {
8433 PrintAndLogEx(FAILED
, "expected 16 bytes data, got %i", datalen
);
8438 PrintAndLogEx(INFO
, "Writing block number:%2d data:%s", b
, sprint_hex_inrow(data
, sizeof(data
)));
8440 uint8_t blockno
= (uint8_t)b
;
8441 int res
= mfG4SetBlock(pwd
, blockno
, data
, MAGIC_INIT
| MAGIC_OFF
);
8443 PrintAndLogEx(ERR
, "Can't write block. error=%d", res
);
8450 static int CmdHF14AGen4View(const char *Cmd
) {
8452 CLIParserContext
*ctx
;
8453 CLIParserInit(&ctx
, "hf mf gview",
8454 "View `magic gen4 gtu` card memory",
8458 void *argtable
[] = {
8460 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8461 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8462 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8463 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8464 arg_str0("p", "pwd", "<hex>", "password 4bytes"),
8465 arg_lit0("v", "verbose", "verbose output"),
8468 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8469 bool m0
= arg_get_lit(ctx
, 1);
8470 bool m1
= arg_get_lit(ctx
, 2);
8471 bool m2
= arg_get_lit(ctx
, 3);
8472 bool m4
= arg_get_lit(ctx
, 4);
8475 uint8_t pwd
[4] = {0};
8476 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8478 bool verbose
= arg_get_lit(ctx
, 6);
8482 if (pwd_len
!= 4 && pwd_len
!= 0) {
8483 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8487 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8488 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8490 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8495 memset(s
, 0, sizeof(s
));
8496 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8498 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8499 strncpy(s
, "Mini", 5);
8501 block_cnt
= MIFARE_1K_MAXBLOCK
;
8502 strncpy(s
, "1K", 3);
8504 block_cnt
= MIFARE_2K_MAXBLOCK
;
8505 strncpy(s
, "2K", 3);
8507 block_cnt
= MIFARE_4K_MAXBLOCK
;
8508 strncpy(s
, "4K", 3);
8510 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8513 PrintAndLogEx(SUCCESS
, "View magic gen4 GTU MIFARE Classic " _GREEN_("%s"), s
);
8516 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
8517 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
8519 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8523 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
8526 if (i
== 0) flags
|= MAGIC_INIT
;
8527 if (i
+ 1 == block_cnt
) flags
|= MAGIC_OFF
;
8529 int res
= mfG4GetBlock(pwd
, i
, dump
+ (i
* MFBLOCK_SIZE
), flags
);
8530 if (res
!= PM3_SUCCESS
) {
8531 PrintAndLogEx(WARNING
, "Can't get magic card block: %u. error=%d", i
, res
);
8532 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8537 PrintAndLogEx(NORMAL
, "." NOLF
);
8539 // 4k READs can be long, so we split status each 64 blocks.
8541 PrintAndLogEx(NORMAL
, "");
8542 PrintAndLogEx(INFO
, "" NOLF
) ;
8546 PrintAndLogEx(NORMAL
, "");
8547 mf_print_blocks(block_cnt
, dump
, verbose
);
8550 mf_print_keys(block_cnt
, dump
);
8557 // save contents of Gent4 GTU card to file / emulator
8558 static int CmdHF14AGen4Save(const char *Cmd
) {
8560 CLIParserContext
*ctx
;
8561 CLIParserInit(&ctx
, "hf mf gsave",
8562 "Save `magic gen4 gtu` card memory to file (bin/json)"
8563 "or into emulator memory",
8565 "hf mf gsave --4k\n"
8566 "hf mf gsave -p DEADBEEF -f hf-mf-01020304.json"
8568 void *argtable
[] = {
8570 arg_lit0(NULL
, "mini", "MIFARE Classic Mini / S20"),
8571 arg_lit0(NULL
, "1k", "MIFARE Classic 1k / S50 (def)"),
8572 arg_lit0(NULL
, "2k", "MIFARE Classic/Plus 2k"),
8573 arg_lit0(NULL
, "4k", "MIFARE Classic 4k / S70"),
8574 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8575 arg_str0("f", "file", "<fn>", "Specify a filename for dump file"),
8576 arg_lit0(NULL
, "emu", "to emulator memory"),
8579 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8580 bool m0
= arg_get_lit(ctx
, 1);
8581 bool m1
= arg_get_lit(ctx
, 2);
8582 bool m2
= arg_get_lit(ctx
, 3);
8583 bool m4
= arg_get_lit(ctx
, 4);
8586 uint8_t pwd
[4] = {0};
8587 CLIGetHexWithReturn(ctx
, 5, pwd
, &pwd_len
);
8590 char filename
[FILE_PATH_SIZE
];
8591 CLIParamStrToBuf(arg_get_str(ctx
, 6), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
8593 bool fill_emulator
= arg_get_lit(ctx
, 7);
8596 // ICEMAN: bug. if device has been using ICLASS commands,
8597 // the device needs to load the HF fpga image. It takes 1.5 second.
8598 set_fpga_mode(FPGA_BITSTREAM_HF
);
8601 if (pwd_len
!= 4 && pwd_len
!= 0) {
8602 PrintAndLogEx(FAILED
, "Must specify 4 bytes, got " _YELLOW_("%u"), pwd_len
);
8606 if ((m0
+ m1
+ m2
+ m4
) > 1) {
8607 PrintAndLogEx(WARNING
, "Only specify one MIFARE Type");
8609 } else if ((m0
+ m1
+ m2
+ m4
) == 0) {
8614 memset(s
, 0, sizeof(s
));
8615 uint16_t block_cnt
= MIFARE_1K_MAXBLOCK
;
8617 block_cnt
= MIFARE_MINI_MAXBLOCK
;
8618 strncpy(s
, "Mini", 5);
8620 block_cnt
= MIFARE_1K_MAXBLOCK
;
8621 strncpy(s
, "1K", 3);
8623 block_cnt
= MIFARE_2K_MAXBLOCK
;
8624 strncpy(s
, "2K", 3);
8626 block_cnt
= MIFARE_4K_MAXBLOCK
;
8627 strncpy(s
, "4K", 3);
8629 PrintAndLogEx(WARNING
, "Please specify a MIFARE Type");
8633 // Select card to get UID/UIDLEN information
8634 clearCommandBuffer();
8635 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
8636 PacketResponseNG resp
;
8637 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
8638 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
8639 return PM3_ETIMEOUT
;
8646 3: proprietary Anticollision
8648 uint64_t select_status
= resp
.oldarg
[0];
8649 if (select_status
== 0) {
8650 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
8655 iso14a_card_select_t card
;
8656 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
8659 uint16_t bytes
= block_cnt
* MFBLOCK_SIZE
;
8660 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
8662 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
8666 PrintAndLogEx(SUCCESS
, "Dumping magic gen4 GTU MIFARE Classic " _GREEN_("%s") " card memory", s
);
8667 PrintAndLogEx(INFO
, "." NOLF
);
8669 for (uint16_t i
= 0; i
< block_cnt
; i
++) {
8672 flags
|= MAGIC_INIT
;
8674 if (i
+ 1 == block_cnt
) {
8678 int res
= mfG4GetBlock(pwd
, i
, dump
+ (i
* MFBLOCK_SIZE
), flags
);
8679 if (res
!= PM3_SUCCESS
) {
8680 PrintAndLogEx(NORMAL
, "");
8681 PrintAndLogEx(WARNING
, "Can't get magic card block: %u. error=%d", i
, res
);
8682 PrintAndLogEx(HINT
, "Verify your card size, and try again or try another tag position");
8688 PrintAndLogEx(NORMAL
, "." NOLF
);
8690 // 4k READs can be long, so we split status each 64 blocks.
8691 if (i
% 64 == 0 && i
!= 0) {
8692 PrintAndLogEx(NORMAL
, "");
8693 PrintAndLogEx(INFO
, "" NOLF
) ;
8697 PrintAndLogEx(NORMAL
, "");
8699 if (fill_emulator
) {
8700 PrintAndLogEx(INFO
, "uploading to emulator memory");
8701 PrintAndLogEx(INFO
, "." NOLF
);
8703 g_conn
.block_after_ACK
= true;
8707 uint16_t bytes_left
= bytes
;
8709 // 12 is the size of the struct the fct mf_eml_set_mem_xt uses to transfer to device
8710 uint16_t max_avail_blocks
= ((PM3_CMD_DATA_SIZE
- 12) / MFBLOCK_SIZE
) * MFBLOCK_SIZE
;
8712 while (bytes_left
> 0 && cnt
< block_cnt
) {
8713 if (bytes_left
== MFBLOCK_SIZE
) {
8714 // Disable fast mode on last packet
8715 g_conn
.block_after_ACK
= false;
8718 uint16_t chunk_size
= MIN(max_avail_blocks
, bytes_left
);
8719 uint16_t blocks_to_send
= chunk_size
/ MFBLOCK_SIZE
;
8721 if (mf_eml_set_mem_xt(dump
+ offset
, cnt
, blocks_to_send
, MFBLOCK_SIZE
) != PM3_SUCCESS
) {
8722 PrintAndLogEx(FAILED
, "Can't set emulator mem at block: %3d", cnt
);
8727 cnt
+= blocks_to_send
;
8728 offset
+= chunk_size
;
8729 bytes_left
-= chunk_size
;
8730 PrintAndLogEx(NORMAL
, "." NOLF
);
8734 PrintAndLogEx(NORMAL
, "");
8735 PrintAndLogEx(SUCCESS
, "uploaded " _YELLOW_("%d") " bytes to emulator memory", bytes
);
8738 // user supplied filename?
8740 char *fptr
= filename
;
8741 fptr
+= snprintf(fptr
, sizeof(filename
), "hf-mf-");
8742 FillFileNameByUID(fptr
, card
.uid
, "-dump", card
.uidlen
);
8745 pm3_save_mf_dump(filename
, dump
, bytes
, jsfCardMemory
);
8750 // change Gent4 GTU card access password
8751 static int CmdHF14AGen4ChangePwd(const char *Cmd
) {
8753 CLIParserContext
*ctx
;
8754 CLIParserInit(&ctx
, "hf mf gchpwd",
8755 "Change access password for Gen4 GTU card. WARNING! If you dont KNOW the password - you CAN'T access it!!!",
8756 "hf mf gchpwd --pwd 00000000 --newpwd 01020304"
8758 void *argtable
[] = {
8760 arg_str0("p", "pwd", "<hex>", "password 4 bytes"),
8761 arg_str0("n", "newpwd", "<hex>", "new password 4 bytes"),
8762 arg_lit0("v", "verbose", "verbose output"),
8765 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8768 uint8_t pwd
[4] = {0};
8769 CLIGetHexWithReturn(ctx
, 1, pwd
, &pwd_len
);
8771 int new_pwd_len
= 0;
8772 uint8_t new_pwd
[4] = {0};
8773 CLIGetHexWithReturn(ctx
, 2, new_pwd
, &new_pwd_len
);
8775 bool verbose
= arg_get_lit(ctx
, 3);
8780 PrintAndLogEx(FAILED
, "Old password must be 4 bytes long, got " _YELLOW_("%u"), pwd_len
);
8784 if (new_pwd_len
!= 4) {
8785 PrintAndLogEx(FAILED
, "New password must be 4 bytes long, got " _YELLOW_("%u"), new_pwd_len
);
8789 int res
= mfG4ChangePassword(pwd
, new_pwd
, verbose
);
8790 if (res
!= PM3_SUCCESS
) {
8791 PrintAndLogEx(ERR
, "Change password error");
8795 PrintAndLogEx(SUCCESS
, "Change password ( " _GREEN_("ok") " )");
8799 static void parse_gdm_cfg(const uint8_t *d
) {
8800 PrintAndLogEx(NORMAL
, "");
8801 PrintAndLogEx(SUCCESS
, "------------------- " _CYAN_("GDM Gen4 Configuration") " -----------------------------------------");
8802 PrintAndLogEx(SUCCESS
, _YELLOW_("%s"), sprint_hex_inrow(d
, MFBLOCK_SIZE
));
8803 PrintAndLogEx(SUCCESS
, _YELLOW_("%02X%02X") "............................ %s %s"
8806 , (d
[0] == 0x85 && d
[1] == 0x00) ? "Magic wakeup disabled" : _GREEN_("Magic wakeup enabled")
8807 , (d
[0] == 0x85 && d
[1] == 0x00) ? "" : ((d
[0] == 0x7A && d
[1] == 0xFF) ? _GREEN_("with GDM cfg block access") : _RED_(", no GDM cfg block access"))
8809 PrintAndLogEx(SUCCESS
, "...." _YELLOW_("%02X") ".......................... Magic wakeup style " _YELLOW_("%s"), d
[2], ((d
[2] == 0x85) ? "GDM 20(7)/23" : "Gen1a 40(7)/43"));
8810 PrintAndLogEx(SUCCESS
, "......" _YELLOW_("%02X%02X%02X") ".................... unknown", d
[3], d
[4], d
[5]);
8811 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");
8812 PrintAndLogEx(SUCCESS
, ".............." _YELLOW_("%02X") "................ %s", d
[7], (d
[7] == 0x5A) ? _GREEN_("CUID enabled") : "CUID Disabled");
8813 PrintAndLogEx(SUCCESS
, "................" _YELLOW_("%02X") ".............. n/a", d
[8]);
8818 pers
= _YELLOW_("Unfused");
8821 pers
= _CYAN_("UIDFO, double size UID");
8824 pers
= _CYAN_("UIDF1, double size UID, optional usage of selection process shortcut");
8827 pers
= _GREEN_("UIDF2, single size random ID");
8830 pers
= _GREEN_("UIDF3, single size NUID");
8833 pers
= "4B UID from Block 0";
8836 PrintAndLogEx(SUCCESS
, ".................." _YELLOW_("%02X") "............ MFC EV1 perso. " _YELLOW_("%s"), d
[9], pers
);
8837 PrintAndLogEx(SUCCESS
, "...................." _YELLOW_("%02X") ".......... %s", d
[10], (d
[10] == 0x5A) ? _GREEN_("Shadow mode enabled") : "Shadow mode disabled");
8838 PrintAndLogEx(SUCCESS
, "......................" _YELLOW_("%02X") "........ %s", d
[11], (d
[11] == 0x5A) ? _GREEN_("Magic auth enabled") : "Magic auth disabled");
8839 PrintAndLogEx(SUCCESS
, "........................" _YELLOW_("%02X") "...... %s", d
[12], (d
[12] == 0x5A) ? _GREEN_("Static encrypted nonce enabled") : "Static encrypted nonce disabled");
8840 PrintAndLogEx(SUCCESS
, ".........................." _YELLOW_("%02X") ".... %s", d
[13], (d
[13] == 0x5A) ? _GREEN_("MFC EV1 signature enabled") : "MFC EV1 signature disabled");
8841 PrintAndLogEx(SUCCESS
, "............................" _YELLOW_("%02X") ".. n/a", d
[14]);
8842 PrintAndLogEx(SUCCESS
, ".............................." _YELLOW_("%02X") " SAK", d
[15]);
8843 PrintAndLogEx(NORMAL
, "");
8846 static int CmdHF14AGen4_GDM_ParseCfg(const char *Cmd
) {
8847 CLIParserContext
*ctx
;
8848 CLIParserInit(&ctx
, "hf mf gdmparsecfg",
8849 "Parse configuration data on a magic gen4 GDM card",
8850 "hf mf gdmparsecfg -d 850000000000000000005A5A00000008"
8852 void *argtable
[] = {
8854 arg_str1("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8857 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8859 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
8861 CLIGetHexWithReturn(ctx
, 1, block
, &blen
);
8864 if (blen
!= MFBLOCK_SIZE
) {
8865 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
8869 parse_gdm_cfg(block
);
8874 static int CmdHF14AGen4_GDM_Cfg(const char *Cmd
) {
8875 CLIParserContext
*ctx
;
8876 CLIParserInit(&ctx
, "hf mf gdmcfg",
8877 "Get configuration data from magic gen4 GDM card.",
8880 void *argtable
[] = {
8882 arg_str0("k", "key", "<hex>", "key 6 bytes (only for regular wakeup)"),
8883 arg_lit0(NULL
, "gen1a", "use gen1a (40/43) magic wakeup"),
8884 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
8887 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
8890 uint8_t key
[6] = {0};
8891 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
8892 bool gen1a
= arg_get_lit(ctx
, 2);
8893 bool gdm
= arg_get_lit(ctx
, 3);
8897 if (keylen
!= 6 && keylen
!= 0) {
8898 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
8903 PrintAndLogEx(FAILED
, "Can only specify a single magic wakeup command");
8907 if ((gen1a
|| gdm
) && keylen
!= 0) {
8908 PrintAndLogEx(FAILED
, "Cannot use a key in combination with a magic wakeup");
8912 mf_readblock_ex_t payload
= {
8913 .read_cmd
= MIFARE_MAGIC_GDM_READ_CFG
,
8916 memcpy(payload
.key
, key
, sizeof(payload
.key
));
8919 payload
.wakeup
= MF_WAKE_GEN1A
;
8920 payload
.auth_cmd
= 0;
8922 payload
.wakeup
= MF_WAKE_GDM_ALT
;
8923 payload
.auth_cmd
= 0;
8925 payload
.wakeup
= MF_WAKE_WUPA
;
8926 payload
.auth_cmd
= MIFARE_MAGIC_GDM_AUTH_KEY
;
8929 clearCommandBuffer();
8930 SendCommandNG(CMD_HF_MIFARE_READBL_EX
, (uint8_t *)&payload
, sizeof(payload
));
8931 PacketResponseNG resp
;
8932 if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL_EX
, &resp
, 1500) == false) {
8933 PrintAndLogEx(WARNING
, "command execution time out");
8934 return PM3_ETIMEOUT
;
8937 if (resp
.status
== PM3_SUCCESS
&& resp
.length
== MFBLOCK_SIZE
) {
8938 parse_gdm_cfg(resp
.data
.asBytes
);
8940 PrintAndLogEx(NORMAL
, "");
8946 static int CmdHF14AGen4_GDM_SetCfg(const char *Cmd
) {
8947 CLIParserContext
*ctx
;
8948 CLIParserInit(&ctx
, "hf mf gdmsetcfg",
8949 "Set configuration data on a magic gen4 GDM card",
8950 "hf mf gdmsetcfg -d 850000000000000000005A5A00000008"
8952 void *argtable
[] = {
8954 arg_str1("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
8955 arg_str0("k", "key", "<hex>", "key 6 bytes (only for regular wakeup)"),
8956 arg_lit0(NULL
, "gen1a", "use gen1a (40/43) magic wakeup"),
8957 arg_lit0(NULL
, "gdm", "use gdm alt (20/23) magic wakeup"),
8960 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
8962 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
8964 CLIGetHexWithReturn(ctx
, 1, block
, &blen
);
8966 uint8_t key
[6] = {0};
8967 CLIGetHexWithReturn(ctx
, 2, key
, &keylen
);
8968 bool gen1a
= arg_get_lit(ctx
, 3);
8969 bool gdm
= arg_get_lit(ctx
, 4);
8972 if (blen
!= MFBLOCK_SIZE
) {
8973 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
8977 if (keylen
!= 6 && keylen
!= 0) {
8978 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
8983 PrintAndLogEx(FAILED
, "Can only specify a single magic wakeup command");
8987 if ((gen1a
|| gdm
) && keylen
!= 0) {
8988 PrintAndLogEx(FAILED
, "Cannot use a key in combination with a magic wakeup");
8992 mf_writeblock_ex_t payload
= {
8993 .write_cmd
= MIFARE_MAGIC_GDM_WRITE_CFG
,
8996 memcpy(payload
.block_data
, block
, sizeof(payload
.block_data
));
8997 memcpy(payload
.key
, key
, sizeof(payload
.key
));
9000 payload
.wakeup
= MF_WAKE_GEN1A
;
9001 payload
.auth_cmd
= 0;
9003 payload
.wakeup
= MF_WAKE_GDM_ALT
;
9004 payload
.auth_cmd
= 0;
9006 payload
.wakeup
= MF_WAKE_WUPA
;
9007 payload
.auth_cmd
= MIFARE_MAGIC_GDM_AUTH_KEY
;
9010 clearCommandBuffer();
9011 SendCommandNG(CMD_HF_MIFARE_WRITEBL_EX
, (uint8_t *)&payload
, sizeof(payload
));
9012 PacketResponseNG resp
;
9013 if (WaitForResponseTimeout(CMD_HF_MIFARE_WRITEBL_EX
, &resp
, 1500) == false) {
9014 PrintAndLogEx(WARNING
, "command execution time out");
9015 return PM3_ETIMEOUT
;
9018 if (resp
.status
== PM3_SUCCESS
) {
9019 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
9020 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf gdmcfg") "` to verify");
9022 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
9027 static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd
) {
9029 CLIParserContext
*ctx
;
9030 CLIParserInit(&ctx
, "hf mf gdmsetblk",
9031 "Set block data on a magic gen4 GDM card\n"
9032 "`--force` param is used to override warnings like bad ACL writes.\n"
9033 " if not specified, it will exit if detected",
9034 "hf mf gdmsetblk --blk 1 -d 000102030405060708090a0b0c0d0e0f"
9036 void *argtable
[] = {
9038 arg_int1(NULL
, "blk", "<dec>", "block number"),
9039 arg_str0("d", "data", "<hex>", "bytes to write, 16 hex bytes"),
9040 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9041 arg_lit0(NULL
, "force", "override warnings"),
9044 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9046 int b
= arg_get_int_def(ctx
, 1, 1);
9048 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
9050 CLIGetHexWithReturn(ctx
, 2, block
, &blen
);
9053 uint8_t key
[6] = {0};
9054 CLIGetHexWithReturn(ctx
, 3, key
, &keylen
);
9056 bool force
= arg_get_lit(ctx
, 4);
9059 if (blen
!= MFBLOCK_SIZE
) {
9060 PrintAndLogEx(WARNING
, "expected %u HEX bytes. got %i", MFBLOCK_SIZE
, blen
);
9064 if (b
< 0 || b
>= MIFARE_4K_MAXBLOCK
) {
9065 PrintAndLogEx(FAILED
, "target block number out-of-range, got %i", b
);
9069 if (keylen
!= 6 && keylen
!= 0) {
9070 PrintAndLogEx(FAILED
, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen
);
9074 uint8_t blockno
= (uint8_t)b
;
9076 if (mf_analyse_st_block(blockno
, block
, force
) != PM3_SUCCESS
) {
9080 PrintAndLogEx(INFO
, "Writing block no %d, key %s", blockno
, sprint_hex_inrow(key
, sizeof(key
)));
9081 PrintAndLogEx(INFO
, "data: %s", sprint_hex(block
, sizeof(block
)));
9086 uint8_t data
[MFBLOCK_SIZE
]; // data to be written
9089 payload
.blockno
= blockno
;
9090 memcpy(payload
.key
, key
, sizeof(payload
.key
));
9091 memcpy(payload
.data
, block
, sizeof(payload
.data
));
9093 clearCommandBuffer();
9094 SendCommandNG(CMD_HF_MIFARE_G4_GDM_WRBL
, (uint8_t *)&payload
, sizeof(payload
));
9095 PacketResponseNG resp
;
9096 if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_WRBL
, &resp
, 1500) == false) {
9097 PrintAndLogEx(WARNING
, "command execution time out");
9098 return PM3_ETIMEOUT
;
9101 if (resp
.status
== PM3_SUCCESS
) {
9102 PrintAndLogEx(SUCCESS
, "Write ( " _GREEN_("ok") " )");
9103 PrintAndLogEx(HINT
, "try `" _YELLOW_("hf mf rdbl") "` to verify");
9104 } else if (resp
.status
== PM3_ETEAROFF
) {
9105 PrintAndLogEx(INFO
, "Tear off triggered");
9108 PrintAndLogEx(FAILED
, "Write ( " _RED_("fail") " )");
9113 static int CmdHF14AMfValue(const char *Cmd
) {
9115 CLIParserContext
*ctx
;
9116 CLIParserInit(&ctx
, "hf mf value",
9117 "MIFARE Classic value data commands\n",
9118 "hf mf value --blk 16 -k FFFFFFFFFFFF --set 1000\n"
9119 "hf mf value --blk 16 -k FFFFFFFFFFFF --inc 10\n"
9120 "hf mf value --blk 16 -k FFFFFFFFFFFF -b --dec 10\n"
9121 "hf mf value --blk 16 -k FFFFFFFFFFFF -b --get\n"
9122 "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"
9123 "hf mf value --get -d 87D612007829EDFF87D6120011EE11EE\n"
9125 void *argtable
[] = {
9127 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9128 arg_lit0("a", NULL
, "input key type is key A (def)"),
9129 arg_lit0("b", NULL
, "input key type is key B"),
9130 arg_u64_0(NULL
, "inc", "<dec>", "Increment value by X (0 - 2147483647)"),
9131 arg_u64_0(NULL
, "dec", "<dec>", "Decrement value by X (0 - 2147483647)"),
9132 arg_u64_0(NULL
, "set", "<dec>", "Set value to X (-2147483647 - 2147483647)"),
9133 arg_u64_0(NULL
, "transfer", "<dec>", "Transfer value to other block (after inc/dec/restore)"),
9134 arg_str0(NULL
, "tkey", "<hex>", "transfer key, 6 hex bytes (if transfer is preformed to other sector)"),
9135 arg_lit0(NULL
, "ta", "transfer key type is key A (def)"),
9136 arg_lit0(NULL
, "tb", "transfer key type is key B"),
9137 arg_lit0(NULL
, "get", "Get value from block"),
9138 arg_lit0(NULL
, "res", "Restore (copy value to card buffer, should be used with --transfer)"),
9139 arg_int0(NULL
, "blk", "<dec>", "block number"),
9140 arg_str0("d", "data", "<hex>", "block data to extract values from (16 hex bytes)"),
9143 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9145 uint8_t blockno
= (uint8_t)arg_get_int_def(ctx
, 13, 1);
9147 uint8_t keytype
= MF_KEY_A
;
9148 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9150 PrintAndLogEx(WARNING
, "Choose one single input key type");
9152 } else if (arg_get_lit(ctx
, 3)) {
9156 uint8_t transferkeytype
= MF_KEY_A
;
9157 if (arg_get_lit(ctx
, 9) && arg_get_lit(ctx
, 10)) {
9159 PrintAndLogEx(WARNING
, "Choose one single transfer key type");
9161 } else if (arg_get_lit(ctx
, 10)) {
9162 transferkeytype
= MF_KEY_B
;
9166 uint8_t key
[6] = {0};
9167 CLIGetHexWithReturn(ctx
, 1, key
, &keylen
);
9169 int transferkeylen
= 0;
9170 uint8_t transferkey
[6] = {0};
9171 CLIGetHexWithReturn(ctx
, 8, transferkey
, &transferkeylen
);
9174 Value /Value Value BLK /BLK BLK /BLK
9175 00000000 FFFFFFFF 00000000 10 EF 10 EF
9176 BLK is used to reference where the backup come from, I suspect it's just the current block for the actual value ?
9177 increment and decrement are an unsigned value
9178 set value is a signed value
9180 We are getting signed and/or bigger values to allow a default to be set meaning users did not supply that option.
9182 int64_t incval
= (int64_t)arg_get_u64_def(ctx
, 4, -1); // Inc by -1 is invalid, so not set.
9183 int64_t decval
= (int64_t)arg_get_u64_def(ctx
, 5, -1); // Dec by -1 is invalid, so not set.
9184 int64_t setval
= (int64_t)arg_get_u64_def(ctx
, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set
9185 int64_t trnval
= (int64_t)arg_get_u64_def(ctx
, 7, -1); // block to transfer to
9186 bool getval
= arg_get_lit(ctx
, 11);
9187 bool resval
= arg_get_lit(ctx
, 12);
9189 uint8_t data
[16] = {0};
9190 CLIGetHexWithReturn(ctx
, 14, data
, &dlen
);
9196 // Action: 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
9197 // iceman: TODO - should be enum
9201 // Need to check we only have 1 of inc/dec/set and get the value from the selected option
9202 int optionsprovided
= 0;
9207 if ((incval
<= 0) || (incval
> 2147483647)) {
9208 PrintAndLogEx(WARNING
, "increment value must be between 1 and 2147483647. Got %lli", incval
);
9211 value
= (uint32_t)incval
;
9217 if ((decval
<= 0) || (decval
> 2147483647)) {
9218 PrintAndLogEx(WARNING
, "decrement value must be between 1 and 2147483647. Got %lli", decval
);
9221 value
= (uint32_t)decval
;
9224 if (setval
!= 0x7FFFFFFFFFFFFFFF) {
9227 if ((setval
< -2147483647) || (setval
> 2147483647)) {
9228 PrintAndLogEx(WARNING
, "set value must be between -2147483647 and 2147483647. Got %lli", setval
);
9231 value
= (uint32_t)setval
;
9236 PrintAndLogEx(WARNING
, "You can't use restore without using transfer");
9248 PrintAndLogEx(WARNING
, "date length must be 16 hex bytes long, got %d", dlen
);
9253 if (optionsprovided
> 1) {
9254 PrintAndLogEx(WARNING
, "must have one and only one of --inc, --dec, --set or --data");
9258 if (trnval
!= -1 && action
> 2) {
9259 PrintAndLogEx(WARNING
, "You can't use transfer without using --inc, --dec or --res");
9263 if (trnval
!= -1 && transferkeylen
== 0 && mfSectorNum(trnval
) != mfSectorNum(blockno
)) {
9264 PrintAndLogEx(WARNING
, "Transfer is preformed to other sector, but no key for new sector provided");
9268 // don't want to write value data and break something
9269 if ((blockno
== 0) ||
9270 (mfIsSectorTrailer(blockno
)) ||
9272 (trnval
!= -1 && mfIsSectorTrailer(trnval
))) {
9273 PrintAndLogEx(WARNING
, "invalid block number, should be a data block");
9279 uint8_t isok
= true;
9280 if (g_session
.pm3_present
== false)
9283 // 0 Increment, 1 - Decrement, 2 - Restore, 3 - Set, 4 - Get, 5 - Decode from data
9286 uint8_t block
[MFBLOCK_SIZE
] = {0x00};
9287 memcpy(block
, (uint8_t *)&value
, 4);
9289 uint8_t cmddata
[34];
9290 memcpy(cmddata
, key
, sizeof(key
));
9291 // Key == 6 data went to 10, so lets offset 9 for inc/dec
9294 PrintAndLogEx(INFO
, "Value incremented by : %d", (int32_t)value
);
9297 PrintAndLogEx(INFO
, "Value decremented by : %d", (int32_t)value
);
9300 // 00 if increment, 01 if decrement, 02 if restore
9301 cmddata
[9] = action
;
9305 // transfer to block
9306 cmddata
[10] = trnval
;
9308 memcpy(cmddata
+ 27, transferkey
, sizeof(transferkey
));
9309 if (mfSectorNum(trnval
) != mfSectorNum(blockno
)) {
9310 cmddata
[33] = 1; // should send nested auth
9312 PrintAndLogEx(INFO
, "Transfer block no %u to block %" PRId64
, blockno
, trnval
);
9317 PrintAndLogEx(INFO
, "Writing block no %u, key type:%c - %s", blockno
, (keytype
== MF_KEY_B
) ? 'B' : 'A', sprint_hex_inrow(key
, sizeof(key
)));
9319 PrintAndLogEx(INFO
, "Writing block no %u, key type:%02x - %s", blockno
, MIFARE_AUTH_KEYA
+ keytype
, sprint_hex_inrow(key
, sizeof(key
)));
9323 memcpy(cmddata
+ 11, block
, sizeof(block
));
9325 clearCommandBuffer();
9326 SendCommandMIX(CMD_HF_MIFARE_VALUE
, blockno
, keytype
, transferkeytype
, cmddata
, sizeof(cmddata
));
9328 PacketResponseNG resp
;
9329 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
9330 PrintAndLogEx(FAILED
, "command execution time out");
9331 return PM3_ETIMEOUT
;
9333 isok
= resp
.oldarg
[0] & 0xff;
9334 } else { // set value
9335 // To set a value block (or setup) we can use the normal mifare classic write block
9336 // So build the command options can call CMD_HF_MIFARE_WRITEBL
9337 PrintAndLogEx(INFO
, "set value to : %d", (int32_t)value
);
9339 uint8_t writedata
[26] = {0x00};
9340 int32_t invertvalue
= value
^ 0xFFFFFFFF;
9341 memcpy(writedata
, key
, sizeof(key
));
9342 memcpy(writedata
+ 10, (uint8_t *)&value
, 4);
9343 memcpy(writedata
+ 14, (uint8_t *)&invertvalue
, 4);
9344 memcpy(writedata
+ 18, (uint8_t *)&value
, 4);
9345 writedata
[22] = blockno
;
9346 writedata
[23] = (blockno
^ 0xFF);
9347 writedata
[24] = blockno
;
9348 writedata
[25] = (blockno
^ 0xFF);
9350 clearCommandBuffer();
9351 SendCommandMIX(CMD_HF_MIFARE_WRITEBL
, blockno
, keytype
, 0, writedata
, sizeof(writedata
));
9353 PacketResponseNG resp
;
9354 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 1500) == false) {
9355 PrintAndLogEx(FAILED
, "command execution time out");
9356 return PM3_ETIMEOUT
;
9359 isok
= resp
.oldarg
[0] & 0xff;
9363 PrintAndLogEx(SUCCESS
, "Update ... : " _GREEN_("success"));
9365 // all ok so set flag to read current value
9367 PrintAndLogEx(FAILED
, "Update ... : " _RED_("failed"));
9371 // If all went well getval will be true, so read the current value and display
9378 // already have data from command line
9381 res
= mf_read_block(blockno
, keytype
, key
, data
);
9383 if (mfSectorNum(trnval
) != mfSectorNum(blockno
))
9384 res
= mf_read_block(trnval
, transferkeytype
, transferkey
, data
);
9386 res
= mf_read_block(trnval
, keytype
, key
, data
);
9390 if (res
== PM3_SUCCESS
) {
9391 if (mfc_value(data
, &readvalue
)) {
9392 PrintAndLogEx(SUCCESS
, "Dec ...... : " _YELLOW_("%" PRIi32
), readvalue
);
9393 PrintAndLogEx(SUCCESS
, "Hex ...... : " _YELLOW_("0x%" PRIX32
), readvalue
);
9395 PrintAndLogEx(FAILED
, "No value block detected");
9398 PrintAndLogEx(FAILED
, "failed to read value block");
9405 static int CmdHFMFHidEncode(const char *Cmd
) {
9406 CLIParserContext
*ctx
;
9407 CLIParserInit(&ctx
, "hf mf encodehid",
9408 "Encode binary wiegand to card\n"
9409 "Use either --bin or --wiegand/--fc/--cn",
9410 "hf mf encodehid --bin 10001111100000001010100011 -> FC 31 CN 337 (H10301)\n"
9411 "hf mf encodehid -w H10301 --fc 31 --cn 337\n"
9414 void *argtable
[] = {
9416 arg_str0(NULL
, "bin", "<bin>", "Binary string i.e 0001001001"),
9417 arg_u64_0(NULL
, "fc", "<dec>", "facility code"),
9418 arg_u64_0(NULL
, "cn", "<dec>", "card number"),
9419 arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
9420 arg_lit0("v", "verbose", "verbose output"),
9423 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
9425 uint8_t bin
[121] = {0};
9426 int bin_len
= sizeof(bin
) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated
9427 CLIGetStrWithReturn(ctx
, 1, bin
, &bin_len
);
9429 wiegand_card_t card
;
9430 memset(&card
, 0, sizeof(wiegand_card_t
));
9431 card
.FacilityCode
= arg_get_u32_def(ctx
, 2, 0);
9432 card
.CardNumber
= arg_get_u32_def(ctx
, 3, 0);
9434 char format
[16] = {0};
9436 CLIParamStrToBuf(arg_get_str(ctx
, 4), (uint8_t *)format
, sizeof(format
), &format_len
);
9438 bool verbose
= arg_get_lit(ctx
, 5);
9442 if (bin_len
> 120) {
9443 PrintAndLogEx(ERR
, "Binary wiegand string must be less than 120 bits");
9447 if (bin_len
== 0 && card
.FacilityCode
== 0 && card
.CardNumber
== 0) {
9448 PrintAndLogEx(ERR
, "Must provide either --cn/--fc or --bin");
9452 uint8_t blocks
[] = {
9453 0x1B, 0x01, 0x4D, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9454 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9455 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A,
9456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9457 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9459 0x48, 0x49, 0x44, 0x20, 0x49, 0x53, 0x78, 0x77, 0x88, 0xAA, 0x20, 0x47, 0x52, 0x45, 0x41, 0x54,
9463 char mfcbin
[121] = {0};
9465 memcpy(mfcbin
+ 1, bin
, bin_len
);
9468 uint8_t hex
[15] = {0};
9469 binstr_2_bytes(hex
, &hexlen
, mfcbin
);
9471 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 1 + (15 - hexlen
), hex
, hexlen
);
9473 wiegand_message_t packed
;
9474 memset(&packed
, 0, sizeof(wiegand_message_t
));
9476 int format_idx
= HIDFindCardFormat(format
);
9477 if (format_idx
== -1) {
9478 PrintAndLogEx(WARNING
, "Unknown format: " _YELLOW_("%s"), format
);
9482 if (HIDPack(format_idx
, &card
, &packed
, false) == false) {
9483 PrintAndLogEx(WARNING
, "The card data could not be encoded in the selected format.");
9487 // iceman: only for formats w length smaller than 37.
9490 // increase length to allow setting bit just above real data
9493 set_bit_by_position(&packed
, true, 0);
9495 #ifdef HOST_LITTLE_ENDIAN
9496 packed
.Mid
= BSWAP_32(packed
.Mid
);
9497 packed
.Bot
= BSWAP_32(packed
.Bot
);
9500 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 8, &packed
.Mid
, sizeof(packed
.Mid
));
9501 memcpy(blocks
+ (MFBLOCK_SIZE
* 4) + 12, &packed
.Bot
, sizeof(packed
.Bot
));
9504 uint8_t empty
[MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9506 for (uint8_t i
= 0; i
< (sizeof(blocks
) / MFBLOCK_SIZE
); i
++) {
9509 PrintAndLogEx(INFO
, "Writing %u - %s", (i
+ 1), sprint_hex_inrow(blocks
+ (i
* MFBLOCK_SIZE
), MFBLOCK_SIZE
));
9512 if (mf_write_block((i
+ 1), MF_KEY_A
, empty
, blocks
+ (i
* MFBLOCK_SIZE
)) == PM3_EFAILED
) {
9513 if (mf_write_block((i
+ 1), MF_KEY_B
, empty
, blocks
+ (i
* MFBLOCK_SIZE
)) == PM3_EFAILED
) {
9514 PrintAndLogEx(WARNING
, "failed writing block %d using default empty key", (i
+ 1));
9521 PrintAndLogEx(WARNING
, "Make sure card is wiped before running this command");
9523 PrintAndLogEx(NORMAL
, "");
9527 static int CmdHF14AMfInfo(const char *Cmd
) {
9528 CLIParserContext
*ctx
;
9529 CLIParserInit(&ctx
, "hf mf info",
9530 "Information and check vulnerabilities in a MIFARE Classic card\n"
9531 "Some cards in order to extract information you need to specify key\n"
9532 "and/or specific keys in the command line",
9534 "hf mf info -k FFFFFFFFFFFF -n -v\n"
9537 void *argtable
[] = {
9539 arg_int0(NULL
, "blk", "<dec>", "block number"),
9540 arg_lit0("a", NULL
, "input key type is key A (def)"),
9541 arg_lit0("b", NULL
, "input key type is key B"),
9542 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9543 arg_lit0("n", "nack", "do nack test"),
9544 arg_lit0("v", "verbose", "verbose output"),
9547 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
9549 int blockn
= arg_get_int_def(ctx
, 1, 0);
9551 uint8_t keytype
= MF_KEY_A
;
9552 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9554 PrintAndLogEx(WARNING
, "Choose one single input key type");
9556 } else if (arg_get_lit(ctx
, 3)) {
9561 uint8_t key
[100 * MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9562 CLIGetHexWithReturn(ctx
, 4, key
, &keylen
);
9564 bool do_nack_test
= arg_get_lit(ctx
, 5);
9565 bool verbose
= arg_get_lit(ctx
, 6);
9568 uint8_t dbg_curr
= DBG_NONE
;
9569 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
9573 if (keylen
!= 0 && keylen
!= MIFARE_KEY_SIZE
) {
9574 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9578 clearCommandBuffer();
9579 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
9580 PacketResponseNG resp
;
9581 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
9582 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
9586 iso14a_card_select_t card
;
9587 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
9593 3: proprietary Anticollision
9595 uint64_t select_status
= resp
.oldarg
[0];
9597 if (select_status
== 0) {
9598 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
9599 return select_status
;
9602 if (select_status
== 3) {
9603 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
9606 PrintAndLogEx(SUCCESS
, "ATQA: %02X %02X", card
.atqa
[1], card
.atqa
[0]);
9608 return select_status
;
9611 PrintAndLogEx(NORMAL
, "");
9612 PrintAndLogEx(INFO
, "--- " _CYAN_("ISO14443-a Information") " ---------------------");
9613 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
9614 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
9615 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
9617 if (setDeviceDebugLevel(verbose
? MAX(dbg_curr
, DBG_INFO
) : DBG_NONE
, false) != PM3_SUCCESS
) {
9621 uint8_t signature
[32] = {0};
9622 int res
= read_mfc_ev1_signature(signature
);
9623 if (res
== PM3_SUCCESS
) {
9624 mfc_ev1_print_signature(card
.uid
, card
.uidlen
, signature
, sizeof(signature
));
9627 PrintAndLogEx(NORMAL
, "");
9628 PrintAndLogEx(INFO
, "--- " _CYAN_("Keys Information"));
9630 uint8_t fkey
[MIFARE_KEY_SIZE
] = {0};
9631 uint8_t fKeyType
= 0xFF;
9633 uint64_t tmpkey
= 0;
9634 mfc_algo_saflok_one(card
.uid
, 0, MF_KEY_A
, &tmpkey
);
9635 num_to_bytes(tmpkey
, MIFARE_KEY_SIZE
, key
+ MIFARE_KEY_SIZE
);
9638 uint8_t *keyBlock
= NULL
;
9639 uint32_t keycnt
= 0;
9640 res
= mf_load_keys(&keyBlock
, &keycnt
, key
, MIFARE_KEY_SIZE
* 2, NULL
, 0, true);
9641 if (res
!= PM3_SUCCESS
) {
9645 // create/initialize key storage structure
9646 sector_t
*e_sector
= NULL
;
9647 if (initSectorTable(&e_sector
, sectorsCnt
) != PM3_SUCCESS
) {
9652 uint8_t blockdata
[MFBLOCK_SIZE
] = {0};
9653 res
= mf_check_keys_fast(sectorsCnt
, true, true, 1, keycnt
, keyBlock
, e_sector
, false, verbose
);
9654 if (res
== PM3_SUCCESS
|| res
== PM3_EPARTIAL
) {
9656 if (e_sector
[0].foundKey
[MF_KEY_A
]) {
9657 PrintAndLogEx(SUCCESS
, "Sector 0 key A... " _GREEN_("%012" PRIX64
), e_sector
[0].Key
[MF_KEY_A
]);
9659 num_to_bytes(e_sector
[0].Key
[MF_KEY_A
], MIFARE_KEY_SIZE
, fkey
);
9660 if (mf_read_block(0, MF_KEY_A
, key
, blockdata
) == PM3_SUCCESS
) {
9661 fKeyType
= MF_KEY_A
;
9665 if (e_sector
[0].foundKey
[MF_KEY_B
]) {
9666 PrintAndLogEx(SUCCESS
, "Sector 0 key B... " _GREEN_("%012" PRIX64
), e_sector
[0].Key
[MF_KEY_B
]);
9668 if (fKeyType
== 0xFF) {
9669 num_to_bytes(e_sector
[0].Key
[MF_KEY_B
], MIFARE_KEY_SIZE
, fkey
);
9670 if (mf_read_block(0, MF_KEY_B
, key
, blockdata
) == PM3_SUCCESS
) {
9671 fKeyType
= MF_KEY_B
;
9676 if (e_sector
[1].foundKey
[MF_KEY_A
]) {
9677 PrintAndLogEx(SUCCESS
, "Sector 1 key A... " _GREEN_("%012" PRIX64
), e_sector
[1].Key
[MF_KEY_A
]);
9681 uint8_t k08s
[6] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F};
9682 uint8_t k08
[6] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1};
9683 uint8_t k32
[6] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60};
9684 if (mf_read_block(0, 4, k08s
, blockdata
) == PM3_SUCCESS
) {
9685 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s
, sizeof(k08s
)));
9686 fKeyType
= MF_KEY_BD
;
9687 memcpy(fkey
, k08s
, sizeof(fkey
));
9689 } else if (mf_read_block(0, 4, k08
, blockdata
) == PM3_SUCCESS
) {
9690 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08
, sizeof(k08
)));
9691 fKeyType
= MF_KEY_BD
;
9692 memcpy(fkey
, k08
, sizeof(fkey
));
9693 } else if (mf_read_block(0, 4, k32
, blockdata
) == PM3_SUCCESS
) {
9694 PrintAndLogEx(SUCCESS
, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32
, sizeof(k32
)));
9695 fKeyType
= MF_KEY_BD
;
9696 memcpy(fkey
, k32
, sizeof(fkey
));
9699 if (fKeyType
!= 0xFF) {
9700 PrintAndLogEx(SUCCESS
, "Block 0.... %s | " NOLF
, sprint_hex_inrow(blockdata
, MFBLOCK_SIZE
));
9701 PrintAndLogEx(NORMAL
, "%s", sprint_ascii(blockdata
+ 8, 8));
9704 PrintAndLogEx(NORMAL
, "");
9705 PrintAndLogEx(INFO
, "--- " _CYAN_("Fingerprint"));
9707 if (fKeyType
!= 0xFF) {
9708 // cards with known backdoor
9709 if (card
.sak
!= 0x20 && memcmp(blockdata
+ 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) {
9710 // backdoor might be present, or just a clone reusing Fudan MF data...
9711 PrintAndLogEx(SUCCESS
, "Fudan based card");
9712 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08s
, sizeof(fkey
)) == 0
9713 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9714 && (blockdata
[8] == 0x03 || blockdata
[8] == 0x04) && blockdata
[15] == 0x90) {
9715 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S");
9716 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08s
, sizeof(fkey
)) == 0
9717 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x00\x03\x00\x10", 4) == 0
9718 && blockdata
[15] == 0x90) {
9719 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S-7B");
9720 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9721 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9722 && blockdata
[15] == 0x98) {
9723 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08S **98");
9724 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9725 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x08\x04\x00", 3) == 0
9726 && (blockdata
[8] >= 0x01 && blockdata
[8] <= 0x03) && blockdata
[15] == 0x1D) {
9727 PrintAndLogEx(SUCCESS
, "Fudan FM11RF08");
9728 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k32
, sizeof(fkey
)) == 0
9729 && card
.sak
== 0x18 && memcmp(blockdata
+ 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) {
9730 PrintAndLogEx(SUCCESS
, "Fudan FM11RF32");
9731 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9732 && card
.sak
== 0x20 && memcmp(blockdata
+ 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) {
9733 PrintAndLogEx(SUCCESS
, "Fudan FM11RF32 (SAK=20)");
9734 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9735 && card
.sak
== 0x28 && (
9736 (memcmp(blockdata
+ 5, "\x28\x04\x00\x90\x10\x15\x01\x00\x00\x00\x00", 11) == 0) ||
9737 (memcmp(blockdata
+ 5, "\x28\x04\x00\x90\x11\x15\x01\x00\x00\x00\x00", 11) == 0))) {
9738 // Note: it also has ATS =
9739 // 10 78 80 90 02 20 90 00 00 00 00 00 + UID + CRC
9740 PrintAndLogEx(SUCCESS
, "Fudan FM1208-10");
9741 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9742 && card
.sak
== 0x28 && memcmp(blockdata
+ 5, "\x28\x04\x00\x90\x53\xB7\x0C\x00\x00\x00\x00", 11) == 0) {
9743 // Note: it also has ATS =
9744 // 10 78 80 B0 02 20 90 00 00 00 00 00 + UID + CRC
9745 PrintAndLogEx(SUCCESS
, "Fudan FM1216-137");
9746 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9747 && card
.sak
== 0x88 && memcmp(blockdata
+ 5, "\x88\x04\x00\x43", 4) == 0) {
9748 PrintAndLogEx(SUCCESS
, "Infineon SLE66R35");
9749 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9750 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x44", 4) == 0) {
9751 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5003");
9752 } else if (fKeyType
== MF_KEY_BD
&& memcmp(fkey
, k08
, sizeof(fkey
)) == 0
9753 && card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x45", 4) == 0) {
9754 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5004");
9755 } else if (fKeyType
== MF_KEY_BD
) {
9756 PrintAndLogEx(SUCCESS
, _RED_("Unknown card with backdoor, please report details!"));
9759 if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x46", 4) == 0) {
9760 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5005");
9761 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x47", 4) == 0) {
9762 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5006");
9763 } else if (card
.sak
== 0x09 && memcmp(blockdata
+ 5, "\x89\x04\x00\x47", 4) == 0) {
9764 PrintAndLogEx(SUCCESS
, "NXP MF1ICS2006");
9765 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\x48", 4) == 0) {
9766 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5007");
9767 } else if (card
.sak
== 0x08 && memcmp(blockdata
+ 5, "\x88\x04\x00\xc0", 4) == 0) {
9768 PrintAndLogEx(SUCCESS
, "NXP MF1ICS5035");
9770 PrintAndLogEx(SUCCESS
, "unknown");
9773 if (e_sector
[1].foundKey
[MF_KEY_A
] && (e_sector
[1].Key
[MF_KEY_A
] == 0x2A2C13CC242A)) {
9774 PrintAndLogEx(SUCCESS
, "Dorma Kaba SAFLOK detected");
9778 PrintAndLogEx(INFO
, "<n/a>");
9781 PrintAndLogEx(NORMAL
, "");
9782 PrintAndLogEx(INFO
, "--- " _CYAN_("Magic Tag Information"));
9783 if (detect_mf_magic(true, MF_KEY_B
, e_sector
[0].Key
[MF_KEY_B
]) == MAGIC_FLAG_NONE
) {
9784 if (detect_mf_magic(true, MF_KEY_A
, e_sector
[0].Key
[MF_KEY_A
]) == MAGIC_FLAG_NONE
) {
9785 PrintAndLogEx(INFO
, "<n/a>");
9792 PrintAndLogEx(NORMAL
, "");
9793 PrintAndLogEx(INFO
, "--- " _CYAN_("PRNG Information"));
9795 res
= detect_classic_static_nonce();
9796 if (res
== NONCE_STATIC
) {
9797 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes"));
9801 if (res
== NONCE_NORMAL
) {
9803 res
= detect_classic_prng();
9805 PrintAndLogEx(SUCCESS
, "Prng....... " _GREEN_("weak"));
9806 } else if (res
== 0) {
9807 PrintAndLogEx(SUCCESS
, "Prng....... " _YELLOW_("hard"));
9809 PrintAndLogEx(FAILED
, "Prng........ " _RED_("fail"));
9812 // detect static encrypted nonce
9813 if (keylen
== MIFARE_KEY_SIZE
) {
9814 res
= detect_classic_static_encrypted_nonce(blockn
, keytype
, key
);
9815 if (res
== NONCE_STATIC
) {
9816 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes"));
9817 fKeyType
= 0xFF; // dont detect twice
9818 } else if (res
== NONCE_SUPERSTATIC
) {
9819 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes, even when nested"));
9820 fKeyType
= 0xFF; // dont detect twice
9821 } else if (res
== NONCE_STATIC_ENC
) {
9822 PrintAndLogEx(SUCCESS
, "Static enc nonce... " _RED_("yes"));
9823 fKeyType
= 0xFF; // dont detect twice
9827 if (fKeyType
!= 0xFF) {
9828 res
= detect_classic_static_encrypted_nonce(0, fKeyType
, fkey
);
9829 if (res
== NONCE_STATIC
) {
9830 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes"));
9831 } else if (res
== NONCE_SUPERSTATIC
) {
9832 PrintAndLogEx(SUCCESS
, "Static nonce... " _YELLOW_("yes, even when nested"));
9833 } else if (res
== NONCE_STATIC_ENC
) {
9834 PrintAndLogEx(SUCCESS
, "Static enc nonce... " _RED_("yes"));
9839 detect_classic_nackbug(verbose
);
9843 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
9847 PrintAndLogEx(NORMAL
, "");
9851 static int CmdHF14AMfISEN(const char *Cmd
) {
9852 CLIParserContext
*ctx
;
9853 CLIParserInit(&ctx
, "hf mf isen",
9854 "Information about Static Encrypted Nonce properties in a MIFARE Classic card",
9856 "Default behavior:\n"
9857 "auth(blk)-auth(blk2)-auth(blk2)-...\n"
9858 "Default behavior when wrong key2:\n"
9859 "auth(blk)-auth(blk2) auth(blk)-auth(blk2) ...\n"
9862 void *argtable
[] = {
9864 arg_int0(NULL
, "blk", "<dec>", "block number"),
9865 arg_lit0("a", NULL
, "input key type is key A (def)"),
9866 arg_lit0("b", NULL
, "input key type is key B"),
9867 arg_int0("c", NULL
, "<dec>", "input key type is key A + offset"),
9868 arg_str0("k", "key", "<hex>", "key, 6 hex bytes"),
9869 arg_int0(NULL
, "blk2", "<dec>", "nested block number (default=same)"),
9870 arg_lit0(NULL
, "a2", "nested input key type is key A (default=same)"),
9871 arg_lit0(NULL
, "b2", "nested input key type is key B (default=same)"),
9872 arg_int0(NULL
, "c2", "<dec>", "nested input key type is key A + offset"),
9873 arg_str0(NULL
, "key2", "<hex>", "nested key, 6 hex bytes (default=same)"),
9874 arg_int0("n", NULL
, "<dec>", "number of nonces (default=2)"),
9875 arg_lit0(NULL
, "reset", "reset between attempts, even if auth was successful"),
9876 arg_lit0(NULL
, "hardreset", "hard reset (RF off/on) between attempts, even if auth was successful"),
9877 arg_lit0(NULL
, "addread", "auth(blk)-read(blk)-auth(blk2)"),
9878 arg_lit0(NULL
, "addauth", "auth(blk)-auth(blk)-auth(blk2)"),
9879 arg_lit0(NULL
, "incblk2", "auth(blk)-auth(blk2)-auth(blk2+4)-..."),
9880 arg_lit0(NULL
, "corruptnrar", "corrupt {nR}{aR}, but with correct parity"),
9881 arg_lit0(NULL
, "corruptnrarparity", "correct {nR}{aR}, but with corrupted parity"),
9883 arg_rem("FM11RF08S specific options:", "Incompatible with above options, except -k; output in JSON"),
9884 arg_lit0(NULL
, "collect_fm11rf08s", "collect all nT/{nT}/par_err."),
9885 arg_lit0(NULL
, "collect_fm11rf08s_with_data", "collect all nT/{nT}/par_err and data blocks."),
9886 arg_str0("f", "file", "<fn>", "Specify a filename for collected data"),
9889 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
9891 int blockn
= arg_get_int_def(ctx
, 1, 0);
9893 uint8_t keytype
= MF_KEY_A
;
9894 if (arg_get_lit(ctx
, 2) && arg_get_lit(ctx
, 3)) {
9896 PrintAndLogEx(WARNING
, "Choose one single input key type");
9898 } else if (arg_get_lit(ctx
, 3)) {
9901 uint8_t prev_keytype
= keytype
;
9902 keytype
= arg_get_int_def(ctx
, 4, keytype
);
9903 if ((arg_get_lit(ctx
, 2) || arg_get_lit(ctx
, 3)) && (keytype
!= prev_keytype
)) {
9905 PrintAndLogEx(WARNING
, "Choose one single input key type");
9910 uint8_t key
[MIFARE_KEY_SIZE
] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
9911 CLIGetHexWithReturn(ctx
, 5, key
, &keylen
);
9913 int blockn_nested
= arg_get_int_def(ctx
, 6, blockn
);
9915 uint8_t keytype_nested
= keytype
;
9916 if (arg_get_lit(ctx
, 7) && arg_get_lit(ctx
, 8)) {
9918 PrintAndLogEx(WARNING
, "Choose one single nested input key type");
9920 } else if (arg_get_lit(ctx
, 7)) {
9921 keytype_nested
= MF_KEY_A
;
9922 } else if (arg_get_lit(ctx
, 8)) {
9923 keytype_nested
= MF_KEY_B
;
9925 uint8_t prev_keytype_nested
= keytype_nested
;
9926 keytype_nested
= arg_get_int_def(ctx
, 9, keytype_nested
);
9927 if ((arg_get_lit(ctx
, 7) || arg_get_lit(ctx
, 8)) && (keytype_nested
!= prev_keytype_nested
)) {
9929 PrintAndLogEx(WARNING
, "Choose one single nested input key type");
9933 int keylen_nested
= 0;
9934 uint8_t key_nested
[MIFARE_KEY_SIZE
];
9935 memcpy(key_nested
, key
, MIFARE_KEY_SIZE
);
9936 CLIGetHexWithReturn(ctx
, 10, key_nested
, &keylen_nested
);
9938 int nr_nested
= arg_get_int_def(ctx
, 11, 2);
9940 bool reset
= arg_get_lit(ctx
, 12);
9941 bool hardreset
= arg_get_lit(ctx
, 13);
9942 if (reset
&& hardreset
) {
9944 PrintAndLogEx(WARNING
, "Choose one single type of reset");
9947 bool addread
= arg_get_lit(ctx
, 14);
9948 bool addauth
= arg_get_lit(ctx
, 15);
9949 bool incblk2
= arg_get_lit(ctx
, 16);
9950 bool corruptnrar
= arg_get_lit(ctx
, 17);
9951 bool corruptnrarparity
= arg_get_lit(ctx
, 18);
9952 bool collect_fm11rf08s
= arg_get_lit(ctx
, 21);
9953 bool collect_fm11rf08s_with_data
= arg_get_lit(ctx
, 22);
9954 if (collect_fm11rf08s_with_data
) {
9955 collect_fm11rf08s
= 1;
9958 char filename
[FILE_PATH_SIZE
] = {0};
9959 CLIParamStrToBuf(arg_get_str(ctx
, 23), (uint8_t *)filename
, FILE_PATH_SIZE
, &fnlen
);
9963 uint8_t dbg_curr
= DBG_NONE
;
9964 if (getDeviceDebugLevel(&dbg_curr
) != PM3_SUCCESS
) {
9968 if (keylen
!= 0 && keylen
!= MIFARE_KEY_SIZE
) {
9969 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9973 if (keylen_nested
!= 0 && keylen_nested
!= MIFARE_KEY_SIZE
) {
9974 PrintAndLogEx(ERR
, "Key length must be %u bytes", MIFARE_KEY_SIZE
);
9978 clearCommandBuffer();
9979 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
, 0, 0, NULL
, 0);
9980 PacketResponseNG resp
;
9981 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
9982 PrintAndLogEx(DEBUG
, "iso14443a card select timeout");
9986 iso14a_card_select_t card
;
9987 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
9993 3: proprietary Anticollision
9995 uint64_t select_status
= resp
.oldarg
[0];
9997 if (select_status
== 0) {
9998 PrintAndLogEx(DEBUG
, "iso14443a card select failed");
9999 return select_status
;
10002 if (select_status
== 3) {
10003 PrintAndLogEx(INFO
, "Card doesn't support standard iso14443-3 anticollision");
10006 if (collect_fm11rf08s
) {
10007 uint64_t t1
= msclock();
10008 uint32_t flags
= collect_fm11rf08s_with_data
;
10009 SendCommandMIX(CMD_HF_MIFARE_ACQ_STATIC_ENCRYPTED_NONCES
, flags
, 0, 0, key
, sizeof(key
));
10010 if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE
, &resp
, 1000)) {
10011 if (resp
.status
== PM3_ESOFT
) {
10015 uint8_t num_sectors
= MIFARE_1K_MAXSECTOR
+ 1;
10016 iso14a_fm11rf08s_nonces_with_data_t nonces_dump
= {0};
10017 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
10018 // reconstruct full nt
10020 nt
= bytes_to_num(resp
.data
.asBytes
+ ((sec
* 2) * 8), 2);
10021 nt
= nt
<< 16 | prng_successor(nt
, 16);
10022 num_to_bytes(nt
, 4, nonces_dump
.nt
[sec
][0]);
10023 nt
= bytes_to_num(resp
.data
.asBytes
+ (((sec
* 2) + 1) * 8), 2);
10024 nt
= nt
<< 16 | prng_successor(nt
, 16);
10025 num_to_bytes(nt
, 4, nonces_dump
.nt
[sec
][1]);
10027 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
10028 memcpy(nonces_dump
.nt_enc
[sec
][0], resp
.data
.asBytes
+ ((sec
* 2) * 8) + 4, 4);
10029 memcpy(nonces_dump
.nt_enc
[sec
][1], resp
.data
.asBytes
+ (((sec
* 2) + 1) * 8) + 4, 4);
10031 for (uint8_t sec
= 0; sec
< num_sectors
; sec
++) {
10032 nonces_dump
.par_err
[sec
][0] = resp
.data
.asBytes
[((sec
* 2) * 8) + 2];
10033 nonces_dump
.par_err
[sec
][1] = resp
.data
.asBytes
[(((sec
* 2) + 1) * 8) + 2];
10035 if (collect_fm11rf08s_with_data
) {
10036 int bytes
= MIFARE_1K_MAXBLOCK
* MFBLOCK_SIZE
;
10038 uint8_t *dump
= calloc(bytes
, sizeof(uint8_t));
10039 if (dump
== NULL
) {
10040 PrintAndLogEx(WARNING
, "Fail, cannot allocate memory");
10041 return PM3_EFAILED
;
10043 if (!GetFromDevice(BIG_BUF_EML
, dump
, bytes
, 0, NULL
, 0, NULL
, 2500, false)) {
10044 PrintAndLogEx(WARNING
, "Fail, transfer from device time-out");
10046 return PM3_ETIMEOUT
;
10048 for (uint8_t blk
= 0; blk
< MIFARE_1K_MAXBLOCK
; blk
++) {
10049 memcpy(nonces_dump
.blocks
[blk
], dump
+ blk
* MFBLOCK_SIZE
, MFBLOCK_SIZE
);
10053 t1
= msclock() - t1
;
10054 PrintAndLogEx(SUCCESS
, "time: " _YELLOW_("%" PRIu64
) " ms", t1
);
10057 snprintf(filename
, sizeof(filename
), "hf-mf-%s-nonces%s", sprint_hex_inrow(card
.uid
, card
.uidlen
), collect_fm11rf08s_with_data
? "_with_data" : "");
10059 if (pm3_save_fm11rf08s_nonces(filename
, &nonces_dump
, collect_fm11rf08s_with_data
) != PM3_SUCCESS
) {
10060 return PM3_EFAILED
;
10062 return PM3_SUCCESS
;
10065 PrintAndLogEx(NORMAL
, "");
10066 PrintAndLogEx(INFO
, "--- " _CYAN_("ISO14443-a Information") " ---------------------");
10067 PrintAndLogEx(SUCCESS
, " UID: " _GREEN_("%s"), sprint_hex(card
.uid
, card
.uidlen
));
10068 PrintAndLogEx(SUCCESS
, "ATQA: " _GREEN_("%02X %02X"), card
.atqa
[1], card
.atqa
[0]);
10069 PrintAndLogEx(SUCCESS
, " SAK: " _GREEN_("%02X [%" PRIu64
"]"), card
.sak
, resp
.oldarg
[0]);
10071 // if (setDeviceDebugLevel(DBG_DEBUG, false) != PM3_SUCCESS) {
10072 if (setDeviceDebugLevel(DBG_EXTENDED
, false) != PM3_SUCCESS
) {
10073 return PM3_EFAILED
;
10076 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);
10077 if (res
== NONCE_STATIC
) {
10078 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes"));
10079 } else if (res
== NONCE_SUPERSTATIC
) {
10080 PrintAndLogEx(SUCCESS
, "Static nonce......... " _YELLOW_("yes, even when nested"));
10081 } else if (res
== NONCE_STATIC_ENC
) {
10082 PrintAndLogEx(SUCCESS
, "Static enc nonce..... " _RED_("yes"));
10084 if (setDeviceDebugLevel(dbg_curr
, false) != PM3_SUCCESS
) {
10085 return PM3_EFAILED
;
10088 PrintAndLogEx(NORMAL
, "");
10089 return PM3_SUCCESS
;
10092 static command_t CommandTable
[] = {
10093 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
10094 {"list", CmdHF14AMfList
, AlwaysAvailable
, "List MIFARE history"},
10095 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("recovery") " -----------------------"},
10096 {"info", CmdHF14AMfInfo
, IfPm3Iso14443a
, "mfc card Info"},
10097 {"isen", CmdHF14AMfISEN
, IfPm3Iso14443a
, "mfc card Info Static Encrypted Nonces"},
10098 {"darkside", CmdHF14AMfDarkside
, IfPm3Iso14443a
, "Darkside attack"},
10099 {"nested", CmdHF14AMfNested
, IfPm3Iso14443a
, "Nested attack"},
10100 {"hardnested", CmdHF14AMfNestedHard
, AlwaysAvailable
, "Nested attack for hardened MIFARE Classic cards"},
10101 {"staticnested", CmdHF14AMfNestedStatic
, IfPm3Iso14443a
, "Nested attack against static nonce MIFARE Classic cards"},
10102 {"brute", CmdHF14AMfSmartBrute
, IfPm3Iso14443a
, "Smart bruteforce to exploit weak key generators"},
10103 {"autopwn", CmdHF14AMfAutoPWN
, IfPm3Iso14443a
, "Automatic key recovery tool for MIFARE Classic"},
10104 // {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
10105 {"nack", CmdHf14AMfNack
, IfPm3Iso14443a
, "Test for MIFARE NACK bug"},
10106 {"chk", CmdHF14AMfChk
, IfPm3Iso14443a
, "Check keys"},
10107 {"fchk", CmdHF14AMfChk_fast
, IfPm3Iso14443a
, "Check keys fast, targets all keys on card"},
10108 {"decrypt", CmdHf14AMfDecryptBytes
, AlwaysAvailable
, "Decrypt Crypto1 data from sniff or trace"},
10109 {"supercard", CmdHf14AMfSuperCard
, IfPm3Iso14443a
, "Extract info from a `super card`"},
10110 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("operations") " -----------------------"},
10111 {"auth4", CmdHF14AMfAuth4
, IfPm3Iso14443a
, "ISO14443-4 AES authentication"},
10112 {"acl", CmdHF14AMfAcl
, AlwaysAvailable
, "Decode and print MIFARE Classic access rights bytes"},
10113 {"dump", CmdHF14AMfDump
, IfPm3Iso14443a
, "Dump MIFARE Classic tag to binary file"},
10114 {"mad", CmdHF14AMfMAD
, AlwaysAvailable
, "Checks and prints MAD"},
10115 {"personalize", CmdHFMFPersonalize
, IfPm3Iso14443a
, "Personalize UID (MIFARE Classic EV1 only)"},
10116 {"rdbl", CmdHF14AMfRdBl
, IfPm3Iso14443a
, "Read MIFARE Classic block"},
10117 {"rdsc", CmdHF14AMfRdSc
, IfPm3Iso14443a
, "Read MIFARE Classic sector"},
10118 {"restore", CmdHF14AMfRestore
, IfPm3Iso14443a
, "Restore MIFARE Classic binary file to tag"},
10119 {"setmod", CmdHf14AMfSetMod
, IfPm3Iso14443a
, "Set MIFARE Classic EV1 load modulation strength"},
10120 {"value", CmdHF14AMfValue
, AlwaysAvailable
, "Value blocks"},
10121 {"view", CmdHF14AMfView
, AlwaysAvailable
, "Display content from tag dump file"},
10122 {"wipe", CmdHF14AMfWipe
, IfPm3Iso14443a
, "Wipe card to zeros and default keys/acc"},
10123 {"wrbl", CmdHF14AMfWrBl
, IfPm3Iso14443a
, "Write MIFARE Classic block"},
10124 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("simulation") " -----------------------"},
10125 {"sim", CmdHF14AMfSim
, IfPm3Iso14443a
, "Simulate MIFARE card"},
10126 {"ecfill", CmdHF14AMfECFill
, IfPm3Iso14443a
, "Fill emulator memory with help of keys from emulator"},
10127 {"eclr", CmdHF14AMfEClear
, IfPm3Iso14443a
, "Clear emulator memory"},
10128 {"egetblk", CmdHF14AMfEGetBlk
, IfPm3Iso14443a
, "Get emulator memory block"},
10129 {"egetsc", CmdHF14AMfEGetSc
, IfPm3Iso14443a
, "Get emulator memory sector"},
10130 {"ekeyprn", CmdHF14AMfEKeyPrn
, IfPm3Iso14443a
, "Print keys from emulator memory"},
10131 {"eload", CmdHF14AMfELoad
, IfPm3Iso14443a
, "Upload file into emulator memory"},
10132 {"esave", CmdHF14AMfESave
, IfPm3Iso14443a
, "Save emulator memory to file"},
10133 {"esetblk", CmdHF14AMfESet
, IfPm3Iso14443a
, "Set emulator memory block"},
10134 {"eview", CmdHF14AMfEView
, IfPm3Iso14443a
, "View emulator memory"},
10135 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("magic gen1") " -----------------------"},
10136 {"cgetblk", CmdHF14AMfCGetBlk
, IfPm3Iso14443a
, "Read block from card"},
10137 {"cgetsc", CmdHF14AMfCGetSc
, IfPm3Iso14443a
, "Read sector from card"},
10138 {"cload", CmdHF14AMfCLoad
, IfPm3Iso14443a
, "Load dump to card"},
10139 {"csave", CmdHF14AMfCSave
, IfPm3Iso14443a
, "Save dump from card into file or emulator"},
10140 {"csetblk", CmdHF14AMfCSetBlk
, IfPm3Iso14443a
, "Write block to card"},
10141 {"csetuid", CmdHF14AMfCSetUID
, IfPm3Iso14443a
, "Set UID on card"},
10142 {"cview", CmdHF14AMfCView
, IfPm3Iso14443a
, "View card"},
10143 {"cwipe", CmdHF14AMfCWipe
, IfPm3Iso14443a
, "Wipe card to default UID/Sectors/Keys"},
10144 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
10145 {"gen3uid", CmdHf14AGen3UID
, IfPm3Iso14443a
, "Set UID without changing manufacturer block"},
10146 {"gen3blk", CmdHf14AGen3Block
, IfPm3Iso14443a
, "Overwrite manufacturer block"},
10147 {"gen3freeze", CmdHf14AGen3Freeze
, IfPm3Iso14443a
, "Perma lock UID changes. irreversible"},
10148 {"-----------", CmdHelp
, IfPm3Iso14443a
, "-------------------- " _CYAN_("magic gen4 GTU") " --------------------------"},
10149 {"ginfo", CmdHF14AGen4Info
, IfPm3Iso14443a
, "Info about configuration of the card"},
10150 {"ggetblk", CmdHF14AGen4GetBlk
, IfPm3Iso14443a
, "Read block from card"},
10151 {"gload", CmdHF14AGen4Load
, IfPm3Iso14443a
, "Load dump to card"},
10152 {"gsave", CmdHF14AGen4Save
, IfPm3Iso14443a
, "Save dump from card into file or emulator"},
10153 {"gsetblk", CmdHF14AGen4SetBlk
, IfPm3Iso14443a
, "Write block to card"},
10154 {"gview", CmdHF14AGen4View
, IfPm3Iso14443a
, "View card"},
10155 {"gchpwd", CmdHF14AGen4ChangePwd
, IfPm3Iso14443a
, "Change card access password. Warning!"},
10156 {"-----------", CmdHelp
, IfPm3Iso14443a
, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
10157 {"gdmcfg", CmdHF14AGen4_GDM_Cfg
, IfPm3Iso14443a
, "Read config block from card"},
10158 {"gdmsetcfg", CmdHF14AGen4_GDM_SetCfg
, IfPm3Iso14443a
, "Write config block to card"},
10159 {"gdmparsecfg", CmdHF14AGen4_GDM_ParseCfg
, AlwaysAvailable
, "Parse config block to card"},
10160 {"gdmsetblk", CmdHF14AGen4_GDM_SetBlk
, IfPm3Iso14443a
, "Write block to card"},
10161 {"-----------", CmdHelp
, IfPm3Iso14443a
, "----------------------- " _CYAN_("ndef") " -----------------------"},
10162 // {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
10163 {"ndefformat", CmdHFMFNDEFFormat
, IfPm3Iso14443a
, "Format MIFARE Classic Tag as NFC Tag"},
10164 {"ndefread", CmdHFMFNDEFRead
, IfPm3Iso14443a
, "Read and print NDEF records from card"},
10165 {"ndefwrite", CmdHFMFNDEFWrite
, IfPm3Iso14443a
, "Write NDEF records to card"},
10166 {"encodehid", CmdHFMFHidEncode
, IfPm3Iso14443a
, "Encode a HID Credential / NDEF record to card"},
10167 {NULL
, NULL
, NULL
, NULL
}
10171 static int CmdHelp(const char *Cmd
) {
10172 (void)Cmd
; // Cmd is not used so far
10173 CmdsHelp(CommandTable
);
10174 return PM3_SUCCESS
;
10177 int CmdHFMF(const char *Cmd
) {
10178 clearCommandBuffer();
10179 return CmdsParse(CommandTable
, Cmd
);