From 4c3265daec524232c713ae9b35be76ce5fbec08b Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sun, 26 Mar 2023 20:26:50 +0200 Subject: [PATCH 1/9] text --- doc/magic_cards_notes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index fb7ba7fd2..da545a24b 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -575,6 +575,13 @@ Read config: 2. send 0xE000, will return the configuration bytes. `results: 850000000000000000005A5A00000008` + +Mapping of configuration bytes so far: +``` +850000000000000000005A5A00000008 + ^^ --> SAK +``` + Write config: 1. sending custom auth with all zeros key 2. send 0xE100 From 0f0a5d7f043632d4b540215141cf9fb16e9b6106 Mon Sep 17 00:00:00 2001 From: AloneLiberty <111039319+AloneLiberty@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:25:03 +0300 Subject: [PATCH 2/9] Fix lost arguments --- armsrc/mifareutil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index b11625339..6f8acc348 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -139,7 +139,7 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) { - return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL, false); + return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, ntptr, timing, false); } int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm) { From a9b3a69100fe0e97eb28b8a936f0c544fa91decc Mon Sep 17 00:00:00 2001 From: Einstein2150 Date: Wed, 29 Mar 2023 20:37:02 +0200 Subject: [PATCH 3/9] Update Mac-OS-X-Homebrew-Installation-Instructions.md Fix for Apple Silicon (M1) installation with arch -arm64 prefix Signed-off-by: Einstein2150 --- .../Mac-OS-X-Homebrew-Installation-Instructions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md index 4de2ec373..3b2e31530 100644 --- a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md @@ -54,6 +54,8 @@ Then you are missing Rosetta 2 and need to install it: `/usr/sbin/softwareupdate Homebrew has changed their prefix to differentiate between native Apple Silicon and Intel compiled binaries. The Makefile attempts to account for this but please note that whichever terminal or application you're using must be running under Architecture "Apple" as seen by Activity Monitor as all child processes inherit the Rosetta 2 environment of their parent. You can check which architecture you're currently running under with a `uname -m` in your terminal. +The fastest option is to run the brew command with the `arch -arm64` prefix i.e. `arch -arm64 brew install --HEAD --with-blueshark proxmark3`. This doesn't require running the whole terminal in Rosetta 2. + Visual Studio Code still runs under Rosetta 2 and if you're developing for proxmark3 on an Apple Silicon Mac you might want to consider running the Insiders build which has support for running natively on Apple Silicon. ## Install Proxmark3 tools From dab3171ba6fd409b63efc965c6bf88ef0224ba1c Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Mar 2023 22:38:03 +0200 Subject: [PATCH 4/9] added loadbinarykeys fct which takes fn and loads binary MFC keys into two arrays KeyA, KeyB. --- client/src/fileutils.c | 80 ++++++++++++++++++++++++++++++++++-------- client/src/fileutils.h | 16 +++++++++ 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 3182f47c3..8a6049d3c 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -304,12 +304,12 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si return PM3_EMALLOC; } - /* We should have a valid filename now, e.g. dumpdata-3.bin */ + // We should have a valid filename now, e.g. dumpdata-3.bin - /*Opening file for writing in binary mode*/ + // Opening file for writing in binary mode FILE *f = fopen(fileName, "wb"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); free(fileName); return PM3_EFILE; } @@ -336,12 +336,12 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t int blocks = datalen / blocksize; uint16_t currblock = 1; - /* We should have a valid filename now, e.g. dumpdata-3.bin */ + // We should have a valid filename now, e.g. dumpdata-3.bin - /*Opening file for writing in text mode*/ + // Opening file for writing in text mode FILE *f = fopen(fileName, "w+"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); retval = PM3_EFILE; goto out; } @@ -770,7 +770,7 @@ int saveFileWAVE(const char *preferredName, const int *data, size_t datalen) { FILE *wave_file = fopen(fileName, "wb"); if (!wave_file) { - PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); retval = PM3_EFILE; goto out; } @@ -806,7 +806,7 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen) { FILE *f = fopen(fileName, "w"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); retval = PM3_EFILE; goto out; } @@ -939,7 +939,7 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, FILE *f = fopen(path, "rb"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; } @@ -1050,7 +1050,7 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { FILE *f = fopen(path, "r"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; } @@ -1427,6 +1427,7 @@ int loadFileJSONroot(const char *preferredName, void **proot, bool verbose) { return retval; } +// iceman: todo - move all unsafe functions like this from client source. int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint32_t *keycnt) { // t5577 == 4 bytes // mifare == 6 bytes @@ -1463,7 +1464,7 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale FILE *f = fopen(path, "r"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); retval = PM3_EFILE; goto out; } @@ -1566,7 +1567,7 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key FILE *f = fopen(path, "r"); if (!f) { - PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", path); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); retval = PM3_EFILE; goto out; } @@ -1619,6 +1620,57 @@ out: return retval; } +int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen) { + + char *path; + int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false); + if (res != PM3_SUCCESS) { + return PM3_EFILE; + } + + FILE *f = fopen(path, "rb"); + if (!f) { + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); + free(path); + return PM3_EFILE; + } + free(path); + + // get filesize in order to malloc memory + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + if (fsize <= 0) { + PrintAndLogEx(FAILED, "error, when getting filesize"); + fclose(f); + return PM3_EFILE; + } + + // Half is KEY A, half is KEY B + fsize /= 2; + + *keya = calloc(fsize, sizeof(uint8_t)); + if (*keya == NULL) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); + fclose(f); + return PM3_EMALLOC; + } + + *alen = fread(*keya, 1, fsize, f); + + *keyb = calloc(fsize, sizeof(uint8_t)); + if (*keyb == NULL) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); + fclose(f); + return PM3_EMALLOC; + } + + *blen = fread(*keyb, 1, fsize, f); + fclose(f); + return PM3_SUCCESS; +} + mfu_df_e detect_mfu_dump_format(uint8_t **dump, size_t *dumplen, bool verbose) { mfu_df_e retval = MFU_DF_UNKNOWN; @@ -2058,7 +2110,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl } if (res != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", fn); + PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fn); return PM3_EFILE; } @@ -2068,7 +2120,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize) { if (d == NULL || n == 0) { - PrintAndLogEx(INFO, "No data to save. Skipping..."); + PrintAndLogEx(INFO, "No data to save, skipping..."); return PM3_EINVARG; } diff --git a/client/src/fileutils.h b/client/src/fileutils.h index fc5d274aa..18e0fbd7e 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -236,6 +236,7 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale */ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint32_t *keycnt); +int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen); typedef enum { MFU_DF_UNKNOWN, @@ -276,5 +277,20 @@ DumpFileType_t getfiletype(const char *filename); */ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen); + +/** STUB + * @brief Utility function to save data to three file files (BIN/EML/JSON). + * It also tries to save according to user preferences set dump folder paths. + * E.g. dumpdata.bin + * E.g. dumpdata.eml + * E.g. dumpdata.json + + * @param fn + * @param d The binary data to write to the file + * @param n the length of the data + * @param jsft json format type for the different memory cards (MFC, MFUL, LEGIC, 14B, 15, ICLASS etc) + * @param blocksize + * @return PM3_SUCCESS if OK + */ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft, size_t blocksize); #endif // FILEUTILS_H From 27b3ba041255b434678251cde4508159295c38a2 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Mar 2023 22:38:27 +0200 Subject: [PATCH 5/9] text --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4121234df..a8f8d819b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,8 +39,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato) - Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve) - Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve) - - Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb) - + - Added `hf legic info` command for other sources (@0xdeb) + - Added `hf legic einfo` - views emulator menory (@0xdeb) + - Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb) ## [Nitride.4.16191][2023-01-29] - Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox) From 4d28c852acab53d1654f5f95270ff75a4e6fb145 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Mar 2023 22:40:26 +0200 Subject: [PATCH 6/9] extracted load keys and mfc tag memory based on @didierA and @alejandro12120 PR. --- client/src/cmdhfmf.c | 459 ++++++++++++++++++++++--------------------- 1 file changed, 238 insertions(+), 221 deletions(-) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index d5d0e913b..e4b15c19e 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -38,15 +38,22 @@ #include "wiegand_formats.h" #include "wiegand_formatutils.h" -#define MIFARE_4K_MAXBLOCK 256 -#define MIFARE_2K_MAXBLOCK 128 -#define MIFARE_1K_MAXBLOCK 64 -#define MIFARE_MINI_MAXBLOCK 20 +#define MIFARE_4K_MAXBLOCK 256 +#define MIFARE_2K_MAXBLOCK 128 +#define MIFARE_1K_MAXBLOCK 64 +#define MIFARE_MINI_MAXBLOCK 20 -#define MIFARE_MINI_MAXSECTOR 5 -#define MIFARE_1K_MAXSECTOR 16 -#define MIFARE_2K_MAXSECTOR 32 -#define MIFARE_4K_MAXSECTOR 40 +#define MIFARE_4K_MAXSECTOR 40 +#define MIFARE_2K_MAXSECTOR 32 +#define MIFARE_1K_MAXSECTOR 16 +#define MIFARE_MINI_MAXSECTOR 5 + +#define MIFARE_4K_MAX_BYTES 4096 +#define MIFARE_2K_MAX_BYTES 2048 +#define MIFARE_1K_MAX_BYTES 1024 +#define MIFARE_MINI_MAX_BYTES 320 + +#define MIFARE_KEY_SIZE 6 static int CmdHelp(const char *Cmd); @@ -319,9 +326,9 @@ static int mf_print_keys(uint16_t n, uint8_t *d) { for (uint16_t i = 0; i < n; i++) { if (mfIsSectorTrailer(i)) { e_sector[mfSectorNum(i)].foundKey[0] = 1; - e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), 6); + e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE); e_sector[mfSectorNum(i)].foundKey[1] = 1; - e_sector[mfSectorNum(i)].Key[1] = bytes_to_num(d + (i * MFBLOCK_SIZE) + 10, 6); + e_sector[mfSectorNum(i)].Key[1] = bytes_to_num(d + (i * MFBLOCK_SIZE) + 10, MIFARE_KEY_SIZE); } } printKeyTable(sectors, e_sector); @@ -441,6 +448,191 @@ static int mf_analyse_st_block(uint8_t blockno, uint8_t *block, bool force){ return PM3_SUCCESS; } +/* Reads data from tag + * @param card: (output) card info + * @param carddata: (output) card data + * @param numSectors: size of the card + * @param keyFileName: filename containing keys or NULL. +*/ +static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t numSectors, char *keyfn){ + + // Select card to get UID/UIDLEN/ATQA/SAK information + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { + PrintAndLogEx(WARNING, "iso14443a card select timeout"); + return PM3_ETIMEOUT; + } + + uint64_t select_status = resp.oldarg[0]; + if (select_status == 0) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + return PM3_SUCCESS; + } + + // store card info + memcpy(card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + char *fptr = NULL; + if (keyfn == NULL || keyfn[0] == '\0') { + fptr = GenerateFilename("hf-mf-", "-key.bin"); + if (fptr == NULL) + return PM3_ESOFT; + + keyfn = fptr ; + } + + PrintAndLogEx(INFO, "Using... %s", keyfn); + + size_t alen = 0, blen = 0; + uint8_t *keyA, *keyB; + if (loadFileBinaryKey(keyfn, "", (void**)&keyA, (void**)&keyB, &alen, &blen) != PM3_SUCCESS) { + free(fptr); + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, "Reading sector access bits..."); + PrintAndLogEx(INFO, "." NOLF); + + uint8_t rights[40][4] = {0}; + + mf_readblock_t payload; + uint8_t current_key; + for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { + current_key = MF_KEY_A; + for (uint8_t tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { + PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); + + payload.blockno = mfFirstBlockOfSector(sectorNo) + mfNumBlocksPerSector(sectorNo) - 1; + payload.keytype = current_key; + + memcpy(payload.key, (current_key == MF_KEY_A) ? keyA + (sectorNo * MIFARE_KEY_SIZE) : keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) { + + uint8_t *data = resp.data.asBytes; + if (resp.status == PM3_SUCCESS) { + rights[sectorNo][0] = ((data[7] & 0x10) >> 2) | ((data[8] & 0x1) << 1) | ((data[8] & 0x10) >> 4); // C1C2C3 for data area 0 + rights[sectorNo][1] = ((data[7] & 0x20) >> 3) | ((data[8] & 0x2) << 0) | ((data[8] & 0x20) >> 5); // C1C2C3 for data area 1 + rights[sectorNo][2] = ((data[7] & 0x40) >> 4) | ((data[8] & 0x4) >> 1) | ((data[8] & 0x40) >> 6); // C1C2C3 for data area 2 + rights[sectorNo][3] = ((data[7] & 0x80) >> 5) | ((data[8] & 0x8) >> 2) | ((data[8] & 0x80) >> 7); // C1C2C3 for sector trailer + break; + } else if (tries == (MIFARE_SECTOR_RETRY / 2)) { // after half unsuccessful tries, give key B a go + PrintAndLogEx(WARNING, "\ntrying with key B instead..."); + current_key = MF_KEY_B; + PrintAndLogEx(INFO, "." NOLF); + } else if (tries == (MIFARE_SECTOR_RETRY - 1)) { // on last try set defaults + PrintAndLogEx(FAILED, "\ncould not get access rights for sector %2d. Trying with defaults...", sectorNo); + rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; + rights[sectorNo][3] = 0x01; + } + } else { + PrintAndLogEx(FAILED, "\ncommand execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); + rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; + rights[sectorNo][3] = 0x01; + } + } + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Finished reading sector access bits"); + PrintAndLogEx(INFO, "Dumping all blocks from card..."); + + for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { + for (uint8_t blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) { + bool received = false; + current_key = MF_KEY_A; + uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5; + if (rights[sectorNo][data_area] == 0x07) { // no key would work + PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d, skipping", sectorNo, blockNo); + continue; + } + + for (uint8_t tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { + if (mfIsSectorTrailer(blockNo)) { + + // sector trailer. At least the Access Conditions can always be read with key A. + payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; + payload.keytype = current_key; + memcpy(payload.key, (current_key == MF_KEY_A) ? keyA + (sectorNo * MIFARE_KEY_SIZE) : keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); + } else { + // data block. Check if it can be read with key A or key B + if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { + // only key B would work + payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; + payload.keytype = MF_KEY_B; + memcpy(payload.key, keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); + } else { + // key A would work + payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; + payload.keytype = current_key; + memcpy(payload.key, (current_key == MF_KEY_A) ? keyA + (sectorNo * MIFARE_KEY_SIZE) : keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); + } + } + + if (received) { + if (resp.status == PM3_SUCCESS) { + // break the re-try loop + break; + } + if ((current_key == MF_KEY_A) && (tries == (MIFARE_SECTOR_RETRY / 2))) { + // Half the tries failed with key A. Swap for key B + current_key = MF_KEY_B; + + // clear out keyA since it failed. + memset(keyA + (sectorNo * MIFARE_KEY_SIZE), 0x00, MIFARE_KEY_SIZE); + } + } + } + + if (received) { + + if (resp.status == PM3_SUCCESS) { + + uint8_t *data = resp.data.asBytes; + + if (mfIsSectorTrailer(blockNo)) { + // sector trailer. Fill in the keys. + memcpy(data , keyA + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + memcpy(data + 10, keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); + } + + memcpy(carddata + (MFBLOCK_SIZE * (mfFirstBlockOfSector(sectorNo) + blockNo)), data, MFBLOCK_SIZE); + PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo); + } else { + PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo); + } + } else { + PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo); + } + } + } + + free(fptr); + free(keyA); + free(keyB); + + PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks"); + return PM3_SUCCESS ; +} + static int CmdHF14AMfAcl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf acl", @@ -820,6 +1012,7 @@ static int CmdHF14AMfDump(const char *Cmd) { arg_lit0(NULL, "1k", "MIFARE Classic 1k / S50 (def)"), arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"), arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"), + arg_lit0(NULL, "ns", "no save to file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -836,7 +1029,7 @@ static int CmdHF14AMfDump(const char *Cmd) { bool m1 = arg_get_lit(ctx, 4); bool m2 = arg_get_lit(ctx, 5); bool m4 = arg_get_lit(ctx, 6); - + bool nosave = arg_get_lit(ctx, 7); CLIParserFree(ctx); uint64_t t1 = msclock(); @@ -850,244 +1043,68 @@ static int CmdHF14AMfDump(const char *Cmd) { } uint8_t numSectors = MIFARE_1K_MAXSECTOR; + uint16_t bytes = MIFARE_1K_MAX_BYTES; if (m0) { numSectors = MIFARE_MINI_MAXSECTOR; + bytes = MIFARE_MINI_MAX_BYTES; } else if (m1) { numSectors = MIFARE_1K_MAXSECTOR; + bytes = MIFARE_1K_MAX_BYTES; } else if (m2) { numSectors = MIFARE_2K_MAXSECTOR; - } else if (m4) { + bytes = MIFARE_2K_MAX_BYTES; + } else if (m4) { numSectors = MIFARE_4K_MAXSECTOR; + bytes = MIFARE_4K_MAX_BYTES; } else { PrintAndLogEx(WARNING, "Please specify a MIFARE Type"); return PM3_EINVARG; } - uint8_t sectorNo, blockNo; - uint8_t keyA[40][6]; - uint8_t keyB[40][6]; - uint8_t rights[40][4]; - uint8_t carddata[256][16]; - - FILE *f; - PacketResponseNG resp; - - char *fptr; - - // Select card to get UID/UIDLEN/ATQA/SAK information - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { - PrintAndLogEx(WARNING, "iso14443a card select timeout"); - return PM3_ETIMEOUT; + // read card + iso14a_card_select_t card ; + uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t)); + if (mem == NULL) { + PrintAndLogEx(ERR, "failed to allocate memory"); + return PM3_EMALLOC; } - - uint64_t select_status = resp.oldarg[0]; - if (select_status == 0) { - PrintAndLogEx(WARNING, "iso14443a card select failed"); - return PM3_SUCCESS; - } - - // store card info - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - if (keyFilename[0] == 0x00) { - fptr = GenerateFilename("hf-mf-", "-key.bin"); - if (fptr == NULL) - return PM3_ESOFT; - - strncpy(keyFilename, fptr, sizeof(keyFilename) - 1); - free(fptr); - } - - if ((f = fopen(keyFilename, "rb")) == NULL) { - PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), keyFilename); - return PM3_EFILE; - } - - PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename); - - // Read keys A from file - size_t bytes_read; - for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - bytes_read = fread(keyA[sectorNo], 1, MFKEY_SIZE, f); - if (bytes_read != MFKEY_SIZE) { - PrintAndLogEx(ERR, "File reading error."); - fclose(f); - return PM3_EFILE; - } - } - - // Read keys B from file - for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - bytes_read = fread(keyB[sectorNo], 1, MFKEY_SIZE, f); - if (bytes_read != MFKEY_SIZE) { - PrintAndLogEx(ERR, "File reading error."); - fclose(f); - return PM3_EFILE; - } - } - - fclose(f); - - PrintAndLogEx(INFO, "Reading sector access bits..."); - PrintAndLogEx(INFO, "." NOLF); - - uint8_t tries; - mf_readblock_t payload; - uint8_t current_key; - for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - current_key = MF_KEY_A; - for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { - PrintAndLogEx(NORMAL, "." NOLF); - fflush(stdout); - - payload.blockno = mfFirstBlockOfSector(sectorNo) + mfNumBlocksPerSector(sectorNo) - 1; - payload.keytype = current_key; - - memcpy(payload.key, current_key == MF_KEY_A ? keyA[sectorNo] : keyB[sectorNo], sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) { - - uint8_t *data = resp.data.asBytes; - if (resp.status == PM3_SUCCESS) { - rights[sectorNo][0] = ((data[7] & 0x10) >> 2) | ((data[8] & 0x1) << 1) | ((data[8] & 0x10) >> 4); // C1C2C3 for data area 0 - rights[sectorNo][1] = ((data[7] & 0x20) >> 3) | ((data[8] & 0x2) << 0) | ((data[8] & 0x20) >> 5); // C1C2C3 for data area 1 - rights[sectorNo][2] = ((data[7] & 0x40) >> 4) | ((data[8] & 0x4) >> 1) | ((data[8] & 0x40) >> 6); // C1C2C3 for data area 2 - rights[sectorNo][3] = ((data[7] & 0x80) >> 5) | ((data[8] & 0x8) >> 2) | ((data[8] & 0x80) >> 7); // C1C2C3 for sector trailer - break; - } else if (tries == (MIFARE_SECTOR_RETRY / 2)) { // after half unsuccessful tries, give key B a go - PrintAndLogEx(WARNING, "\ntrying with key B instead..."); - current_key = MF_KEY_B; - PrintAndLogEx(INFO, "." NOLF); - } else if (tries == (MIFARE_SECTOR_RETRY - 1)) { // on last try set defaults - PrintAndLogEx(FAILED, "\ncould not get access rights for sector %2d. Trying with defaults...", sectorNo); - rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; - rights[sectorNo][3] = 0x01; - } - } else { - PrintAndLogEx(FAILED, "\ncommand execute timeout when trying to read access rights for sector %2d. Trying with defaults...", sectorNo); - rights[sectorNo][0] = rights[sectorNo][1] = rights[sectorNo][2] = 0x00; - rights[sectorNo][3] = 0x01; - } - } - } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Finished reading sector access bits"); - PrintAndLogEx(INFO, "Dumping all blocks from card..."); - - for (sectorNo = 0; sectorNo < numSectors; sectorNo++) { - for (blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) { - bool received = false; - current_key = MF_KEY_A; - uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5; - if (rights[sectorNo][data_area] == 0x07) { // no key would work - PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d, skipping", sectorNo, blockNo); - continue; - } - for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { - if (blockNo == mfNumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. - - payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; - payload.keytype = current_key; - memcpy(payload.key, current_key == MF_KEY_A ? keyA[sectorNo] : keyB[sectorNo], sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); - } else { // data block. Check if it can be read with key A or key B - if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work - - payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; - payload.keytype = MF_KEY_B; - memcpy(payload.key, keyB[sectorNo], sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); - } else { // key A would work - - payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; - payload.keytype = current_key; - memcpy(payload.key, current_key == MF_KEY_A ? keyA[sectorNo] : keyB[sectorNo], sizeof(payload.key)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); - } - } - if (received) { - if (resp.status == PM3_SUCCESS) { - // break the re-try loop - break; - } - if ((current_key == MF_KEY_A) && (tries == (MIFARE_SECTOR_RETRY / 2))) { - // Half the tries failed with key A. Swap for key B - current_key = MF_KEY_B; - - // clear out keyA since it failed. - memset(keyA[sectorNo], 0x00, sizeof(keyA[sectorNo])); - } - } - } - - if (received) { - uint8_t *data = resp.data.asBytes; - if (blockNo == mfNumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. - data[0] = (keyA[sectorNo][0]); - data[1] = (keyA[sectorNo][1]); - data[2] = (keyA[sectorNo][2]); - data[3] = (keyA[sectorNo][3]); - data[4] = (keyA[sectorNo][4]); - data[5] = (keyA[sectorNo][5]); - - data[10] = (keyB[sectorNo][0]); - data[11] = (keyB[sectorNo][1]); - data[12] = (keyB[sectorNo][2]); - data[13] = (keyB[sectorNo][3]); - data[14] = (keyB[sectorNo][4]); - data[15] = (keyB[sectorNo][5]); - } - if (resp.status == PM3_SUCCESS) { - memcpy(carddata[mfFirstBlockOfSector(sectorNo) + blockNo], data, 16); - PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo); - } else { - PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo); - } - } else { - PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo); - } - } + int res = mfc_read_tag(&card, mem, numSectors, keyFilename); + if (res != PM3_SUCCESS) { + free(mem); + return res; } PrintAndLogEx(SUCCESS, "time: %" PRIu64 " seconds\n", (msclock() - t1) / 1000); - PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks"); + // Skip saving card data to file + if (nosave) { + PrintAndLogEx(INFO, "Called with no save option"); + free(mem); + return PM3_SUCCESS; + } + // Save to file if (strlen(dataFilename) < 1) { - fptr = GenerateFilename("hf-mf-", "-dump"); - if (fptr == NULL) + char *fptr = GenerateFilename("hf-mf-", "-dump"); + if (fptr == NULL) { + free(mem); return PM3_ESOFT; + } strcpy(dataFilename, fptr); free(fptr); } - uint16_t bytes = 16 * (mfFirstBlockOfSector(numSectors - 1) + mfNumBlocksPerSector(numSectors - 1)); - - saveFile(dataFilename, ".bin", (uint8_t *)carddata, bytes); - saveFileEML(dataFilename, (uint8_t *)carddata, bytes, MFBLOCK_SIZE); + saveFile(dataFilename, ".bin", mem, bytes); + saveFileEML(dataFilename, mem, bytes, MFBLOCK_SIZE); iso14a_mf_extdump_t xdump; xdump.card_info = card; - xdump.dump = (uint8_t *)carddata; + xdump.dump = mem; xdump.dumplen = bytes; saveFileJSON(dataFilename, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + free(mem); return PM3_SUCCESS; } @@ -6892,11 +6909,11 @@ static int CmdHF14AMfView(const char *Cmd) { } uint16_t block_cnt = MIN(MIFARE_1K_MAXBLOCK, (bytes_read / MFBLOCK_SIZE)); - if (bytes_read == 320) + if (bytes_read == MIFARE_MINI_MAX_BYTES) block_cnt = MIFARE_MINI_MAXBLOCK; - else if (bytes_read == 2048) + else if (bytes_read == MIFARE_2K_MAX_BYTES) block_cnt = MIFARE_2K_MAXBLOCK; - else if (bytes_read == 4096) + else if (bytes_read == MIFARE_4K_MAX_BYTES) block_cnt = MIFARE_4K_MAXBLOCK; if (verbose) { From e03f7ed6d2db7dcd1e4ce262984fdaab51d6d234 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Thu, 30 Mar 2023 22:41:44 +0200 Subject: [PATCH 7/9] text --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f8d819b..bf31728a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001) - Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001) - Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001) - Changed magic note to include a section about GDM tags (@iceman1001) From 222ef4e084d969012c1ddf1fe1ea09145d230a58 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 1 Apr 2023 12:24:32 +0200 Subject: [PATCH 8/9] addded static encrypted nonce checks to nested --- armsrc/mifarecmd.c | 33 +++++++++++++++++++++++++++++++-- client/src/cmdhfmf.c | 29 ++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 7eaad3e23..918e977bd 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1154,7 +1154,12 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, } memcpy(prev_enc_nt, receivedAnswer, 4); if (prev_counter == 5) { - if (g_dbglevel >= DBG_EXTENDED) DbpString("Static encrypted nonce detected, exiting..."); + if (g_dbglevel >= DBG_EXTENDED) { + DbpString("Static encrypted nonce detected, exiting..."); + uint32_t a = bytes_to_num(prev_enc_nt, 4); + uint32_t b = bytes_to_num(receivedAnswer, 4); + Dbprintf("( %08x vs %08x )", a, b); + } isOK = PM3_ESTATIC_NONCE; break; } @@ -1224,6 +1229,9 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 LED_B_ON(); WDT_HIT(); + uint8_t prev_enc_nt[] = {0, 0, 0, 0}; + uint8_t prev_counter = 0; + uint16_t unsuccessful_tries = 0; uint16_t davg = 0; dmax = 0; @@ -1266,11 +1274,13 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 }; // cards with fixed nonce + /* if (nt1 == nt2) { Dbprintf("Nested: %08x vs %08x", nt1, nt2); break; } - + */ + uint32_t nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 101; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); @@ -1292,6 +1302,25 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 isOK = PM3_EFAILED; } } + + if (prev_enc_nt[0] == receivedAnswer[0] && + prev_enc_nt[1] == receivedAnswer[1] && + prev_enc_nt[2] == receivedAnswer[2] && + prev_enc_nt[3] == receivedAnswer[3] + ) { + prev_counter++; + } + memcpy(prev_enc_nt, receivedAnswer, 4); + if (prev_counter == 5) { + if (g_dbglevel >= DBG_EXTENDED) { + DbpString("Static encrypted nonce detected, exiting..."); + uint32_t a = bytes_to_num(prev_enc_nt, 4); + uint32_t b = bytes_to_num(receivedAnswer, 4); + Dbprintf("( %08x vs %08x )", a, b); + } + isOK = PM3_ESTATIC_NONCE; + break; + } } if (rtr > 1) diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index e4b15c19e..725a3dff4 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -1528,7 +1528,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't PrintAndLogEx(ERR, "Command execute timeout\n"); break; case PM3_EOPABORTED: - PrintAndLogEx(WARNING, "Button pressed. Aborted.\n"); + PrintAndLogEx(WARNING, "Button pressed. Aborted\n"); break; case PM3_EFAILED: PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); @@ -1536,6 +1536,9 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't case PM3_ESOFT: PrintAndLogEx(FAILED, "No valid key found"); break; + case PM3_ESTATIC_NONCE: + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); + break; case PM3_SUCCESS: key64 = bytes_to_num(keyBlock, 6); @@ -1560,7 +1563,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't } return PM3_SUCCESS; default : - PrintAndLogEx(ERR, "Unknown error.\n"); + PrintAndLogEx(ERR, "Unknown error\n"); } return PM3_SUCCESS; @@ -1608,15 +1611,18 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't PrintAndLogEx(ERR, "Command execute timeout\n"); break; case PM3_EOPABORTED: - PrintAndLogEx(WARNING, "button pressed. Aborted.\n"); + PrintAndLogEx(WARNING, "button pressed. Aborted\n"); break; case PM3_EFAILED : - PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); + PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable)\n"); break; case PM3_ESOFT: //key not found calibrate = false; continue; + case PM3_ESTATIC_NONCE: + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); + break; case PM3_SUCCESS: calibrate = false; e_sector[sectorNo].foundKey[trgKeyType] = 1; @@ -1625,7 +1631,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); continue; default : - PrintAndLogEx(ERR, "Unknown error.\n"); + PrintAndLogEx(ERR, "Unknown error\n"); } free(e_sector); return PM3_ESOFT; @@ -2179,13 +2185,13 @@ static int CmdHF14AMfNestedHard(const char *Cmd) { if (isOK) { switch (isOK) { case PM3_ETIMEOUT : - PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n"); + PrintAndLogEx(ERR, "Error: No response from Proxmark3\n"); break; case PM3_EOPABORTED: - PrintAndLogEx(WARNING, "Button pressed. Aborted.\n"); + PrintAndLogEx(WARNING, "Button pressed. Aborted\n"); break; case PM3_ESTATIC_NONCE: - PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted.\n"); + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); break; default : break; @@ -2841,6 +2847,11 @@ tryNested: } break; } + case PM3_ESTATIC_NONCE: + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); + free(e_sector); + free(fptr); + return isOK; case PM3_SUCCESS: { calibrate = false; e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); @@ -2878,7 +2889,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack break; } case PM3_ESTATIC_NONCE: { - PrintAndLogEx(ERR, "\nError: Static encrypted nonce detected. Aborted.\n"); + PrintAndLogEx(ERR, "\nError: Static encrypted nonce detected. Aborted\n"); break; } default: { From 6e0a6aa1e630c6863e81aace77f20278ca1fbd71 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Sat, 1 Apr 2023 12:43:34 +0200 Subject: [PATCH 9/9] fix detection --- armsrc/mifarecmd.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 918e977bd..f5e88a34c 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1229,7 +1229,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 LED_B_ON(); WDT_HIT(); - uint8_t prev_enc_nt[] = {0, 0, 0, 0}; + uint32_t prev_enc_nt = 0; uint8_t prev_counter = 0; uint16_t unsuccessful_tries = 0; @@ -1303,20 +1303,16 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 } } - if (prev_enc_nt[0] == receivedAnswer[0] && - prev_enc_nt[1] == receivedAnswer[1] && - prev_enc_nt[2] == receivedAnswer[2] && - prev_enc_nt[3] == receivedAnswer[3] - ) { + + if (nt1 == nt2) { prev_counter++; } - memcpy(prev_enc_nt, receivedAnswer, 4); + prev_enc_nt = nt2; + if (prev_counter == 5) { if (g_dbglevel >= DBG_EXTENDED) { DbpString("Static encrypted nonce detected, exiting..."); - uint32_t a = bytes_to_num(prev_enc_nt, 4); - uint32_t b = bytes_to_num(receivedAnswer, 4); - Dbprintf("( %08x vs %08x )", a, b); + Dbprintf("( %08x vs %08x )", prev_enc_nt, nt2); } isOK = PM3_ESTATIC_NONCE; break;