1 //-----------------------------------------------------------------------------
2 // Copyright (C) Matías A. Ré Medina 2016
3 // Copyright (C) Michael Roland 2024
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // main code for HF MIFARE Classic chk/ecfill/sim aka MattyRun
19 //-----------------------------------------------------------------------------
21 #include "hf_mattyrun.h"
27 #include "commonutil.h"
30 #include "fpgaloader.h"
31 #include "iso14443a.h"
32 #include "mifarecmd.h"
33 #include "mifaresim.h" // mifare1ksim
34 #include "mifareutil.h"
35 #include "proxmark3_arm.h"
36 #include "standalone.h" // standalone definitions
42 * `hf_mattyrun` tries to dump MIFARE Classic cards into emulator memory and emulates them.
44 * This standalone mode uses a predefined dictionary to authenticate to MIFARE Classic
45 * cards (cf. `hf mf chk`) and to dump the card into emulator memory (cf. `hf mf ecfill`).
46 * Once a card has been dumped, the card is emulated (cf. `hf mf sim`). Emulation will
47 * start even if only a partial dump could be retrieved from the card (e.g. due to missing
50 * This standalone mode is specifically designed for devices without flash. However,
51 * users can pass data to/from the standalone mode through emulator memory (assuming
52 * continuous (battery) power supply):
54 * - Keys can be added to the dictionary by loading them into the emulator before
55 * starting the standalone mode. You can use `hf mf eload -f dump_file` to load
56 * any existing card dump. All keys from the key slots in the sector trailers
57 * are added to the dictionary. Note that you can fill both keys in all sector
58 * trailers available for a 4K card to store your user dictionary. Sector and key
59 * type are ignored during chk; all user keys will be tested for all sectors and
62 * - Once a card has been cloned into emulator memory, you can extract the dump by
63 * ending the standalone mode and retrieving the emulator memory (`hf mf eview`
64 * or `hf mf esave [--mini|--1k|--2k|--4k] -f dump_file`).
66 * This standalone mode will log status information via USB. In addition, the LEDs
67 * display status information:
69 * - Waiting for card: LED C is on, LED D blinks.
70 * - Tying to authenticate: LED C and D are on; LED D will blink on errors.
71 * - Nested attack (NOT IMPLEMENTED!): LED B is on.
72 * - Loading card data into emulator memory: LED B and C are on.
73 * - Starting emulation: LED A, B, and C are on. LED D is on if only a partial
75 * - Emulation started: All LEDS are off.
77 * You can use the user button to interact with the standalone mode. During
78 * emulation, (short) pressing the button ends emulation and returns to card
79 * discovery. Long pressing the button ends the standalone mode.
81 * Developers can configure the behavior of the standalone mode through the below
84 * - MATTYRUN_PRINT_KEYS: Activate display of actually used key dictionary on startup.
85 * - MATTYRUN_NO_ECFILL: Do not load and emulate card (only discovered keys are stored).
86 * - MATTYRUN_MFC_DEFAULT_KEYS: Compiled-in default dictionary defined in a separate
87 * header file (`hf_mattyrun.h`) for easier customization. You can add your customized
89 * - MATTYRUN_MFC_ESSENTIAL_KEYS: Compiled-in dictionary of keys that should be tested
90 * before any user dictionary.
92 * This is a major rewrite of the original `hf_mattyrun` by Matías A. Ré Medina.
93 * The original version is described [here](http://bit.ly/2c9nZXR) (in Spanish).
96 // Pseudo-configuration block
97 static bool const MATTYRUN_PRINT_KEYS
= false; // Print assembled key dictionary on startup.
98 static bool const MATTYRUN_NO_ECFILL
= false; // Do not load and emulate card.
101 // TODO: Do we want to add flags to mark keys to be tested only as key A / key B?
102 static uint64_t const MATTYRUN_MFC_KEY_BITS
= 0x00FFFFFFFFFFFF;
103 static uint64_t const MATTYRUN_MFC_KEY_FLAG_UNUSED
= 0x10000000000000;
105 // Set of priority keys to be used
106 static uint64_t const MATTYRUN_MFC_ESSENTIAL_KEYS
[] = {
107 0xFFFFFFFFFFFF, // Default key
108 0x000000000000, // Blank key
109 0xA0A1A2A3A4A5, // MAD key
110 0x5C8FF9990DA2, // Mifare 1k EV1 (S50) hidden blocks, Signature data 16 A
111 0x75CCB59C9BED, // Mifare 1k EV1 (S50) hidden blocks, Signature data 17 A
112 0xD01AFEEB890A, // Mifare 1k EV1 (S50) hidden blocks, Signature data 16 B
113 0x4B791BEA7BCC, // Mifare 1k EV1 (S50) hidden blocks, Signature data 17 B
114 0xD3F7D3F7D3F7, // AN1305 MIFARE Classic as NFC Type MIFARE Classic Tag Public Key A
118 static uint8_t mattyrun_uid
[10];
119 static uint32_t mattyrun_cuid
;
120 static iso14a_card_select_t mattyrun_card
;
122 // Discover ISO 14443A cards
123 static bool saMifareDiscover(void) {
125 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN
);
127 if (iso14443a_select_card(mattyrun_uid
, &mattyrun_card
, &mattyrun_cuid
, true, 0, true) == 0) {
128 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
);
136 // Customized MifareChkKeys that operates on the already detected card in
137 // mattyrun_card and tests authentication with our dictionary
138 static int saMifareChkKeys(uint8_t const blockNo
, uint8_t const keyType
, bool const clearTrace
,
139 uint16_t const keyCount
, uint64_t const *const mfKeys
, uint64_t *const key
) {
143 struct Crypto1State mpcs
= {0, 0};
144 struct Crypto1State
*pcs
;
147 uint8_t selectRetries
= 16;
148 uint8_t cascade_levels
= 0;
154 int oldbg
= g_dbglevel
;
155 g_dbglevel
= DBG_NONE
;
159 for (uint16_t i
= 0; i
< keyCount
; ++i
) {
161 uint64_t mfKey
= mfKeys
[i
];
162 if ((mfKey
& MATTYRUN_MFC_KEY_FLAG_UNUSED
) != 0) {
163 // skip unused dictionary key slot
166 mfKey
&= MATTYRUN_MFC_KEY_BITS
;
168 if (mattyrun_card
.uidlen
== 0) {
169 if (!saMifareDiscover()) {
170 --i
; // try same key once again
172 if (selectRetries
> 0) {
180 if (cascade_levels
== 0) {
181 switch (mattyrun_card
.uidlen
) {
195 // No need for anticollision. Since we sucessfully selected the card before,
196 // we can directly select the card again
197 if (iso14443a_fast_select_card(mattyrun_uid
, cascade_levels
) == 0) {
198 --i
; // try same key once again
200 if (selectRetries
> 0) {
211 authres
= mifare_classic_auth(pcs
, mattyrun_cuid
, blockNo
, keyType
, mfKey
, AUTH_FIRST
);
213 uint8_t dummy_answer
= 0;
214 ReaderTransmit(&dummy_answer
, 1, NULL
);
215 // wait for the card to become ready again
216 SpinDelayUs(AUTHENTICATION_TIMEOUT
);
238 DbpString(" HF MIFARE Classic chk/ecfill/sim - aka MattyRun");
243 DbpString(">> HF MIFARE Classic chk/ecfill/sim - aka MattyRun started <<");
245 // Comment this line below if you want to see debug messages.
248 // Allocate dictionary buffer
249 uint64_t *const mfcKeys
= (uint64_t *)BigBuf_malloc(
250 sizeof(uint64_t) * (ARRAYLEN(MATTYRUN_MFC_ESSENTIAL_KEYS
) +
251 ARRAYLEN(MATTYRUN_MFC_DEFAULT_KEYS
) +
252 MIFARE_4K_MAXSECTOR
* 2));
253 uint16_t mfcKeyCount
= 0;
255 // Load essential keys to dictionary buffer
256 for (uint16_t i
= 0; i
< ARRAYLEN(MATTYRUN_MFC_ESSENTIAL_KEYS
); ++i
) {
257 uint64_t mfKey
= MATTYRUN_MFC_ESSENTIAL_KEYS
[i
];
258 for (uint16_t j
= 0; j
< mfcKeyCount
; ++j
) {
259 if (mfKey
== mfcKeys
[j
]) {
260 // skip redundant dictionary key
261 mfKey
= MATTYRUN_MFC_KEY_FLAG_UNUSED
;
265 if ((mfKey
& MATTYRUN_MFC_KEY_FLAG_UNUSED
) == 0) {
266 mfcKeys
[mfcKeyCount
] = mfKey
;
271 // Load user keys from emulator memory to dictionary buffer
272 for (uint8_t sectorNo
= 0; sectorNo
< MIFARE_4K_MAXSECTOR
; ++sectorNo
) {
273 for (uint8_t keyType
= 0; keyType
< 2; ++keyType
) {
274 uint64_t mfKey
= emlGetKey(sectorNo
, keyType
);
275 for (uint16_t j
= 0; j
< mfcKeyCount
; ++j
) {
276 if (mfKey
== mfcKeys
[j
]) {
277 // skip redundant dictionary key
278 mfKey
= MATTYRUN_MFC_KEY_FLAG_UNUSED
;
282 if ((mfKey
& MATTYRUN_MFC_KEY_FLAG_UNUSED
) == 0) {
283 mfcKeys
[mfcKeyCount
] = mfKey
;
289 // Load additional keys to dictionary buffer
290 for (uint16_t i
= 0; i
< ARRAYLEN(MATTYRUN_MFC_DEFAULT_KEYS
); ++i
) {
291 uint64_t mfKey
= MATTYRUN_MFC_DEFAULT_KEYS
[i
];
292 for (uint16_t j
= 0; j
< mfcKeyCount
; ++j
) {
293 if (mfKey
== mfcKeys
[j
]) {
294 // skip redundant dictionary key
295 mfKey
= MATTYRUN_MFC_KEY_FLAG_UNUSED
;
299 if ((mfKey
& MATTYRUN_MFC_KEY_FLAG_UNUSED
) == 0) {
300 mfcKeys
[mfcKeyCount
] = mfKey
;
305 // Call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) only after extracting keys from
306 // emulator memory as it may destroy the contents of the emulator memory
307 FpgaDownloadAndGo(FPGA_BITSTREAM_HF
);
309 // Pretty print keys to be checked
310 if (MATTYRUN_PRINT_KEYS
) {
311 DbpString("[+] Printing mfc key dictionary");
312 for (uint16_t i
= 0; i
< mfcKeyCount
; ++i
) {
313 uint64_t mfKey
= mfcKeys
[i
];
314 if ((mfKey
& MATTYRUN_MFC_KEY_FLAG_UNUSED
) != 0) {
315 // skip unused dictionary key slot
318 Dbprintf("[-] key[%5" PRIu16
"] = %012" PRIx64
"", i
, mfKey
);
320 DbpString("[+] --------------------------------------------------------");
323 uint8_t sectorsCnt
= MIFARE_4K_MAXSECTOR
;
324 bool keyFound
= false;
325 bool allKeysFound
= true;
326 bool partialEmulation
= false;
327 bool validKey
[2][MIFARE_4K_MAXSECTOR
];
328 uint8_t foundKey
[2][MIFARE_4K_MAXSECTOR
][6];
335 } state
= STATE_READ
;
341 // Exit from MattyRun when usbcommand is received
342 if (data_available()) break;
344 // Exit from MattyRun on long-press of user button
345 int button_pressed
= BUTTON_HELD(280);
346 if (button_pressed
== BUTTON_HOLD
) {
347 WAIT_BUTTON_RELEASED();
351 if (state
== STATE_READ
) {
353 // If detected, try to authenticate with dictionary keys.
360 if (!saMifareDiscover()) {
361 SpinErr(LED_D
, 50, 2);
365 switch (mattyrun_card
.uidlen
) {
367 Dbprintf("[=] Card detected: ATQA=%02x%02x, SAK=%02x, %dB UID=%02x%02x%02x%02x",
368 mattyrun_card
.atqa
[1], mattyrun_card
.atqa
[0], mattyrun_card
.sak
, mattyrun_card
.uidlen
,
369 mattyrun_card
.uid
[0], mattyrun_card
.uid
[1], mattyrun_card
.uid
[2], mattyrun_card
.uid
[3]);
372 Dbprintf("[=] Card detected: ATQA=%02x%02x, SAK=%02x, %dB UID=%02x%02x%02x%02x%02x%02x%02x",
373 mattyrun_card
.atqa
[1], mattyrun_card
.atqa
[0], mattyrun_card
.sak
, mattyrun_card
.uidlen
,
374 mattyrun_card
.uid
[0], mattyrun_card
.uid
[1], mattyrun_card
.uid
[2], mattyrun_card
.uid
[3],
375 mattyrun_card
.uid
[4], mattyrun_card
.uid
[5], mattyrun_card
.uid
[6]);
378 Dbprintf("[=] Card detected: ATQA=%02x%02x, SAK=%02x, %dB UID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
379 mattyrun_card
.atqa
[1], mattyrun_card
.atqa
[0], mattyrun_card
.sak
, mattyrun_card
.uidlen
,
380 mattyrun_card
.uid
[0], mattyrun_card
.uid
[1], mattyrun_card
.uid
[2], mattyrun_card
.uid
[3],
381 mattyrun_card
.uid
[4], mattyrun_card
.uid
[5], mattyrun_card
.uid
[6],
382 mattyrun_card
.uid
[7], mattyrun_card
.uid
[8], mattyrun_card
.uid
[9]);
386 sectorsCnt
= MIFARE_4K_MAXSECTOR
;
388 // Initialization of validKeys and foundKeys:
389 // - validKey will store whether the sector has a valid A/B key.
390 // - foundKey will store the found A/B key for each sector.
391 for (uint8_t keyType
= 0; keyType
< 2; ++keyType
) {
392 for (uint8_t sectorNo
= 0; sectorNo
< sectorsCnt
; ++sectorNo
) {
393 validKey
[keyType
][sectorNo
] = false;
394 memset(foundKey
[keyType
][sectorNo
], 0xFF, 6);
402 // Iterates through each sector, checking if there is a correct key
403 for (uint8_t keyType
= 0; keyType
< 2 && !err
; ++keyType
) {
404 for (uint8_t sec
= 0; sec
< sectorsCnt
&& !err
; ++sec
) {
405 uint64_t currentKey
= 0;
406 Dbprintf("[=] Testing sector %3" PRIu8
" (block %3" PRIu8
") for key %c",
407 sec
, FirstBlockOfSector(sec
), (keyType
== 0) ? 'A' : 'B');
408 int key
= saMifareChkKeys(FirstBlockOfSector(sec
), keyType
, true,
409 mfcKeyCount
, &mfcKeys
[0], ¤tKey
);
411 DbpString("[" _RED_("!") "] " _RED_("Failed to select card!"));
412 SpinErr(LED_D
, 50, 2);
413 err
= true; // fall back into idle mode since we can't select card anymore
415 } else if (key
== -3) {
418 case MIFARE_MINI_MAXSECTOR
:
419 case MIFARE_1K_MAXSECTOR
:
420 case MIFARE_2K_MAXSECTOR
:
421 case MIFARE_4K_MAXSECTOR
:
423 case (MIFARE_MINI_MAXSECTOR
+ 2):
424 case (MIFARE_1K_MAXSECTOR
+ 2):
425 case (MIFARE_2K_MAXSECTOR
+ 2):
426 case (MIFARE_4K_MAXSECTOR
+ 2):
429 Dbprintf("[" _RED_("!") "] " _RED_("Unexpected number of sectors (%" PRIu8
")!"),
431 SpinErr(LED_D
, 250, 3);
432 allKeysFound
= false;
436 } else if (key
< 0) {
437 Dbprintf("[" _RED_("!") "] " _RED_("No key %c found for sector %" PRIu8
"!"),
438 (keyType
== 0) ? 'A' : 'B', sec
);
439 SpinErr(LED_D
, 50, 3);
441 allKeysFound
= false;
444 num_to_bytes(currentKey
, 6, foundKey
[keyType
][sec
]);
445 validKey
[keyType
][sec
] = true;
447 Dbprintf("[=] Found valid key: %012" PRIx64
"", currentKey
);
452 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
);
460 DbpString("[" _GREEN_("+") "] " _GREEN_("All keys found"));
463 } else if (keyFound
) {
464 DbpString("[" _RED_("!") "] " _RED_("Some keys could not be found!"));
465 state
= STATE_ATTACK
;
468 DbpString("[" _RED_("!") "] " _RED_("No keys found!"));
469 DbpString("[" _RED_("!") "] " _RED_("There's nothing I can do without at least one valid key, sorry!"));
470 SpinErr(LED_D
, 250, 5);
474 } else if (state
== STATE_ATTACK
) {
475 // Do nested attack, set allKeysFound = true
482 // no room to run nested attack on device (iceman)
483 DbpString("[" _RED_("!") "] " _RED_("There's currently no nested attack in MattyRun, sorry!"));
484 // allKeysFound = true;
489 } else if (state
== STATE_LOAD
) {
490 // Transfer found keys to memory.
491 // If enabled, load full card content into emulator memory.
500 uint8_t mblock
[MIFARE_BLOCK_SIZE
];
501 for (uint8_t sectorNo
= 0; sectorNo
< sectorsCnt
; ++sectorNo
) {
502 if (validKey
[0][sectorNo
] || validKey
[1][sectorNo
]) {
503 emlGetMem(mblock
, FirstBlockOfSector(sectorNo
) + NumBlocksPerSector(sectorNo
) - 1, 1);
504 for (uint8_t keyType
= 0; keyType
< 2; ++keyType
) {
505 if (validKey
[keyType
][sectorNo
]) {
506 memcpy(mblock
+ keyType
* 10, foundKey
[keyType
][sectorNo
], 6);
509 emlSetMem_xt(mblock
, FirstBlockOfSector(sectorNo
) + NumBlocksPerSector(sectorNo
) - 1, 1, MIFARE_BLOCK_SIZE
);
513 DbpString("[=] Found keys have been transferred to the emulator memory.");
515 if (MATTYRUN_NO_ECFILL
) {
521 partialEmulation
= false;
522 DbpString("[=] Filling emulator memory using key A");
523 filled
= MifareECardLoad(sectorsCnt
, MF_KEY_A
, NULL
);
524 if (filled
!= PM3_SUCCESS
) {
525 DbpString("[" _YELLOW_("-") "] " _YELLOW_("Only partially filled using key A, retry with key B!"));
526 DbpString("[=] Filling emulator memory using key B");
527 filled
= MifareECardLoad(sectorsCnt
, MF_KEY_B
, NULL
);
528 if (filled
!= PM3_SUCCESS
) {
529 DbpString("[" _YELLOW_("-") "] " _YELLOW_("Only partially filled using key B!"));
532 if (filled
!= PM3_SUCCESS
) {
533 DbpString("[" _RED_("!") "] " _RED_("Emulator memory could not be completely filled due to errors!"));
534 SpinErr(LED_D
, 50, 8);
535 partialEmulation
= true;
537 DbpString("[" _GREEN_("+") "] " _GREEN_("Emulator memory filled completely."));
540 state
= STATE_EMULATE
;
543 } else if (state
== STATE_EMULATE
) {
544 // Finally, emulate the cloned card.
551 DbpString("[=] Started emulation. Press button to abort at anytime.");
553 if (partialEmulation
) {
555 DbpString("[=] Partial memory dump loaded. Trying best effort emulation approach.");
558 uint16_t simflags
= 0;
559 FLAG_SET_UID_IN_DATA(simflags
, mattyrun_card
.uidlen
);
560 uint16_t atqa
= (uint16_t)bytes_to_num(mattyrun_card
.atqa
, 2);
563 Mifare1ksim(simflags
, 0, mattyrun_uid
, atqa
, mattyrun_card
.sak
);
565 DbpString("[=] Emulation ended.");
572 BigBuf_free_keep_EM();
574 SpinErr((LED_A
| LED_B
| LED_C
| LED_D
), 250, 5);
575 DbpString("[=] Standalone mode MattyRun ended.");
577 DbpString("[" _YELLOW_("-") "] " _YELLOW_("Download card clone with `hf mf esave [--mini|--1k|--2k|--4k] -f dump_file`."));
579 DbpString("[=] You can take shell back :) ...");