mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
load additional user-defined keys from emulator memory
This commit is contained in:
parent
ff997bed26
commit
83a4f7476f
1 changed files with 108 additions and 26 deletions
|
@ -42,6 +42,9 @@ on a blank card.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "standalone.h" // standalone definitions
|
#include "standalone.h" // standalone definitions
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#include "appmain.h"
|
#include "appmain.h"
|
||||||
#include "fpgaloader.h"
|
#include "fpgaloader.h"
|
||||||
|
@ -62,11 +65,23 @@ static uint32_t mattyrun_cuid;
|
||||||
static iso14a_card_select_t mattyrun_card;
|
static iso14a_card_select_t mattyrun_card;
|
||||||
|
|
||||||
// Pseudo-configuration block.
|
// Pseudo-configuration block.
|
||||||
static bool const mattyrun_printKeys = false; // Prints keys
|
static bool const MATTYRUN_PRINT_KEYS = false; // Prints keys
|
||||||
static bool const mattyrun_ecfill = true; // Fill emulator memory with cards content.
|
static bool const MATTYRUN_ECFILL = true; // Fill emulator memory with cards content.
|
||||||
|
|
||||||
// Set of keys to be used.
|
// Set of keys to be used.
|
||||||
static uint64_t const mattyrun_mfKeys[] = {
|
static uint64_t const MATTYRUN_MFC_KEY_BITS = 0x00FFFFFFFFFFFF;
|
||||||
|
static uint64_t const MATTYRUN_MFC_KEY_FLAG_UNUSED = 0x10000000000000;
|
||||||
|
static uint64_t const MATTYRUN_MFC_ESSENTIAL_KEYS[] = {
|
||||||
|
0xFFFFFFFFFFFF, // Default key
|
||||||
|
0x000000000000, // Blank key
|
||||||
|
0xA0A1A2A3A4A5, // MAD key
|
||||||
|
0x5C8FF9990DA2, // Mifare 1k EV1 (S50) hidden blocks, Signature data 16 A
|
||||||
|
0x75CCB59C9BED, // Mifare 1k EV1 (S50) hidden blocks, Signature data 17 A
|
||||||
|
0xD01AFEEB890A, // Mifare 1k EV1 (S50) hidden blocks, Signature data 16 B
|
||||||
|
0x4B791BEA7BCC, // Mifare 1k EV1 (S50) hidden blocks, Signature data 17 B
|
||||||
|
0xD3F7D3F7D3F7, // AN1305 MIFARE Classic as NFC Type MIFARE Classic Tag Public Key A
|
||||||
|
};
|
||||||
|
static uint64_t const MATTYRUN_MFC_DEFAULT_KEYS[] = {
|
||||||
// Default key
|
// Default key
|
||||||
0xFFFFFFFFFFFF,
|
0xFFFFFFFFFFFF,
|
||||||
// Blank key
|
// Blank key
|
||||||
|
@ -2270,6 +2285,13 @@ static int saMifareChkKeys(uint8_t const blockNo, uint8_t const keyType, bool co
|
||||||
|
|
||||||
for (uint16_t i = 0; i < keyCount; ++i) {
|
for (uint16_t i = 0; i < keyCount; ++i) {
|
||||||
|
|
||||||
|
uint64_t mfKey = mfKeys[i];
|
||||||
|
if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) != 0) {
|
||||||
|
// skip unused dictionary key slot
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mfKey &= MATTYRUN_MFC_KEY_BITS;
|
||||||
|
|
||||||
if (mattyrun_card.uidlen == 0) {
|
if (mattyrun_card.uidlen == 0) {
|
||||||
if (!saMifareDiscover()) {
|
if (!saMifareDiscover()) {
|
||||||
--i; // try same key once again
|
--i; // try same key once again
|
||||||
|
@ -2305,7 +2327,7 @@ static int saMifareChkKeys(uint8_t const blockNo, uint8_t const keyType, bool co
|
||||||
|
|
||||||
selectRetries = 16;
|
selectRetries = 16;
|
||||||
|
|
||||||
authres = mifare_classic_auth(pcs, mattyrun_cuid, blockNo, keyType, mfKeys[i], AUTH_FIRST);
|
authres = mifare_classic_auth(pcs, mattyrun_cuid, blockNo, keyType, mfKey, AUTH_FIRST);
|
||||||
if (authres) {
|
if (authres) {
|
||||||
uint8_t dummy_answer = 0;
|
uint8_t dummy_answer = 0;
|
||||||
ReaderTransmit(&dummy_answer, 1, NULL);
|
ReaderTransmit(&dummy_answer, 1, NULL);
|
||||||
|
@ -2318,7 +2340,7 @@ static int saMifareChkKeys(uint8_t const blockNo, uint8_t const keyType, bool co
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*key = mfKeys[i];
|
*key = mfKey;
|
||||||
retval = i;
|
retval = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2350,24 +2372,84 @@ void ModInfo(void) {
|
||||||
*/
|
*/
|
||||||
void RunMod(void) {
|
void RunMod(void) {
|
||||||
StandAloneMode();
|
StandAloneMode();
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
|
||||||
DbpString(">> HF Mifare chk/dump/sim a.k.a MattyRun Started <<");
|
DbpString(">> HF Mifare chk/dump/sim a.k.a MattyRun Started <<");
|
||||||
|
|
||||||
// Comment this line below if you want to see debug messages.
|
// Comment this line below if you want to see debug messages.
|
||||||
// usb_disable();
|
// usb_disable();
|
||||||
|
|
||||||
uint16_t const mfKeysCnt = ARRAYLEN(mattyrun_mfKeys);
|
// Allocate dictionary buffer
|
||||||
|
uint64_t * const mfcKeys = (uint64_t *)BigBuf_malloc(
|
||||||
|
sizeof(uint64_t) * (ARRAYLEN(MATTYRUN_MFC_ESSENTIAL_KEYS) +
|
||||||
|
ARRAYLEN(MATTYRUN_MFC_DEFAULT_KEYS) +
|
||||||
|
MIFARE_4K_MAXSECTOR * 2));
|
||||||
|
uint16_t mfcKeyCount = 0;
|
||||||
|
|
||||||
// Pretty print of the keys to be checked.
|
// Load essential keys to dictionary buffer
|
||||||
if (mattyrun_printKeys) {
|
for (uint16_t i = 0; i < ARRAYLEN(MATTYRUN_MFC_ESSENTIAL_KEYS); ++i) {
|
||||||
DbpString("[+] Printing mf keys");
|
uint64_t mfKey = MATTYRUN_MFC_ESSENTIAL_KEYS[i];
|
||||||
for (uint16_t keycnt = 0; keycnt < mfKeysCnt; ++keycnt) {
|
for (uint16_t j = 0; j < mfcKeyCount; ++j) {
|
||||||
uint8_t key[6];
|
if (mfKey == mfcKeys[j]) {
|
||||||
num_to_bytes(mattyrun_mfKeys[keycnt], 6, &key[0]);
|
// skip redundant dictionary key
|
||||||
Dbprintf("[-] chk mf key[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
|
mfKey = MATTYRUN_MFC_KEY_FLAG_UNUSED;
|
||||||
key[0], key[1], key[2], key[3], key[4], key[5]);
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DbpString(" --------------------------------------------------------");
|
if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
|
||||||
|
mfcKeys[mfcKeyCount] = mfKey;
|
||||||
|
++mfcKeyCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load user keys from emulator memory to dictionary buffer
|
||||||
|
for (uint8_t sectorNo = 0; sectorNo < MIFARE_4K_MAXSECTOR; ++sectorNo) {
|
||||||
|
for (uint8_t keyType = 0; keyType < 2; ++keyType) {
|
||||||
|
uint64_t mfKey = emlGetKey(sectorNo, keyType);
|
||||||
|
for (uint16_t j = 0; j < mfcKeyCount; ++j) {
|
||||||
|
if (mfKey == mfcKeys[j]) {
|
||||||
|
// skip redundant dictionary key
|
||||||
|
mfKey = MATTYRUN_MFC_KEY_FLAG_UNUSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
|
||||||
|
mfcKeys[mfcKeyCount] = mfKey;
|
||||||
|
++mfcKeyCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load additional keys to dictionary buffer
|
||||||
|
for (uint16_t i = 0; i < ARRAYLEN(MATTYRUN_MFC_DEFAULT_KEYS); ++i) {
|
||||||
|
uint64_t mfKey = MATTYRUN_MFC_DEFAULT_KEYS[i];
|
||||||
|
for (uint16_t j = 0; j < mfcKeyCount; ++j) {
|
||||||
|
if (mfKey == mfcKeys[j]) {
|
||||||
|
// skip redundant dictionary key
|
||||||
|
mfKey = MATTYRUN_MFC_KEY_FLAG_UNUSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) == 0) {
|
||||||
|
mfcKeys[mfcKeyCount] = mfKey;
|
||||||
|
++mfcKeyCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call FpgaDownloadAndGo(FPGA_BITSTREAM_HF) only after extracting keys from
|
||||||
|
// emulator memory as it may destroy the contents of the emulator memory.
|
||||||
|
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||||
|
|
||||||
|
// Pretty print keys to be checked
|
||||||
|
if (MATTYRUN_PRINT_KEYS) {
|
||||||
|
DbpString("[+] Printing mfc key dictionary");
|
||||||
|
for (uint16_t i = 0; i < mfcKeyCount; ++i) {
|
||||||
|
uint64_t mfKey = mfcKeys[i];
|
||||||
|
if ((mfKey & MATTYRUN_MFC_KEY_FLAG_UNUSED) != 0) {
|
||||||
|
// skip unused dictionary key slot
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Dbprintf("[-] key[%5" PRIu16 "] = %012" PRIx64 "", i, mfKey);
|
||||||
|
}
|
||||||
|
DbpString("[+] --------------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sectorsCnt = MIFARE_4K_MAXSECTOR;
|
uint8_t sectorsCnt = MIFARE_4K_MAXSECTOR;
|
||||||
|
@ -2451,8 +2533,8 @@ void RunMod(void) {
|
||||||
for (uint8_t keyType = 0; keyType < 2 && !err; ++keyType) {
|
for (uint8_t keyType = 0; keyType < 2 && !err; ++keyType) {
|
||||||
for (uint8_t sec = 0; sec < sectorsCnt && !err; ++sec) {
|
for (uint8_t sec = 0; sec < sectorsCnt && !err; ++sec) {
|
||||||
uint64_t currentKey;
|
uint64_t currentKey;
|
||||||
Dbprintf("[=] Testing sector %3d (block %3d) for key %c (with %i keys)", sec, FirstBlockOfSector(sec), (keyType == 0) ? 'A' : 'B', mfKeysCnt);
|
Dbprintf("[=] Testing sector %3" PRIu8 " (block %3" PRIu8 ") for key %c", sec, FirstBlockOfSector(sec), (keyType == 0) ? 'A' : 'B');
|
||||||
int key = saMifareChkKeys(FirstBlockOfSector(sec), keyType, true, mfKeysCnt, &mattyrun_mfKeys[0], ¤tKey);
|
int key = saMifareChkKeys(FirstBlockOfSector(sec), keyType, true, mfcKeyCount, &mfcKeys[0], ¤tKey);
|
||||||
if (key == -2) {
|
if (key == -2) {
|
||||||
DbpString("[" _RED_("!") "] " _RED_("Failed to select card!"));
|
DbpString("[" _RED_("!") "] " _RED_("Failed to select card!"));
|
||||||
SpinErr(LED_D, 50, 2);
|
SpinErr(LED_D, 50, 2);
|
||||||
|
@ -2463,13 +2545,13 @@ void RunMod(void) {
|
||||||
if (sec == MIFARE_MINI_MAXSECTOR || sec == MIFARE_1K_MAXSECTOR || sec == MIFARE_2K_MAXSECTOR || sec == MIFARE_4K_MAXSECTOR) {
|
if (sec == MIFARE_MINI_MAXSECTOR || sec == MIFARE_1K_MAXSECTOR || sec == MIFARE_2K_MAXSECTOR || sec == MIFARE_4K_MAXSECTOR) {
|
||||||
} else if (sec == (MIFARE_MINI_MAXSECTOR + 2) || sec == (MIFARE_1K_MAXSECTOR + 2) || sec == (MIFARE_2K_MAXSECTOR + 2) || sec == (MIFARE_4K_MAXSECTOR + 2)) {
|
} else if (sec == (MIFARE_MINI_MAXSECTOR + 2) || sec == (MIFARE_1K_MAXSECTOR + 2) || sec == (MIFARE_2K_MAXSECTOR + 2) || sec == (MIFARE_4K_MAXSECTOR + 2)) {
|
||||||
} else {
|
} else {
|
||||||
Dbprintf("[" _RED_("!") "] " _RED_("Unexpected number of sectors (%d)!"), sec);
|
Dbprintf("[" _RED_("!") "] " _RED_("Unexpected number of sectors (%" PRIu8 ")!"), sec);
|
||||||
SpinErr(LED_D, 250, 3);
|
SpinErr(LED_D, 250, 3);
|
||||||
allKeysFound = false;
|
allKeysFound = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (key < 0) {
|
} else if (key < 0) {
|
||||||
Dbprintf("[" _RED_("!") "] " _RED_("No key %c found for sector %d!"), (keyType == 0) ? 'A' : 'B', sec);
|
Dbprintf("[" _RED_("!") "] " _RED_("No key %c found for sector %" PRIu8 "!"), (keyType == 0) ? 'A' : 'B', sec);
|
||||||
SpinErr(LED_D, 250, 3);
|
SpinErr(LED_D, 250, 3);
|
||||||
allKeysFound = false;
|
allKeysFound = false;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2477,9 +2559,7 @@ void RunMod(void) {
|
||||||
num_to_bytes(currentKey, 6, foundKey[keyType][sec]);
|
num_to_bytes(currentKey, 6, foundKey[keyType][sec]);
|
||||||
validKey[keyType][sec] = true;
|
validKey[keyType][sec] = true;
|
||||||
keyFound = true;
|
keyFound = true;
|
||||||
Dbprintf("[=] Found valid key: %02x%02x%02x%02x%02x%02x",
|
Dbprintf("[=] Found valid key: %012" PRIx64 "", currentKey);
|
||||||
foundKey[keyType][sec][0], foundKey[keyType][sec][1], foundKey[keyType][sec][2],
|
|
||||||
foundKey[keyType][sec][3], foundKey[keyType][sec][4], foundKey[keyType][sec][5]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2536,7 +2616,7 @@ void RunMod(void) {
|
||||||
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; ++sectorNo) {
|
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; ++sectorNo) {
|
||||||
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
|
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
|
||||||
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4)
|
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4)
|
||||||
for (uint16_t keyType = 0; keyType < 2; ++keyType) {
|
for (uint8_t keyType = 0; keyType < 2; ++keyType) {
|
||||||
if (validKey[keyType][sectorNo]) {
|
if (validKey[keyType][sectorNo]) {
|
||||||
memcpy(mblock + keyType * 10, foundKey[keyType][sectorNo], 6);
|
memcpy(mblock + keyType * 10, foundKey[keyType][sectorNo], 6);
|
||||||
}
|
}
|
||||||
|
@ -2547,7 +2627,7 @@ void RunMod(void) {
|
||||||
|
|
||||||
DbpString("[=] Found keys have been transferred to the emulator memory.");
|
DbpString("[=] Found keys have been transferred to the emulator memory.");
|
||||||
|
|
||||||
if (!mattyrun_ecfill) {
|
if (!MATTYRUN_ECFILL) {
|
||||||
state = STATE_READ;
|
state = STATE_READ;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2608,6 +2688,8 @@ void RunMod(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigBuf_free_keep_EM();
|
||||||
|
|
||||||
SpinErr((LED_A | LED_B | LED_C | LED_D), 250, 5);
|
SpinErr((LED_A | LED_B | LED_C | LED_D), 250, 5);
|
||||||
DbpString("[=] You can take shell back :) ...");
|
DbpString("[=] You can take shell back :) ...");
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue