diff --git a/CHANGELOG.md b/CHANGELOG.md index 16354bcac..e1f3cf2c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ 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] + - Added `hf mf cwipe` magic chinese card (gen1a) wipe to default state (@merlokk) + - Added 'pm3_mf7b_wipe.py' python script. Wipes magic S70 7B Gen2 card. (@vulnersCom) + - Added `hf mfp chk` Mifare plus command for check keys from public keys list, from dictionary or 1 and 2-byte bruteforce (@merlokk) + - Change `hf 15` - some refactoring (@grspy) + - Added `hf 15 writeafi` and `hf 15 writedsfid` (@grspy) + - Added detailed info for SLIX2 tags in `hf 15 info` (@grspy) - Fix hf list felica and hf felica sniff (@7homasSutter) - Added hf felica wrunencrypted (@7homasSutter) - Added hf felica rdunencrypted (@7homasSutter) diff --git a/README.md b/README.md index b306ad542..7e4c28145 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ # RRG / Iceman repo - Proxmark3 -This repo is based on iceman fork for Proxmark3. - -It supports RDV4.0 and other Proxmark3 platforms as well. - | Releases | Linux & OSX CI | Windows CI | Coverity | | ------------------- |:-------------------:| -------------------:| -------------------:| | [![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)| ---- + + # PROXMARK INSTALLATION AND OVERVIEW @@ -29,10 +26,12 @@ It supports RDV4.0 and other Proxmark3 platforms as well. |[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) || |[Donations](#Donations)||| -## Support on other Proxmark3 platforms + +## Build for non-RDV4 Proxmark3 platforms In order to build this repo for other Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md) + ## What has changed? On the hardware side: @@ -110,4 +109,3 @@ Nothing says thank you as much as a donation. So if you feel the love, do feel f https://www.patreon.com/iceman1001 -All support is welcome! diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f1fd3eb9c..7ea08e59c 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -929,6 +929,7 @@ void BruteforceIso15693Afi(uint32_t speed) { uint8_t buf[ISO15_MAX_FRAME]; memset(buf, 0x00, sizeof(buf)); int datalen = 0, recvlen = 0; + bool aborted = false; Iso15693InitReader(); @@ -966,7 +967,9 @@ void BruteforceIso15693Afi(uint32_t speed) { Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); } - if (BUTTON_PRESS()) { + aborted = BUTTON_PRESS(); + + if (aborted) { DbpString("button pressed, aborting.."); break; } @@ -974,6 +977,12 @@ void BruteforceIso15693Afi(uint32_t speed) { DbpString("AFI Bruteforcing done."); switch_off(); + + if (aborted) { + reply_ng(CMD_ACK, PM3_EOPABORTED, NULL, 0); + } else { + reply_ng(CMD_ACK, PM3_SUCCESS, NULL, 0); + } } // Allows to directly send commands to the tag via the client diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index bb4fb343d..ea7e8482a 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -32,6 +32,7 @@ #include "crc16.h" #include "dbprint.h" #include "ticks.h" +#include "usb_cdc.h" // usb_poll_validate_length #ifndef HARDNESTED_AUTHENTICATION_TIMEOUT # define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) @@ -918,7 +919,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 for (rtr = 0; rtr < 17; rtr++) { // Test if the action was cancelled - if (BUTTON_PRESS()) { + if (BUTTON_PRESS() || usb_poll_validate_length()) { isOK = -2; break; } @@ -998,6 +999,12 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 target_nt[i] = 0; while (target_nt[i] == 0) { // continue until we have an unambiguous nonce + // Test if the action was cancelled + if (BUTTON_PRESS() || usb_poll_validate_length()) { + isOK = -2; + break; + } + // prepare next select. No need to power down the card. if (mifare_classic_halt(pcs, cuid)) { if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error"); diff --git a/client/Makefile b/client/Makefile index a6d987560..4babb528f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -134,6 +134,7 @@ CORESRCS = uart_posix.c \ CMDSRCS = crapto1/crapto1.c \ crapto1/crypto1.c \ + mifare/mifaredefault.c \ mifare/mfkey.c \ tea.c \ fido/additional_ca.c \ diff --git a/client/cmddata.c b/client/cmddata.c index d13eee46d..cb78642b2 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -406,7 +406,7 @@ static int CmdSetDebugMode(const char *Cmd) { void printDemodBuff(void) { int len = DemodBufferLen; if (len < 1) { - PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer"); + PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer"); return; } if (len > 512) len = 512; @@ -458,7 +458,7 @@ int CmdPrintDemodBuff(const char *Cmd) { if (errors) return usage_data_printdemodbuf(); if (DemodBufferLen == 0) { - PrintAndLogEx(NORMAL, "Demodbuffer is empty"); + PrintAndLogEx(WARNING, "Demodbuffer is empty"); return PM3_ESOFT; } if (lstrip) { @@ -491,9 +491,9 @@ int CmdPrintDemodBuff(const char *Cmd) { if (numBits == 0) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex); + PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex); } else { - PrintAndLogEx(NORMAL, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32)); + PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32)); } return PM3_SUCCESS; } diff --git a/client/cmdhf.c b/client/cmdhf.c index dd21c2649..06ad64317 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -77,7 +77,7 @@ int CmdHFSearch(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_search(); - PrintAndLogEx(INFO, "Checking for known tags...\n"); + PrintAndLogEx(INFO, "Checking for known tags..."); PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ThinFilm tag..."); @@ -100,13 +100,10 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ISO15693 tag..."); if (IfPm3Iso15693()) { - if (readHF15Uid(false) == 1) { + if (readHF15Uid(false)) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n"); - DropField(); return PM3_SUCCESS; } - // until refactoring of ISO15693 cmds, this is needed. - DropField(); } PROMPT_CLEARLINE; @@ -155,8 +152,10 @@ int CmdHFSearch(const char *Cmd) { } } - PrintAndLogEx(INPLACE, "No known/supported 13.56 MHz tags found"); + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, "done"); PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(FAILED, _RED_("No known/supported 13.56 MHz tags found")); return PM3_ESOFT; } @@ -166,7 +165,7 @@ int CmdHFTune(const char *Cmd) { int iter = param_get32ex(Cmd, 0, 0, 10); PacketResponseNG resp; - PrintAndLogEx(SUCCESS, "Measuring HF antenna, click button or press Enter to exit"); + PrintAndLogEx(SUCCESS, "Measuring HF antenna," _YELLOW_("click button") " or press" _YELLOW_("Enter") "to exit"); clearCommandBuffer(); uint8_t mode[] = {1}; SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 777b7d25c..4aac73855 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -256,20 +256,20 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { } if (select_status == 3) { - PrintAndLogEx(NORMAL, "E->Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); + PrintAndLogEx(INFO, "E->Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); return 1; } - PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(card->uid, card->uidlen)); - PrintAndLogEx(NORMAL, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); - PrintAndLogEx(NORMAL, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); + PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); + PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(NORMAL, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); + PrintAndLogEx(INFO, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); return 1; } - PrintAndLogEx(NORMAL, " ATS: %s", sprint_hex(card->ats, card->ats_len)); + PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card->ats, card->ats_len)); return 0; } @@ -334,18 +334,18 @@ static int CmdHF14AReader(const char *Cmd) { } if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return 1; } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); } if (!disconnectAfter) { @@ -422,7 +422,7 @@ static int CmdHF14ACUIDs(const char *Cmd) { for (uint16_t m = 0; m < card->uidlen; m++) { sprintf(&uid_string[2 * m], "%02X", card->uid[m]); } - PrintAndLogEx(NORMAL, "%s", uid_string); + PrintAndLogEx(SUCCESS, "%s", uid_string); } } PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000); @@ -528,9 +528,9 @@ int CmdHF14ASim(const char *Cmd) { if (keypress && (flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { // inform device to break the sim loop since client has exited - SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); } - + if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) showSectorTable(); @@ -551,30 +551,29 @@ int CmdHF14ASniff(const char *Cmd) { return PM3_SUCCESS; } -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode) { static uint8_t responseNum = 0; uint16_t cmdc = 0; *dataoutlen = 0; if (activateField) { - responseNum = 1; PacketResponseNG resp; // Anticollision + SELECT card SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } // check result if (resp.oldarg[0] == 0) { - PrintAndLogEx(ERR, "No card in field."); + if (!silentMode) PrintAndLogEx(ERR, "No card in field."); return 1; } if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { - PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); + if (!silentMode) PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); return 1; } @@ -583,12 +582,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } if (resp.oldarg[0] == 0) { // ats_len - PrintAndLogEx(ERR, "Can't get ATS."); + if (!silentMode) PrintAndLogEx(ERR, "Can't get ATS."); return 1; } } @@ -610,7 +609,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav int iLen = resp.oldarg[0]; if (!iLen) { - PrintAndLogEx(ERR, "No card response."); + if (!silentMode) PrintAndLogEx(ERR, "No card response."); return 1; } @@ -619,12 +618,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav *dataoutlen = 0; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + if (!silentMode) PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } if (recv[0] != data[0]) { - PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); + if (!silentMode) PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); return 2; } @@ -632,12 +631,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav // CRC Check if (iLen == -1) { - PrintAndLogEx(ERR, "ISO 14443A CRC error."); + if (!silentMode) PrintAndLogEx(ERR, "ISO 14443A CRC error."); return 3; } } else { - PrintAndLogEx(ERR, "Reply timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Reply timeout."); return 4; } @@ -1273,16 +1272,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return select_status; } + PrintAndLogEx(NORMAL, ""); + if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return select_status; } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); bool isMifareClassic = true; switch (card.sak) { @@ -1296,7 +1297,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (tagT != UL_ERROR) ul_print_type(tagT, 0); else - PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)"); + PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)"); // reconnect for further tests clearCommandBuffer(); @@ -1313,49 +1314,49 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } break; case 0x01: - PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance"); + PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance"); break; case 0x04: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); isMifareClassic = false; break; case 0x08: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); break; case 0x09: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k"); break; case 0x0A: - PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)"); + PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)"); break; case 0x10: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2"); break; case 0x11: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2"); break; case 0x18: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); break; case 0x20: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); isMifareClassic = false; break; case 0x24: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1"); isMifareClassic = false; break; case 0x28: - PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1"); + PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1"); break; case 0x38: - PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); + PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); break; case 0x88: - PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K"); + PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K"); break; case 0x98: - PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS"); + PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS"); break; default: ; @@ -1363,7 +1364,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { // Double & triple sized UID, can be mapped to a manufacturer. if (card.uidlen > 4) { - PrintAndLogEx(NORMAL, "MANUFACTURER : %s", getTagInfo(card.uid[0])); + PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0])); } // try to request ATS even if tag claims not to support it @@ -1382,12 +1383,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { int pos; if (select_status == 2) { - PrintAndLogEx(NORMAL, "SAK incorrectly claims that card doesn't support RATS"); + PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS"); } - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]); + PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]); if (card.ats[0] != card.ats_len - 2) { - PrintAndLogEx(NORMAL, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); + PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); } if (card.ats[0] > 1) { // there is a format byte (T0) @@ -1396,7 +1397,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { tc1 = (card.ats[1] & 0x40) == 0x40; int16_t fsci = card.ats[1] & 0x0f; - PrintAndLogEx(NORMAL, " - T0 : TA1 is%s present, TB1 is%s present, " + PrintAndLogEx(SUCCESS, " - T0 : TA1 is%s present, TB1 is%s present, " "TC1 is%s present, FSCI is %d (FSC = %d)", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), @@ -1417,7 +1418,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (card.ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; - PrintAndLogEx(NORMAL, " - TA1 : different divisors are%s supported, " + PrintAndLogEx(SUCCESS, " - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", ((card.ats[pos] & 0x80) ? " NOT" : ""), dr, @@ -1429,7 +1430,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (tb1) { uint32_t sfgi = card.ats[pos] & 0x0F; uint32_t fwi = card.ats[pos] >> 4; - PrintAndLogEx(NORMAL, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)", + PrintAndLogEx(SUCCESS, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)", (sfgi), sfgi ? "" : "(not needed) ", sfgi ? (1 << 12) << sfgi : 0, @@ -1439,7 +1440,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { pos++; } if (tc1) { - PrintAndLogEx(NORMAL, " - TC1 : NAD is%s supported, CID is%s supported", + PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported", (card.ats[pos] & 0x01) ? "" : " NOT", (card.ats[pos] & 0x02) ? "" : " NOT"); pos++; @@ -1453,63 +1454,63 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { tip = "-> MIFARE Plus S 2K or 4K"; } } - PrintAndLogEx(NORMAL, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); + PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); if (card.ats[pos] == 0xC1) { - PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type"); - PrintAndLogEx(NORMAL, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); + PrintAndLogEx(SUCCESS, " c1 -> Mifare or (multiple) virtual cards of various type"); + PrintAndLogEx(SUCCESS, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); switch (card.ats[pos + 2] & 0xf0) { case 0x10: - PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire"); + PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); break; case 0x20: - PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus"); + PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); break; } switch (card.ats[pos + 2] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> <1 kByte"); + PrintAndLogEx(SUCCESS, " x0 -> <1 kByte"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> 1 kByte"); + PrintAndLogEx(SUCCESS, " x1 -> 1 kByte"); break; case 0x02: - PrintAndLogEx(NORMAL, " x2 -> 2 kByte"); + PrintAndLogEx(SUCCESS, " x2 -> 2 kByte"); break; case 0x03: - PrintAndLogEx(NORMAL, " x3 -> 4 kByte"); + PrintAndLogEx(SUCCESS, " x3 -> 4 kByte"); break; case 0x04: - PrintAndLogEx(NORMAL, " x4 -> 8 kByte"); + PrintAndLogEx(SUCCESS, " x4 -> 8 kByte"); break; } switch (card.ats[pos + 3] & 0xf0) { case 0x00: - PrintAndLogEx(NORMAL, " 0x -> Engineering sample"); + PrintAndLogEx(SUCCESS, " 0x -> Engineering sample"); break; case 0x20: - PrintAndLogEx(NORMAL, " 2x -> Released"); + PrintAndLogEx(SUCCESS, " 2x -> Released"); break; } switch (card.ats[pos + 3] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> Generation 1"); + PrintAndLogEx(SUCCESS, " x0 -> Generation 1"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> Generation 2"); + PrintAndLogEx(SUCCESS, " x1 -> Generation 2"); break; case 0x02: - PrintAndLogEx(NORMAL, " x2 -> Generation 3"); + PrintAndLogEx(SUCCESS, " x2 -> Generation 3"); break; } switch (card.ats[pos + 4] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported"); + PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported"); + PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported"); break; case 0x0E: - PrintAndLogEx(NORMAL, " xE -> no VCS command supported"); + PrintAndLogEx(SUCCESS, " xE -> no VCS command supported"); break; } } @@ -1552,9 +1553,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == 0x9000) { - if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------"); + if (verbose) PrintAndLogEx(SUCCESS, "------------- Application OK -----------"); } else { - if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------"); + if (verbose) PrintAndLogEx(WARNING, "----------- Application blocked --------"); } PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index fcea5f5cf..83fb2c69d 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh -// 2011, Merlok -// 2015,216,2017 iceman, marshmellow, piwi +// 2011,2019 Merlok +// 2015,2016,2017 iceman, marshmellow, piwi // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of // the license. @@ -30,6 +30,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); const char *getTagInfo(uint8_t uid); int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); #endif diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index ba8db1f92..c57055e4b 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -528,9 +528,10 @@ static bool HF14B_Std_Info(bool verbose) { switch (status) { case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; @@ -662,9 +663,10 @@ static bool HF14B_Std_Reader(bool verbose) { switch (status) { case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; @@ -808,13 +810,13 @@ static int CmdHF14BWriteSri(const char *Cmd) { } if (blockno == 0xff) { - PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]", + PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) ); } else { - PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]", + PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 883364607..c2bd777e3 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -31,6 +31,7 @@ #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "iso15693tools.h" +#include "crypto/libpcrypto.h" #include "graph.h" #include "crc16.h" // iso15 crc @@ -207,10 +208,20 @@ const productName uidmapping[] = { { 0, 0, "no tag-info available" } // must be the last entry }; -// fast method to just read the UID of a tag (collission detection not supported) +uint8_t nxp_public_keys[][33] = { + // ICODE SLIX2 / DNA + { + 0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3, + 0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71, + 0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64, + 0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0 + }, +}; + +// fast method to just read the UID of a tag (collision detection not supported) // *buf should be large enough to fit the 64bit uid -// returns 1 if suceeded -static int getUID(uint8_t *buf) { +// returns 1 if succeeded +static bool getUID(uint8_t *buf) { PacketResponseNG resp; uint8_t data[5]; @@ -233,12 +244,14 @@ static int getUID(uint8_t *buf) { uint8_t resplen = resp.oldarg[0]; if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) { memcpy(buf, resp.data.asBytes + 2, 8); - return 1; + DropField(); + return true; } } } // retry - return PM3_SUCCESS; + DropField(); + return false; } // get a product description based on the UID @@ -273,7 +286,7 @@ static const char *TagErrorStr(uint8_t error) { case 0x01: return "The command is not supported"; case 0x02: - return "The command is not recognised"; + return "The command is not recognized"; case 0x03: return "The option is not supported."; case 0x0f: @@ -349,6 +362,24 @@ static int usage_15_findafi(void) { "Usage: hf 15 findafi"); return PM3_SUCCESS; } +static int usage_15_writeafi(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi \n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tafi#: AFI number 0-255"); + return PM3_SUCCESS; +} +static int usage_15_writedsfid(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 writedsfid \n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tdsfid#: DSFID number 0-255"); + return PM3_SUCCESS; +} static int usage_15_dump(void) { PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n" "\n" @@ -381,6 +412,7 @@ static int usage_15_raw(void) { {"-r", "do not read response" }, {"-2", "use slower '1 out of 256' mode" }, {"-c", "calculate and append CRC" }, + {"-p", "leave the signal field ON" }, {"", "Tip: turn on debugging for verbose output"}, }; PrintAndLogEx(NORMAL, "Usage: hf 15 raw [-r] [-2] [-c] <0A 0B 0C ... hex>\n"); @@ -440,7 +472,7 @@ static int usage_15_csetuid(void) { * Parameters: * **cmd command line */ -static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 +static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 int temp; uint8_t uid[8] = {0x00}; uint32_t tmpreqlen = 0; @@ -467,7 +499,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * switch (**cmd) { case 0: PrintAndLogEx(WARNING, "missing addr"); - return 0; + return false; break; case 'u': case 'U': @@ -482,10 +514,10 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found"); - return 0; + return false; } memcpy(&req[tmpreqlen], uid, sizeof(uid)); - PrintAndLogEx(NORMAL, "Detected UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid)); tmpreqlen += sizeof(uid); break; default: @@ -498,7 +530,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * uid[7 - i] = temp & 0xff; } - PrintAndLogEx(NORMAL, "Using UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid)); memcpy(&req[tmpreqlen], uid, sizeof(uid)); tmpreqlen += sizeof(uid); break; @@ -509,7 +541,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * while (**cmd == ' ' || **cmd == '\t')(*cmd)++; *reqlen = tmpreqlen; - return 1; + return true; } // Mode 3 @@ -523,7 +555,7 @@ static int CmdHF15Demod(const char *Cmd) { int max = 0, maxPos = 0; int skip = 4; - if (GraphTraceLen < 1000) return 0; + if (GraphTraceLen < 1000) return PM3_ESOFT; // First, correlate for SOF for (i = 0; i < 1000; i++) { @@ -537,7 +569,7 @@ static int CmdHF15Demod(const char *Cmd) { } } - PrintAndLogEx(NORMAL, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip)); + PrintAndLogEx(INFO, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip)); i = maxPos + ARRAYLEN(FrameSOF) / skip; int k = 0; @@ -560,7 +592,7 @@ static int CmdHF15Demod(const char *Cmd) { corr1 *= 4; if (corrEOF > corr1 && corrEOF > corr0) { - PrintAndLogEx(NORMAL, "EOF at %d", i); + PrintAndLogEx(INFO, "EOF at %d", i); break; } else if (corr1 > corr0) { i += ARRAYLEN(Logic1) / skip; @@ -574,22 +606,22 @@ static int CmdHF15Demod(const char *Cmd) { mask = 0x01; } if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) { - PrintAndLogEx(NORMAL, "ran off end!"); + PrintAndLogEx(INFO, "ran off end!"); break; } } if (mask != 0x01) { PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)"); - PrintAndLogEx(NORMAL, " mask = %02x", mask); + PrintAndLogEx(INFO, " mask = %02x", mask); } - PrintAndLogEx(NORMAL, "%d octets", k); + PrintAndLogEx(INFO, "%d octets", k); for (i = 0; i < k; i++) - PrintAndLogEx(NORMAL, "# %2d: %02x ", i, outBuf[i]); + PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]); - PrintAndLogEx(NORMAL, "CRC %04x", Crc15(outBuf, k - 2)); - return 0; + PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2)); + return PM3_SUCCESS; } // * Acquire Samples as Reader (enables carrier, sends inquiry) @@ -602,7 +634,181 @@ static int CmdHF15Samples(const char *Cmd) { SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0); getSamples(0, false); - return 0; + return PM3_SUCCESS; +} + +// Get NXP system information from SLIX2 tag/VICC +static int NxpSysInfo(uint8_t *uid) { + PacketResponseNG resp; + uint8_t *recv; + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen; + uint8_t arg1 = 1; + + if (uid != NULL) { + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_GETNXPSYSTEMINFO; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + AddCrc15(req, reqlen); + reqlen += 2; + + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + uint32_t status = resp.oldarg[0]; + + if (status < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command"); + return PM3_EWRONGANSVER; + } + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + bool signature = false; + bool easmode = false; + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " NXP SYSINFO : %s", sprint_hex(recv, 8)); + PrintAndLogEx(NORMAL, " Password protection configuration:"); + PrintAndLogEx(NORMAL, " * Page L read%s password protected", (recv[2] & 0x01 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page L write%s password protected", (recv[2] & 0x02 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page H read%s password protected", (recv[2] & 0x08 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page H write%s password protected", (recv[2] & 0x20 ? "" : " not")); + + PrintAndLogEx(NORMAL, " Lock bits:"); + PrintAndLogEx(NORMAL, " * AFI%s locked", (recv[3] & 0x01 ? "" : " not")); // AFI lock bit + PrintAndLogEx(NORMAL, " * EAS%s locked", (recv[3] & 0x02 ? "" : " not")); // EAS lock bit + PrintAndLogEx(NORMAL, " * DSFID%s locked", (recv[3] & 0x03 ? "" : " not")); // DSFID lock bit + PrintAndLogEx(NORMAL, " * Password protection configuration%s locked", (recv[3] & 0x04 ? "" : " not")); // Password protection pointer address and access conditions lock bit + + PrintAndLogEx(NORMAL, " Features:"); + PrintAndLogEx(NORMAL, " * User memory password protection%s supported", (recv[4] & 0x01 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Counter feature%s supported", (recv[4] & 0x02 ? "" : " not")); + PrintAndLogEx(NORMAL, " * EAS ID%s supported by EAS ALARM command", (recv[4] & 0x03 ? "" : " not")); + easmode = (recv[4] & 0x03 ? true : false); + PrintAndLogEx(NORMAL, " * EAS password protection%s supported", (recv[4] & 0x04 ? "" : " not")); + PrintAndLogEx(NORMAL, " * AFI password protection%s supported", (recv[4] & 0x10 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Extended mode%s supported by INVENTORY READ command", (recv[4] & 0x20 ? "" : " not")); + PrintAndLogEx(NORMAL, " * EAS selection%s supported by extended mode in INVENTORY READ command", (recv[4] & 0x40 ? "" : " not")); + PrintAndLogEx(NORMAL, " * READ SIGNATURE command%s supported", (recv[5] & 0x01 ? "" : " not")); + signature = (recv[5] & 0x01 ? true : false); + PrintAndLogEx(NORMAL, " * Password protection for READ SIGNATURE command%s supported", (recv[5] & 0x02 ? "" : " not")); + PrintAndLogEx(NORMAL, " * STAY QUIET PERSISTENT command%s supported", (recv[5] & 0x03 ? "" : " not")); + PrintAndLogEx(NORMAL, " * ENABLE PRIVACY command%s supported", (recv[5] & 0x10 ? "" : " not")); + PrintAndLogEx(NORMAL, " * DESTROY command%s supported", (recv[5] & 0x20 ? "" : " not")); + PrintAndLogEx(NORMAL, " * Additional 32 bits feature flags are%s transmitted", (recv[5] & 0x80 ? "" : " not")); + + if (easmode) { + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_EASALARM; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + AddCrc15(req, reqlen); + reqlen += 2; + + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "iso15693 card select failed"); + } else { + uint32_t status = resp.oldarg[0]; + + PrintAndLogEx(NORMAL, ""); + + if (status < 2) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active"); + } else { + recv = resp.data.asBytes; + + if (!(recv[0] & ISO15_RES_ERROR)) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active."); + PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32)); + } + } + } + } + + if (signature) { + // Check if we can also read the signature + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_READSIGNATURE; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + AddCrc15(req, reqlen); + reqlen += 2; + + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + uint32_t status = resp.oldarg[0]; + + if (status < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command"); + return PM3_EWRONGANSVER; + } + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + uint8_t signature[32] = {0x00}; + memcpy(signature, recv + 1, 32); + + int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false); + bool is_valid = (res == 0); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " Tag Signature"); + PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA"); + PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33)); + PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1"); + PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32)); + PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed")); + } + } + + return PM3_SUCCESS; } /** @@ -621,11 +827,12 @@ static int CmdHF15Info(const char *Cmd) { uint8_t arg1 = 1; char cmdbuf[100] = {0}; char *cmd = cmdbuf; + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_SYSINFO)) - return 0; + return PM3_SUCCESS; AddCrc15(req, reqlen); reqlen += 2; @@ -637,56 +844,69 @@ static int CmdHF15Info(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(WARNING, "iso15693 card select failed"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, recv + 2)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(recv + 2)); - PrintAndLogEx(NORMAL, " SYSINFO : %s", sprint_hex(recv, status - 2)); + memcpy(uid, recv + 2, sizeof(uid)); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2)); + PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2)); // DSFID if (recv[1] & 0x01) - PrintAndLogEx(NORMAL, " - DSFID supported [0x%02X]", recv[10]); + PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", recv[10]); else - PrintAndLogEx(NORMAL, " - DSFID not supported"); + PrintAndLogEx(SUCCESS, " - DSFID not supported"); // AFI if (recv[1] & 0x02) - PrintAndLogEx(NORMAL, " - AFI supported [0x%02X]", recv[11]); + PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", recv[11]); else - PrintAndLogEx(NORMAL, " - AFI not supported"); + PrintAndLogEx(SUCCESS, " - AFI not supported"); // IC reference if (recv[1] & 0x08) - PrintAndLogEx(NORMAL, " - IC reference supported [0x%02X]", recv[14]); + PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", recv[14]); else - PrintAndLogEx(NORMAL, " - IC reference not supported"); + PrintAndLogEx(SUCCESS, " - IC reference not supported"); // memory if (recv[1] & 0x04) { - PrintAndLogEx(NORMAL, " - Tag provides info on memory layout (vendor dependent)"); + PrintAndLogEx(SUCCESS, " - Tag provides info on memory layout (vendor dependent)"); uint8_t blocks = recv[12] + 1; uint8_t size = (recv[13] & 0x1F); - PrintAndLogEx(NORMAL, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); + PrintAndLogEx(SUCCESS, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); } else { - PrintAndLogEx(NORMAL, " - Tag does not provide information on memory layout"); + PrintAndLogEx(SUCCESS, " - Tag does not provide information on memory layout"); } - PrintAndLogEx(NORMAL, "\n"); - return 0; + + // Check if SLIX2 and attempt to get NXP System Information + if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) { + return NxpSysInfo(uid); + } + + PrintAndLogEx(NORMAL, ""); + + return PM3_SUCCESS; } // Record Activity without enabling carrier @@ -697,7 +917,7 @@ static int CmdHF15Record(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_RAWADC, NULL, 0); - return 0; + return PM3_SUCCESS; } static int CmdHF15Reader(const char *Cmd) { @@ -705,7 +925,7 @@ static int CmdHF15Reader(const char *Cmd) { if (cmdp == 'h') return usage_15_reader(); readHF15Uid(true); - return 0; + return PM3_SUCCESS; } // Simulation is still not working very good @@ -717,20 +937,23 @@ static int CmdHF15Sim(const char *Cmd) { uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if (param_gethex(Cmd, 0, uid, 16)) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); - return 0; + return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid))); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8); - return 0; + return PM3_SUCCESS; } // finds the AFI (Application Family Identifier) of a card, by trying all values // (There is no standard way of reading the AFI, although some tags support this) // helptext -static int CmdHF15Afi(const char *Cmd) { +static int CmdHF15FindAfi(const char *Cmd) { + PacketResponseNG resp; + uint32_t timeout = 0; + char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_15_findafi(); @@ -738,7 +961,138 @@ static int CmdHF15Afi(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); - return 0; + + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + timeout++; + + // should be done in about 2 minutes + if (timeout > 180) { + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); + DropField(); + return PM3_ETIMEOUT; + } + } + + DropField(); + return resp.status; // PM3_EOPABORTED or PM3_SUCCESS +} + +// Writes the AFI (Application Family Identifier) of a card +static int CmdHF15WriteAfi(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writeafi(); + + PacketResponseNG resp; + uint8_t *recv; + + // arg: len, speed, recv? + // arg0 (datalen, cmd len? .arg0 == crc?) + // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) + // arg2 (recv == 1 == expect a response) + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int afinum; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); + + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEAFI)) + return PM3_SUCCESS; + + req[0] |= ISO15_REQ_OPTION; // Since we are writing + + afinum = strtol(cmd, NULL, 0); + + req[reqlen++] = (uint8_t)afinum; + + AddCrc15(req, reqlen); + reqlen += 2; + + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X", afinum); + + return PM3_SUCCESS; +} + +// Writes the DSFID (Data Storage Format Identifier) of a card +static int CmdHF15WriteDsfid(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writedsfid(); + + PacketResponseNG resp; + uint8_t *recv; + + // arg: len, speed, recv? + // arg0 (datalen, cmd len? .arg0 == crc?) + // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) + // arg2 (recv == 1 == expect a response) + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int dsfidnum; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); + + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEDSFID)) + return PM3_SUCCESS; + + req[0] |= ISO15_REQ_OPTION; // Since we are writing + + dsfidnum = strtol(cmd, NULL, 0); + + req[reqlen++] = (uint8_t)dsfidnum; + + AddCrc15(req, reqlen); + reqlen += 2; + + //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X", dsfidnum); + + return PM3_SUCCESS; } typedef struct { @@ -777,7 +1131,7 @@ static int CmdHF15Dump(const char *Cmd) { if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found."); - return 1; + return PM3_ESOFT; } if (fileNameLen < 1) { @@ -789,7 +1143,7 @@ static int CmdHF15Dump(const char *Cmd) { } // detect blocksize from card :) - PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); int blocknum = 0; uint8_t *recv = NULL; @@ -847,8 +1201,10 @@ static int CmdHF15Dump(const char *Cmd) { fflush(stdout); } } - PrintAndLogEx(NORMAL, "\n"); + DropField(); + + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); for (int i = 0; i < blocknum; i++) { @@ -871,8 +1227,7 @@ static int CmdHF15List(const char *Cmd) { /* // Record Activity without enabling carrier -static int CmdHF15Sniff(const char *Cmd) -{ +static int CmdHF15Sniff(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0); return PM3_SUCCESS; @@ -886,7 +1241,7 @@ static int CmdHF15Raw(const char *Cmd) { PacketResponseNG resp; int reply = 1, fast = 1, i = 0; - bool crc = false; + bool crc = false, leaveSignalON = false; char buf[5] = ""; uint8_t data[100]; uint32_t datalen = 0, temp; @@ -909,9 +1264,13 @@ static int CmdHF15Raw(const char *Cmd) { case 'C': crc = true; break; + case 'p': + case 'P': + leaveSignalON = true; + break; default: PrintAndLogEx(WARNING, "Invalid option"); - return 0; + return PM3_EINVARG; } i += 2; continue; @@ -932,7 +1291,7 @@ static int CmdHF15Raw(const char *Cmd) { continue; } PrintAndLogEx(WARNING, "Invalid char on input"); - return 0; + return PM3_EINVARG; } if (crc) { @@ -946,12 +1305,16 @@ static int CmdHF15Raw(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t len = resp.oldarg[0]; - PrintAndLogEx(NORMAL, "received %i octets", len); - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + PrintAndLogEx(INFO, "received %i octets", len); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, len)); } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); } } + + if (!leaveSignalON) + DropField(); + return PM3_SUCCESS; } @@ -975,7 +1338,7 @@ static int CmdHF15Readmulti(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READMULTI)) - return 0; + return PM3_SUCCESS; // add OPTION flag, in order to get lock-info req[0] |= ISO15_REQ_OPTION; @@ -1000,25 +1363,28 @@ static int CmdHF15Readmulti(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { PrintAndLogEx(FAILED, "CRC failed"); - return 2; + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } int start = 1; // skip status byte @@ -1061,7 +1427,7 @@ static int CmdHF15Read(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READ)) - return 0; + return PM3_SUCCESS; // add OPTION flag, in order to get lock-info req[0] |= ISO15_REQ_OPTION; @@ -1077,26 +1443,29 @@ static int CmdHF15Read(const char *Cmd) { SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; + PrintAndLogEx(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; + PrintAndLogEx(ERR, "iso15693 card select failed"); + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { - PrintAndLogEx(NORMAL, "CRC failed"); - return 2; + PrintAndLogEx(ERR, "CRC failed"); + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } // print response @@ -1130,7 +1499,7 @@ static int CmdHF15Write(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITE)) - return 0; + return PM3_SUCCESS; // *cmd -> page num ; *cmd2 -> data cmd2 = cmd; @@ -1154,32 +1523,35 @@ static int CmdHF15Write(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); + PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { PrintAndLogEx(FAILED, "CRC failed"); - return 2; + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { - PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; } PrintAndLogEx(NORMAL, "OK"); @@ -1250,13 +1622,13 @@ static int CmdHF15Restore(const char *Cmd) { if ((f = fopen(filename, "rb")) == NULL) { PrintAndLogEx(WARNING, "Could not find file %s", filename); - return 2; + return PM3_EFILE; } if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found"); fclose(f); - return 3; + return PM3_ESOFT; } PrintAndLogEx(INFO, "Restoring data blocks."); @@ -1274,7 +1646,7 @@ static int CmdHF15Restore(const char *Cmd) { } else if (bytes_read != blocksize) { PrintAndLogEx(ERR, "File reading error (%s), %zu bytes read instead of %zu bytes.", filename, bytes_read, blocksize); fclose(f); - return 2; + return PM3_EFILE; } for (int j = 0; j < blocksize; j++) @@ -1322,22 +1694,23 @@ static int CmdHF15CSetUID(const char *Cmd) { if (param_gethex(Cmd, 0, uid, 16)) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); - return 1; + return PM3_EINVARG; } if (uid[0] != 0xe0) { PrintAndLogEx(WARNING, "UID must begin with the byte " _YELLOW_("E0")); - return 1; + return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "new UID | %s", sprint_hex(uid, sizeof(uid))); - PrintAndLogEx(NORMAL, "Using backdoor Magic tag function"); + PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid))); if (!getUID(oldUid)) { - PrintAndLogEx(FAILED, "Can't get old UID."); + PrintAndLogEx(FAILED, "Can't get old/current UID."); return PM3_ESOFT; } + PrintAndLogEx(INFO, "Using backdoor magic tag function"); + // Command 1 : 02213E00000000 data[0][0] = 0x02; data[0][1] = 0x21; @@ -1383,8 +1756,8 @@ static int CmdHF15CSetUID(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t len = resp.oldarg[0]; - PrintAndLogEx(NORMAL, "received %i octets", len); - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + PrintAndLogEx(INFO, "received %i octets", len); + PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, len)); } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); } @@ -1396,18 +1769,23 @@ static int CmdHF15CSetUID(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); - PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); - - return PM3_SUCCESS; + if (memcmp(newUid, uid, 8) != 0) { + PrintAndLogEx(FAILED, "Setting UID on tag failed."); + return PM3_ESOFT; + } else { + PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); + PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); + return PM3_SUCCESS; + } } static command_t CommandTable[] = { {"help", CmdHF15Help, AlwaysAvailable, "This help"}, {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"}, {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"}, - {"findafi", CmdHF15Afi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, + {"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, + {"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"}, + {"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO15693 tag"}, {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, // {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, {"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"}, @@ -1436,14 +1814,14 @@ int CmdHF15(const char *Cmd) { } // used with 'hf search' -int readHF15Uid(bool verbose) { +bool readHF15Uid(bool verbose) { uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if (!getUID(uid)) { if (verbose) PrintAndLogEx(WARNING, "No tag found."); - return 0; + return false; } - - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, uid)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(uid)); - return 1; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid)); + return true; } diff --git a/client/cmdhf15.h b/client/cmdhf15.h index b3f64ac70..81530a58c 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -15,6 +15,6 @@ int CmdHF15(const char *Cmd); -int readHF15Uid(bool verbose); +bool readHF15Uid(bool verbose); #endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index af5d26eaf..e83ee39bf 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -16,7 +16,7 @@ #include #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "ui.h" #include "util_posix.h" @@ -38,8 +38,8 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { m = m > 0 ? m : 1; n = n > 0 ? n : 1; - PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m); - PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000); + PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m); + PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000); // repeat n times for (uint32_t i = 0; i < n; i++) { // execute PACE @@ -58,15 +58,15 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]); } // print nonce - PrintAndLogEx(NORMAL, "Length: %zu, Nonce: %s", nonce_length, nonce); + PrintAndLogEx(SUCCESS, "Length: %zu, Nonce: %s", nonce_length, nonce); free(nonce); } if (i < n - 1) { sleep(d); } } - PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000); - return 1; + PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000); + return PM3_SUCCESS; } // perform the PACE protocol by replaying APDUs @@ -98,9 +98,9 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { ); if (scan_return < 1) { - PrintAndLogEx(NORMAL, (char *)usage_msg); + PrintAndLogEx(INFO, (char *)usage_msg); PrintAndLogEx(WARNING, "Not enough APDUs! Try again!"); - return 0; + return PM3_SUCCESS; } skip += skip_add; apdu_lengths[i]++; @@ -110,8 +110,8 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { if (Cmd[skip] == '\0') { if (i < ARRAYLEN(apdu_lengths) - 1) { - PrintAndLogEx(NORMAL, (char *)usage_msg); - return 0; + PrintAndLogEx(INFO, (char *)usage_msg); + return PM3_SUCCESS; } break; } @@ -146,7 +146,7 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { WaitForResponse(CMD_ACK, &resp); if (resp.oldarg[0] != 0) { PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j); - return 0; + return PM3_ESOFT; } } } @@ -156,22 +156,22 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0); WaitForResponse(CMD_ACK, &resp); if (resp.oldarg[0] != 0) { - PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); - PrintAndLogEx(NORMAL, "Measured times:"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + PrintAndLogEx(SUCCESS, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); + PrintAndLogEx(SUCCESS, "Measured times:"); + PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); } else { - PrintAndLogEx(NORMAL, "PACE replay successful!"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + PrintAndLogEx(SUCCESS, "PACE replay successful!"); + PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); } - return 1; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -184,7 +184,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFEPA(const char *Cmd) { diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index 8c8b83b89..5144902ad 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -320,12 +320,12 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) { uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); if (verbose) { - PrintAndLogEx(NORMAL, "Client Received %i octets", len); + PrintAndLogEx(SUCCESS, "Client Received %i octets", len); if (!len || len < 2) { PrintAndLogEx(ERR, "Could not receive data correctly!"); return false; } - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len)); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len)); if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); } @@ -400,7 +400,7 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat uint16_t numbits = 0; clearCommandBuffer(); if (verbose) { - PrintAndLogEx(NORMAL, "Send RAW COMMAND - Frame: %s", sprint_hex(data, datalen)); + PrintAndLogEx(INFO, "Send raw command - Frame: %s", sprint_hex(data, datalen)); } SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); } @@ -438,11 +438,11 @@ static void print_rd_noEncrpytion_response(felica_read_without_encryption_respon char bl_element_number[4]; temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); strcpy(bl_element_number, temp); - PrintAndLogEx(NORMAL, "\t%s\t| %s ", bl_element_number, bl_data); + PrintAndLogEx(INFO, "\t%s\t| %s ", bl_element_number, bl_data); } else { - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); } } @@ -454,7 +454,7 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve PacketResponseNG resp; if (datalen > 0) { if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } felica_request_service_response_t rqs_response; @@ -462,9 +462,9 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve if (rqs_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Service Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number))); - PrintAndLogEx(NORMAL, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number))); + PrintAndLogEx(SUCCESS, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions))); } return PM3_SUCCESS; } @@ -484,7 +484,7 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, verbose)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { memcpy(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); @@ -522,7 +522,7 @@ int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, verbose)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); @@ -548,8 +548,7 @@ static int CmdHFFelicaAuthentication1(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_authentication1(); case 'i': @@ -656,8 +655,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_write_without_encryption(); case 'i': @@ -696,9 +694,9 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { datalen += 2; felica_status_response_t wr_noCry_resp; if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); if (wr_noCry_resp.status_flags.status_flag1[0] == 0x00 && wr_noCry_resp.status_flags.status_flag2[0] == 0x00) { PrintAndLogEx(SUCCESS, "Writing data successful!\n"); } else { @@ -727,8 +725,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_read_without_encryption(); case 'i': @@ -781,7 +778,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { if (long_block_numbers) { last_block_number = 0xFFFF; } - PrintAndLogEx(NORMAL, "Block Element\t| Data "); + PrintAndLogEx(INFO, "Block Element\t| Data "); for (int i = 0x00; i < last_block_number; i++) { data[15] = i; AddCrc(data, datalen); @@ -803,7 +800,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { datalen += 2; felica_read_without_encryption_response_t rd_noCry_resp; if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "Block Element\t| Data "); + PrintAndLogEx(INFO, "Block Element\t| Data "); print_rd_noEncrpytion_response(&rd_noCry_resp); } } @@ -825,8 +822,7 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_response(); case 'i': @@ -856,15 +852,15 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_request_request_response_t rq_response; memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t)); if (rq_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); } } return PM3_SUCCESS; @@ -887,8 +883,7 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_specification_version(); case 'i': @@ -931,24 +926,24 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_request_spec_response_t spec_response; memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t)); if (spec_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2))); if (spec_response.status_flags.status_flag1[0] == 0x00) { - PrintAndLogEx(NORMAL, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version))); - PrintAndLogEx(NORMAL, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version))); - PrintAndLogEx(NORMAL, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option))); + PrintAndLogEx(SUCCESS, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version))); + PrintAndLogEx(SUCCESS, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version))); + PrintAndLogEx(SUCCESS, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option))); if (spec_response.number_of_option[0] == 0x01) { - PrintAndLogEx(NORMAL, "Option Version List:"); + PrintAndLogEx(SUCCESS, "Option Version List:"); for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) { - PrintAndLogEx(NORMAL, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2)); + PrintAndLogEx(SUCCESS, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2)); } } } @@ -974,8 +969,7 @@ static int CmdHFFelicaResetMode(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_reset_mode(); case 'i': @@ -1018,16 +1012,16 @@ static int CmdHFFelicaResetMode(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_status_response_t reset_mode_response; memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); if (reset_mode_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2))); } } return PM3_SUCCESS; @@ -1048,8 +1042,7 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_system_code(); case 'i': @@ -1079,18 +1072,18 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_syscode_response_t rq_syscode_response; memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t)); if (rq_syscode_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems))); - PrintAndLogEx(NORMAL, " - System Codes: enumerated in ascending order starting from System 0."); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems))); + PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0."); for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) { - PrintAndLogEx(NORMAL, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2)); + PrintAndLogEx(SUCCESS, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2)); } } } @@ -1114,8 +1107,7 @@ static int CmdHFFelicaRequestService(const char *Cmd) { strip_cmds(Cmd); while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_service(); case 'i': @@ -1151,7 +1143,7 @@ static int CmdHFFelicaRequestService(const char *Cmd) { if (param_getlength(Cmd, paramCount) == 4) { param_gethex(Cmd, paramCount++, data + 11, 4); } else { - PrintAndLogEx(ERR, "Incorrect Parameter length!"); + PrintAndLogEx(ERR, "Incorrect parameter length!"); return PM3_EINVARG; } @@ -1186,7 +1178,8 @@ static int CmdHFFelicaRequestService(const char *Cmd) { } static int CmdHFFelicaNotImplementedYet(const char *Cmd) { - PrintAndLogEx(NORMAL, "Feature not implemented Yet!"); + PrintAndLogEx(INFO, "Feature not implemented yet."); + PrintAndLogEx(INFO, "Feel free to contribute!"); return PM3_SUCCESS; } @@ -1198,12 +1191,10 @@ static int CmdHFFelicaSniff(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'h': + switch (tolower(Cmd[i + 1])) { case 'H': return usage_hf_felica_sniff(); case 's': - case 'S': paramCount++; if (param_getlength(Cmd, paramCount) < 5) { samples2skip = param_get32ex(Cmd, paramCount++, 0, 10); @@ -1213,7 +1204,6 @@ static int CmdHFFelicaSniff(const char *Cmd) { } break; case 't': - case 'T': paramCount++; if (param_getlength(Cmd, paramCount) < 5) { triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10); @@ -1259,7 +1249,7 @@ static int CmdHFFelicaSimLite(const char *Cmd) { } static void printSep() { - PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); + PrintAndLogEx(INFO, "------------------------------------------------------------------------------------"); } static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) { @@ -1495,8 +1485,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { while (Cmd[i] != '\0') { if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_raw(); case 'r': @@ -1540,7 +1529,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { *buf = 0; if (++datalen >= sizeof(data)) { if (crc) - PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); + PrintAndLogEx(WARNING, "Buffer is full, we can't add CRC to your data"); break; } } @@ -1574,12 +1563,12 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; clearCommandBuffer(); - PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(data, datalen)); + PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(data, datalen)); SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); if (reply) { if (active_select) { - PrintAndLogEx(NORMAL, "Active select wait for FeliCa."); + PrintAndLogEx(SUCCESS, "Active select wait for FeliCa."); PacketResponseNG resp_IDm; waitCmdFelica(1, &resp_IDm, 1); } @@ -1625,15 +1614,15 @@ int readFelicaUid(bool verbose) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "FeliCa tag info"); - PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); - PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); - PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); + PrintAndLogEx(SUCCESS, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); + PrintAndLogEx(SUCCESS, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); + PrintAndLogEx(SUCCESS, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); - PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); - PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); - PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); + PrintAndLogEx(SUCCESS, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); + PrintAndLogEx(SUCCESS, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); + PrintAndLogEx(SUCCESS, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); - PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); + PrintAndLogEx(SUCCESS, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); set_last_known_card(card); break; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index b57996af1..ae1109717 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -334,15 +334,15 @@ static void fuse_config(const picopass_hdr *hdr) { if (isset(fuses, FUSE_FPERS)) PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]"); else - PrintAndLogEx(NORMAL, " Mode: Application [Locked]"); + PrintAndLogEx(SUCCESS, " Mode: Application [Locked]"); if (isset(fuses, FUSE_CODING1)) { - PrintAndLogEx(NORMAL, " Coding: RFU"); + PrintAndLogEx(SUCCESS, " Coding: RFU"); } else { if (isset(fuses, FUSE_CODING0)) - PrintAndLogEx(NORMAL, " Coding: ISO 14443-2 B/ISO 15693"); + PrintAndLogEx(SUCCESS, " Coding: ISO 14443-2 B/ISO 15693"); else - PrintAndLogEx(NORMAL, " Coding: ISO 14443B only"); + PrintAndLogEx(SUCCESS, " Coding: ISO 14443B only"); } // 1 1 if (isset(fuses, FUSE_CRYPT1) && isset(fuses, FUSE_CRYPT0)) PrintAndLogEx(SUCCESS, " Crypt: Secured page, keys not locked"); @@ -354,7 +354,7 @@ static void fuse_config(const picopass_hdr *hdr) { if (notset(fuses, FUSE_CRYPT1) && notset(fuses, FUSE_CRYPT0)) PrintAndLogEx(NORMAL, " Crypt: No auth possible. Read only if RA is enabled"); if (isset(fuses, FUSE_RA)) - PrintAndLogEx(NORMAL, " RA: Read access enabled"); + PrintAndLogEx(SUCCESS, " RA: Read access enabled"); else PrintAndLogEx(WARNING, " RA: Read access not enabled"); } @@ -2827,12 +2827,13 @@ int readIclass(bool loop, bool verbose) { } if (readStatus & FLAG_ICLASS_READER_CSN) { - PrintAndLogEx(NORMAL, " CSN: %s", sprint_hex(data, 8)); + PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(SUCCESS, " CSN: %s", sprint_hex(data, 8)); tagFound = true; } if (readStatus & FLAG_ICLASS_READER_CC) { - PrintAndLogEx(NORMAL, " CC: %s", sprint_hex(data + 16, 8)); + PrintAndLogEx(SUCCESS, " CC: %s", sprint_hex(data + 16, 8)); } if (readStatus & FLAG_ICLASS_READER_CONF) { @@ -2847,7 +2848,7 @@ int readIclass(bool loop, bool verbose) { bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); - PrintAndLogEx(NORMAL, " App IA: %s", sprint_hex(data + 8 * 5, 8)); + PrintAndLogEx(SUCCESS, " App IA: %s", sprint_hex(data + 8 * 5, 8)); if (isHidRange) { if (legacy) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 4a72397e3..022857584 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -210,7 +210,7 @@ static int CmdLegicInfo(const char *Cmd) { crc = data[4]; uint32_t calc_crc = CRC8Legic(data, 4); - PrintAndLogEx(NORMAL, _YELLOW_("CDF: System Area")); + PrintAndLogEx(SUCCESS, _YELLOW_("CDF: System Area")); PrintAndLogEx(NORMAL, "------------------------------------------------------"); PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s", data[0], @@ -229,7 +229,7 @@ static int CmdLegicInfo(const char *Cmd) { // New unwritten media? if (dcf == 0xFFFF) { - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=NM (New Media)", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=NM (New Media)", dcf, data[5], data[6] @@ -262,7 +262,7 @@ static int CmdLegicInfo(const char *Cmd) { stamp_len = 0xfc - data[6]; } - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u", dcf, data[5], data[6], @@ -281,7 +281,7 @@ static int CmdLegicInfo(const char *Cmd) { strncpy(token_type, "IM", sizeof(token_type) - 1); } - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)", dcf, data[5], data[6], @@ -294,7 +294,7 @@ static int CmdLegicInfo(const char *Cmd) { if (dcf != 0xFFFF) { if (bIsSegmented) { - PrintAndLogEx(NORMAL, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X", + PrintAndLogEx(SUCCESS, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X", data[7] & 0x0f, (data[7] & 0x70) >> 4, (data[7] & 0x80) >> 7, @@ -305,11 +305,11 @@ static int CmdLegicInfo(const char *Cmd) { // Header area is only available on IM-S cards, on master tokens this data is the master token data itself if (bIsSegmented || dcf > 60000) { if (dcf > 60000) { - PrintAndLogEx(NORMAL, "Master token data"); - PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 8, 14)); + PrintAndLogEx(SUCCESS, "Master token data"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 8, 14)); } else { - PrintAndLogEx(NORMAL, "Remaining Header Area"); - PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 9, 13)); + PrintAndLogEx(SUCCESS, "Remaining Header Area"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 9, 13)); } } } @@ -323,7 +323,7 @@ static int CmdLegicInfo(const char *Cmd) { if (dcf > 60000) goto out; - PrintAndLogEx(NORMAL, _YELLOW_("\nADF: User Area")); + PrintAndLogEx(SUCCESS, _YELLOW_("\nADF: User Area")); PrintAndLogEx(NORMAL, "------------------------------------------------------"); if (bIsSegmented) { @@ -356,20 +356,20 @@ static int CmdLegicInfo(const char *Cmd) { segCalcCRC = CRC8Legic(segCrcBytes, 8); segCRC = data[i + 4] ^ crc; - PrintAndLogEx(NORMAL, "Segment | %02u ", segmentNum); - PrintAndLogEx(NORMAL, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X", + PrintAndLogEx(SUCCESS, "Segment | %02u ", segmentNum); + PrintAndLogEx(SUCCESS, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X", data[i] ^ crc, data[i + 1] ^ crc, data[i + 2] ^ crc, data[i + 3] ^ crc ); - PrintAndLogEx(NORMAL, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)", + PrintAndLogEx(SUCCESS, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)", segment_len, segment_flag, (segment_flag & 0x4) >> 2, (segment_flag & 0x8) >> 3 ); - PrintAndLogEx(NORMAL, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)", + PrintAndLogEx(SUCCESS, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)", wrp, wrc, ((data[i + 3] ^ crc) & 0x80) >> 7, @@ -380,7 +380,7 @@ static int CmdLegicInfo(const char *Cmd) { i += 5; if (hasWRC) { - PrintAndLogEx(NORMAL, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); + PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -393,7 +393,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (hasWRP) { - PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len); + PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -406,7 +406,7 @@ static int CmdLegicInfo(const char *Cmd) { // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...) if (wrp_len == 8) { - PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"), + PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"), data[i - 4] ^ crc, data[i - 3] ^ crc, data[i - 2] ^ crc @@ -414,7 +414,7 @@ static int CmdLegicInfo(const char *Cmd) { } } if (remain_seg_payload_len > 0) { - PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); + PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -444,14 +444,14 @@ static int CmdLegicInfo(const char *Cmd) { int wrp_len = (wrp - wrc); int remain_seg_payload_len = (card.cardsize - 22 - wrp); - PrintAndLogEx(NORMAL, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u", + PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u", wrp, wrc, (data[7] & 0x80) >> 7 ); if (hasWRC) { - PrintAndLogEx(NORMAL, "WRC protected area: (I %d | WRC %d)", i, wrc); + PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, wrc, 16); @@ -460,7 +460,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (hasWRP) { - PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len); + PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, wrp_len, 16); @@ -470,7 +470,7 @@ static int CmdLegicInfo(const char *Cmd) { // Q: does this one work? // A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage if (wrp_len == 8) { - PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"), + PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"), data[i - 4], data[i - 3], data[i - 2] @@ -479,7 +479,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (remain_seg_payload_len > 0) { - PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len); + PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, remain_seg_payload_len, 16); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 23b418599..dc42cae62 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -13,7 +13,7 @@ #include #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "fileutils.h" #include "cmdtrace.h" @@ -3665,6 +3665,56 @@ static int CmdHF14AMfCSetUID(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14AMfCWipe(const char *cmd) { + uint8_t uid[8] = {0x00}; + int uidLen = 0; + uint8_t atqa[2] = {0x00}; + int atqaLen = 0; + uint8_t sak[1] = {0x00}; + int sakLen = 0; + + CLIParserInit("hf mf cwipe", + "Wipe gen1 magic chinese card. Set UID/ATQA/SAK/Data/Keys/Access to default values.", + "Usage:\n\thf mf cwipe -> wipe card.\n" + "\thf mfp mf cwipe -u 09080706 -a 0004 -s 18 -> set UID, ATQA and SAK and wipe card."); + + void *argtable[] = { + arg_param_begin, + arg_str0("uU", "uid", "", "UID for card"), + arg_str0("aA", "atqa", "", "ATQA for card"), + arg_str0("sS", "sak", "", "SAK for card"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + CLIGetHexWithReturn(1, uid, &uidLen); + CLIGetHexWithReturn(2, atqa, &atqaLen); + CLIGetHexWithReturn(3, sak, &sakLen); + CLIParserFree(); + + if (uidLen && uidLen != 4) { + PrintAndLogEx(ERR, "UID length must be 4 bytes instead of: %d", uidLen); + return PM3_EINVARG; + } + if (atqaLen && atqaLen != 2) { + PrintAndLogEx(ERR, "UID length must be 2 bytes instead of: %d", atqaLen); + return PM3_EINVARG; + } + if (sakLen && sakLen != 1) { + PrintAndLogEx(ERR, "UID length must be 1 byte instead of: %d", sakLen); + return PM3_EINVARG; + } + + int res = mfCWipe((uidLen) ? uid : NULL, (atqaLen) ? atqa : NULL, (sakLen) ? sak : NULL); + if (res) { + PrintAndLogEx(ERR, "Can't wipe card. error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Card wiped successfully"); + return PM3_SUCCESS; +} + static int CmdHF14AMfCSetBlk(const char *Cmd) { uint8_t block[16] = {0x00}; uint8_t blockNo = 0; @@ -4211,7 +4261,7 @@ static int CmdHF14AMfAuth4(const char *Cmd) { return PM3_ESOFT; } - return MifareAuth4(NULL, keyn, key, true, false, true); + return MifareAuth4(NULL, keyn, key, true, false, true, true, false); } // https://www.nxp.com/docs/en/application-note/AN10787.pdf @@ -4446,6 +4496,7 @@ static command_t CommandTable[] = { {"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"}, {"-----------", CmdHelp, IfPm3Iso14443a, ""}, {"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID (magic chinese card)"}, + {"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"}, {"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block (magic chinese card)"}, {"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block (magic chinese card)"}, {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"}, diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 17dd97289..63e5a5be5 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -33,7 +33,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); - return 0; + return PM3_ETIMEOUT; } uint8_t isOK = resp.oldarg[0] & 0xff; if (!isOK) { @@ -49,7 +49,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(WARNING, "Command unsuccessful"); break; } - return 0; + return PM3_ESOFT; } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------"); @@ -82,7 +82,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { uint8_t data[1] = {GET_FREE_MEMORY}; SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) - return 0; + return PM3_ETIMEOUT; uint8_t tmp[3]; memcpy(tmp, resp.data.asBytes + 3, 3); @@ -105,7 +105,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { */ - return 1; + return PM3_SUCCESS; } /* @@ -189,10 +189,12 @@ void getKeySettings(uint8_t *aid) { PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str); str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO"; PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str); + { uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; } isOK = resp.oldarg[0] & 0xff; if (!isOK) { @@ -206,24 +208,27 @@ void getKeySettings(uint8_t *aid) { { uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES"); { uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES"); { uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES"); @@ -237,7 +242,7 @@ void getKeySettings(uint8_t *aid) { { uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a memcpy(data + 1, aid, 3); - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, " Timed-out"); @@ -252,8 +257,9 @@ void getKeySettings(uint8_t *aid) { // KEY SETTINGS { uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { return; } @@ -294,8 +300,9 @@ void getKeySettings(uint8_t *aid) { // KEY VERSION - AMK { uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, " Timed-out"); return; @@ -318,11 +325,10 @@ void getKeySettings(uint8_t *aid) { // LOOP over numOfKeys that we got before. // From 0x01 to numOfKeys. We already got 0x00. (AMK) // TODO (iceman) - for (int i = 0x01; i <= 0x0f; ++i) { - - } - - + /* + for (int i = 0x01; i <= 0x0f; ++i) { + } + */ } } @@ -333,17 +339,18 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { uint8_t aid[3]; { uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - return 0; + return PM3_ETIMEOUT; } + isOK = resp.oldarg[0] & 0xff; if (!isOK) { PrintAndLogEx(NORMAL, "Command unsuccessful"); - return 0; + return PM3_ESOFT; } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------"); @@ -368,7 +375,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { { uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a memcpy(data + 1, &resp.data.asBytes[i], 3); - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) { @@ -384,7 +391,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { // Get File IDs { uint8_t data[1] = {GET_FILE_IDS}; // 0x6f - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) { @@ -405,7 +412,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { // Get ISO File IDs { uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) { @@ -422,13 +429,9 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { } } } - - } PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - - - return 1; + return PM3_SUCCESS; } // MIAFRE DesFire Authentication @@ -456,7 +459,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344"); PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"); - return 0; + return PM3_SUCCESS; } uint8_t cmdAuthMode = param_get8(Cmd, 0); uint8_t cmdAuthAlgo = param_get8(Cmd, 1); @@ -466,25 +469,24 @@ static int CmdHF14ADesAuth(const char *Cmd) { case 1: if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; case 2: if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; case 3: if (cmdAuthAlgo != 4) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; default: PrintAndLogEx(WARNING, "Wrong Auth mode"); - return 1; - break; + return PM3_EINVARG; } switch (cmdAuthAlgo) { @@ -510,8 +512,9 @@ static int CmdHF14ADesAuth(const char *Cmd) { // key if (param_gethex(Cmd, 3, key, keylength * 2)) { PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength); - return 1; + return PM3_EINVARG; } + // algo, keylength, uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES) memcpy(data + 1, key, keylength); @@ -521,7 +524,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { PrintAndLogEx(WARNING, "Client command execute timeout"); - return 0; + return PM3_ETIMEOUT; } uint8_t isOK = resp.oldarg[0] & 0xff; @@ -536,7 +539,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { PrintAndLogEx(NORMAL, "Client command failed."); } PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - return 1; + return PM3_SUCCESS; } @@ -553,7 +556,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFMFDes(const char *Cmd) { diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index c6af6305a..ec7c4cc72 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -25,6 +25,8 @@ #include "cliparser/cliparser.h" #include "emv/dump.h" #include "mifare/mifaredefault.h" +#include "util_posix.h" +#include "fileutils.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -88,7 +90,7 @@ static int CmdHFMFPInfo(const char *cmd) { int datalen = 0; // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161 uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; - int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); if (!res && datalen > 1 && data[0] == 0x09) { SLmode = 0; } @@ -105,7 +107,7 @@ static int CmdHFMFPInfo(const char *cmd) { DropField(); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPWritePerso(const char *cmd) { @@ -169,7 +171,7 @@ static int CmdHFMFPWritePerso(const char *cmd) { } PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; } uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; @@ -245,7 +247,7 @@ static int CmdHFMFPInitPerso(const char *cmd) { PrintAndLogEx(INFO, "Done."); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPCommitPerso(const char *cmd) { @@ -286,7 +288,7 @@ static int CmdHFMFPCommitPerso(const char *cmd) { } PrintAndLogEx(INFO, "Switch level OK."); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPAuth(const char *cmd) { @@ -324,7 +326,7 @@ static int CmdHFMFPAuth(const char *cmd) { return 1; } - return MifareAuth4(NULL, keyn, key, true, false, verbose); + return MifareAuth4(NULL, keyn, key, true, false, true, verbose, false); } static int CmdHFMFPRdbl(const char *cmd) { @@ -392,7 +394,7 @@ static int CmdHFMFPRdbl(const char *cmd) { PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -491,7 +493,7 @@ static int CmdHFMFPRdsc(const char *cmd) { PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -532,7 +534,7 @@ static int CmdHFMFPRdsc(const char *cmd) { } DropField(); - return 0; + return PM3_SUCCESS; } static int CmdHFMFPWrbl(const char *cmd) { @@ -595,7 +597,7 @@ static int CmdHFMFPWrbl(const char *cmd) { PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -634,7 +636,333 @@ static int CmdHFMFPWrbl(const char *cmd) { DropField(); PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; +} + +#define AES_KEY_LEN 16 +#define MAX_KEYS_LIST_LEN 1024 + +int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], + bool verbose) { + int res; + bool selectCard = true; + uint8_t keyn[2] = {0}; + + // sector number from 0 + for (uint8_t sector = startSector; sector <= endSector; sector++) { + // 0-keyA 1-keyB + for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { + // main cycle with key check + for (int i = 0; i < keyListLen; i++) { + if (i % 10 == 0) { + if (!verbose) + printf("."); + if (kbd_enter_pressed()) { + PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); + DropField(); + return PM3_EOPABORTED; + } + } + + uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + + for (int retry = 0; retry < 4; retry++) { + res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); + if (res != 2) + break; + + if (verbose) + PrintAndLogEx(WARNING, "retried[%d]...", retry); + else + printf("R"); + + DropField(); + selectCard = true; + msleep(100); + } + + if (verbose) + PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + + // key for [sector,keyAB] found + if (res == 0) { + if (verbose) + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + else + printf("+"); + foundKeys[keyAB][sector][0] = 0x01; + memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); + DropField(); + selectCard = true; + msleep(50); + break; + } + + // 5 - auth error (rnd not equal) + if (res != 5) { + if (verbose) + PrintAndLogEx(ERR, "Exchange error. Aborted."); + else + printf("E"); + DropField(); + return PM3_ECARDEXCHANGE; + } + + selectCard = false; + } + } + } + + DropField(); + return PM3_SUCCESS; +} + +void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyListLen, uint32_t *startPattern) { + for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { + keyList[*keyListLen][0] = (pt >> 8) & 0xff; + keyList[*keyListLen][1] = pt & 0xff; + memcpy(&keyList[*keyListLen][2], &keyList[*keyListLen][0], 2); + memcpy(&keyList[*keyListLen][4], &keyList[*keyListLen][0], 4); + memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); + (*keyListLen)++; + *startPattern = pt; + if (*keyListLen == MAX_KEYS_LIST_LEN) + break; + } + (*startPattern)++; +} + +static int CmdHFMFPChk(const char *cmd) { + int res; + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; + size_t keyListLen = 0; + uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; + + CLIParserInit("hf mfp chk", + "Checks keys with Mifare Plus card.", + "Usage:\n" + " hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" + " hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n" + " hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" + " hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" + " hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("aA", "keya", "check only key A (by default check all keys)."), + arg_lit0("bB", "keyb", "check only key B (by default check all keys)."), + arg_int0("sS", "startsec", "Start sector Num (0..255)", NULL), + arg_int0("eE", "endsec", "End sector Num (0..255)", NULL), + arg_str0("kK", "key", "", "Key for checking (HEX 16 bytes)"), + arg_str0("dD", "dict", "", "file with keys dictionary"), + arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), + arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), + arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), + arg_str0("jJ", "json", "", "json file to save keys"), + arg_lit0("vV", "verbose", "verbose mode."), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool keyA = arg_get_lit(1); + bool keyB = arg_get_lit(2); + uint8_t startSector = arg_get_int_def(3, 0); + uint8_t endSector = arg_get_int_def(4, 0); + + uint8_t vkey[16] = {0}; + int vkeylen = 0; + CLIGetHexWithReturn(5, vkey, &vkeylen); + if (vkeylen > 0) { + if (vkeylen == 16) { + memcpy(&keyList[keyListLen], vkey, 16); + keyListLen++; + } else { + PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); + CLIParserFree(); + return PM3_EINVARG; + } + } + + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(6), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); + CLIParserFree(); + return PM3_EINVARG; + } + + bool pattern1b = arg_get_lit(7); + bool pattern2b = arg_get_lit(8); + + if (pattern1b && pattern2b) { + PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); + CLIParserFree(); + return PM3_EINVARG; + } + + if (dict_filenamelen && (pattern1b || pattern2b)) { + PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(); + return PM3_EINVARG; + } + + uint32_t startPattern = 0x0000; + uint8_t vpattern[2]; + int vpatternlen = 0; + CLIGetHexWithReturn(9, vpattern, &vpatternlen); + if (vpatternlen > 0) { + if (vpatternlen > 0 && vpatternlen <= 2) { + startPattern = (vpattern[0] << 8) + vpattern[1]; + } else { + PrintAndLogEx(ERR, "Pattern must be 2-byte length."); + CLIParserFree(); + return PM3_EINVARG; + } + if (!pattern2b) + PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); + } + + uint8_t jsonname[250] = {0}; + int jsonnamelen = 0; + if (CLIParamStrToBuf(arg_get_str(10), jsonname, sizeof(jsonname), &jsonnamelen)) { + PrintAndLogEx(ERR, "Invalid json name."); + CLIParserFree(); + return PM3_EINVARG; + } + jsonname[jsonnamelen] = 0; + + bool verbose = arg_get_lit(11); + + CLIParserFree(); + + uint8_t startKeyAB = 0; + uint8_t endKeyAB = 1; + if (keyA && !keyB) + endKeyAB = 0; + if (!keyA && keyB) + startKeyAB = 1; + + if (endSector < startSector) + endSector = startSector; + + // 1-byte pattern search mode + if (pattern1b) { + for (int i = 0; i < 0x100; i++) + memset(keyList[i], i, 16); + + keyListLen = 0x100; + } + + // 2-byte pattern search mode + if (pattern2b) + Fill2bPattern(keyList, &keyListLen, &startPattern); + + // dictionary mode + size_t endFilePosition = 0; + if (dict_filenamelen) { + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true); + keyListLen = keycnt; + if (endFilePosition) + PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded."); + } + + if (keyListLen == 0) { + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) + break; + + keyListLen++; + } + } + + if (keyListLen == 0) { + PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); + return PM3_EINVARG; + } + + if (!verbose) + printf("Search keys:"); + while (true) { + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); + if (res == PM3_EOPABORTED) + break; + if (pattern2b && startPattern < 0x10000) { + if (!verbose) + printf("p"); + keyListLen = 0; + Fill2bPattern(keyList, &keyListLen, &startPattern); + continue; + } + if (dict_filenamelen && endFilePosition) { + if (!verbose) + printf("d"); + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + keyListLen = keycnt; + continue; + } + break; + } + if (!verbose) + printf("\n"); + + // print result + bool printedHeader = false; + for (uint8_t sector = startSector; sector <= endSector; sector++) { + if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) { + if (!printedHeader) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------."); + PrintAndLogEx(INFO, "|sector| key A | key B |"); + PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|"); + printedHeader = true; + } + PrintAndLogEx(INFO, "| %02d |%32s|%32s|", + sector, + (foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN), + (foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN)); + } + } + if (!printedHeader) + PrintAndLogEx(INFO, "No keys found("); + else + PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n"); + + // save keys to json + if ((jsonnamelen > 0) && printedHeader) { + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0}; + uint8_t atslen = 0; + if (select_status == 1 || select_status == 2) { + memcpy(data, card.uid, card.uidlen); + data[10] = card.sak; + data[11] = card.atqa[1]; + data[12] = card.atqa[0]; + atslen = card.ats_len; + data[13] = atslen; + memcpy(&data[14], card.ats, atslen); + } + + // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] + memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1)); + saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64); + } + + return PM3_SUCCESS; } static int CmdHFMFPMAD(const char *cmd) { @@ -728,7 +1056,7 @@ static int CmdHFMFPMAD(const char *cmd) { } } - return 0; + return PM3_SUCCESS; } static int CmdHFMFPNDEF(const char *cmd) { @@ -832,7 +1160,7 @@ static int CmdHFMFPNDEF(const char *cmd) { NDEFDecodeAndPrint(data, datalen, verbose); - return 0; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -845,6 +1173,7 @@ static command_t CommandTable[] = { {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"}, {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"}, + {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {NULL, NULL, 0, NULL} @@ -853,7 +1182,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFMFP(const char *Cmd) { diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index d7bdce1fc..7d2b8cfc6 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -445,7 +445,7 @@ static int ul_ev1_pwdgen_selftest() { uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80}; uint32_t pwd4 = ul_ev1_pwdgenD(uid4); PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--"); - return 0; + return PM3_SUCCESS; } //------------------------------------ @@ -565,7 +565,7 @@ static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { static int ulc_authentication(uint8_t *key, bool switch_off_field) { clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16); + SendCommandMIX(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0; if (resp.oldarg[0] == 1) return 1; @@ -2262,7 +2262,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data)); wait4response(MFU_NTAG_SPECIAL_PWD); @@ -2278,7 +2278,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { data[3] = 0; PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data)); wait4response(MFU_NTAG_SPECIAL_PACK); // Signature @@ -2286,7 +2286,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { memcpy(data, mem->signature + i, 4); PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); } @@ -2295,7 +2295,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { memcpy(data, mem->version + i, 4); PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); } } @@ -2309,7 +2309,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { //Send write Block memcpy(data, mem->data + (b * 4), 4); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); printf("."); fflush(stdout); @@ -2329,7 +2329,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { uint8_t b = blocks[i]; memcpy(data, mem->data + (b * 4), 4); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4)); } @@ -2338,7 +2338,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { DropField(); free(dump); PrintAndLogEx(INFO, "Finish restore"); - return 0; + return PM3_SUCCESS; } // // Load emulator with dump file @@ -2388,7 +2388,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { else PrintAndLogEx(WARNING, "Authentication failed"); - return 0; + return PM3_SUCCESS; } /** @@ -2500,11 +2500,11 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { if (param_gethex(Cmd, 0, pwd, 32)) { PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); - return 1; + return PM3_EINVARG; } clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); + SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { @@ -2512,13 +2512,13 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16)); } else { PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff)); - return 1; + return PM3_ESOFT; } } else { PrintAndLogEx(WARNING, "command execution time out"); - return 1; + return PM3_ETIMEOUT; } - return 0; + return PM3_SUCCESS; } // @@ -2556,7 +2556,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = uid[2]; data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2568,7 +2568,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = uid[5]; data[3] = uid[6]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2580,7 +2580,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = oldblock2[2]; data[3] = oldblock2[3]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2611,11 +2611,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { if (select_status == 0) { PrintAndLogEx(WARNING, "iso14443a card select failed"); - return 1; + return PM3_ESOFT; } if (card.uidlen != 4) { PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen); - return 1; + return PM3_ESOFT; } memcpy(uid, card.uid, sizeof(uid)); } else { @@ -2654,13 +2654,13 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { , divkey // output ); - PrintAndLogEx(NORMAL, "-- 3DES version"); - PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); - PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLogEx(NORMAL, "block :\t %0d", block); - PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey + 1, 6)); + PrintAndLogEx(SUCCESS, "-- 3DES version"); + PrintAndLogEx(SUCCESS, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); + PrintAndLogEx(SUCCESS, "UID :\t %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(SUCCESS, "block :\t %0d", block); + PrintAndLogEx(SUCCESS, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(SUCCESS, "Message :\t %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(SUCCESS, "Diversified key: %s", sprint_hex(divkey + 1, 6)); for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) { dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; @@ -2690,11 +2690,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { , newpwd // output ); - PrintAndLogEx(NORMAL, "\n-- DES version"); - PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + PrintAndLogEx(SUCCESS, "\n-- DES version"); + PrintAndLogEx(SUCCESS, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(SUCCESS, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(SUCCESS, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); mbedtls_des3_free(&ctx); // next. from the diversify_key method. diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index ae404b22d..98de42b7b 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -220,14 +220,14 @@ static int topaz_print_CC(uint8_t *data) { return PM3_ESOFT; // no NDEF message } - PrintAndLogEx(NORMAL, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); - PrintAndLogEx(NORMAL, " %02x: NDEF Magic Number", data[0]); - PrintAndLogEx(NORMAL, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLogEx(SUCCESS, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); + PrintAndLogEx(SUCCESS, " %02x: NDEF Magic Number", data[0]); + PrintAndLogEx(SUCCESS, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); uint16_t memsize = (data[2] + 1) * 8; topaz_tag.size = memsize; topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t)); - PrintAndLogEx(NORMAL, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); - PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3], + PrintAndLogEx(SUCCESS, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); + PrintAndLogEx(SUCCESS, " %02x: %s / %s", data[3], (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F) == 0 ? "Write access granted without any security" : (data[3] & 0x0F) == 0x0F ? "No write access granted at all" : "(RFU)"); return PM3_SUCCESS; @@ -301,7 +301,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) { uint16_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4); uint16_t area_start = pages_addr * bytes_per_page + byte_offset; - PrintAndLogEx(NORMAL, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", + PrintAndLogEx(SUCCESS, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", size_in_bits, area_start, bytes_locked_per_bit); @@ -333,7 +333,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) { uint16_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256; uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); uint16_t area_start = pages_addr * bytes_per_page + byte_offset; - PrintAndLogEx(NORMAL, "Reserved Memory of %d bytes at byte offset 0x%02x.", + PrintAndLogEx(SUCCESS, "Reserved Memory of %d bytes at byte offset 0x%02x.", size_in_bytes, area_start); reserved_memory_control_TLV_present = true; @@ -345,11 +345,11 @@ static void topaz_print_control_TLVs(uint8_t *memory) { } if (!lock_TLV_present) { - PrintAndLogEx(NORMAL, "(No Lock Control TLV present)"); + PrintAndLogEx(SUCCESS, "(No Lock Control TLV present)"); } if (!reserved_memory_control_TLV_present) { - PrintAndLogEx(NORMAL, "(No Reserved Memory Control TLV present)"); + PrintAndLogEx(SUCCESS, "(No Reserved Memory Control TLV present)"); } } @@ -376,7 +376,7 @@ static int topaz_read_dynamic_data(void) { // read and print the dynamic memory static void topaz_print_dynamic_data(void) { if (topaz_tag.size > TOPAZ_STATIC_MEMORY) { - PrintAndLogEx(NORMAL, "Dynamic Data blocks:"); + PrintAndLogEx(SUCCESS, "Dynamic Data blocks:"); if (topaz_read_dynamic_data() == 0) { PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); @@ -435,19 +435,19 @@ static int CmdHFTopazReader(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", atqa[1], atqa[0]); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]); topaz_tag.HR01[0] = rid_response[0]; topaz_tag.HR01[1] = rid_response[1]; // ToDo: CRC check - PrintAndLogEx(NORMAL, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", + PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic"); - PrintAndLogEx(NORMAL, "HR1 : %02x", rid_response[1]); + PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]); status = topaz_rall(uid_echo, rall_response); @@ -458,7 +458,7 @@ static int CmdHFTopazReader(const char *Cmd) { } memcpy(topaz_tag.uid, rall_response + 2, 7); - PrintAndLogEx(NORMAL, "UID : %02x %02x %02x %02x %02x %02x %02x", + PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x", topaz_tag.uid[6], topaz_tag.uid[5], topaz_tag.uid[4], @@ -467,13 +467,13 @@ static int CmdHFTopazReader(const char *Cmd) { topaz_tag.uid[1], topaz_tag.uid[0]); - PrintAndLogEx(NORMAL, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"), topaz_tag.uid[6], getTagInfo(topaz_tag.uid[6])); memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":"); + PrintAndLogEx(SUCCESS, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":"); PrintAndLogEx(NORMAL, "block# | offset | Data | Locked"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); char line[80]; @@ -488,7 +488,7 @@ static int CmdHFTopazReader(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Reserved block " _YELLOW_("0x0D")":"); + PrintAndLogEx(SUCCESS, "Static Reserved block " _YELLOW_("0x0D")":"); for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0d][j]); } @@ -496,7 +496,7 @@ static int CmdHFTopazReader(const char *Cmd) { PrintAndLogEx(NORMAL, " 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d * 8, line, "n/a"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Lockbits and OTP Bytes:"); + PrintAndLogEx(SUCCESS, "Static Lockbits and OTP Bytes:"); for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0e][j]); } @@ -507,7 +507,7 @@ static int CmdHFTopazReader(const char *Cmd) { status = topaz_print_CC(&topaz_tag.data_blocks[1][0]); if (status == PM3_ESOFT) { - PrintAndLogEx(NORMAL, "No NDEF message data present"); + PrintAndLogEx(SUCCESS, "No NDEF message data present"); topaz_switch_off_field(); return PM3_SUCCESS; } @@ -528,13 +528,13 @@ static int CmdHFTopazReader(const char *Cmd) { static int CmdHFTopazSim(const char *Cmd) { (void)Cmd; // Cmd is not used so far - PrintAndLogEx(NORMAL, "not yet implemented"); + PrintAndLogEx(INFO, "not yet implemented"); return PM3_SUCCESS; } static int CmdHFTopazCmdRaw(const char *Cmd) { (void)Cmd; // Cmd is not used so far - PrintAndLogEx(NORMAL, "not yet implemented. Use hf 14 raw with option -T."); + PrintAndLogEx(INFO, "not yet implemented. Use hf 14 raw with option -T."); return PM3_SUCCESS; } diff --git a/client/cmdhw.c b/client/cmdhw.c index 5eb6c7100..3c5e65f17 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -86,7 +86,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { char asBuff[120]; memset(asBuff, 0, sizeof(asBuff)); uint32_t mem_avail = 0; - PrintAndLogEx(NORMAL, "\n [ Hardware ] "); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Hardware ]")); switch (iChipID) { case 0x270B0A40: @@ -447,13 +447,13 @@ static int CmdSetDivisor(const char *Cmd) { uint8_t arg = param_get8ex(Cmd, 0, 95, 10); if (arg < 19) { - PrintAndLogEx(ERR, "divisor must be between 19 and 255"); + PrintAndLogEx(ERR, "divisor must be between" _YELLOW_("19") " and " _YELLOW_("255") ); return PM3_EINVARG; } // 12 000 000 (12MHz) clearCommandBuffer(); SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg)); - PrintAndLogEx(SUCCESS, "Divisor set, expected %.1f kHz", ((double)12000 / (arg + 1))); + PrintAndLogEx(SUCCESS, "Divisor set, expected " _YELLOW_("%.1f")" kHz", ((double)12000 / (arg + 1))); return PM3_SUCCESS; } @@ -514,11 +514,11 @@ static int CmdStatus(const char *Cmd) { static int CmdTia(const char *Cmd) { (void)Cmd; // Cmd is not used so far clearCommandBuffer(); - PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition..."); + PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)..."); PacketResponseNG resp; SendCommandNG(CMD_TIA, NULL, 0); if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false) - PrintAndLogEx(WARNING, "Tia command failed. You probably need to unplug the Proxmark3."); + PrintAndLogEx(WARNING, "TIA command failed. You probably need to unplug the Proxmark3."); PrintAndLogEx(INFO, "TIA done."); return PM3_SUCCESS; } @@ -528,7 +528,7 @@ static int CmdPing(const char *Cmd) { if (len > PM3_CMD_DATA_SIZE) len = PM3_CMD_DATA_SIZE; if (len) { - PrintAndLogEx(INFO, "Ping sent with payload len=%d", len); + PrintAndLogEx(INFO, "Ping sent with payload len = %d", len); } else { PrintAndLogEx(INFO, "Ping sent"); } @@ -702,26 +702,24 @@ void pm3_version(bool verbose, bool oneliner) { SendCommandNG(CMD_VERSION, NULL, 0); if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) { - PrintAndLogEx(NORMAL, "\n" _BLUE_(" [ Proxmark3 RFID instrument ]") "\n"); - PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Proxmark3 RFID instrument ]")); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ CLIENT ]")); PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info? PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH); -//#if PLATFORM == PM3RDV4 if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) { - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 ]")); } else { - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 ]")); PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 Extras ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 Extras ]")); PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent")); if (IfPm3FpcUsartDevFromUsb()) { PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present")); } } -//#endif PrintAndLogEx(NORMAL, ""); diff --git a/client/cmdlf.c b/client/cmdlf.c index 236bfc526..7c454a7a0 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -798,7 +798,7 @@ int CmdLFfskSim(const char *Cmd) { size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t); } @@ -900,7 +900,7 @@ int CmdLFaskSim(const char *Cmd) { size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t); } @@ -993,13 +993,13 @@ int CmdLFpskSim(const char *Cmd) { if (errors) return usage_lf_simpsk(); if (dataLen == 0) { //using DemodBuffer - PrintAndLogEx(NORMAL, "Getting Clocks"); + PrintAndLogEx(INFO, "Getting Clocks"); if (clk == 0) clk = GetPskClock("", false); - PrintAndLogEx(NORMAL, "clk: %d", clk); + PrintAndLogEx(INFO, "clk: %d", clk); if (!carrier) carrier = GetPskCarrier("", false); - PrintAndLogEx(NORMAL, "carrier: %d", carrier); + PrintAndLogEx(INFO, "carrier: %d", carrier); } else { setDemodBuff(data, dataLen, 0); @@ -1015,12 +1015,12 @@ int CmdLFpskSim(const char *Cmd) { //need to convert psk2 to psk1 data before sim psk2TOpsk1(DemodBuffer, DemodBufferLen); } else { - PrintAndLogEx(NORMAL, "Sorry, PSK3 not yet available"); + PrintAndLogEx(WARNING, "Sorry, PSK3 not yet available"); } } size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t); } diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c index 1a204ed41..717bf2587 100644 --- a/client/cmdlfnexwatch.c +++ b/client/cmdlfnexwatch.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdlfnexwatch.h" +#include // PRIu #include // tolower #include "commonutil.h" // ARRAYLEN @@ -80,9 +81,9 @@ static int CmdNexWatchDemod(const char *Cmd) { //checksum check (TBD) //output - PrintAndLogEx(NORMAL, "NexWatch ID: %d", ID); + PrintAndLogEx(SUCCESS, "NexWatch ID: " _YELLOW_("%"PRIu32) , ID); if (invert) { - PrintAndLogEx(NORMAL, "Had to Invert - probably NexKey"); + PrintAndLogEx(INFO, "Had to Invert - probably NexKey"); for (size_t i = 0; i < size; i++) DemodBuffer[i] ^= 1; } diff --git a/client/cmdtrace.c b/client/cmdtrace.c index 67f15be59..7e9b53548 100644 --- a/client/cmdtrace.c +++ b/client/cmdtrace.c @@ -50,21 +50,21 @@ static int usage_trace_list() { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace list 14a f"); PrintAndLogEx(NORMAL, " trace list iclass"); - return 0; + return PM3_SUCCESS; } static int usage_trace_load() { PrintAndLogEx(NORMAL, "Load protocol data from file to trace buffer."); PrintAndLogEx(NORMAL, "Usage: trace load "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace load mytracefile.bin"); - return 0; + return PM3_SUCCESS; } static int usage_trace_save() { PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to file."); PrintAndLogEx(NORMAL, "Usage: trace save "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace save mytracefile.bin"); - return 0; + return PM3_SUCCESS; } static bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) { @@ -450,7 +450,7 @@ static int CmdTraceLoad(const char *Cmd) { if ((f = fopen(filename, "rb")) == NULL) { PrintAndLogEx(FAILED, "Could not open file " _YELLOW_("%s"), filename); - return 0; + return PM3_EIO; } // get filesize in order to malloc memory @@ -461,12 +461,12 @@ static int CmdTraceLoad(const char *Cmd) { if (fsize < 0) { PrintAndLogEx(FAILED, "error, when getting filesize"); fclose(f); - return 3; + return PM3_EIO; } if (fsize < 4) { PrintAndLogEx(FAILED, "error, file is too small"); fclose(f); - return 4; + return PM3_ESOFT; } if (trace) @@ -476,21 +476,21 @@ static int CmdTraceLoad(const char *Cmd) { if (!trace) { PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); fclose(f); - return 2; + return PM3_EMALLOC; } size_t bytes_read = fread(trace, 1, fsize, f); traceLen = bytes_read; fclose(f); PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes) loaded from file %s", traceLen, filename); - return 0; + return PM3_SUCCESS; } static int CmdTraceSave(const char *Cmd) { if (traceLen == 0) { PrintAndLogEx(WARNING, "trace is empty, nothing to save"); - return 0; + return PM3_SUCCESS; } char filename[FILE_PATH_SIZE]; @@ -499,7 +499,7 @@ static int CmdTraceSave(const char *Cmd) { param_getstr(Cmd, 0, filename, sizeof(filename)); saveFile(filename, ".bin", trace, traceLen); - return 0; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -513,7 +513,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdTrace(const char *Cmd) { @@ -604,15 +604,20 @@ int CmdTraceList(const char *Cmd) { uint16_t tracepos = 0; // reserv some space. - if (!trace) + if (!trace) { trace = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); + if (trace == NULL) { + PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); + return PM3_EMALLOC; + } + } if (isOnline) { // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE PacketResponseNG response; if (!GetFromDevice(BIG_BUF, trace, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 4000, true)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; + return PM3_ETIMEOUT; } traceLen = response.oldarg[2]; @@ -621,13 +626,13 @@ int CmdTraceList(const char *Cmd) { if (p == NULL) { PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); free(trace); - return 2; + return PM3_EMALLOC; } trace = p; if (!GetFromDevice(BIG_BUF, trace, traceLen, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); free(trace); - return 3; + return PM3_ETIMEOUT; } } } @@ -678,6 +683,6 @@ int CmdTraceList(const char *Cmd) { break; } } - return 0; + return PM3_SUCCESS; } diff --git a/client/dictionaries/mfp_default_keys.dic b/client/dictionaries/mfp_default_keys.dic new file mode 100644 index 000000000..0f20b69bf --- /dev/null +++ b/client/dictionaries/mfp_default_keys.dic @@ -0,0 +1,27 @@ +ffffffffffffffffffffffffffffffff +00000000000000000000000000000000 +a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7 +b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7 +d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 +11111111111111111111111111111111 +22222222222222222222222222222222 +33333333333333333333333333333333 +44444444444444444444444444444444 +55555555555555555555555555555555 +66666666666666666666666666666666 +77777777777777777777777777777777 +88888888888888888888888888888888 +99999999999999999999999999999999 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +cccccccccccccccccccccccccccccccc +dddddddddddddddddddddddddddddddd +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +000102030405060708090a0b0c0d0e0f +0102030405060708090a0b0c0d0e0f10 +00010203040506070809101112131415 +01020304050607080910111213141516 +16151413121110090807060504030201 +15141312111009080706050403020100 +0f0e0d0c0b0a09080706050403020100 +100f0e0d0c0b0a090807060504030201 diff --git a/client/fileutils.c b/client/fileutils.c index ebdb662ca..7c10fe50c 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -352,6 +352,34 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s case jsf15: case jsfLegic: case jsfT5555: + case jsfMfPlusKeys: + JsonSaveStr(root, "FileType", "mfp"); + JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7); + JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1); + JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2); + uint8_t atslen = data[13]; + if (atslen > 0) + JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen); + + uint8_t vdata[2][64][16 + 1] = {{{0}}}; + memcpy(vdata, &data[14 + atslen], 2 * 64 * 17); + + for (size_t i = 0; i < datalen; i++) { + char path[PATH_MAX_LENGTH] = {0}; + + if (vdata[0][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16); + } + + if (vdata[1][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16); + } + } + break; default: break; } @@ -715,20 +743,29 @@ out: } int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) { + // t5577 == 4bytes + // mifare == 6 bytes + // mf plus == 16 bytes + // iclass == 8 bytes + // default to 6 bytes. + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { + keylen = 6; + } + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true); +} + +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition, bool verbose) { + if (endFilePosition) + *endFilePosition = 0; if (data == NULL) return PM3_EINVARG; + uint16_t vkeycnt = 0; + char *path; if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) return PM3_EFILE; - // t5577 == 4bytes - // mifare == 6 bytes - // iclass == 8 bytes - // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { - keylen = 6; - } - // double up since its chars keylen <<= 1; @@ -744,8 +781,17 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u goto out; } + if (startFilePosition) + fseek(f, startFilePosition, SEEK_SET); + // read file - while (fgets(line, sizeof(line), f)) { + while (!feof(f)) { + size_t filepos = ftell(f); + if (!fgets(line, sizeof(line), f)) { + if (endFilePosition) + *endFilePosition = 0; + break; + } // add null terminator line[keylen] = 0; @@ -758,23 +804,32 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); + if (!CheckStringIsHEXValue(line)) continue; + + // cant store more data + if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) { + retval = 1; + if (endFilePosition) + *endFilePosition = filepos; + break; } - uint64_t key = strtoull(line, NULL, 16); + if (hex_to_bytes(line, data + counter, keylen >> 1) != (keylen >> 1)) + continue; - num_to_bytes(key, keylen >> 1, data + counter); - (*keycnt)++; + vkeycnt++; memset(line, 0, sizeof(line)); counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path); + if (verbose) + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; + if (keycnt) + *keycnt = vkeycnt; out: free(path); return retval; @@ -790,9 +845,10 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key // t5577 == 4bytes // mifare == 6 bytes + // mf plus == 16 bytes // iclass == 8 bytes // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } @@ -848,10 +904,8 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); + if (CheckStringIsHEXValue(line)) continue; - } uint64_t key = strtoull(line, NULL, 16); diff --git a/client/fileutils.h b/client/fileutils.h index eb4b57c82..523e957a7 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -61,6 +61,7 @@ typedef enum { jsfLegic, jsfT55x7, jsfT5555, + jsfMfPlusKeys, } JSONFileType; typedef enum { @@ -175,13 +176,32 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ * * @param preferredName * @param data The data array to store the loaded bytes from file - * @param maxdatalen maximum size of data array in bytes - * @param datalen the number of bytes loaded from file + * @param datalen the number of bytes loaded from file. may be NULL * @param keylen the number of bytes a key per row is + * @param keycnt key count that lays in data. may be NULL * @return 0 for ok, 1 for failz */ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt); +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. mfc_default_keys.dic + * can be executed several times for big dictionaries and checks length of buffer + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file. may be NULL + * @param keylen the number of bytes a key per row is + * @param keycnt key count that lays in data. may be NULL + * @param startFilePosition start position in dictionary file. used for big dictionaries. + * @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL + * @param verbose print messages if true + * @return 0 for ok, 1 for failz +*/ +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition, bool verbose); + /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. * E.g. mfc_default_keys.dic diff --git a/client/luascripts/read_pwd_mem.lua b/client/luascripts/read_pwd_mem.lua index 8456fd51f..ffc00a998 100644 --- a/client/luascripts/read_pwd_mem.lua +++ b/client/luascripts/read_pwd_mem.lua @@ -26,10 +26,10 @@ example = -- This will print the stored Mifare dictionary keys script run read_pwd_mem -m - + -- This will print the stored t55xx dictionary passwords script run read_pwd_mem -t - + -- This will print the stored iClass dictionary keys script run read_pwd_mem -i ]] diff --git a/client/luascripts/read_pwd_mem_spiffs.lua b/client/luascripts/read_pwd_mem_spiffs.lua index 33afa0fe9..89ef64e6d 100644 --- a/client/luascripts/read_pwd_mem_spiffs.lua +++ b/client/luascripts/read_pwd_mem_spiffs.lua @@ -16,7 +16,7 @@ example = -- This will read the other.log file in SPIFFS and print the stored passwords script run read_pwd_mem_spiffs -f other.log - + -- This will delete the hf_bog.log file from SPIFFS script run read_pwd_mem_spiffs -r ]] @@ -68,7 +68,7 @@ local function main(args) -- offset if o == 'f' then filename = a end - + -- remove if o == 'r' then removeflag = true end @@ -79,7 +79,7 @@ local function main(args) core.console("mem spiffs remove " ..filename) return end - + data, length, err = core.GetFromFlashMemSpiffs(filename) if data == nil then return oops('Problem while reading file from SPIFFS') end diff --git a/client/mifare/mifare4.c b/client/mifare/mifare4.c index 5cdca2e14..8bf0788b4 100644 --- a/client/mifare/mifare4.c +++ b/client/mifare/mifare4.c @@ -168,21 +168,24 @@ int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); } -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) { uint8_t data[257] = {0}; int datalen = 0; uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; uint8_t RndB[17] = {0}; + if (silentMode) + verbose = false; + if (session) session->Authenticated = false; uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; - int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 2; } @@ -190,20 +193,20 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF PrintAndLogEx(INFO, "phase2: %s", sprint_hex(cmd2, 33)); - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 4; } @@ -241,12 +244,12 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF } if (memcmp(&raw[4], &RndA[1], 16)) { - PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal"); + if (!silentMode) PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal"); if (verbose) { PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16)); PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16)); } - DropField(); + if (dropFieldIfError) DropField(); return 5; } @@ -311,7 +314,7 @@ static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateFi if (VerboseMode) PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); - int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false); if (VerboseMode) PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); @@ -380,7 +383,7 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum); mf4Session session; - int res = MifareAuth4(&session, keyn, key, true, true, verbose); + int res = MifareAuth4(&session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res); return res; diff --git a/client/mifare/mifare4.h b/client/mifare/mifare4.h index 31eac1fdb..fe07aceaf 100644 --- a/client/mifare/mifare4.h +++ b/client/mifare/mifare4.h @@ -45,7 +45,7 @@ void mfpSetVerboseMode(bool verbose); const char *mfpGetErrorDescription(uint8_t errorCode); int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode); int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); diff --git a/client/mifare/mifaredefault.c b/client/mifare/mifaredefault.c new file mode 100644 index 000000000..b41859f09 --- /dev/null +++ b/client/mifare/mifaredefault.c @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2017 Merlok +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Mifare default constants +//----------------------------------------------------------------------------- + +#include "mifaredefault.h" +#include "commonutil.h" // ARRAYLEN + +const char *g_mifare_plus_default_keys[] = { + "ffffffffffffffffffffffffffffffff", // default key + "00000000000000000000000000000000", + "a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7", // MAD key + "b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7", + "d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7", // NDEF key + "11111111111111111111111111111111", + "22222222222222222222222222222222", + "33333333333333333333333333333333", + "44444444444444444444444444444444", + "55555555555555555555555555555555", + "66666666666666666666666666666666", + "77777777777777777777777777777777", + "88888888888888888888888888888888", + "99999999999999999999999999999999", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddd", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "000102030405060708090a0b0c0d0e0f", + "0102030405060708090a0b0c0d0e0f10", + "00010203040506070809101112131415", + "01020304050607080910111213141516" +}; +size_t g_mifare_plus_default_keys_len = ARRAYLEN(g_mifare_plus_default_keys); diff --git a/client/mifare/mifaredefault.h b/client/mifare/mifaredefault.h index 7232510a0..cdc103676 100644 --- a/client/mifare/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -44,4 +44,7 @@ static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +extern const char *g_mifare_plus_default_keys[]; +extern size_t g_mifare_plus_default_keys_len; + #endif diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 39d2d6001..86676696d 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -24,7 +24,6 @@ #include "mfkey.h" #include "util_posix.h" // msclock - int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { uint32_t uid = 0; uint32_t nt = 0, nr = 0, ar = 0; @@ -361,7 +360,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_NESTED, (uint8_t *)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 1500)) return PM3_ETIMEOUT; + if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 2000)) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return PM3_ETIMEOUT; + } if (resp.status != PM3_SUCCESS) return PM3_ESOFT; @@ -615,6 +617,50 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_ return mfCSetBlock(0, block0, oldUID, params); } +int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) { + uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; + uint8_t blockD[16] = {0x00}; + uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t params = MAGIC_SINGLE; + + if (uid != NULL) { + memcpy(block0, uid, 4); + block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; + } + if (sak != NULL) + block0[5] = sak[0]; + + if (atqa != NULL) { + block0[6] = atqa[1]; + block0[7] = atqa[0]; + } + int res; + for (int blockNo = 0; blockNo < 4 * 16; blockNo++) { + for (int retry = 0; retry < 3; retry++) { + if (blockNo == 0) { + res = mfCSetBlock(blockNo, block0, NULL, params); + } else { + if (mfIsSectorTrailer(blockNo)) + res = mfCSetBlock(blockNo, blockK, NULL, params); + else + res = mfCSetBlock(blockNo, blockD, NULL, params); + } + + if (res == PM3_SUCCESS) + break; + PrintAndLogEx(WARNING, "Retry block[%d]...", blockNo); + } + + if (res) { + PrintAndLogEx(ERR, "Error setting block[%d]: %d", blockNo, res); + return res; + } + } + DropField(); + + return PM3_SUCCESS; +} + int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) { clearCommandBuffer(); diff --git a/client/mifare/mifarehost.h b/client/mifare/mifarehost.h index 11bd3f29c..50ed9d8e2 100644 --- a/client/mifare/mifarehost.h +++ b/client/mifare/mifarehost.h @@ -73,6 +73,7 @@ int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard); +int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak); int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); diff --git a/client/proxmark3.c b/client/proxmark3.c index bb291ee6c..c28a93396 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -33,26 +33,25 @@ static void showBanner(void) { PrintAndLogEx(NORMAL, "\n"); #if defined(__linux__) || (__APPLE__) || (_WIN32) - PrintAndLogEx(NORMAL, _BLUE_("██████╗ ███╗ ███╗ ████╗ ") " ...iceman fork"); - PrintAndLogEx(NORMAL, _BLUE_("██╔══██╗████╗ ████║ ══█║") " ...dedicated to " _BLUE_("RDV40")); - PrintAndLogEx(NORMAL, _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); - PrintAndLogEx(NORMAL, _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net"); - PrintAndLogEx(NORMAL, _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/"); - PrintAndLogEx(NORMAL, _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0"); + PrintAndLogEx(NORMAL, " " _BLUE_("██████╗ ███╗ ███╗ ████╗ ")); + PrintAndLogEx(NORMAL, " " _BLUE_("██╔══██╗████╗ ████║ ══█║")); + PrintAndLogEx(NORMAL, " " _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); + PrintAndLogEx(NORMAL, " " _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net"); + PrintAndLogEx(NORMAL, " " _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/"); + PrintAndLogEx(NORMAL, " " _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0"); #else - PrintAndLogEx(NORMAL, "======. ===. ===. ====. ...iceman fork"); - PrintAndLogEx(NORMAL, "==...==.====. ====. ..=. ...dedicated to RDV40"); - PrintAndLogEx(NORMAL, "======..==.====.==. ====.."); - PrintAndLogEx(NORMAL, "==..... ==..==..==. ..=. iceman@icesql.net"); - PrintAndLogEx(NORMAL, "==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/"); - PrintAndLogEx(NORMAL, "... ... ... ..... pre-release v4.0"); + PrintAndLogEx(NORMAL, " ======. ===. ===. ====."); + PrintAndLogEx(NORMAL, " ==...==.====. ====. ..=."); + PrintAndLogEx(NORMAL, " ======..==.====.==. ====.."); + PrintAndLogEx(NORMAL, " ==..... ==..==..==. ..=. iceman@icesql.net"); + PrintAndLogEx(NORMAL, " ==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/"); + PrintAndLogEx(NORMAL, " ... ... ... ..... pre-release v4.0"); #endif - PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/"); - PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001"); +// PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/"); +// PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001"); // printf("\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP"); - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); fflush(stdout); - g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; } @@ -807,7 +806,7 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); if (!session.pm3_present) - PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check \"%s -h\" if it's not what you want.\n", exec_name); + PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name); #ifdef HAVE_GUI diff --git a/client/util.c b/client/util.c index 58dce8eca..856091231 100644 --- a/client/util.c +++ b/client/util.c @@ -394,6 +394,46 @@ void print_blocks(uint32_t *data, size_t len) { } } +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) { + char buf[4] = {0}; + int indx = 0; + int bytesValueLen = 0; + while (hexValue[indx]) { + if (hexValue[indx] == '\t' || hexValue[indx] == ' ') { + indx++; + continue; + } + + if (isxdigit(hexValue[indx])) { + buf[strlen(buf)] = hexValue[indx]; + } else { + // if we have symbols other than spaces and hex + return -1; + } + + if (maxBytesValueLen && bytesValueLen >= maxBytesValueLen) { + // if we dont have space in buffer and have symbols to translate + return -2; + } + + if (strlen(buf) >= 2) { + uint32_t temp = 0; + sscanf(buf, "%x", &temp); + bytesValue[bytesValueLen] = (uint8_t)(temp & 0xff); + memset(buf, 0, sizeof(buf)); + bytesValueLen++; + } + + indx++; + } + + if (strlen(buf) > 0) + //error when not completed hex bytes + return -3; + + return bytesValueLen; +} + // takes a number (uint64_t) and creates a binarray in dest. void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { while (len--) { diff --git a/client/util.h b/client/util.h index d549458c4..afa12811b 100644 --- a/client/util.h +++ b/client/util.h @@ -55,6 +55,7 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st void print_blocks(uint32_t *data, size_t len); +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen); void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); diff --git a/doc/jtag_notes.md b/doc/jtag_notes.md index 8e31f1112..42001d91d 100644 --- a/doc/jtag_notes.md +++ b/doc/jtag_notes.md @@ -63,6 +63,9 @@ GND | 6 ## Third party notes on using a BusPirate * https://github.com/Proxmark/proxmark3/wiki/Debricking-Proxmark3-with-buspirate +* https://b4cktr4ck2.github.io/De-Brickify-Pm3-RDV2/ +* https://scund00r.com/all/rfid/2018/05/18/debrick-proxmark.html +* https://joanbono.github.io/PoC/Flashing_Proxmark3.html ## Third party notes on using a J-Link @@ -72,8 +75,6 @@ GND | 6 * http://www.lucasoldi.com/2017/01/17/unbrick-proxmark3-with-a-raspberry-pi-and-openocd/ -# Windows - ## Third party notes on using a J-Link on Windows * https://github.com/Proxmark/proxmark3/wiki/De-Bricking-Segger diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 892ec533f..e775b3413 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -590,6 +590,8 @@ typedef struct { #define PM3_EWRONGANSVER -16 // Memory out-of-bounds error client/pm3: error when a read/write is outside the expected array #define PM3_EOUTOFBOUND -17 +// exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer +#define PM3_ECARDEXCHANGE -18 // No data pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98 // Quit program client: reserved, order to quit the program diff --git a/tools/pm3_mf7b_wipe.py b/tools/pm3_mf7b_wipe.py new file mode 100644 index 000000000..9f7b29c6b --- /dev/null +++ b/tools/pm3_mf7b_wipe.py @@ -0,0 +1,150 @@ +#! /usr/bin/env python3.6 +# -*- coding: utf-8 -*- +# +# VULNERS OPENSOURCE +# __________________ +# +# Vulners Project [https://vulners.com] +# All Rights Reserved. +# +# Author: Kir [isox@vulners.com] +# Credits: Dennis Goh [dennis@rfidresearchgroup.com] +# +# This helper script is made for wiping S50 7byte UID cards with Gen2 magic commands from restored state to blank one. +# +# Scenario: +# You want to clone 7byte Mifare 1k card using RfidResearchGroup Proxmark3 RDV4.0 +# +# Step 1: Dumping original card and making a Mifare 7byte UID clone using S50 7byte UID +# +# Place original card to the reader. +# Dump data and recover keys +# +# hf mf autopwn +# +# You will get data, EML and key file. Backup this file, you will need them to wipe the card back to blank state. +# Place blank S50 card to the reader. +# +# Get first line from EML file (block0) and write it down using command +# +# Place it here +# | +# | +# v +# hf mf wrbl 0 B FFFFFFFFFFFF 046E46AAA53480084400120111003113 +# +# Now restore all the data using built-in restore command +# +# hf mf restore +# +# Step 2: Recovering S50 7byte UID card to the blank state +# +# Find current card data files from Step 1 in your backup or if you lost them create them again using 'hf mf autopwn' command. +# Place them in current working directory. +# +# Read hf-mf-CARD_UID-data.eml file and copy it content with CTRL-C. +# Place it to the eml variable in this script. +# +# Check execution command and check device and command name: 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1' +# +# Run script and review key blocks returning to default FFFFFFFFFFFF state. +# Be patient! It is executing aprox 3 minutes. +# Success one result looks like: +# +# Block 0: Success: isOk:01 +# Block 3: Success: isOk:01 +# Block 7: Success: isOk:01 +# Block 11: Success: isOk:01 +# Block 15: Success: isOk:01 +# Block 19: Success: isOk:01 +# Block 23: Success: isOk:01 +# Block 27: Success: isOk:01 +# Block 31: Success: isOk:01 +# Block 35: Success: isOk:01 +# Block 39: Success: isOk:01 +# Block 43: Success: isOk:01 +# Block 47: Success: isOk:01 +# Block 51: Success: isOk:01 +# Block 55: Success: isOk:01 +# Block 59: Success: isOk:01 +# Block 63: Success: isOk:01 +# +# Thats it! Your S50 7byte UID card is wiped back. Now you can return back to Step 1 of this manual. +# +# + + + + +import subprocess + +# EML data var te get keys of +EML_FILE_DATA = """PLACE RAW hf-mf-CARD_UID-data.eml FILE CONTENT OF CURRENTLY LOADED CARD HERE""" +# Change your device name here if it differs from the default Proxmark3 RDV4.0 +PROXMARK_BIN_EXEC_STRING = 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1' +# Constants +DEFAULT_ACCESS_BLOCK = "FFFFFFFFFFFFFF078000FFFFFFFFFFFF" +F12_KEY = "FFFFFFFFFFFF" + +def exec_proxmark_cmd(command, retry = 2, input=""): + exec_ok = False + retry_c = 0 + while not exec_ok and retry_c < retry: + sh_command = PROXMARK_BIN_EXEC_STRING % command + rst = subprocess.run(sh_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8")) + + proxmark_reply = rst.stdout.decode("utf-8") + proxmark_status = proxmark_reply.splitlines()[-1:][0].strip() + if proxmark_status == "isOk:01": + return True, "Success: " + proxmark_status + retry_c += 1 + return False, "Error: %s , status %s" % (proxmark_reply.splitlines()[-2:][0], proxmark_status) + + +def chunk(iterable,n): + """assumes n is an integer>0 + """ + iterable=iter(iterable) + while True: + result=[] + for i in range(n): + try: + a=next(iterable) + except StopIteration: + break + else: + result.append(a) + if result: + yield result + else: + break + +sector_array = [sector for sector in chunk(EML_FILE_DATA.splitlines(), 4)] +block = 0 +block_success = {} + +for sector in sector_array: + key_A = sector[3][:12] + key_B = sector[3][-12:] + for _block in range(0,4): + if sector_array.index(sector) == 0 and block == 0: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, sector[0])) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, sector[0])) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, sector[0])) + block_success[block] = verbose + + elif _block == 3: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, DEFAULT_ACCESS_BLOCK)) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, DEFAULT_ACCESS_BLOCK)) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, DEFAULT_ACCESS_BLOCK)) + block_success[block] = verbose + + _block += 1 + block += 1 + +for block in block_success: + print("Block %s: %s" % (block ,block_success[block]))