Merge pull request #2747 from Eltrick/stylise-dormakaba
[RRG-proxmark3.git] / armsrc / Standalone / hf_mattyrun.c
blobad1e6b863150da2c4a238471257c2f59a7125658
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.
5 //
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"
23 #include <inttypes.h>
25 #include "appmain.h"
26 #include "BigBuf.h"
27 #include "commonutil.h"
28 #include "crc16.h"
29 #include "dbprint.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
37 #include "string.h"
38 #include "ticks.h"
39 #include "util.h"
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
48 * keys).
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
60 * for both key types.
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
74 * dump is available.
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
82 * constants:
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
88 * dictionaries here.
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.
100 // Key flags
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
117 // Internal state
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) {
124 SpinDelay(500);
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);
129 SpinDelay(500);
130 return false;
133 return true;
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) {
141 int retval = -1;
143 struct Crypto1State mpcs = {0, 0};
144 struct Crypto1State *pcs;
145 pcs = &mpcs;
147 uint8_t selectRetries = 16;
148 uint8_t cascade_levels = 0;
149 int authres = 0;
151 if (clearTrace)
152 clear_trace();
154 int oldbg = g_dbglevel;
155 g_dbglevel = DBG_NONE;
157 set_tracing(false);
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
164 continue;
166 mfKey &= MATTYRUN_MFC_KEY_BITS;
168 if (mattyrun_card.uidlen == 0) {
169 if (!saMifareDiscover()) {
170 --i; // try same key once again
171 --selectRetries;
172 if (selectRetries > 0) {
173 continue;
174 } else {
175 retval = -2;
176 break;
179 } else {
180 if (cascade_levels == 0) {
181 switch (mattyrun_card.uidlen) {
182 case 4:
183 cascade_levels = 1;
184 break;
185 case 7:
186 cascade_levels = 2;
187 break;
188 case 10:
189 cascade_levels = 3;
190 break;
191 default:
192 break;
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
199 --selectRetries;
200 if (selectRetries > 0) {
201 continue;
202 } else {
203 retval = -2;
204 break;
209 selectRetries = 16;
211 authres = mifare_classic_auth(pcs, mattyrun_cuid, blockNo, keyType, mfKey, AUTH_FIRST);
212 if (authres) {
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);
217 if (authres == 1) {
218 retval = -3;
219 break;
220 } else {
221 continue;
224 *key = mfKey;
225 retval = i;
226 break;
229 crypto1_deinit(pcs);
231 set_tracing(false);
232 g_dbglevel = oldbg;
234 return retval;
237 void ModInfo(void) {
238 DbpString(" HF MIFARE Classic chk/ecfill/sim - aka MattyRun");
241 void RunMod(void) {
242 StandAloneMode();
243 DbpString(">> HF MIFARE Classic chk/ecfill/sim - aka MattyRun started <<");
245 // Comment this line below if you want to see debug messages.
246 // usb_disable();
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;
262 break;
265 if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
266 mfcKeys[mfcKeyCount] = mfKey;
267 ++mfcKeyCount;
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;
279 break;
282 if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
283 mfcKeys[mfcKeyCount] = mfKey;
284 ++mfcKeyCount;
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;
296 break;
299 if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
300 mfcKeys[mfcKeyCount] = mfKey;
301 ++mfcKeyCount;
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
316 continue;
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];
330 enum {
331 STATE_READ,
332 STATE_ATTACK,
333 STATE_LOAD,
334 STATE_EMULATE,
335 } state = STATE_READ;
337 for (;;) {
339 WDT_HIT();
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();
348 break;
351 if (state == STATE_READ) {
352 // Wait for card.
353 // If detected, try to authenticate with dictionary keys.
355 LED_A_OFF();
356 LED_B_OFF();
357 LED_C_ON();
358 LED_D_OFF();
360 if (!saMifareDiscover()) {
361 SpinErr(LED_D, 50, 2);
362 continue;
365 switch (mattyrun_card.uidlen) {
366 case 4:
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]);
370 break;
371 case 7:
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]);
376 break;
377 default:
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]);
383 break;
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);
398 keyFound = false;
399 allKeysFound = true;
400 bool err = false;
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], &currentKey);
410 if (key == -2) {
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
414 break;
415 } else if (key == -3) {
416 sectorsCnt = sec;
417 switch (sec) {
418 case MIFARE_MINI_MAXSECTOR:
419 case MIFARE_1K_MAXSECTOR:
420 case MIFARE_2K_MAXSECTOR:
421 case MIFARE_4K_MAXSECTOR:
422 break;
423 case (MIFARE_MINI_MAXSECTOR + 2):
424 case (MIFARE_1K_MAXSECTOR + 2):
425 case (MIFARE_2K_MAXSECTOR + 2):
426 case (MIFARE_4K_MAXSECTOR + 2):
427 break;
428 default:
429 Dbprintf("[" _RED_("!") "] " _RED_("Unexpected number of sectors (%" PRIu8 ")!"),
430 sec);
431 SpinErr(LED_D, 250, 3);
432 allKeysFound = false;
433 break;
435 break;
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);
440 LED_C_ON();
441 allKeysFound = false;
442 continue;
443 } else {
444 num_to_bytes(currentKey, 6, foundKey[keyType][sec]);
445 validKey[keyType][sec] = true;
446 keyFound = true;
447 Dbprintf("[=] Found valid key: %012" PRIx64 "", currentKey);
452 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
454 if (err) {
455 SpinOff(500);
456 continue;
459 if (allKeysFound) {
460 DbpString("[" _GREEN_("+") "] " _GREEN_("All keys found"));
461 state = STATE_LOAD;
462 continue;
463 } else if (keyFound) {
464 DbpString("[" _RED_("!") "] " _RED_("Some keys could not be found!"));
465 state = STATE_ATTACK;
466 continue;
467 } else {
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);
471 continue;
474 } else if (state == STATE_ATTACK) {
475 // Do nested attack, set allKeysFound = true
477 LED_A_OFF();
478 LED_B_ON();
479 LED_C_OFF();
480 LED_D_OFF();
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;
486 state = STATE_LOAD;
487 continue;
489 } else if (state == STATE_LOAD) {
490 // Transfer found keys to memory.
491 // If enabled, load full card content into emulator memory.
493 LED_A_OFF();
494 LED_B_ON();
495 LED_C_ON();
496 LED_D_OFF();
498 emlClearMem();
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) {
516 state = STATE_READ;
517 continue;
520 int filled;
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;
536 } else {
537 DbpString("[" _GREEN_("+") "] " _GREEN_("Emulator memory filled completely."));
540 state = STATE_EMULATE;
541 continue;
543 } else if (state == STATE_EMULATE) {
544 // Finally, emulate the cloned card.
546 LED_A_ON();
547 LED_B_ON();
548 LED_C_ON();
549 LED_D_OFF();
551 DbpString("[=] Started emulation. Press button to abort at anytime.");
553 if (partialEmulation) {
554 LED_D_ON();
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);
562 SpinDelay(1000);
563 Mifare1ksim(simflags, 0, mattyrun_uid, atqa, mattyrun_card.sak);
565 DbpString("[=] Emulation ended.");
566 state = STATE_READ;
567 continue;
572 BigBuf_free_keep_EM();
574 SpinErr((LED_A | LED_B | LED_C | LED_D), 250, 5);
575 DbpString("[=] Standalone mode MattyRun ended.");
576 DbpString("");
577 DbpString("[" _YELLOW_("-") "] " _YELLOW_("Download card clone with `hf mf esave [--mini|--1k|--2k|--4k] -f dump_file`."));
578 DbpString("");
579 DbpString("[=] You can take shell back :) ...");
580 LEDsoff();