diff --git a/CHANGELOG.md b/CHANGELOG.md index 94d492c41..ca0fede15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ 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] + +## [Seven.4.16717][2023-06-25] + - Change `hf 14a info` - now identifes QL88 tags (@iceman1001) + - Added support for compiling on iOS (@The-SamminAter) + - Fixed viewing MFC dump - border char is now white (@iceman1001) + - Changed `data diff` - to print filenames in header if it fits (@iceman1001) + - Changed viewing MFC dump files - it now colors ACL + GPB bytes (@iceman1001) + - Added `hf mf supercard --furui` - now supports key recovery from Furui detection card. Thanks foxushka! (@iceman1001) + - Added `hf topaz dump --ns` - now supports nosave param (@iceman1001) + - Changed `hf topaz rdbl` - unified output (@iceman1001) + - Fixed `hf topaz wrbl` - now supports tear off and write_nonerase command (@iceman1001) + - Fixed `hf mf` commands (@iceman1001) + - Fixed `hf mfp` commands (@iceman1001) + - Added more default keys (@iceman1001) Thanks anon! - Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001) - Fixed `hf 15693/iclass sniff` trace timings (@nvx) - Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp) diff --git a/Makefile.defs b/Makefile.defs index bcbbaa67e..76409a37d 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -75,7 +75,15 @@ else endif ifeq ($(platform),Darwin) - USE_BREW ?= 1 + ifeq ($(shell uname -p),arm64) + # The platform is iOS + USE_BREW ?= 0 + # iOS refuses to compile unless this is set + export IPHONEOS_DEPLOYMENT_TARGET=11.0 + else + # M* macOS devices return arm + USE_BREW ?= 1 + endif USE_MACPORTS ?= 0 AR= /usr/bin/ar rcs RANLIB= /usr/bin/ranlib @@ -132,6 +140,10 @@ ifeq ($(shell expr $(CC_VERSION) \>= 10), 1) endif endif ifeq ($(platform),Darwin) + ifeq ($(shell uname -p),arm64) + # iOS will refuse to compile without the minimum target of iOS 11.0 + DEFCFLAGS += -mios-version-min=11.0 + endif # their readline has strict-prototype issues DEFCFLAGS += -Wno-strict-prototypes # some warnings about braced initializers on structs we want to ignore diff --git a/README.md b/README.md index 20416bdbb..9096c9559 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Iceman Fork - Proxmark3 a RFID / NFC project. +# Iceman Fork - Proxmark3 The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the vast majority of RFID tags on a global scale. Originally built by Jonathan Westhues, the device is now the goto tool for RFID Analysis for the enthusiast. Iceman repository is considered to be the pinnacle of features and functionality, enabling a huge range of extremely useful and convenient commands and LUA scripts to automate chip identification, penetration testing, and programming diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 01eed12c1..9cff73f63 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -3094,13 +3094,33 @@ void ReaderIso14443a(PacketCommandNG *c) { } } - if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred - FpgaDisableTracing(); - reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); + if ((param & ISO14A_TOPAZMODE)) { + + if (cmd[0] == TOPAZ_WRITE_E8 || cmd[0] == TOPAZ_WRITE_NE8) { + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred + FpgaDisableTracing(); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); + } else { + arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + } + } else { + arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + } + } else { - arg0 = ReaderReceive(buf, par); - FpgaDisableTracing(); - reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred + FpgaDisableTracing(); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); + } else { + arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + } } } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 703f1288f..a52b953ff 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1835,20 +1835,20 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla switch_off(); DbpString(""); - DbpString(_CYAN_("Sniff statistics")); - DbpString("================================="); - Dbprintf(" DecodeTag State........%d", dtag.state); - Dbprintf(" DecodeTag byteCnt......%d", dtag.len); - Dbprintf(" DecodeTag posCount.....%d", dtag.posCount); - Dbprintf(" DecodeTagFSK State.....%d", dtagfsk.state); - Dbprintf(" DecodeTagFSK byteCnt...%d", dtagfsk.len); - Dbprintf(" DecodeTagFSK count.....%d", dtagfsk.count); - Dbprintf(" DecodeReader State.....%d", dreader.state); - Dbprintf(" DecodeReader byteCnt...%d", dreader.byteCount); - Dbprintf(" DecodeReader posCount..%d", dreader.posCount); - Dbprintf(" Trace length..........." _YELLOW_("%d"), BigBuf_get_traceLen()); - DbpString(""); - + if (g_dbglevel > DBG_ERROR) { + DbpString(_CYAN_("Sniff statistics")); + DbpString("================================="); + Dbprintf("DecodeTag State........ %d", dtag.state); + Dbprintf("DecodeTag byteCnt...... %d", dtag.len); + Dbprintf("DecodeTag posCount..... %d", dtag.posCount); + Dbprintf("DecodeTagFSK State..... %d", dtagfsk.state); + Dbprintf("DecodeTagFSK byteCnt... %d", dtagfsk.len); + Dbprintf("DecodeTagFSK count..... %d", dtagfsk.count); + Dbprintf("DecodeReader State..... %d", dreader.state); + Dbprintf("DecodeReader byteCnt... %d", dreader.byteCount); + Dbprintf("DecodeReader posCount.. %d", dreader.posCount); + } + Dbprintf("Trace length........... " _YELLOW_("%d"), BigBuf_get_traceLen()); } // Initialize Proxmark3 as ISO15693 reader diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 5dd5dfcf6..c8a2d5fa2 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -484,8 +484,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { if (res == PM3_ETEAROFF) { retval = PM3_ETEAROFF; goto OUT; - } else if (res) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + } else if (res != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); retval = PM3_ESOFT; goto OUT; } @@ -554,7 +554,7 @@ void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t if (res == PM3_ETEAROFF) { retval = PM3_ETEAROFF; goto OUT; - } else if (res) { + } else if (res != PM3_SUCCESS) { retval = PM3_ESOFT; goto OUT; } @@ -688,8 +688,8 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { break; }; - if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); break; }; @@ -777,8 +777,8 @@ static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, boo } } - if (mifare_ultra_writeblock(blockNo, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock(blockNo, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(0); return; }; @@ -851,8 +851,8 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) { } } - if (mifare_ultra_writeblock_compat(blockNo, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock_compat(blockNo, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(0); return; }; @@ -896,8 +896,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[1] = pwd[6]; blockdata[2] = pwd[5]; blockdata[3] = pwd[4]; - if (mifare_ultra_writeblock(44, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock(44, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(44); return; }; @@ -906,8 +906,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[1] = pwd[2]; blockdata[2] = pwd[1]; blockdata[3] = pwd[0]; - if (mifare_ultra_writeblock(45, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock(45, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(45); return; }; @@ -916,8 +916,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[1] = pwd[14]; blockdata[2] = pwd[13]; blockdata[3] = pwd[12]; - if (mifare_ultra_writeblock(46, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock(46, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(46); return; }; @@ -926,8 +926,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[1] = pwd[10]; blockdata[2] = pwd[9]; blockdata[3] = pwd[8]; - if (mifare_ultra_writeblock(47, blockdata)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error"); + if (mifare_ultra_writeblock(47, blockdata) != PM3_SUCCESS) { + if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error"); OnError(47); return; }; @@ -1522,7 +1522,6 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, target_ks[0] = nt2 ^ target_nt[0]; // second collection - if (mifare_classic_halt(pcs, cuid)) { continue; } @@ -2303,64 +2302,98 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype) { int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { - uint32_t cuid = 0; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // variables - uint8_t dataoutbuf[16] = {0x00}; - uint8_t dataoutbuf2[16] = {0x00}; - uint8_t uid[10] = {0x00}; - LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); set_tracing(true); + // variables + bool have_uid = false; + uint8_t cascade_levels = 0; + uint32_t cuid = 0; + uint8_t uid[10] = {0x00}; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + int retval = PM3_SUCCESS; - if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - retval = PM3_ESOFT; - if (g_dbglevel > DBG_ERROR) Dbprintf("Can't select card"); - goto out; - } + for (uint8_t s = 0; s < sectorcnt; s++) { + uint64_t ui64Key = emlGetKey(s, keytype); - for (uint8_t sectorNo = 0; sectorNo < sectorcnt; sectorNo++) { - uint64_t ui64Key = emlGetKey(sectorNo, keytype); - if (sectorNo == 0) { - if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) { - retval = PM3_EPARTIAL; - if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo); + // MFC 1K EV1 sector 16,17 don't use key A. + if ((sectorcnt == 18) && (keytype == 0) && s > 15) { + continue; + } + + // use fast select + if (have_uid == false) { // need a full select cycle to get the uid first + iso14a_card_select_t card_info; + if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) { continue; } - } else { - if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) { - retval = PM3_EPARTIAL; - if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); + + switch (card_info.uidlen) { + case 4 : + cascade_levels = 1; + break; + case 7 : + cascade_levels = 2; + break; + case 10: + cascade_levels = 3; + break; + default: + break; + } + have_uid = true; + } else { // no need for anticollision. We can directly select the card + if (iso14443a_fast_select_card(uid, cascade_levels) == 0) { continue; } } - for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { - if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { - retval = PM3_EPARTIAL; - - if (g_dbglevel > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); - continue; + // Auth + if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(s), keytype, ui64Key, AUTH_FIRST)) { + retval = PM3_EPARTIAL; + if (g_dbglevel > DBG_ERROR) { + Dbprintf("Sector %2d - Auth error", s); } + continue; + } - if (memcmp(dataoutbuf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - continue; - } +#define MAX_RETRIES 2 - if (blockNo < NumBlocksPerSector(sectorNo) - 1) { - emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); - } else { // sector trailer, keep the keys, set only the AC - emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); - memcpy(dataoutbuf2 + 6, dataoutbuf + 6, 4); - emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); + uint8_t data[16] = {0x00}; + for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) { + + memset(data, 0x00, sizeof(data)); + + for (uint8_t r = 0; r < MAX_RETRIES; r++) { + + if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(s) + b, data)) { + retval |= PM3_EPARTIAL; + if (g_dbglevel > DBG_ERROR) { + Dbprintf("Error reading sector %2d block %2d", s, b); + } + continue; + } + + // No need to copy empty + if (memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { + continue; + } + + if (b < NumBlocksPerSector(s) - 1) { + emlSetMem(data, FirstBlockOfSector(s) + b, 1); + } else { + // sector trailer, keep the keys, set only the AC + uint8_t st[16] = {0x00}; + emlGetMem(st, FirstBlockOfSector(s) + b, 1); + memcpy(st + 6, data + 6, 4); + emlSetMem(st, FirstBlockOfSector(s) + b, 1); + } } } } @@ -2368,9 +2401,6 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { int res = mifare_classic_halt(pcs, cuid); (void)res; - if (g_dbglevel >= DBG_INFO) DbpString("Emulator fill sectors finished"); - -out: crypto1_deinit(pcs); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -2601,6 +2631,7 @@ void MifareCIdent(bool is_mfc) { uint8_t gen4gmd[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92}; uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0}; uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D}; + uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE); uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE); uint8_t *uid = BigBuf_malloc(10); @@ -2757,7 +2788,24 @@ void MifareCIdent(bool is_mfc) { isGen = MAGIC_GEN_4GDM; } } + + if (isGen != MAGIC_GEN_4GDM) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(40); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true); + if (res == 2) { + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) { + isGen = MAGIC_QL88; + } + crypto1_deinit(pcs); + } + } } + } }; @@ -2836,6 +2884,10 @@ OUT: crypto1_deinit(pcs); } +// FUDAN card w static encrypted nonces +// 2B F9 1C 1B D5 08 48 48 03 A4 B1 B1 75 FF 2D 90 +// ^^ ^^ + void OnSuccessMagic(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -3218,7 +3270,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain) { return; }; - if (mifare_desfire_des_auth1(cuid, dataout)) { + if (mifare_desfire_des_auth1(cuid, dataout) != PM3_SUCCESS) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication part1: Fail."); OnError(4); return; @@ -3238,7 +3290,7 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) { isOK = mifare_desfire_des_auth2(cuid, key, dataout); - if (isOK) { + if (isOK != PM3_SUCCESS) { if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); OnError(4); return; diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index c2f81df21..5aa1a054a 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -46,6 +46,15 @@ #include "dbprint.h" #include "ticks.h" +static bool IsKeyBReadable(uint8_t blockNo) { + uint8_t sector_trailer[16]; + emlGetMem(sector_trailer, SectorTrailer(blockNo), 1); + uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) + | ((sector_trailer[8] >> 2) & 0x02) + | ((sector_trailer[8] >> 7) & 0x01); + return (AC == 0x00 || AC == 0x01 || AC == 0x02); +} + static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { uint8_t sector_trailer[16]; emlGetMem(sector_trailer, blockNo, 1); @@ -872,8 +881,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 break; } */ - - if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { + blockNo = receivedCmd_dec[1]; + if (MifareBlockToSector(blockNo) != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); FpgaDisableTracing(); @@ -881,6 +890,18 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); break; } + + // Compliance of MIFARE Classic EV1 1K Datasheet footnote of Table 8 + // If access bits show that key B is Readable, any subsequent memory access will be refused. + + if (cardAUTHKEY == AUTHKEYB && IsKeyBReadable(blockNo)) { + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + + if (g_dbglevel >= DBG_ERROR) + Dbprintf("[MFEMUL_WORK] Access denied: Reader tried to access memory on authentication with key B while key B is readable in sector (0x%02x)", cardAUTHSC); + break; + } } // case MFEMUL_WORK => CMD READ block diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 472c2616f..b17ac19bc 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -433,8 +433,8 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t } if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; + if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return PM3_EFAILED; } uint8_t d_block[18], d_block_enc[18]; @@ -465,11 +465,11 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; if ((len != 1) || (res != 0x0A)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); - return 2; + if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res); + return PM3_EFAILED; } } - return 0; + return PM3_SUCCESS; } int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) { @@ -480,7 +480,7 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { - return 1; + return PM3_EFAILED; } uint8_t d_block[18], d_block_enc[18]; @@ -511,14 +511,12 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; if ((len != 1) || (res != 0x0A)) { - return 2; + return PM3_EFAILED; } } - return 0; + return PM3_SUCCESS; } - - int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) { // variables uint16_t len = 0; @@ -540,8 +538,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; + if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + return PM3_EFAILED; } memcpy(d_block, blockData, 4); @@ -566,12 +564,12 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3; if ((len != 1) || (res != 0x0A)) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res); - return 2; + if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res); + return PM3_EFAILED; } } - return 0; + return PM3_SUCCESS; } int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { @@ -585,9 +583,10 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (g_dbglevel >= DBG_ERROR) + if (g_dbglevel >= DBG_INFO) { Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); - return 1; + } + return PM3_EFAILED; } memcpy(d_block, blockData, 16); @@ -599,11 +598,12 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { len = ReaderReceive(receivedAnswer, receivedAnswerPar); if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (g_dbglevel >= DBG_ERROR) + if (g_dbglevel >= DBG_INFO) { Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len); - return 2; + } + return PM3_EFAILED; } - return 0; + return PM3_SUCCESS; } int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) { @@ -618,11 +618,12 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) { len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL); if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK - if (g_dbglevel >= DBG_ERROR) + if (g_dbglevel >= DBG_INFO) { Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len); - return 1; + } + return PM3_EFAILED; } - return 0; + return PM3_SUCCESS; } int mifare_classic_halt_ex(struct Crypto1State *pcs) { uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00}; @@ -729,8 +730,8 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { uint64_t emlGetKey(int sectorNum, int keyType) { uint8_t key[6] = {0x00}; - uint8_t *emCARD = BigBuf_get_EM_addr(); - memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); + uint8_t *em = BigBuf_get_EM_addr(); + memcpy(key, em + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); return bytes_to_num(key, 6); } @@ -804,9 +805,10 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) { len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { - if (g_dbglevel >= DBG_ERROR) + if (g_dbglevel >= DBG_INFO) { Dbprintf("Cmd Error: %02x", receivedAnswer[0]); - return 1; + } + return PM3_EFAILED; } if (len == 12) { @@ -817,9 +819,9 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) { receivedAnswer[10], receivedAnswer[11]); } memcpy(blockData, receivedAnswer, 12); - return 0; + return PM3_SUCCESS; } - return 1; + return PM3_EFAILED; } int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) { @@ -834,9 +836,10 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) { len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL); if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { - if (g_dbglevel >= DBG_ERROR) + if (g_dbglevel >= DBG_ERROR) { Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); - return 1; + } + return PM3_EFAILED; } if (len == 12) { @@ -847,7 +850,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) { receivedAnswer[10], receivedAnswer[11]); } memcpy(blockData, receivedAnswer, 12); - return 0; + return PM3_SUCCESS; } - return 1; + return PM3_EFAILED; } diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 3fd255997..8759c00f3 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}") if (APPLE) message(STATUS "Apple device detected.") set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC}) - set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") + + find_library(UIKIT_LIBRARY UIKit) + if (NOT UIKIT_LIBRARY) + message(STATUS "UIKit.framework NOT found!") + else() + message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}") + set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit") + endif() + + find_library(APPKIT_LIBRARY AppKit) + if (NOT APPKIT_LIBRARY) + message(STATUS "AppKit.framework NOT found!") + else() + message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}") + set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") + endif() + endif (APPLE) if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND)) diff --git a/client/Makefile b/client/Makefile index d0cee355e..d44e67011 100644 --- a/client/Makefile +++ b/client/Makefile @@ -434,7 +434,13 @@ LDFLAGS += $(MYLDFLAGS) PM3LDFLAGS = $(LDFLAGS) ifeq ($(platform),Darwin) - PM3LDFLAGS += -framework Foundation -framework AppKit + ifeq ($(shell uname -p),arm64) + # The platform is iOS + PM3LDFLAGS += -framework Foundation -framework UIKit + else + # M* macOS devices return arm + PM3LDFLAGS += -framework Foundation -framework AppKit + endif endif ################### diff --git a/client/deps/hardnested/Makefile b/client/deps/hardnested/Makefile index 1667e036f..badace7e5 100644 --- a/client/deps/hardnested/Makefile +++ b/client/deps/hardnested/Makefile @@ -22,6 +22,9 @@ endif ifneq ($(findstring aarch64, $(cpu_arch)), ) IS_SIMD_ARCH=arm64 endif +ifneq ($(findstring iP, $(cpu_arch)), ) + IS_SIMD_ARCH=arm64 +endif ifneq ($(IS_SIMD_ARCH), ) MULTIARCHSRCS = hardnested_bf_core.c hardnested_bitarray_core.c diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 63598f78b..d32346428 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -31,6 +31,11 @@ D01AFEEB890A # 17 B 4B791BEA7BCC # +# QL88 keys +# 17 A/B +2612C6DE84CA +707B11FC1481 +# # B0B1B2B3B4B5 C0C1C2C3C4C5 @@ -145,6 +150,9 @@ F1D83F964314 222222222222 27DD91F1FCF1 # +# Hotel system +505209016A1F +# # Directory and eventlog KeyB 2BA9621E0A36 # diff --git a/client/dictionaries/t55xx_default_pwds.dic b/client/dictionaries/t55xx_default_pwds.dic index e56904ea4..fc9c6bb8b 100644 --- a/client/dictionaries/t55xx_default_pwds.dic +++ b/client/dictionaries/t55xx_default_pwds.dic @@ -37,7 +37,7 @@ A5B4C3D2 E9920427 # paxton bullit? 575F4F4B -# +# Hotel system 50520901 # iCopy-X 20206666 @@ -52,6 +52,8 @@ C0F5009A # prefered pwds of members in the community FEEDBEEF DEADC0DE +# derived from BCARD key B +A9EF2AFC # Default pwd, simple: 00000000 11111111 diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 2ac10f871..60e7b4004 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}") if (APPLE) message(STATUS "Apple device detected.") set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC}) - set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") + + find_library(UIKIT_LIBRARY UIKit) + if (NOT UIKIT_LIBRARY) + message(STATUS "UIKit.framework NOT found!") + else() + message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}") + set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit") + endif() + + find_library(APPKIT_LIBRARY AppKit) + if (NOT APPKIT_LIBRARY) + message(STATUS "AppKit.framework NOT found!") + else() + message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}") + set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit") + endif() + endif (APPLE) if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND)) diff --git a/client/luascripts/hf_legic.lua b/client/luascripts/hf_legic.lua index 21684b6fb..cbec05f9f 100644 --- a/client/luascripts/hf_legic.lua +++ b/client/luascripts/hf_legic.lua @@ -2520,11 +2520,11 @@ function modifyMode() --- -- edit data-portion of single segment ["ed"] = function(x) - if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10) - else sel=selectSegment(inTAG) end + if (type(x) == "string" and string.len(x)>0) then sel=tonumber(x,10) + else sel = selectSegment(inTAG) end if (istable(inTAG.SEG[sel])) then - local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 - inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data, uid) + local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2 + inTAG.SEG[sel].data = editSegmentData(inTAG.SEG[sel].data, uid) end end, --- diff --git a/client/luascripts/lf_ident_json.lua b/client/luascripts/lf_ident_json.lua index 73794547c..11657910d 100644 --- a/client/luascripts/lf_ident_json.lua +++ b/client/luascripts/lf_ident_json.lua @@ -113,7 +113,7 @@ local function getDefault(block0) block0 = block0:upper() - local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks + local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks local T55X7_RAW_CONFIG_BLOCK = '000880E0' --// compat mode, RF/32, manchester, 7 data blocks local T55X7_EM_UNIQUE_CONFIG_BLOCK = '00148040' --// emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks -- FDXB requires data inversion and BiPhase 57 is simply BipHase 50 inverted, so we can either do it using the modulation scheme or the inversion flag diff --git a/client/pyscripts/pm3_help2json.py b/client/pyscripts/pm3_help2json.py index 8099b5d7c..34faedec5 100755 --- a/client/pyscripts/pm3_help2json.py +++ b/client/pyscripts/pm3_help2json.py @@ -62,21 +62,19 @@ def build_arg_parser(): def build_help_regex(): - """The regex uses to parse the full text output of help data from the pm3 client.""" - # Reads the divider followed by the command itself re_command = r'-{87}\n(?P.+)\n' # Reads if the command is available offline re_offline = r'available offline: (?Pyes|no)\n+' # Reads the description lines - re_description = r'(?P(?:.+\n)+)\n+' + re_description = r'(?P\n[\s\S]*?(?=usage:))' # Reads the usage string re_usage = r'(?:usage:\n(?P(?:.+\n)+)\n+)?' # Reads the options and there individual descriptions re_options = r'(?:options:\n(?P(?:.+\n)+)\n+)?' # Reads the notes and examples - re_notes = r'(?:examples\/notes:\n(?P(?:.+\n)+)\n+)?' + re_notes = r'(?:examples\/notes:\n(?P[\s\S]*?(?=(===|---|\n\n))))' # Combine them into a single regex object - re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE); + re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE) return re_full diff --git a/client/resources/aidlist.json b/client/resources/aidlist.json index ff574dd6a..9173d0a10 100644 --- a/client/resources/aidlist.json +++ b/client/resources/aidlist.json @@ -2255,13 +2255,21 @@ "Description": "Student ID cards", "Type": "identity" }, + { + "AID": "D2760000254D010200", + "Vendor": "Zentraler Kreditausschuss (ZKA)", + "Country": "Germany", + "Name": "Girocard Jugendschutz", + "Description": "Age verification", + "Type": "identity" + }, { "AID": "A000000809434343444B467631", "Vendor": "Car Connectivity Consortium (CCC)", "Country": "", "Name": "Digital Car Key Framework", "Description": "Used during key provisioning and configuration", - "Type": "access" + "Type": "" }, { "AID": "A000000809434343444B417631", @@ -2295,13 +2303,69 @@ "Description": "AID prefix used by MIFARE 2GO-based cards", "Type": "" }, + { + "AID": "A00000039656434103F1216000000000", + "Vendor": "LV Monorail", + "Country": "United States", + "Name": "Las Vegas Monorail", + "Description": "", + "Type": "transport" + }, + { + "AID": "A00000039656434103F8852200000000", + "Vendor": "Ubian", + "Country": "Slovakia", + "Name": "Ubian digital transit card", + "Description": "DESFire-based virtual transit card", + "Type": "transport" + }, + { + "AID": "DE5C0D1F1CADA5", + "Vendor": "CRTM", + "Country": "Spain", + "Name": "Madrid transit card", + "Description": "DESFire-based transit card", + "Type": "transport" + }, + { + "AID": "A00000F21100", + "Vendor": "PTV", + "Country": "Australia", + "Name": "Myki transit card", + "Description": "DESFire-based transit card", + "Type": "transport" + }, + { + "AID": "637001ff4c41", + "Vendor": "Cubic", + "Country": "United States", + "Name": "LA Tap", + "Description": "DESFire-based transit card (ASCII cp\\x01\\xffLA)", + "Type": "transport" + }, + { + "AID": "637001ff574d415441", + "Vendor": "Cubic", + "Country": "United States", + "Name": "Smart Trip", + "Description": "DESFire-based transit card (ASCII cp\\x01\\xffWMATA)", + "Type": "transport" + }, + { + "AID": "637001ff434c4950504552", + "Vendor": "Cubic", + "Country": "United States", + "Name": "Clipper", + "Description": "DESFire-based transit card (ASCII cp\\x01\\xffCLIPPER)", + "Type": "transport" + }, { "AID": "A0000002164954534F2D31", "Vendor": "ITSO", "Country": "United Kingdom", "Name": "ITSO CMD2", "Description": "AID used by ITSO for smartcard/phone-based transit cards", - "Type": "transit" + "Type": "transport" }, { "AID": "A000000632010105", @@ -2309,22 +2373,38 @@ "Country": "China", "Name": "China T-Union", "Description": "Universal transit card used by many big public transit operators", - "Type": "transit" - }, - { - "AID": "D2760000254D010200", - "Vendor": "Zentraler Kreditausschuss (ZKA)", - "Country": "Germany", - "Name": "Girocard Jugendschutz", - "Description": "Age verification", - "Type": "" + "Type": "transport" }, { "AID": "A00000000491", "Vendor": "MasterCard International", "Country": "", "Name": "Mastercard Private Label Transit", - "Description": "AID prefix used by transit cards that use private label mastercards (E.g. Ventra and HOP)", - "Type": "transit" + "Description": "AID prefix used by transit cards that use private label mastercard", + "Type": "transport" + }, + { + "AID": "A0000000049100", + "Vendor": "MasterCard International", + "Country": "United States", + "Name": "HOP Fastpass", + "Description": "", + "Type": "transport" + }, + { + "AID": "A0000000049101", + "Vendor": "MasterCard International", + "Country": "United States", + "Name": "Ventra", + "Description": "", + "Type": "transport" + }, + { + "AID": "A000000858044F53452E4348", + "Vendor": "Apple", + "Country": "", + "Name": "AirDrop connection negotiation", + "Description": "Used by NFC-based AirDrop negotiation added in IOS17", + "Type": "" } ] diff --git a/client/resources/mad.json b/client/resources/mad.json index cfa6294d3..38cdf2636 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -4073,6 +4073,20 @@ "service_provider": "HID Corporation", "system_integrator": "HID Corporation" }, + { + "application": "City transport, prepaid ticket, cardholder, servicespass", + "company": "Ridango AS", + "mad": "0x3C56", + "service_provider": "Pilet.ee ekaart", + "system_integrator": "Pilet.ee ekaart" + }, + { + "application": "City transport, prepaid ticket, cardholder, servicespass", + "company": "Ridango AS", + "mad": "0x3D56", + "service_provider": "Pilet.ee ekaart", + "system_integrator": "Pilet.ee ekaart" + }, { "application": "City transport bus, ferry, administration", "company": "VFJ Technology Pty Ltd", diff --git a/client/src/cmddata.c b/client/src/cmddata.c index 9524cbc63..032d31f85 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -2939,7 +2939,7 @@ static int CmdDiff(const char *Cmd) { // "data diff -a fileA --cb\n" "data diff --fa fileA -b fileB\n" "data diff --fa fileA --fb fileB\n" - "data diff --ea --cb\n" +// "data diff --ea --cb\n" ); void *argtable[] = { @@ -3083,10 +3083,19 @@ static int CmdDiff(const char *Cmd) { PrintAndLogEx(INFO, "inB null"); int hdr_sln = (width * 4) + 2; + char hdr0[300] = {0}; - char hdr0[200] = " # | " _CYAN_("a"); - memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2); - strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b")); + int max_fn_space = (width * 5); + + if (fnlenA && fnlenB && (max_fn_space > fnlenA) && (max_fn_space > fnlenB)) { + snprintf(hdr0, sizeof(hdr0) - 1, " # | " _CYAN_("%.*s"), max_fn_space, filenameA); + memset(hdr0 + strlen(hdr0), ' ', hdr_sln - strlen(filenameA) - 1); + snprintf(hdr0 + strlen(hdr0), sizeof(hdr0) - 1 - strlen(hdr0), "| " _CYAN_("%.*s"), max_fn_space, filenameB); + } else { + strcat(hdr0, " # | " _CYAN_("a")); + memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2); + strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b")); + } char hdr1[200] = "----+"; memset(hdr1 + strlen(hdr1), '-', hdr_sln); diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index d0083fbb5..29a985b29 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -2229,33 +2229,35 @@ int infoHF14B(bool verbose, bool do_aid_search) { // get and print general info about all known 14b chips int readHF14B(bool loop, bool verbose) { + bool found = false; do { + found = false; + // try std 14b (atqb) - if (HF14B_std_reader(verbose)) - if (loop) - continue; + found |= HF14B_std_reader(verbose); + if (found && loop) + continue; // try ST Microelectronics 14b - if (HF14B_st_reader(verbose)) - if (loop) - continue; + found |= HF14B_st_reader(verbose); + if (found && loop) + continue; // try ASK CT 14b - if (HF14B_ask_ct_reader(verbose)) - if (loop) - continue; + found |= HF14B_ask_ct_reader(verbose); + if (found && loop) + continue; // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_other_reader(verbose)) - if (loop) - continue; - + found |= HF14B_other_reader(verbose); + if (found && loop) + continue; } while (loop && kbd_enter_pressed() == false); - if (verbose) { + if (verbose && found == false) { PrintAndLogEx(FAILED, "no ISO 14443-B tag found"); } - return PM3_EOPABORTED; + return (found) ? PM3_SUCCESS : PM3_EOPABORTED; } diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index c80f8cac4..c16bfb10b 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -48,7 +48,7 @@ #define Logic1 Iso15693Logic1 #define FrameEOF Iso15693FrameEOF #define CARD_MEMORY_SIZE 4096 -#define HF15_UID_LENGTH 8 +#define HF15_UID_LENGTH 8 #ifndef Crc15 # define Crc15(data, len) Crc16ex(CRC_15693, (data), (len)) diff --git a/client/src/cmdhffudan.c b/client/src/cmdhffudan.c index 502425f83..38ef8eef5 100644 --- a/client/src/cmdhffudan.c +++ b/client/src/cmdhffudan.c @@ -355,7 +355,7 @@ static int CmdHFFudanWrBl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf fudan wrbl", "Write fudan block with 4 hex bytes of data\n", - "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304" + "hf fudan wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304" ); void *argtable[] = { arg_param_begin, diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index ba6d984ad..a48bbb98e 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -683,8 +683,13 @@ static int CmdHFiClassSniff(const char *Cmd) { WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing"); + if (jam_epurse_update) { + PrintAndLogEx(HINT, "Verify if the jam worked by comparing value in trace and block 2"); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 02a43e0aa..b842ddf54 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -682,7 +682,7 @@ static int CmdLegicCalcCrc(const char *Cmd) { switch (type) { case 16: - init_table(CRC_LEGIC); + init_table(CRC_LEGIC_16); PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0])); break; default: diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index fe0ee46b0..5ddd3f1fa 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -189,7 +189,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i if (cmd[1] == 0x01 && cmdsize == 7) { snprintf(exp, size, "ECP1"); return PM3_SUCCESS; - } else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0f) + 7) { + } else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0F) + 7) { // Byte 3 is the reader type switch (cmd[3]) { case 0x01: @@ -201,6 +201,9 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i case 0x03: snprintf(exp, size, "ECP2 (Identity)"); break; + case 0x05: + snprintf(exp, size, "ECP2 (AirDrop)"); + break; default: snprintf(exp, size, "ECP2"); break; @@ -496,7 +499,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool uint8_t key[8]; if (check_known_default(csn, epurse, rmac, tmac, key)) { - snprintf(exp, size, "CHECK ( %s )", sprint_hex_inrow(key, 8)); + snprintf(exp, size, "CHECK ( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8)); } else { snprintf(exp, size, "CHECK"); } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 6aac4677c..2eb7fa415 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -226,10 +226,38 @@ bool mfc_value(const uint8_t *d, int32_t *val) { } void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { + if (blockno == 0) { - PrintAndLogEx(INFO, "%3d | " _RED_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); + char ascii[24] = {0}; + ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); + PrintAndLogEx(INFO, "%3d | " _RED_("%s") "| " _RED_("%s"), + blockno, + sprint_hex(d, MFBLOCK_SIZE), + ascii + ); } else if (mfIsSectorTrailer(blockno)) { - PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s"), blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); + + char keya[26] = {0}; + hex_to_buffer((uint8_t *)keya, d, MIFARE_KEY_SIZE, sizeof(keya) - 1, 0, 1, true); + + char acl[20] = {0}; + hex_to_buffer((uint8_t *)acl, d + MIFARE_KEY_SIZE, 3, sizeof(acl) - 1, 0, 1, true); + + char keyb[26] = {0}; + hex_to_buffer((uint8_t *)keyb, d + 10, MIFARE_KEY_SIZE, sizeof(keyb) - 1, 0, 1, true); + + char ascii[24] = {0}; + ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); + + PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"), + blockno, + keya, + acl, + d[9], + keyb, + ascii + ); + } else { int32_t value = 0; if (verbose && mfc_value(d, &value)) { @@ -249,9 +277,38 @@ static void mf_print_block(uint8_t blockno, uint8_t *d, bool verbose) { } if (blockno == 0) { - PrintAndLogEx(INFO, "%s| %3d | " _RED_("%s"), secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); + char ascii[24] = {0}; + ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); + PrintAndLogEx(INFO, "%s| %3d | " _RED_("%s") "| " _RED_("%s"), + secstr, + blockno, + sprint_hex(d, MFBLOCK_SIZE), + ascii + ); + } else if (mfIsSectorTrailer(blockno)) { - PrintAndLogEx(INFO, "%s| %3d | " _YELLOW_("%s"), secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); + + char keya[26] = {0}; + hex_to_buffer((uint8_t *)keya, d, MIFARE_KEY_SIZE, sizeof(keya) - 1, 0, 1, true); + + char acl[20] = {0}; + hex_to_buffer((uint8_t *)acl, d + MIFARE_KEY_SIZE, 3, sizeof(acl) - 1, 0, 1, true); + + char keyb[26] = {0}; + hex_to_buffer((uint8_t *)keyb, d + 10, MIFARE_KEY_SIZE, sizeof(keyb) - 1, 0, 1, true); + + char ascii[24] = {0}; + ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); + + PrintAndLogEx(INFO, "%s| %3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"), + secstr, + blockno, + keya, + acl, + d[9], + keyb, + ascii + ); } else { int32_t value = 0; if (verbose && mfc_value(d, &value)) { @@ -280,8 +337,8 @@ static void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) { PrintAndLogEx(NORMAL, ""); } +// assumes n is in number of blocks 0..255 static int mf_print_keys(uint16_t n, uint8_t *d) { - uint8_t sectors = 0; switch (n) { case MIFARE_MINI_MAXBLOCK: @@ -321,6 +378,7 @@ static int mf_print_keys(uint16_t n, uint8_t *d) { } // MFC dump , extract and save the keys to key file +// assumes n is in number of blocks 0..255 static int mf_save_keys_from_arr(uint16_t n, uint8_t *d) { uint8_t sectors = 0; switch (n) { @@ -360,7 +418,7 @@ static int mf_save_keys_from_arr(uint16_t n, uint8_t *d) { } char fn[FILE_PATH_SIZE] = {0}; - snprintf(fn, sizeof(fn), "hf-mf-%s-keys", sprint_hex_inrow(d, 4)); + snprintf(fn, sizeof(fn), "hf-mf-%s-key", sprint_hex_inrow(d, 4)); saveFile(fn, ".bin", keys, keysize); free(keys); return PM3_SUCCESS; @@ -412,6 +470,7 @@ static bool mf_write_block(const uint8_t *key, uint8_t keytype, uint8_t blockno, return (resp.oldarg[0] & 0xff); } +// assumes n is in number of blocks 0..255 static void mf_analyse_acl(uint16_t n, uint8_t *d) { for (uint16_t b = 3; b < n; b++) { @@ -590,12 +649,13 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n current_key = MF_KEY_A; uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5; if (rights[sectorNo][data_area] == 0x07) { // no key would work - PrintAndLogEx(WARNING, "access rights do not allow reading of sector %2d block %3d, skipping", sectorNo, blockNo); + PrintAndLogEx(WARNING, "access rights do not allow reading of sector " _YELLOW_("%2d") " block " _YELLOW_("%3d") ", skipping", sectorNo, blockNo); continue; } for (uint8_t tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { - if (mfIsSectorTrailer(blockNo)) { + + if (mfIsSectorTrailerBasedOnBlocks(sectorNo, blockNo)) { // sector trailer. At least the Access Conditions can always be read with key A. payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; @@ -649,16 +709,16 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n uint8_t *data = resp.data.asBytes; - if (mfIsSectorTrailer(blockNo)) { + if (mfIsSectorTrailerBasedOnBlocks(sectorNo, blockNo)) { // sector trailer. Fill in the keys. memcpy(data, keyA + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); memcpy(data + 10, keyB + (sectorNo * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); } memcpy(carddata + (MFBLOCK_SIZE * (mfFirstBlockOfSector(sectorNo) + blockNo)), data, MFBLOCK_SIZE); - PrintAndLogEx(SUCCESS, "successfully read block %2d of sector %2d.", blockNo, sectorNo); + PrintAndLogEx(INPLACE, "successfully read block " _YELLOW_("%2d") " of sector " _YELLOW_("%2d"), blockNo, sectorNo); } else { - PrintAndLogEx(FAILED, "could not read block %2d of sector %2d", blockNo, sectorNo); + PrintAndLogEx(FAILED, "\ncould not read block %2d of sector %2d", blockNo, sectorNo); } } else { PrintAndLogEx(WARNING, "command execute timeout when trying to read block %2d of sector %2d.", blockNo, sectorNo); @@ -785,7 +845,8 @@ static int CmdHF14AMfWrBl(const char *Cmd) { " \n" "`--force` param is used to override warnings like bad ACL and BLOCK 0 writes.\n" " if not specified, it will exit if detected", - "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f" + "hf mf wrbl --blk 1 -d 000102030405060708090a0b0c0d0e0f\n" + "hf mf wrbl --blk 1 -k A0A1A2A3A4A5 -d 000102030405060708090a0b0c0d0e0f\n" ); void *argtable[] = { arg_param_begin, @@ -813,7 +874,7 @@ static int CmdHF14AMfWrBl(const char *Cmd) { bool force = arg_get_lit(ctx, 4); int keylen = 0; - uint8_t key[6] = {0}; + uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; CLIGetHexWithReturn(ctx, 5, key, &keylen); uint8_t block[MFBLOCK_SIZE] = {0x00}; @@ -821,6 +882,11 @@ static int CmdHF14AMfWrBl(const char *Cmd) { CLIGetHexWithReturn(ctx, 6, block, &blen); CLIParserFree(ctx); + if (keylen && keylen != 6) { + PrintAndLogEx(WARNING, "Key must be 12 hex digits. Got %d", keylen); + return PM3_EINVARG; + } + if (blen != MFBLOCK_SIZE) { PrintAndLogEx(WARNING, "block data must include 16 HEX bytes. Got %i", blen); return PM3_EINVARG; @@ -879,7 +945,8 @@ static int CmdHF14AMfRdBl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf rdbl", "Read MIFARE Classic block", - "hf mf rdbl --blk 0 -k FFFFFFFFFFFF\n" + "hf mf rdbl --blk 0\n" + "hf mf rdbl --blk 0 -k A0A1A2A3A4A5\n" "hf mf rdbl --blk 3 -v -> get block 3, decode sector trailer\n" ); void *argtable[] = { @@ -904,11 +971,16 @@ static int CmdHF14AMfRdBl(const char *Cmd) { } int keylen = 0; - uint8_t key[6] = {0}; + uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; CLIGetHexWithReturn(ctx, 4, key, &keylen); bool verbose = arg_get_lit(ctx, 5); CLIParserFree(ctx); + if (keylen && keylen != 6) { + PrintAndLogEx(WARNING, "Key must be 12 hex digits. Got %d", keylen); + return PM3_EINVARG; + } + if (b > 255) { return PM3_EINVARG; } @@ -934,7 +1006,8 @@ static int CmdHF14AMfRdSc(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf rdsc", "Read MIFARE Classic sector", - "hf mf rdsc -s 0 -k FFFFFFFFFFFF\n" + "hf mf rdsc -s 0\n" + "hf mf rdsc -s 0 -k A0A1A2A3A4A5\n" ); void *argtable[] = { arg_param_begin, @@ -956,17 +1029,23 @@ static int CmdHF14AMfRdSc(const char *Cmd) { } int keylen = 0; - uint8_t key[6] = {0}; + uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; CLIGetHexWithReturn(ctx, 3, key, &keylen); int s = arg_get_int_def(ctx, 4, 0); bool verbose = arg_get_lit(ctx, 5); CLIParserFree(ctx); - if (s > MIFARE_4K_MAXSECTOR) { + if (keylen && keylen != 6) { + PrintAndLogEx(WARNING, "Key must be 12 hex digits. Got %d", keylen); + return PM3_EINVARG; + } + + if (s >= MIFARE_4K_MAXSECTOR) { PrintAndLogEx(WARNING, "Sector number must be less then 40"); return PM3_EINVARG; } + uint8_t sector = (uint8_t)s; uint16_t sc_size = mfNumBlocksPerSector(sector) * MFBLOCK_SIZE; @@ -1106,7 +1185,7 @@ static int CmdHF14AMfDump(const char *Cmd) { // read card iso14a_card_select_t card ; - uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t)); + uint8_t *mem = calloc(MIFARE_4K_MAX_BYTES, sizeof(uint8_t)); if (mem == NULL) { PrintAndLogEx(ERR, "failed to allocate memory"); return PM3_EMALLOC; @@ -1266,7 +1345,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyfilename); + PrintAndLogEx(INFO, "Using key file... `" _YELLOW_("%s") "`", keyfilename); // try reading card uid and create filename if (datafnlen == 0) { @@ -1299,6 +1378,9 @@ static int CmdHF14AMfRestore(const char *Cmd) { PrintAndLogEx(INFO, "Restoring " _YELLOW_("%s")" to card", datafilename); + PrintAndLogEx(INFO, " blk | "); + PrintAndLogEx(INFO, "-----+------------------------------------------------------------"); + // main loop for restoring. // a bit more complicated than needed // this is because of two things. @@ -1312,7 +1394,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { memcpy(bldata, dump, MFBLOCK_SIZE); // if sector trailer - if (mfNumBlocksPerSector(s) - 1 == b) { + if (mfIsSectorTrailerBasedOnBlocks(s, b)) { if (use_keyfile_for_auth == false) { // replace KEY A memcpy(bldata, keyA + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); @@ -1359,33 +1441,48 @@ static int CmdHF14AMfRestore(const char *Cmd) { // use default key to authenticate for the write command memcpy(wdata, default_key, MIFARE_KEY_SIZE); } - PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata))); + + uint16_t blockno = (mfFirstBlockOfSector(s) + b); + + PrintAndLogEx(INFO, " %3d | %s", blockno, sprint_hex(bldata, sizeof(bldata))); clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, wdata, sizeof(wdata)); + SendCommandMIX(CMD_HF_MIFARE_WRITEBL, blockno, kt, 0, wdata, sizeof(wdata)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - uint8_t isOK = resp.oldarg[0] & 0xff; - if (isOK == 0) { - if (b == 0) { - PrintAndLogEx(INFO, "Writing to manufacture block w key %c ( " _RED_("fail") " )", (kt == MF_KEY_A) ? 'A' : 'B'); - } else { - PrintAndLogEx(FAILED, "Write to block %u w key %c ( " _RED_("fail") " ) ", b, (kt == MF_KEY_A) ? 'A' : 'B'); - } - } else { - // if success, skip to next block - break; - } - } else { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { PrintAndLogEx(WARNING, "Command execute timeout"); + continue; } - } + + int isOK = resp.oldarg[0] & 0xff; + if (isOK == 1) { + // if success, skip to next block + break; + } else if (isOK == PM3_ETEAROFF) { + PrintAndLogEx(INFO, "Tear off triggerd. Recommendation is not to use tear-off with restore command"); + goto out; + } else { + if (b == 0) { + PrintAndLogEx(INFO, "Writing to manufacture block w key " _YELLOW_("%c") " ( " _RED_("fail") " )", + (kt == MF_KEY_A) ? 'A' : 'B' + ); + } else { + PrintAndLogEx(FAILED, "Write to block " _YELLOW_("%u") " w key " _YELLOW_("%c") " ( " _RED_("fail") " ) ", + blockno, + (kt == MF_KEY_A) ? 'A' : 'B' + ); + } + } + } // end loop key types } // end loop B } // end loop S +out: free(ref_dump); free(keyA); free(keyB); + PrintAndLogEx(INFO, "-----+------------------------------------------------------------"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Done!"); return PM3_SUCCESS; } @@ -3387,8 +3484,9 @@ static int CmdHF14AMfChk(const char *Cmd) { CLIParamStrToBuf(arg_get_str(ctx, 12), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); - bool singleSector = blockNo > -1; - if (! singleSector) { + + bool singleSector = (blockNo > -1); + if (singleSector == false) { // start from first trailer block blockNo = 3; } @@ -3411,9 +3509,11 @@ static int CmdHF14AMfChk(const char *Cmd) { } if (singleSector) { - size_t min_sectors_cnt = 0; + // find a MIFARE type that can accommodate the provided block number + size_t min_sectors_cnt = 0; uint8_t s = mfSectorNum(blockNo); + if (s < MIFARE_MINI_MAXSECTOR) { min_sectors_cnt = MIFARE_MINI_MAXSECTOR; } else if (s < MIFARE_1K_MAXSECTOR) { @@ -3426,6 +3526,7 @@ static int CmdHF14AMfChk(const char *Cmd) { PrintAndLogEx(WARNING, "Provided block out of possible MIFARE Type memory map"); return PM3_EINVARG; } + if (sectors_cnt == 1) { sectors_cnt = min_sectors_cnt; } else if (sectors_cnt < min_sectors_cnt) { @@ -3433,6 +3534,7 @@ static int CmdHF14AMfChk(const char *Cmd) { return PM3_EINVARG; } } + if (sectors_cnt == 1) { sectors_cnt = MIFARE_1K_MAXSECTOR; } @@ -3500,6 +3602,7 @@ static int CmdHF14AMfChk(const char *Cmd) { } if (singleSector) break; + b < 127 ? (b += 4) : (b += 16); } } @@ -3555,10 +3658,10 @@ out: PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); //print keys - if (singleSector) - printKeyTableEx(1, e_sector, mfSectorNum(blockNo)); - else - printKeyTable(sectors_cnt, e_sector); +// if (singleSector) +// printKeyTableEx(1, e_sector, mfSectorNum(blockNo)); +// else + printKeyTable(sectors_cnt, e_sector); if (transferToEml) { // fast push mode @@ -3954,6 +4057,7 @@ void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector , strA, resA , strB, resB ); + } PrintAndLogEx(SUCCESS, "-----+-----+--------------+---+--------------+----"); @@ -4042,7 +4146,7 @@ static int CmdHF14AMfEGetSc(const char *Cmd) { bool verbose = arg_get_lit(ctx, 2); CLIParserFree(ctx); - if (s > 39) { + if (s >= MIFARE_4K_MAXSECTOR) { PrintAndLogEx(WARNING, "Sector number must be less then 40"); return PM3_EINVARG; } @@ -5036,7 +5140,8 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { int s = arg_get_int_def(ctx, 1, 0); bool verbose = arg_get_lit(ctx, 2); CLIParserFree(ctx); - if (s > 39) { + + if (s >= MIFARE_4K_MAXSECTOR) { PrintAndLogEx(WARNING, "Sector number must be less then 40"); return PM3_EINVARG; } @@ -5594,28 +5699,27 @@ static int CmdHF14AMfAuth4(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf auth4", "Executes AES authentication command in ISO14443-4", - "hf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" - "hf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); + "hf mf auth4 -n 4000 -k 000102030405060708090a0b0c0d0e0f -> executes authentication\n" + "hf mf auth4 -n 9003 -k FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); void *argtable[] = { arg_param_begin, - arg_str1(NULL, NULL, "", NULL), - arg_str1(NULL, NULL, "", NULL), + arg_str1("n", NULL, "", "key num, 2 hex bytes"), + arg_str1("k", "key", "", "key, 16 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIGetHexWithReturn(ctx, 1, keyn, &keynlen); CLIGetHexWithReturn(ctx, 2, key, &keylen); CLIParserFree(ctx); if (keynlen != 2) { - PrintAndLogEx(ERR, " must be 2 bytes long instead of: %d", keynlen); + PrintAndLogEx(ERR, "Key number must be 2 bytes. Got... %d", keynlen); return PM3_ESOFT; } if (keylen != 16) { - PrintAndLogEx(ERR, " must be 16 bytes long instead of: %d", keylen); + PrintAndLogEx(ERR, "Key must be 16 bytes. Got... %d", keylen); return PM3_ESOFT; } @@ -5635,12 +5739,12 @@ static int CmdHF14AMfMAD(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_lit0("v", "verbose", "show technical data"), - arg_str0(NULL, "aid", "", "print all sectors with specified aid"), - arg_str0("k", "key", "", "key for printing sectors"), + arg_str0(NULL, "aid", "", "print all sectors with specified aid"), + arg_str0("k", "key", "", "key for printing sectors"), arg_lit0("b", "keyb", "use key B for access printing sectors (by default: key A)"), arg_lit0(NULL, "be", "(optional, BigEndian)"), arg_lit0(NULL, "dch", "decode Card Holder information"), - arg_str0("f", "file", "", "load dump file and decode MAD"), + arg_str0("f", "file", "", "load dump file and decode MAD"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -5665,21 +5769,20 @@ static int CmdHF14AMfMAD(const char *Cmd) { // read dump file uint8_t *dump = NULL; size_t bytes_read = 0; - int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK)); + int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, MIFARE_4K_MAX_BYTES); if (res != PM3_SUCCESS) { return res; } uint16_t block_cnt = MIN(MIFARE_1K_MAXBLOCK, (bytes_read / MFBLOCK_SIZE)); - if (bytes_read == 320) + if (bytes_read == MIFARE_MINI_MAX_BYTES) block_cnt = MIFARE_MINI_MAXBLOCK; - else if (bytes_read == 2048) + else if (bytes_read == MIFARE_2K_MAX_BYTES) block_cnt = MIFARE_2K_MAXBLOCK; - else if (bytes_read == 4096) + else if (bytes_read == MIFARE_4K_MAX_BYTES) block_cnt = MIFARE_4K_MAXBLOCK; if (verbose) { - PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, block_cnt, block_cnt); } @@ -5733,6 +5836,30 @@ static int CmdHF14AMfMAD(const char *Cmd) { PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, _CYAN_("VIGIK PACS detected")); } + + if (haveMAD2) { + MAD2DecodeAndPrint(dump + (MIFARE_1K_MAXBLOCK * MF_MAD2_SECTOR), swapmad, verbose); + } + + if (aidlen == 2 || decodeholder) { + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(dump, dump + (0x10 * MIFARE_1K_MAXBLOCK), mad, &madlen, swapmad)) { + PrintAndLogEx(ERR, "can't decode MAD"); + free(dump); + return PM3_ESOFT; + } + + uint16_t aaid = 0x0004; + if (aidlen == 2) { + aaid = (aid[0] << 8) + aid[1]; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid); + + MADCardHolderInfoDecode(dump, bytes_read, verbose); + } free(dump); return PM3_SUCCESS; } @@ -5741,8 +5868,8 @@ static int CmdHF14AMfMAD(const char *Cmd) { return PM3_ENOTTY; - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; + uint8_t sector0[MFBLOCK_SIZE * 4] = {0}; + uint8_t sector10[MFBLOCK_SIZE * 4] = {0}; bool got_first = true; if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0) != PM3_SUCCESS) { @@ -5768,17 +5895,34 @@ static int CmdHF14AMfMAD(const char *Cmd) { return PM3_ESOFT; } + got_first = true; + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10) != PM3_SUCCESS) { + if (verbose) { + PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys"); + } + got_first = false; + } else { + PrintAndLogEx(INFO, "Authentication ( " _GREEN_("ok") " )"); + } + + // User supplied key + if (got_first == false && keylen == 6) { + PrintAndLogEx(INFO, "Trying user specified key..."); + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, userkey, sector10) != PM3_SUCCESS) { + if (verbose) { + PrintAndLogEx(ERR, "error, read sector 10. card doesn't have MAD 2 or the custom key is wrong"); + } + } else { + PrintAndLogEx(INFO, "Authentication ( " _GREEN_("ok") " )"); + } + } + MADPrintHeader(); bool haveMAD2 = false; MAD1DecodeAndPrint(sector0, swapmad, verbose, &haveMAD2); if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys"); - return PM3_ESOFT; - } - MAD2DecodeAndPrint(sector10, swapmad, verbose); } @@ -5796,7 +5940,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { // user specified key if (keylen == 6) { - memcpy(akey, userkey, 6); + memcpy(akey, userkey, sizeof(akey)); } uint16_t aaid = 0x0004; @@ -5809,7 +5953,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { for (int i = 0; i < madlen; i++) { if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; + uint8_t vsector[MFBLOCK_SIZE * 4] = {0}; if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(ERR, "error, read sector %d", i + 1); @@ -5817,7 +5961,7 @@ static int CmdHF14AMfMAD(const char *Cmd) { } for (int j = 0; j < (verbose ? 4 : 3); j ++) - PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * MFBLOCK_SIZE], MFBLOCK_SIZE)); } } } @@ -5827,21 +5971,22 @@ static int CmdHF14AMfMAD(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-------- " _CYAN_("Card Holder Info 0x%04x") " --------", aaid); - uint8_t data[4096] = {0}; + uint8_t data[MIFARE_4K_MAX_BYTES] = {0}; int datalen = 0; for (int i = 0; i < madlen; i++) { if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; + uint8_t vsector[MFBLOCK_SIZE * 4] = {0}; if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(ERR, "error, read sector %d", i + 1); return PM3_ESOFT; } - memcpy(&data[datalen], vsector, 16 * 3); - datalen += 16 * 3; + // skip ST block hence only 3 blocks copy + memcpy(&data[datalen], vsector, MFBLOCK_SIZE * 3); + datalen += MFBLOCK_SIZE * 3; } } @@ -5855,9 +6000,16 @@ static int CmdHF14AMfMAD(const char *Cmd) { if (verbose) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------------ " _CYAN_("MAD sector raw") " -------------"); - for (int i = 0; i < 4; i ++) - PrintAndLogEx(INFO, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v1 sector raw") " -------------"); + for (int i = 0; i < 4; i ++) { + PrintAndLogEx(INFO, "[%d] %s", i, sprint_hex(§or0[i * MFBLOCK_SIZE], MFBLOCK_SIZE)); + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 sector raw") " -------------"); + for (int i = 0; i < 4; i ++) { + PrintAndLogEx(INFO, "[%d] %s", i, sprint_hex(§or10[i * MFBLOCK_SIZE], MFBLOCK_SIZE)); + } } return PM3_SUCCESS; @@ -5888,12 +6040,15 @@ int CmdHFMFNDEFRead(const char *Cmd) { bool verbose = arg_get_lit(ctx, 1); bool verbose2 = arg_get_lit(ctx, 1) > 1; uint8_t aid[2] = {0}; + int aidlen; CLIGetHexWithReturn(ctx, 2, aid, &aidlen); uint8_t key[6] = {0}; + int keylen; CLIGetHexWithReturn(ctx, 3, key, &keylen); bool keyB = arg_get_lit(ctx, 4); + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); @@ -5916,8 +6071,9 @@ int CmdHFMFNDEFRead(const char *Cmd) { uint8_t data[4096] = {0}; int datalen = 0; - if (verbose) + if (verbose) { PrintAndLogEx(INFO, "reading MAD v1 sector"); + } if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, g_mifare_mad_key, sector0)) { PrintAndLogEx(ERR, "error, read sector 0. card doesn't have MAD or doesn't have MAD on default keys"); @@ -5925,27 +6081,27 @@ int CmdHFMFNDEFRead(const char *Cmd) { return PM3_ESOFT; } + if (verbose) { + PrintAndLogEx(INFO, "reading MAD v2 sector"); + } + + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, g_mifare_mad_key, sector10)) { + if (verbose) { + PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD 2 or doesn't have MAD 2 on default keys"); + PrintAndLogEx(INFO, "Skipping MAD 2"); + } + } + bool haveMAD2 = false; - int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + int res = MADCheck(sector0, sector10, verbose, &haveMAD2); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "MAD error %d", res); return res; } - if (haveMAD2) { - if (verbose) - PrintAndLogEx(INFO, "reading MAD v2 sector"); - - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys"); - PrintAndLogEx(HINT, "Try " _YELLOW_("`hf mf ndefread -k `") " with your custom key"); - return PM3_ESOFT; - } - } - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; size_t madlen = 0; - res = MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen, false); + res = MADDecode(sector0, sector10, mad, &madlen, false); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "can't decode MAD"); return res; @@ -6174,7 +6330,7 @@ skipfile: memcpy(block, firstblocks[b], MFBLOCK_SIZE); break; default: { - if (mfIsSectorTrailer(j)) { + if (mfIsSectorTrailerBasedOnBlocks(i, j)) { // ST NDEF memcpy(block, firstblocks[7], MFBLOCK_SIZE); } @@ -6361,7 +6517,7 @@ int CmdHFMFNDEFWrite(const char *Cmd) { return PM3_ESOFT; } - // decode MAD + // decode MAD v1 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; size_t madlen = 0; res = MADDecode(sector0, NULL, mad, &madlen, false); @@ -6654,6 +6810,102 @@ static int CmdHf14AGen3Freeze(const char *Cmd) { return res; } +#define FURUI_MAX_TRACES 8 +static int mfc_furui_recovery(uint8_t items, uint8_t tracedata[FURUI_MAX_TRACES][18]) { + // recover key from collected traces + // outer loop + for (uint8_t i = 0; i < items; i++) { + + // first + nonces_t data; + data.cuid = bytes_to_num(tracedata[i], 4); + data.nonce = bytes_to_num(tracedata[i] + 6, 4); + data.nr = bytes_to_num(tracedata[i] + 10, 4); + data.ar = bytes_to_num(tracedata[i] + 14, 4); + data.at = 0; + + // inner loop + for (uint8_t j = i + 1; j < items; j++) { + + uint8_t *p = tracedata[j]; + PrintAndLogEx(INFO, "%u... %s", i, sprint_hex_inrow(p, 18)); + + // since data stored as block number but its the same key for all blocks in one sector + // we compare with sector number here + uint8_t s = mfSectorNum(tracedata[i][4]); + if (mfSectorNum(p[4]) == s) { + + data.nonce2 = bytes_to_num(p + 6, 4); + data.nr2 = bytes_to_num(p + 10, 4); + data.ar2 = bytes_to_num(p + 14, 4); + data.sector = s; + data.keytype = tracedata[i][5]; + data.state = FIRST; + + uint64_t key64 = -1; + if (mfkey32_moebius(&data, &key64)) { + PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64) " ]", + sprint_hex_inrow(tracedata[i], 4), + data.sector, + (data.keytype == 0x60) ? 'A' : 'B', + key64 + ); + break; + } + } + } + } + return PM3_SUCCESS; +} + +static int mfc_supercard_gen2_recovery(uint8_t items, uint8_t tracedata[FURUI_MAX_TRACES][18]) { + for (uint8_t i = 0; i < items; i++) { + uint8_t *tmp = tracedata[i]; + + // first + uint16_t NT0 = (tmp[6] << 8) | tmp[7]; + + nonces_t data; + data.cuid = bytes_to_num(tmp, 4); + data.nonce = prng_successor(NT0, 31); + data.nr = bytes_to_num(tmp + 8, 4); + data.ar = bytes_to_num(tmp + 12, 4); + data.at = 0; + + // second + for (uint8_t j = i + 1; j < items; j++) { + uint8_t *p = tracedata[j]; + + // since data stored as block number but its the same key for all blocks in one sector + // we compare with sector number here + uint8_t s = mfSectorNum(tmp[5]); + if (mfSectorNum(p[5]) == s) { + + NT0 = (p[6] << 8) | p[7]; + + data.nonce2 = prng_successor(NT0, 31); + data.nr2 = bytes_to_num(p + 8, 4); + data.ar2 = bytes_to_num(p + 12, 4); + data.sector = s; + data.keytype = tmp[4]; + data.state = FIRST; + + uint64_t key64 = -1; + if (mfkey32_moebius(&data, &key64)) { + PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64) " ]", + sprint_hex_inrow(tmp, 4), + data.sector, + (data.keytype == 0x60) ? 'A' : 'B', + key64 + ); + break; + } + } + } + } + return PM3_SUCCESS; +} + static int CmdHf14AMfSuperCard(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mf supercard", @@ -6666,6 +6918,7 @@ static int CmdHf14AMfSuperCard(const char *Cmd) { arg_param_begin, arg_lit0("r", "reset", "Reset card"), arg_str0("u", "uid", "", "New UID (4 hex bytes)"), + arg_lit0(NULL, "furui", "Furui detection card"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -6673,6 +6926,8 @@ static int CmdHf14AMfSuperCard(const char *Cmd) { uint8_t uid[4]; int uidlen = 0; int res = CLIParamHexToBuf(arg_get_str(ctx, 2), uid, sizeof(uid), &uidlen); + bool is_furui = arg_get_lit(ctx, 3); + CLIParserFree(ctx); if (res || (!res && uidlen && uidlen != sizeof(uid))) { @@ -6680,15 +6935,53 @@ static int CmdHf14AMfSuperCard(const char *Cmd) { return PM3_EINVARG; } + uint8_t tracedata[FURUI_MAX_TRACES][18]; + + // Super card FURUI + if (is_furui) { + + // no reset on super card FURUI + if (uidlen || reset_card) { + PrintAndLogEx(FAILED, "Not supported on this card"); + return PM3_SUCCESS; + } + + // read 8 traces + uint8_t i; + for (i = 0; i < FURUI_MAX_TRACES; i++) { + + uint8_t data[] = {0xAA, 0xA8, 0x00, i}; + uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, flags, sizeof(data), 0, data, sizeof(data)); + if (WaitForResponseTimeout(CMD_ACK, NULL, 1500) == false) { + break; + } + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { + break; + } + + uint16_t len = resp.oldarg[0] & 0xFFFF; + if (len != 20) { + break; // Not trace data + } + + PrintAndLogEx(DEBUG, ">>> %s", sprint_hex_inrow(resp.data.asBytes, len)); + memcpy(&tracedata[i], resp.data.asBytes, len - 2); + } + + return mfc_furui_recovery(i, tracedata); + } + #define SUPER_MAX_TRACES 7 - uint8_t trace = 0; - uint8_t traces[SUPER_MAX_TRACES][16]; + // read 7 traces from super card generation 1,2 + uint8_t i = 0; + for (i = 0; i < SUPER_MAX_TRACES; i++) { - // read 7 traces from super card - for (trace = 0; trace < SUPER_MAX_TRACES; trace++) { - - uint8_t data[] = {0x30, 0x00 + trace}; + uint8_t data[] = {0x30, i}; uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443A_READER, flags, sizeof(data), 0, data, sizeof(data)); @@ -6706,11 +6999,12 @@ static int CmdHf14AMfSuperCard(const char *Cmd) { break; // Not trace data } - memcpy(&traces[trace], resp.data.asBytes, len - 2); + PrintAndLogEx(DEBUG, ">>> %s", sprint_hex_inrow(resp.data.asBytes, len)); + memcpy(&tracedata[i], resp.data.asBytes, len - 2); } // Super card generation 2 - if (trace == SUPER_MAX_TRACES) { + if (i == SUPER_MAX_TRACES) { // no reset on super card generation 2. if (uidlen || reset_card) { @@ -6719,174 +7013,140 @@ static int CmdHf14AMfSuperCard(const char *Cmd) { } // recover key from collected traces - for (trace = 0; trace < SUPER_MAX_TRACES; trace++) { - uint8_t *trace_data = traces[trace]; - nonces_t data; + return mfc_supercard_gen2_recovery(i, tracedata); + } - // first - uint16_t NT0 = (trace_data[6] << 8) | trace_data[7]; - data.cuid = bytes_to_num(trace_data, 4); - data.nonce = prng_successor(NT0, 31); - data.nr = bytes_to_num(trace_data + 8, 4); - data.ar = bytes_to_num(trace_data + 12, 4); - data.at = 0; + // Super card generation 1 - // second - for (uint8_t s_strace = trace + 1; s_strace < 7; s_strace++) { - uint8_t *s_trace_data = traces[s_strace]; - if (mfSectorNum(s_trace_data[5]) == mfSectorNum(trace_data[5])) { - NT0 = (s_trace_data[6] << 8) | s_trace_data[7]; - data.nonce2 = prng_successor(NT0, 31); - data.nr2 = bytes_to_num(s_trace_data + 8, 4); - data.ar2 = bytes_to_num(s_trace_data + 12, 4); - data.sector = mfSectorNum(trace_data[5]); - data.keytype = trace_data[4]; - data.state = FIRST; + // Commands: + // a0 - set UID + // b0 - read traces + // c0 - clear card + bool activate_field = true; + bool keep_field_on = true; - uint64_t key64 = -1; - if (mfkey32_moebius(&data, &key64)) { - PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ "_GREEN_("%012" PRIX64) " ]", sprint_hex_inrow(trace_data, 4), data.sector, (data.keytype == 0x60) ? 'A' : 'B', key64); - break; - } - } - } - } - - } else { - - // Super card generation 1 - - // Commands: - // a0 - set UID - // b0 - read traces - // c0 - clear card - bool activate_field = true; - bool keep_field_on = true; - - // change UID on a super card generation 1 - if (uidlen) { - keep_field_on = false; - uint8_t response[6]; - int resplen = 0; - - // --------------- CHANGE UID ---------------- - uint8_t aCHANGE[] = {0x00, 0xa6, 0xa0, 0x00, 0x05, 0xff, 0xff, 0xff, 0xff, 0x00}; - memcpy(aCHANGE + 5, uid, uidlen); - res = ExchangeAPDU14a(aCHANGE, sizeof(aCHANGE), activate_field, keep_field_on, response, sizeof(response), - &resplen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Super card UID change [ " _RED_("fail") " ]"); - DropField(); - return res; - } - - PrintAndLogEx(SUCCESS, "Super card UID change ( " _GREEN_("ok") " )"); - return PM3_SUCCESS; - } - - // reset a super card generation 1 - if (reset_card) { - keep_field_on = false; - uint8_t response[6]; - int resplen = 0; - - // --------------- RESET CARD ---------------- - uint8_t aRESET[] = {0x00, 0xa6, 0xc0, 0x00}; - res = ExchangeAPDU14a(aRESET, sizeof(aRESET), activate_field, keep_field_on, response, sizeof(response), - &resplen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "Super card reset [ " _RED_("fail") " ]"); - DropField(); - return res; - } - PrintAndLogEx(SUCCESS, "Super card reset ( " _GREEN_("ok") " )"); - return PM3_SUCCESS; - } - - - uint8_t responseA[22]; - uint8_t responseB[22]; - int respAlen = 0; - int respBlen = 0; - - // --------------- First ---------------- - uint8_t aFIRST[] = {0x00, 0xa6, 0xb0, 0x00, 0x10}; - res = ExchangeAPDU14a(aFIRST, sizeof(aFIRST), activate_field, keep_field_on, responseA, sizeof(responseA), &respAlen); - if (res != PM3_SUCCESS) { - DropField(); - return res; - } - - // --------------- Second ---------------- - activate_field = false; + // change UID on a super card generation 1 + if (uidlen) { keep_field_on = false; + uint8_t response[6]; + int resplen = 0; - uint8_t aSECOND[] = {0x00, 0xa6, 0xb0, 0x01, 0x10}; - res = ExchangeAPDU14a(aSECOND, sizeof(aSECOND), activate_field, keep_field_on, responseB, sizeof(responseB), &respBlen); + // --------------- CHANGE UID ---------------- + uint8_t aCHANGE[] = {0x00, 0xa6, 0xa0, 0x00, 0x05, 0xff, 0xff, 0xff, 0xff, 0x00}; + memcpy(aCHANGE + 5, uid, uidlen); + res = ExchangeAPDU14a(aCHANGE, sizeof(aCHANGE), activate_field, keep_field_on, response, sizeof(response), + &resplen); if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Super card UID change [ " _RED_("fail") " ]"); DropField(); return res; } - uint8_t outA[16] = {0}; - uint8_t outB[16] = {0}; + PrintAndLogEx(SUCCESS, "Super card UID change ( " _GREEN_("ok") " )"); + return PM3_SUCCESS; + } - uint8_t key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; - for (uint8_t i = 0; i < 16; i += 8) { - des_decrypt(outA + i, responseA + i, key); - des_decrypt(outB + i, responseB + i, key); + // reset a super card generation 1 + if (reset_card) { + keep_field_on = false; + uint8_t response[6]; + int resplen = 0; + + // --------------- RESET CARD ---------------- + uint8_t aRESET[] = {0x00, 0xa6, 0xc0, 0x00}; + res = ExchangeAPDU14a(aRESET, sizeof(aRESET), activate_field, keep_field_on, response, sizeof(response), + &resplen); + if (res != PM3_SUCCESS) { + PrintAndLogEx(FAILED, "Super card reset [ " _RED_("fail") " ]"); + DropField(); + return res; } + PrintAndLogEx(SUCCESS, "Super card reset ( " _GREEN_("ok") " )"); + return PM3_SUCCESS; + } - PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseA, respAlen)); - PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outA, sizeof(outA))); - PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseB, respAlen)); - PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outB, sizeof(outB))); + uint8_t responseA[22]; + uint8_t responseB[22]; + int respAlen = 0; + int respBlen = 0; - if (memcmp(outA, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) { - PrintAndLogEx(INFO, "No trace recorded"); - return PM3_SUCCESS; - } + // --------------- First ---------------- + uint8_t aFIRST[] = {0x00, 0xa6, 0xb0, 0x00, 0x10}; + res = ExchangeAPDU14a(aFIRST, sizeof(aFIRST), activate_field, keep_field_on, responseA, sizeof(responseA), &respAlen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } - // second trace? - if (memcmp(outB, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) { - PrintAndLogEx(INFO, "Only one trace recorded"); - return PM3_SUCCESS; - } + // --------------- Second ---------------- + activate_field = false; + keep_field_on = false; - nonces_t data; + uint8_t aSECOND[] = {0x00, 0xa6, 0xb0, 0x01, 0x10}; + res = ExchangeAPDU14a(aSECOND, sizeof(aSECOND), activate_field, keep_field_on, responseB, sizeof(responseB), &respBlen); + if (res != PM3_SUCCESS) { + DropField(); + return res; + } - // first - uint16_t NT0 = (outA[6] << 8) | outA[7]; - data.cuid = bytes_to_num(outA, 4); - data.nonce = prng_successor(NT0, 31); - data.nr = bytes_to_num(outA + 8, 4); - data.ar = bytes_to_num(outA + 12, 4); - data.at = 0; + uint8_t outA[16] = {0}; + uint8_t outB[16] = {0}; - // second - NT0 = (outB[6] << 8) | outB[7]; - data.nonce2 = prng_successor(NT0, 31); - data.nr2 = bytes_to_num(outB + 8, 4); - data.ar2 = bytes_to_num(outB + 12, 4); - data.sector = mfSectorNum(outA[5]); - data.keytype = outA[4]; - data.state = FIRST; + uint8_t key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + for (i = 0; i < 16; i += 8) { + des_decrypt(outA + i, responseA + i, key); + des_decrypt(outB + i, responseB + i, key); + } - PrintAndLogEx(DEBUG, "A Sector %02x", data.sector); - PrintAndLogEx(DEBUG, "A NT %08x", data.nonce); - PrintAndLogEx(DEBUG, "A NR %08x", data.nr); - PrintAndLogEx(DEBUG, "A AR %08x", data.ar); - PrintAndLogEx(DEBUG, ""); - PrintAndLogEx(DEBUG, "B NT %08x", data.nonce2); - PrintAndLogEx(DEBUG, "B NR %08x", data.nr2); - PrintAndLogEx(DEBUG, "B AR %08x", data.ar2); + PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseA, respAlen)); + PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outA, sizeof(outA))); + PrintAndLogEx(DEBUG, " in : %s", sprint_hex_inrow(responseB, respAlen)); + PrintAndLogEx(DEBUG, "out : %s", sprint_hex_inrow(outB, sizeof(outB))); - uint64_t key64 = -1; - if (mfkey32_moebius(&data, &key64)) { - PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ " _GREEN_("%012" PRIX64) " ]", sprint_hex_inrow(outA, 4), data.sector, (data.keytype == 0x60) ? 'A' : 'B', key64); - } else { - PrintAndLogEx(FAILED, "failed to recover any key"); - } + if (memcmp(outA, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) { + PrintAndLogEx(INFO, "No trace recorded"); + return PM3_SUCCESS; + } + + // second trace? + if (memcmp(outB, "\x01\x01\x01\x01\x01\x01\x01\x01", 8) == 0) { + PrintAndLogEx(INFO, "Only one trace recorded"); + return PM3_SUCCESS; + } + + nonces_t data; + + // first + uint16_t NT0 = (outA[6] << 8) | outA[7]; + data.cuid = bytes_to_num(outA, 4); + data.nonce = prng_successor(NT0, 31); + data.nr = bytes_to_num(outA + 8, 4); + data.ar = bytes_to_num(outA + 12, 4); + data.at = 0; + + // second + NT0 = (outB[6] << 8) | outB[7]; + data.nonce2 = prng_successor(NT0, 31); + data.nr2 = bytes_to_num(outB + 8, 4); + data.ar2 = bytes_to_num(outB + 12, 4); + data.sector = mfSectorNum(outA[5]); + data.keytype = outA[4]; + data.state = FIRST; + + PrintAndLogEx(DEBUG, "A Sector %02x", data.sector); + PrintAndLogEx(DEBUG, "A NT %08x", data.nonce); + PrintAndLogEx(DEBUG, "A NR %08x", data.nr); + PrintAndLogEx(DEBUG, "A AR %08x", data.ar); + PrintAndLogEx(DEBUG, ""); + PrintAndLogEx(DEBUG, "B NT %08x", data.nonce2); + PrintAndLogEx(DEBUG, "B NR %08x", data.nr2); + PrintAndLogEx(DEBUG, "B AR %08x", data.ar2); + + uint64_t key64 = -1; + if (mfkey32_moebius(&data, &key64)) { + PrintAndLogEx(SUCCESS, "UID: %s Sector %02x key %c [ " _GREEN_("%012" PRIX64) " ]", sprint_hex_inrow(outA, 4), data.sector, (data.keytype == 0x60) ? 'A' : 'B', key64); + } else { + PrintAndLogEx(FAILED, "failed to recover any key"); } return PM3_SUCCESS; } @@ -6935,33 +7195,33 @@ static int CmdHF14AMfWipe(const char *Cmd) { return PM3_ESOFT; } - uint8_t keyA[MIFARE_4K_MAXSECTOR * 6]; - uint8_t keyB[MIFARE_4K_MAXSECTOR * 6]; + uint8_t keyA[MIFARE_4K_MAXSECTOR * MIFARE_KEY_SIZE]; + uint8_t keyB[MIFARE_4K_MAXSECTOR * MIFARE_KEY_SIZE]; uint8_t num_sectors = 0; uint8_t mf[MFBLOCK_SIZE]; switch (keyslen) { - case (MIFARE_MINI_MAXSECTOR * 2 * 6): { + case (MIFARE_MINI_MAX_KEY_SIZE): { PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic Mini 320b"); - memcpy(keyA, keys, (MIFARE_MINI_MAXSECTOR * 6)); - memcpy(keyB, keys + (MIFARE_MINI_MAXSECTOR * 6), (MIFARE_MINI_MAXSECTOR * 6)); + memcpy(keyA, keys, (MIFARE_MINI_MAXSECTOR * MIFARE_KEY_SIZE)); + memcpy(keyB, keys + (MIFARE_MINI_MAXSECTOR * MIFARE_KEY_SIZE), (MIFARE_MINI_MAXSECTOR * MIFARE_KEY_SIZE)); num_sectors = NumOfSectors('0'); memcpy(mf, "\x11\x22\x33\x44\x44\x09\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE); break; } - case (MIFARE_1K_MAXSECTOR * 2 * 6): { + case (MIFARE_1K_MAX_KEY_SIZE): { PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic 1K"); - memcpy(keyA, keys, (MIFARE_1K_MAXSECTOR * 6)); - memcpy(keyB, keys + (MIFARE_1K_MAXSECTOR * 6), (MIFARE_1K_MAXSECTOR * 6)); + memcpy(keyA, keys, (MIFARE_1K_MAXSECTOR * MIFARE_KEY_SIZE)); + memcpy(keyB, keys + (MIFARE_1K_MAXSECTOR * MIFARE_KEY_SIZE), (MIFARE_1K_MAXSECTOR * MIFARE_KEY_SIZE)); num_sectors = NumOfSectors('1'); memcpy(mf, "\x11\x22\x33\x44\x44\x08\x04\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE); break; } - case (MIFARE_4K_MAXSECTOR * 2 * 6): { + case (MIFARE_4K_MAX_KEY_SIZE): { PrintAndLogEx(INFO, "Loaded keys matching MIFARE Classic 4K"); - memcpy(keyA, keys, (MIFARE_4K_MAXSECTOR * 6)); - memcpy(keyB, keys + (MIFARE_4K_MAXSECTOR * 6), (MIFARE_4K_MAXSECTOR * 6)); + memcpy(keyA, keys, (MIFARE_4K_MAXSECTOR * MIFARE_KEY_SIZE)); + memcpy(keyB, keys + (MIFARE_4K_MAXSECTOR * MIFARE_KEY_SIZE), (MIFARE_4K_MAXSECTOR * MIFARE_KEY_SIZE)); num_sectors = NumOfSectors('4'); memcpy(mf, "\x11\x22\x33\x44\x44\x18\x02\x00\x62\x63\x64\x65\x66\x67\x68\x69", MFBLOCK_SIZE); break; @@ -6983,6 +7243,8 @@ static int CmdHF14AMfWipe(const char *Cmd) { memset(zeros, 0x00, sizeof(zeros)); uint8_t st[MFBLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + PrintAndLogEx(INFO, " blk | "); + PrintAndLogEx(INFO, "-----+------------------------------------------------------------"); // time to wipe card for (uint8_t s = 0; s < num_sectors; s++) { @@ -7000,7 +7262,7 @@ static int CmdHF14AMfWipe(const char *Cmd) { uint8_t data[26]; memset(data, 0, sizeof(data)); - if (mfIsSectorTrailer(b)) { + if (mfIsSectorTrailerBasedOnBlocks(s, b)) { memcpy(data + 10, st, sizeof(st)); } else { memcpy(data + 10, zeros, sizeof(zeros)); @@ -7015,11 +7277,11 @@ static int CmdHF14AMfWipe(const char *Cmd) { for (int8_t kt = MF_KEY_B; kt > -1; kt--) { if (kt == MF_KEY_A) - memcpy(data, keyA + (s * 6), 6); + memcpy(data, keyA + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); else - memcpy(data, keyB + (s * 6), 6); + memcpy(data, keyB + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); - PrintAndLogEx(INFO, "block %3d: %s" NOLF, mfFirstBlockOfSector(s) + b, sprint_hex(data + 10, MFBLOCK_SIZE)); + PrintAndLogEx(INFO, " %3d | %s" NOLF, mfFirstBlockOfSector(s) + b, sprint_hex(data + 10, MFBLOCK_SIZE)); clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_WRITEBL, mfFirstBlockOfSector(s) + b, kt, 0, data, sizeof(data)); PacketResponseNG resp; @@ -7038,6 +7300,7 @@ static int CmdHF14AMfWipe(const char *Cmd) { } } + PrintAndLogEx(INFO, "-----+------------------------------------------------------------"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Done!"); out: @@ -7105,7 +7368,7 @@ static int CmdHF14AMfView(const char *Cmd) { PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, _CYAN_("VIGIK PACS detected")); - // decode MAD + // decode MAD v1 uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; size_t madlen = 0; res = MADDecode(dump, NULL, mad, &madlen, false); diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 9434d88ed..52f3da57e 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -34,19 +34,12 @@ #include "protocols.h" #include "crypto/libpcrypto.h" #include "cmdhfmf.h" // printblock, header +#include "cmdtrace.h" -static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; +static const uint8_t mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; -typedef enum { - MFP_UNKNOWN = 0, - DESFIRE_MF3ICD40, - DESFIRE_EV1, - DESFIRE_EV2, - DESFIRE_EV3, - DESFIRE_LIGHT, - PLUS_EV1, -} nxp_cardtype_t; +#define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1)) static int CmdHelp(const char *Cmd); @@ -233,9 +226,10 @@ static int get_plus_signature(uint8_t *signature, int *signature_len) { *signature_len = 0; retval = PM3_ESOFT; } - mfpSetVerboseMode(false); + return retval; } + // GET VERSION static int plus_print_version(uint8_t *version) { PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7)); @@ -261,12 +255,12 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false)); return PM3_SUCCESS; } + static int get_plus_version(uint8_t *version, int *version_len) { int resplen = 0, retval = PM3_SUCCESS; mfpSetVerboseMode(false); MFPGetVersion(true, false, version, *version_len, &resplen); - mfpSetVerboseMode(false); *version_len = resplen; if (resplen != 28) { @@ -484,16 +478,16 @@ static int CmdHFMFPWritePerso(const char *Cmd) { mfpSetVerboseMode(verbose); if (!keyLen) { - memmove(key, DefaultKey, 16); + memmove(key, mfp_default_key, 16); keyLen = 16; } if (keyNumLen != 2) { - PrintAndLogEx(ERR, "Key number length must be 2 bytes instead of: %d", keyNumLen); + PrintAndLogEx(ERR, "Key number length must be 2 bytes. Got %d", keyNumLen); return PM3_EINVARG; } if (keyLen != 16) { - PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); + PrintAndLogEx(ERR, "Key length must be 16 bytes. Got %d", keyLen); return PM3_EINVARG; } @@ -507,7 +501,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) { } if (datalen != 3) { - PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); + PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen); return PM3_ESOFT; } @@ -539,17 +533,18 @@ static int CmdHFMFPInitPerso(const char *Cmd) { bool verbose2 = arg_get_lit(ctx, 1) > 1; uint8_t key[256] = {0}; - int keyLen = 0; - CLIGetHexWithReturn(ctx, 2, key, &keyLen); + int keylen = 0; + CLIGetHexWithReturn(ctx, 2, key, &keylen); CLIParserFree(ctx); - if (keyLen && keyLen != 16) { - PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen); + if (keylen && keylen != 16) { + PrintAndLogEx(FAILED, "Key length must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } - if (!keyLen) - memmove(key, DefaultKey, 16); + if (keylen == 0) { + memmove(key, mfp_default_key, sizeof(mfp_default_key)); + } uint8_t keyNum[2] = {0}; uint8_t data[250] = {0}; @@ -572,15 +567,15 @@ static int CmdHFMFPInitPerso(const char *Cmd) { } mfpSetVerboseMode(verbose); - for (int i = 0; i < ARRAYLEN(CardAddresses); i++) { - keyNum[0] = CardAddresses[i] >> 8; - keyNum[1] = CardAddresses[i] & 0xff; + for (int i = 0; i < ARRAYLEN(mfp_card_adresses); i++) { + keyNum[0] = mfp_card_adresses[i] >> 8; + keyNum[1] = mfp_card_adresses[i] & 0xff; res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen); if (!res && (datalen == 3) && data[0] == 0x09) { - PrintAndLogEx(WARNING, "Skipped[%04x]...", CardAddresses[i]); + PrintAndLogEx(WARNING, "Skipped[%04x]...", mfp_card_adresses[i]); } else { if (res || (datalen != 3) || data[0] != 0x90) { - PrintAndLogEx(ERR, "Write error on address %04x", CardAddresses[i]); + PrintAndLogEx(ERR, "Write error on address %04x", mfp_card_adresses[i]); break; } } @@ -597,7 +592,9 @@ static int CmdHFMFPInitPerso(const char *Cmd) { static int CmdHFMFPCommitPerso(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp commitp", - "Executes Commit Perso command. Can be used in SL0 mode only.\nOBS! This command will not be executed if CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.", + "Executes Commit Perso command. Can be used in SL0 mode only.\n" + "OBS! This command will not be executed if \n" + "CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.", "hf mfp commitp\n" // "hf mfp commitp --sl 1" ); @@ -625,7 +622,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) { } if (datalen != 3) { - PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen); + PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen); return PM3_EINVARG; } @@ -633,7 +630,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) { PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return PM3_EINVARG; } - PrintAndLogEx(INFO, "Switch level ( " _GREEN_("ok") " )"); + PrintAndLogEx(INFO, "Switched security level ( " _GREEN_("ok") " )"); return PM3_SUCCESS; } @@ -645,7 +642,7 @@ static int CmdHFMFPAuth(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp auth", - "Executes AES authentication command for Mifare Plus card", + "Executes AES authentication command for MIFARE Plus card", "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data"); @@ -664,12 +661,12 @@ static int CmdHFMFPAuth(const char *Cmd) { CLIParserFree(ctx); if (keynlen != 2) { - PrintAndLogEx(ERR, "ERROR: must be 2 bytes long instead of: %d", keynlen); + PrintAndLogEx(ERR, "ERROR: must be 2 bytes. Got %d", keynlen); return PM3_EINVARG; } if (keylen != 16) { - PrintAndLogEx(ERR, "ERROR: must be 16 bytes long instead of: %d", keylen); + PrintAndLogEx(ERR, "ERROR: must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } @@ -679,7 +676,7 @@ static int CmdHFMFPAuth(const char *Cmd) { static int CmdHFMFPRdbl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp rdbl", - "Reads several blocks from Mifare Plus card", + "Reads blocks from MIFARE Plus card", "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF"); @@ -710,23 +707,23 @@ static int CmdHFMFPRdbl(const char *Cmd) { mfpSetVerboseMode(verbose); if (!keylen) { - memmove(key, DefaultKey, 16); + memmove(key, mfp_default_key, 16); keylen = 16; } if (blockn > 255) { - PrintAndLogEx(ERR, " must be in range [0..255] got: %d", blockn); + PrintAndLogEx(ERR, " must be in range [0..255]. got %d", blockn); return PM3_EINVARG; } if (keylen != 16) { - PrintAndLogEx(ERR, " must be 16 bytes long. got: %d", keylen); + PrintAndLogEx(ERR, " must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } // 3 blocks - wo iso14443-4 chaining if (blocksCount > 3) { - PrintAndLogEx(ERR, "blocks count must be less than 3. got: %d", blocksCount); + PrintAndLogEx(ERR, "blocks count must be less than 3. Got %d", blocksCount); return PM3_EINVARG; } @@ -763,7 +760,7 @@ static int CmdHFMFPRdbl(const char *Cmd) { } if (datalen != 1 + blocksCount * 16 + 8 + 2) { - PrintAndLogEx(ERR, "Error return length:%d", datalen); + PrintAndLogEx(ERR, "Error return length: %d", datalen); return PM3_ESOFT; } @@ -820,17 +817,17 @@ static int CmdHFMFPRdsc(const char *Cmd) { mfpSetVerboseMode(verbose); if (!keylen) { - memmove(key, DefaultKey, 16); + memmove(key, mfp_default_key, 16); keylen = 16; } if (sectorNum > 39) { - PrintAndLogEx(ERR, " must be in range [0..39] got: %d", sectorNum); + PrintAndLogEx(ERR, " must be in range [0..39]. Got %d", sectorNum); return PM3_EINVARG; } if (keylen != 16) { - PrintAndLogEx(ERR, " must be 16 bytes long. got: %d", keylen); + PrintAndLogEx(ERR, " must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } @@ -894,7 +891,7 @@ static int CmdHFMFPRdsc(const char *Cmd) { static int CmdHFMFPWrbl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp wrbl", - "Writes one block to Mifare Plus card", + "Writes one block to MIFARE Plus card", "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n" "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF" ); @@ -928,22 +925,22 @@ static int CmdHFMFPWrbl(const char *Cmd) { mfpSetVerboseMode(verbose); if (!keylen) { - memmove(key, DefaultKey, 16); + memmove(key, mfp_default_key, 16); keylen = 16; } if (blockNum > 255) { - PrintAndLogEx(ERR, " must be in range [0..255] got: %d", blockNum); + PrintAndLogEx(ERR, " must be in range [0..255]. Got %d", blockNum); return PM3_EINVARG; } if (keylen != 16) { - PrintAndLogEx(ERR, " must be 16 bytes long. got: %d", keylen); + PrintAndLogEx(ERR, " must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } if (datainlen != 16) { - PrintAndLogEx(ERR, " must be 16 bytes long. got: %d", datainlen); + PrintAndLogEx(ERR, " must be 16 bytes. Got %d", datainlen); return PM3_EINVARG; } @@ -997,12 +994,9 @@ static int CmdHFMFPWrbl(const char *Cmd) { return PM3_SUCCESS; } -#define AES_KEY_LEN 16 -#define MAX_KEYS_LIST_LEN 1024 - static int plus_key_check(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) { + uint8_t keyList[MAX_AES_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}; @@ -1088,7 +1082,7 @@ static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startK return PM3_SUCCESS; } -static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) { +static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) { for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { keyList[*keyListLen][0] = (pt >> 8) & 0xff; keyList[*keyListLen][1] = pt & 0xff; @@ -1097,7 +1091,7 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3 memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); (*keyListLen)++; *startPattern = pt; - if (*keyListLen == MAX_KEYS_LIST_LEN) + if (*keyListLen == MAX_AES_KEYS_LIST_LEN) break; } (*startPattern)++; @@ -1111,7 +1105,7 @@ static int CmdHFMFPChk(const char *Cmd) { "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, only 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 --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n" "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00"); void *argtable[] = { @@ -1125,7 +1119,7 @@ static int CmdHFMFPChk(const char *Cmd) { 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("j", "json", "", "Json filename to save keys"), + arg_lit0(NULL, "dump", "Dump found keys to JSON file"), arg_lit0("v", "verbose", "Verbose mode"), arg_param_end }; @@ -1136,7 +1130,7 @@ static int CmdHFMFPChk(const char *Cmd) { uint8_t startSector = arg_get_int_def(ctx, 3, 0); uint8_t endSector = arg_get_int_def(ctx, 4, 0); - uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; + uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; uint32_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; @@ -1148,7 +1142,7 @@ static int CmdHFMFPChk(const char *Cmd) { memcpy(&keyList[keyListLen], vkey, 16); keyListLen++; } else { - PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); + PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen); CLIParserFree(ctx); return PM3_EINVARG; } @@ -1185,7 +1179,7 @@ static int CmdHFMFPChk(const char *Cmd) { if (vpatternlen <= 2) { startPattern = (vpattern[0] << 8) + vpattern[1]; } else { - PrintAndLogEx(ERR, "Pattern must be 2-byte length."); + PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen); CLIParserFree(ctx); return PM3_EINVARG; } @@ -1193,17 +1187,8 @@ static int CmdHFMFPChk(const char *Cmd) { 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(ctx, 10), jsonname, sizeof(jsonname), &jsonnamelen)) { - PrintAndLogEx(ERR, "Invalid json name."); - CLIParserFree(ctx); - return PM3_EINVARG; - } - jsonname[jsonnamelen] = 0; - + bool create_dumpfile = arg_get_lit(ctx, 10); bool verbose = arg_get_lit(ctx, 11); - CLIParserFree(ctx); uint8_t startKeyAB = 0; @@ -1227,8 +1212,9 @@ static int CmdHFMFPChk(const char *Cmd) { } // 2-byte pattern search mode - if (pattern2b) + if (pattern2b) { Fill2bPattern(keyList, &keyListLen, &startPattern); + } int res = PM3_SUCCESS; @@ -1295,15 +1281,25 @@ static int CmdHFMFPChk(const char *Cmd) { } break; } - if (verbose == false) + + if (verbose == false) { PrintAndLogEx(NORMAL, ""); + } // print result char strA[46 + 1] = {0}; char strB[46 + 1] = {0}; + uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7}; + bool has_ndef_key = false; bool printedHeader = false; for (uint8_t s = startSector; s <= endSector; s++) { + + if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) || + (memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) { + has_ndef_key = true; + } + if (printedHeader == false) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); @@ -1324,7 +1320,7 @@ static int CmdHFMFPChk(const char *Cmd) { snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------"); } - PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB); + PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB); } if (printedHeader == false) @@ -1333,7 +1329,13 @@ static int CmdHFMFPChk(const char *Cmd) { PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n"); // save keys to json - if ((jsonnamelen > 0) && printedHeader) { + if (create_dumpfile && printedHeader) { + + size_t keys_len = (2 * 64 * (AES_KEY_LEN + 1)); + + uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len]; + memset(data, 0, sizeof(data)); + // Mifare Plus info SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); @@ -1344,8 +1346,6 @@ static int CmdHFMFPChk(const char *Cmd) { 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); @@ -1357,19 +1357,117 @@ static int CmdHFMFPChk(const char *Cmd) { memcpy(&data[14], card.ats, atslen); } + char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t)); + strcpy(fptr, "hf-mfp-"); + + FillFileNameByUID(fptr, card.uid, "-key", card.uidlen); + // 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, NULL); + memcpy(&data[14 + atslen], foundKeys, keys_len); + // 64 here is for how many "rows" there is in the data array. A bit confusing + saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL); + free(fptr); } + // MAD detection + if ((memcmp(&foundKeys[0][0][1], "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", AES_KEY_LEN) == 0)) { + PrintAndLogEx(HINT, "MAD key detected. Try " _YELLOW_("`hf mfp mad`") " for more details"); + } + + // NDEF detection + if (has_ndef_key) { + PrintAndLogEx(HINT, "NDEF key detected. Try " _YELLOW_("`hf mfp ndefread -h`") " for more details"); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } +static int CmdHFMFPDump(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfp dump", + "Dump MIFARE Plus tag to binary file\n" + "If no given, UID will be used as filename", + "hf mfp dump\n" + "hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0("f", "file", "", "filename of dump"), + arg_str0("k", "keys", "", "filename of keys"), + arg_lit0(NULL, "ns", "no save to file"), + arg_lit0("v", "verbose", "Verbose mode"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int datafnlen = 0; + char data_fn[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)data_fn, FILE_PATH_SIZE, &datafnlen); + + int keyfnlen = 0; + char key_fn[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)key_fn, FILE_PATH_SIZE, &keyfnlen); + + bool nosave = arg_get_lit(ctx, 3); + bool verbose = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + mfpSetVerboseMode(verbose); + + // read card + uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t)); + if (mem == NULL) { + PrintAndLogEx(ERR, "failed to allocate memory"); + return PM3_EMALLOC; + } + + /* + iso14a_card_select_t card ; + int res = mfp_read_tag(&card, mem, key_fn); + if (res != PM3_SUCCESS) { + free(mem); + return res; + } + */ + + // Skip saving card data to file + if (nosave) { + PrintAndLogEx(INFO, "Called with no save option"); + free(mem); + return PM3_SUCCESS; + } + /* + // Save to file + if (strlen(data_fn) < 1) { + + char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-dump")) + card.uidlen * 2 + 1, sizeof(uint8_t)); + strcpy(fptr, "hf-mfp-"); + + FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen); + + strcpy(data_fn, fptr); + free(fptr); + } + + saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES); + saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE); + + iso14a_mf_extdump_t xdump; + xdump.card_info = card; + xdump.dump = mem; + xdump.dumplen = MIFARE_4K_MAX_BYTES; + saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL); + */ + free(mem); + return PM3_SUCCESS; +} + + static int CmdHFMFPMAD(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp mad", - "Checks and prints Mifare Application Directory (MAD)", + "Checks and prints MIFARE Application Directory (MAD)", "hf mfp mad\n" "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid"); @@ -1411,9 +1509,7 @@ static int CmdHFMFPMAD(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------"); - PrintAndLogEx(INFO, "-----------------------------------------------------"); + MADPrintHeader(); if (verbose) { PrintAndLogEx(SUCCESS, "Raw:"); @@ -1427,7 +1523,7 @@ static int CmdHFMFPMAD(const char *Cmd) { if (haveMAD2) { if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys"); + PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys"); return PM3_ESOFT; } @@ -1505,6 +1601,36 @@ static int CmdHFMFPMAD(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFMFPNDEFFormat(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfp ndefformat", + "format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n" + "If no given, UID will be used as filename. \n" + "It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n" + "\n" + "If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", + "hf mfp ndefformat\n" + "hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("k", "keys", "", "filename of keys"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + int keyfnlen = 0; + char keyFilename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen); + + CLIParserFree(ctx); + + PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + int CmdHFMFPNDEFRead(const char *Cmd) { CLIParserContext *ctx; @@ -1641,20 +1767,74 @@ int CmdHFMFPNDEFRead(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFMFPNDEFWrite(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf mfp ndefwrite", + "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n", + "hf mfp ndefwrite -d 0300FE -> write empty record to tag\n" + "hf mfp ndefwrite -f myfilename\n" + "hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0("d", NULL, "", "raw NDEF hex bytes"), + arg_str0("f", "file", "", "write raw NDEF file to tag"), + arg_lit0("p", NULL, "fix NDEF record headers / terminator block if missing"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + uint8_t raw[4096] = {0}; + int rawlen; + CLIGetHexWithReturn(ctx, 1, raw, &rawlen); + + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + bool fix_msg = arg_get_lit(ctx, 3); + bool verbose = arg_get_lit(ctx, 4); + CLIParserFree(ctx); + + if (fix_msg) { + PrintAndLogEx(NORMAL, "called with fix NDEF message param"); + } + + if (verbose) { + PrintAndLogEx(NORMAL, ""); + } + PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!"); + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + +static int CmdHFMFPList(const char *Cmd) { + return CmdTraceListAlias(Cmd, "hf mf", "mf"); +} + static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about Mifare Plus tag"}, - {"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"}, - {"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"}, - {"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"}, - {"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"}, - {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"}, - {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"}, - {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"}, - {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, - {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"}, - {"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFMFPList, AlwaysAvailable, "List MIFARE Plus history"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"}, + {"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"}, + {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, + {"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Plus tag to binary file"}, + {"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"}, + {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"}, + {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"}, + {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"}, + {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write block to card"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "---------------- " _CYAN_("personalization") " -------------------"}, + {"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Configure security layer (SL1/SL3 mode)"}, + {"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"}, + {"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("ndef") " ------------------------"}, + {"ndefformat", CmdHFMFPNDEFFormat, IfPm3Iso14443a, "Format MIFARE Plus Tag as NFC Tag"}, + {"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"}, + {"ndefwrite", CmdHFMFPNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"}, + {NULL, NULL, 0, NULL} }; static int CmdHelp(const char *Cmd) { diff --git a/client/src/cmdhfmfp.h b/client/src/cmdhfmfp.h index 7381f87a2..29723b204 100644 --- a/client/src/cmdhfmfp.h +++ b/client/src/cmdhfmfp.h @@ -20,6 +20,30 @@ #include "common.h" + +#define AES_KEY_LEN 16 +#define MAX_AES_KEYS_LIST_LEN 1024 + +typedef enum { + MFP_UNKNOWN = 0, + DESFIRE_MF3ICD40, + DESFIRE_EV1, + DESFIRE_EV2, + DESFIRE_EV3, + DESFIRE_LIGHT, + PLUS_EV1, +} nxp_cardtype_t; + +typedef struct mfp_key_item { + uint8_t a[16]; + uint8_t b[16]; +} mfp_key_item_t; + +typedef struct mfp_keys { + uint8_t success; + mfp_key_item_t *keys; +} mfp_keys_t; + int CmdHFMFP(const char *Cmd); int CmdHFMFPNDEFRead(const char *Cmd); diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index e17032507..9f7f54c53 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -1424,7 +1424,7 @@ static mfu_identify_t *mfu_match_fingerprint(uint8_t *version, uint8_t *data) { uint8_t mtmp[40] = {0}; param_gethex_to_eol(mfu_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml); - bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0); + bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0); if (m2) { PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_ident_table[i].desc); return &mfu_ident_table[i]; @@ -3608,7 +3608,7 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) { if (ul_select(&card)) { // Philips toothbrush needs page 0x21-0x23 uint8_t data[16] = {0x00}; - int status = ul_read(0x21, data, sizeof(data)); + int status = ul_read(0x21, data, sizeof(data)); if (status == -1) { PrintAndLogEx(DEBUG, "Error: tag didn't answer to READ"); } else if (status == 16) { diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index 6311b50ed..4483e3154 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -224,6 +224,8 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) { uint16_t resp_len = 11; uint8_t response[11] = {0}; + // + if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) { topaz_switch_off_field(); return PM3_ESOFT; // WriteErase 8bytes failed @@ -243,6 +245,61 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) { return PM3_ESOFT; } +// write a block (8 Bytes) of a selected Topaz tag. +static int topaz_write_nonerase8_block(uint8_t blockno, uint8_t *block_data) { + + uint8_t atqa[2] = {0}; + uint8_t rid_response[8] = {0}; + int res = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), true); + if (res != PM3_SUCCESS) { + return res; + } + + if (atqa[1] != 0x0c && atqa[0] != 0x00) { + return res; + } + + uint8_t *uid_echo = &rid_response[2]; + uint8_t rall_response[124] = {0}; + + res = topaz_rall(uid_echo, rall_response); + if (res == PM3_ESOFT) { + return res; + } + + // ADD + // 7 6 5 4 3 2 1 0 + // b b b --- Byte 0 - 7 + // B B B B --------- BLOCK + // r ----------------- 0 + // + + uint8_t wr8_cmd[] = {TOPAZ_WRITE_NE8, blockno, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(wr8_cmd + 10, uid_echo, 4); + memcpy(wr8_cmd + 2, block_data, 8); + + uint16_t resp_len = 11; + uint8_t response[11] = {0}; + + // + if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) { + topaz_switch_off_field(); + return PM3_ESOFT; + } + + if (resp_len != 11) { + return PM3_EFAILED; + } + + if (blockno != response[0]) { + return PM3_EFAILED; + } + + if (memcmp(block_data, response + 1, 8) == 0) { + return PM3_SUCCESS; + } + return PM3_ESOFT; +} // search for the lock area descriptor for the lockable area including byteno static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) { @@ -402,6 +459,12 @@ static int topaz_print_CC(uint8_t *data) { return PM3_SUCCESS; } +static void topaz_print_hdr(uint8_t blockno) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " # | block " _GREEN_("0x%02X") " | ascii", blockno); + PrintAndLogEx(INFO, "----+-------------------------+---------"); +} + // return type, length and value of a TLV, starting at memory position *TLV_ptr static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) { *TLV_length = 0; @@ -782,6 +845,7 @@ static int CmdHFTopazDump(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str0("f", "file", "", "filename of dump"), + arg_lit0(NULL, "ns", "no save to file"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -789,6 +853,8 @@ static int CmdHFTopazDump(const char *Cmd) { int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + bool nosave = arg_get_lit(ctx, 2); + CLIParserFree(ctx); int status = readTopazUid(false, false); @@ -811,9 +877,18 @@ static int CmdHFTopazDump(const char *Cmd) { ); } - PrintAndLogEx(INFO, "-------------------------------------------------------------"); topaz_switch_off_field(); + // Skip saving card data to file + if (nosave) { + PrintAndLogEx(INFO, "Called with no save option"); + if (set_dynamic) { + free(topaz_tag.dynamic_memory); + } + return PM3_SUCCESS; + } + + // user supplied filename? if (fnlen < 1) { PrintAndLogEx(INFO, "Using UID as filename"); @@ -888,13 +963,13 @@ static int CmdHFTopazRdBl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf topaz rdbl", - "Read a block", - "hf topaz rdbl -b 7\n" + "Read Topaz block", + "hf topaz rdbl --blk 7\n" ); void *argtable[] = { arg_param_begin, - arg_int1("b", "block", "", "Block number to write"), + arg_int1(NULL, "blk", "", "Block number"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -910,7 +985,11 @@ static int CmdHFTopazRdBl(const char *Cmd) { uint8_t data[8] = {0}; int res = topaz_read_block(blockno, data); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, sizeof(data))); + + topaz_print_hdr(blockno); + + PrintAndLogEx(INFO, " %2d | %s", blockno, sprint_hex_ascii(data, sizeof(data))); + PrintAndLogEx(NORMAL, ""); } topaz_switch_off_field(); @@ -922,13 +1001,13 @@ static int CmdHFTopazWrBl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf topaz wrbl", - "Write a block", - "hf topaz wrbl -b 7 -d 1122334455667788\n" + "Write Topaz block with 8 hex bytes of data", + "hf topaz wrbl --blk 7 -d 1122334455667788\n" ); void *argtable[] = { arg_param_begin, - arg_int1("b", "block", "", "Block number to write"), + arg_int1(NULL, "blk", "", "Block number"), arg_str1("d", "data", "", "Block data (8 hex bytes)"), arg_param_end }; @@ -954,14 +1033,23 @@ static int CmdHFTopazWrBl(const char *Cmd) { PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, dlen)); - // send write Block - int res = topaz_write_erase8_block(blockno, data); + int res; + if (blockno != 13 && blockno != 14) { + // send write/erase block + res = topaz_write_erase8_block(blockno, data); + } else { + // send write/non erase block + res = topaz_write_nonerase8_block(blockno, data); + } if (res == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )"); + PrintAndLogEx(HINT, "try `" _YELLOW_("hf topaz rdbl --blk %u") "` to verify", blockno); + } else { PrintAndLogEx(WARNING, "Write ( " _RED_("fail") " )"); } + PrintAndLogEx(NORMAL, ""); topaz_switch_off_field(); return res; @@ -970,18 +1058,24 @@ static int CmdHFTopazWrBl(const char *Cmd) { static int CmdHelp(const char *Cmd); static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"}, - {"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"}, - {"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"}, - {"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"}, - {"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"}, - {"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"}, - {"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, - {"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"}, - {"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"}, - {"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"}, + {"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"}, + {"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"}, + {"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"}, + {"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"}, + {"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"}, + {"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"}, + {"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"}, + {"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"}, + {"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"}, + {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"}, +// {"ndefformat", CmdHFTopazNDEFFormat, IfPm3Iso14443a, "Format Topaz Tag as NFC Tag"}, +// {"ndefread", CmdHFTopazNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"}, +// {"ndefwrite", CmdHFTopazNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"}, + + {NULL, NULL, 0, NULL} }; static int CmdHelp(const char *Cmd) { diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index fa59894e1..1af21ec20 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -120,7 +120,7 @@ static void decodeHeden2L(uint8_t *bits) { if (bits[offset + 7]) cardnumber += 16384; if (bits[offset + 23]) cardnumber += 32768; - PrintAndLogEx(SUCCESS, " Heden-2L | %u", cardnumber); + PrintAndLogEx(SUCCESS, " Heden-2L...... %u", cardnumber); } // sending three times. Didn't seem to break the previous sim? @@ -301,10 +301,11 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) { ); PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01); + PrintAndLogEx(INFO, ""); PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); // This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS - PrintAndLogEx(SUCCESS, " Printed | __%04d__ [0x%X]", p1, p1); - PrintAndLogEx(SUCCESS, " Internal ID | %" PRIu64, foo); + PrintAndLogEx(SUCCESS, " Printed....... __%04d__ ( 0x%X )", p1, p1); + PrintAndLogEx(SUCCESS, " Internal ID... %" PRIu64, foo); decodeHeden2L(g_DemodBuffer); } else { @@ -336,6 +337,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) { PrintAndLogEx(DEBUG, "DEBUG: Indala - printing DemodBuffer"); printDemodBuff(0, false, false, false); } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -503,7 +505,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) { showbits[bit] = '.' + bits[bit]; } showbits[bit + 1] = '\0'; - PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits); + PrintAndLogEx(SUCCESS, "Partial UID... %s", showbits); return PM3_SUCCESS; } else { for (bit = 0; bit < uidlen; bit++) { @@ -528,7 +530,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) { uid2 = (uid2 << 1) | 1; } } - PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2); + PrintAndLogEx(SUCCESS, "UID... %s ( %x%08x )", showbits, uid1, uid2); } else { uint32_t uid3 = 0; uint32_t uid4 = 0; @@ -549,7 +551,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) { else uid7 = (uid7 << 1) | 1; } - PrintAndLogEx(SUCCESS, "UID | %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); + PrintAndLogEx(SUCCESS, "UID... %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7); } // Checking UID against next occurrences diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index c2e750623..323c7ef7e 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -571,9 +571,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr //2 Not crc-command // Draw the data column - #define TRACE_MAX_LINES 36 +#define TRACE_MAX_LINES 36 // number of hex bytes to be printed per row (16 data + 2 crc) - #define TRACE_MAX_HEX_BYTES 18 +#define TRACE_MAX_HEX_BYTES 18 char line[TRACE_MAX_LINES][160] = {{0}}; @@ -700,8 +700,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr // mark short bytes (less than 8 Bit + Parity) if (protocol == ISO_14443A || - protocol == PROTO_MIFARE || - protocol == THINFILM) { + protocol == PROTO_MIFARE || + protocol == THINFILM) { // approximated with 128 * (9 * data_len); uint16_t bitime = 1056 + 32; @@ -874,13 +874,13 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr } else { - if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) { + if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) { str_padder = 85; // odd case of multiline, and last single byte on empty row has been colorised... if (strlen(line[j]) < 14) { str_padder = 81; } - } + } if (hdr->isResponse) { PrintAndLogEx(NORMAL, " | | |%-*s | %s| %s", @@ -909,7 +909,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse); uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen); - //iceman: colorise crc bytes here will need a refactor of code from above. + //iceman: colorise crc bytes here will need a refactor of code from above. PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s", str_padder, sprint_hex_inrow_spaces(mfData, mfDataLen, 2), diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 3411215c6..4dba2c1e4 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -29,6 +29,7 @@ #include "cmdhficlass.h" // pagemap #include "protocols.h" // iclass defines #include "cmdhftopaz.h" // TOPAZ defines +#include "mifare/mifaredefault.h" // MFP / AES defines #ifdef _WIN32 #include "scandir.h" @@ -543,13 +544,14 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, break; } case jsfMfPlusKeys: { - JsonSaveStr(root, "FileType", "mfp"); + JsonSaveStr(root, "FileType", "mfpkeys"); 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) + if (atslen > 0) { JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen); + } uint8_t vdata[2][64][17] = {{{0}}}; memcpy(vdata, data + (14 + atslen), 2 * 64 * 17); @@ -559,12 +561,12 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, if (vdata[0][i][0]) { snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i); - JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16); + JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN); } if (vdata[1][i][0]) { snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyB", i); - JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16); + JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], AES_KEY_LEN); } } break; @@ -1296,6 +1298,40 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz *datalen += sptr; } + + if (!strcmp(ctype, "mfpkeys")) { + + JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen); + JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen); + JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen); + uint8_t atslen = udata.bytes[13]; + if (atslen > 0) { + JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen); + } + + size_t sptr = (14 + atslen); + + // memcpy(vdata, udata.bytes + (14 + atslen), 2 * 64 * 17); + for (size_t i = 0; i < 64; i++) { + + if ((sptr + (AES_KEY_LEN * 2)) > maxdatalen) { + break; + } + + size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN); + + char blocks[40] = {0}; + snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyA", i); + JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen); + + snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyB", i); + JsonLoadBufAsHex(root, blocks, udata.bytes + offset + AES_KEY_LEN, AES_KEY_LEN, datalen); + + sptr += (2 * AES_KEY_LEN); + } + *datalen += sptr; + } + out: if (callback != NULL) { diff --git a/client/src/mifare/mad.c b/client/src/mifare/mad.c index c870dbb28..54f67a6a4 100644 --- a/client/src/mifare/mad.c +++ b/client/src/mifare/mad.c @@ -190,7 +190,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) uint8_t GPB = sector0[(3 * 16) + 9]; if (verbose) - PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x"), "GPB", GPB); + PrintAndLogEx(SUCCESS, "GPB....... " _GREEN_("0x%02X"), GPB); // DA (MAD available) if (!(GPB & 0x80)) { @@ -200,21 +200,22 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) uint8_t mad_ver = GPB & 0x03; if (verbose) - PrintAndLogEx(SUCCESS, "%14s " _GREEN_("%d"), "MAD version", mad_ver); + PrintAndLogEx(SUCCESS, "Version... " _GREEN_("%d"), mad_ver); // MAD version if ((mad_ver != 0x01) && (mad_ver != 0x02)) { - PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02x"), mad_ver); + PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02X"), mad_ver); return PM3_ESOFT; }; - if (haveMAD2) + if (haveMAD2) { *haveMAD2 = (mad_ver == 2); + } int res = madCRCCheck(sector0, true, 1); - - if (verbose && res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector0[16], _GREEN_("ok")); + if (verbose && res == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector0[16], _GREEN_("ok")); + } if (mad_ver == 2 && sector10) { int res2 = madCRCCheck(sector10, true, 2); @@ -222,7 +223,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) res = res2; if (verbose && !res2) - PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector10[0], _GREEN_("ok")); + PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector10[0], _GREEN_("ok")); } // MA (multi-application card) @@ -284,9 +285,10 @@ static int MADInfoByteDecode(const uint8_t *sector, bool swapmad, int mad_ver, b info = sector[16 + 1] & 0x3f; if (info >= 0xF) { PrintAndLogEx(WARNING, "Invalid Info byte (MAD1) value " _YELLOW_("0x%02x"), info); - if (verbose) + if (verbose) { // I understand the spec in a way that MAD1 InfoByte should not point into MAD2 sectors, @lukaskuzmiak PrintAndLogEx(WARNING, "MAD1 Info byte points outside of MAD1 sector space (0x%02x), report a bug?", info); + } return PM3_ESOFT; } } else { @@ -318,7 +320,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA int ibs = MADInfoByteDecode(sector, swapmad, 1, verbose); if (ibs > 0) { - PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs); + PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs); } else { PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs); } @@ -331,19 +333,19 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA for (int i = 1; i < 16; i++) { uint16_t aid = madGetAID(sector, swapmad, 1, i); if (aid < 6) { - PrintAndLogEx(INFO, - (ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s", - i, - aid, - aid_admin[aid] - ); + PrintAndLogEx(INFO, + (ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s", + i, + aid, + aid_admin[aid] + ); } else if (prev_aid == aid) { - PrintAndLogEx(INFO, - (ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation", - i, - aid - ); + PrintAndLogEx(INFO, + (ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation", + i, + aid + ); } else { char fmt[60]; snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i, aid, "%s"); @@ -356,7 +358,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA } int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { - open_mad_file(&mad_known_aids, verbose); + open_mad_file(&mad_known_aids, false); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 details") " -------------"); @@ -364,14 +366,14 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { int res = madCRCCheck(sector, true, 2); if (verbose) { if (res == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "CRC8 ( %s )", _GREEN_("ok")); + PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _GREEN_("%s") " )", sector[0], "ok"); else - PrintAndLogEx(WARNING, "CRC8 ( %s )", _RED_("fail")); + PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _RED_("%s") " )", sector[0], "fail"); } int ibs = MADInfoByteDecode(sector, swapmad, 2, verbose); if (ibs > 0) { - PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs); + PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs); } else { PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs); } @@ -385,12 +387,21 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { for (int i = 1; i < 8 + 8 + 7 + 1; i++) { uint16_t aid = madGetAID(sector, swapmad, 2, i); if (aid < 6) { - PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (%s)") : " %02d [%04X] (%s)", i + 16, aid, aid_admin[aid]); + PrintAndLogEx(INFO, + (ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s", + i + 16, + aid, + aid_admin[aid] + ); } else if (prev_aid == aid) { - PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (continuation)") : " %02d [%04X] (continuation)", i + 16, aid); + PrintAndLogEx(INFO, + (ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation", + i + 16, + aid + ); } else { - char fmt[30]; - snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [%04X]%s", i + 16, aid, "%s"); + char fmt[60]; + snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i + 16, aid, "%s"); print_aid_description(mad_known_aids, aid, fmt, verbose); prev_aid = aid; } diff --git a/client/src/mifare/mifare4.c b/client/src/mifare/mifare4.c index ec8d1a6bf..7a3ec9f77 100644 --- a/client/src/mifare/mifare4.c +++ b/client/src/mifare/mifare4.c @@ -24,9 +24,9 @@ #include "ui.h" #include "crypto/libpcrypto.h" -static bool VerboseMode = false; +static bool g_verbose_mode = false; void mfpSetVerboseMode(bool verbose) { - VerboseMode = verbose; + g_verbose_mode = verbose; } static const PlusErrorsElm_t PlusErrors[] = { @@ -340,12 +340,12 @@ int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool acti } static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - if (VerboseMode) + if (g_verbose_mode) PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false); - if (VerboseMode) + if (g_verbose_mode) PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); return res; @@ -367,7 +367,7 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount}; if (!plain && mf4session) - CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); + CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], g_verbose_mode); int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); if (res) @@ -377,7 +377,7 @@ int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t mf4session->R_Ctr++; if (mf4session && mac && *dataoutlen > 11) - CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); + CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, g_verbose_mode); return 0; } @@ -386,7 +386,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; memmove(&rcmd[3], data, 16); if (mf4session) - CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); + CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], g_verbose_mode); int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); if (res) @@ -396,7 +396,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo mf4session->W_Ctr++; if (mf4session && mac && *dataoutlen > 3) - CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); + CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, g_verbose_mode); return 0; } @@ -534,7 +534,7 @@ uint8_t mfSectorTrailer(uint16_t blockNo) { if (blockNo < 32 * 4) { return (blockNo | 0x03); } else { - return (blockNo | 0x0f); + return (blockNo | 0x0F); } } @@ -551,3 +551,11 @@ uint8_t mfSectorNum(uint16_t blockNo) { return (32 + (blockNo - 32 * 4) / 16); } + +bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno) { + if (sectorno < 32) { + return ((blockno | 0x03) == blockno); + } else { + return ((blockno | 0x0F) == blockno); + } +} diff --git a/client/src/mifare/mifare4.h b/client/src/mifare/mifare4.h index 80d55db7b..fee12ef6e 100644 --- a/client/src/mifare/mifare4.h +++ b/client/src/mifare/mifare4.h @@ -79,6 +79,7 @@ uint8_t mfFirstBlockOfSector(uint8_t sectorNo); uint8_t mfSectorTrailerOfSector(uint8_t sectorNo); uint8_t mfSectorTrailer(uint16_t blockNo); bool mfIsSectorTrailer(uint16_t blockNo); +bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno); uint8_t mfSectorNum(uint16_t blockNo); diff --git a/client/src/mifare/mifaredefault.h b/client/src/mifare/mifaredefault.h index e3590329d..7bb7e144a 100644 --- a/client/src/mifare/mifaredefault.h +++ b/client/src/mifare/mifaredefault.h @@ -21,6 +21,9 @@ #include "common.h" +#define AES_KEY_LEN 16 +#define MAX_AES_KEYS_LIST_LEN 1024 + #define MFKEY_SIZE 6 #define MFBLOCK_SIZE 16 @@ -41,6 +44,12 @@ #define MIFARE_KEY_SIZE 6 +#define MIFARE_MINI_MAX_KEY_SIZE (MIFARE_MINI_MAXSECTOR * 2 * MIFARE_KEY_SIZE) +#define MIFARE_1K_MAX_KEY_SIZE (MIFARE_1K_MAXSECTOR * 2 * MIFARE_KEY_SIZE) +#define MIFARE_2K_MAX_KEY_SIZE (MIFARE_2K_MAXSECTOR * 2 * MIFARE_KEY_SIZE) +#define MIFARE_4K_MAX_KEY_SIZE (MIFARE_4K_MAXSECTOR * 2 * MIFARE_KEY_SIZE) + + static const uint64_t g_mifare_default_keys[] = { 0xffffffffffff, // Default key (first key used by program if no user defined key) 0xa0a1a2a3a4a5, // NFCForum MAD key diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 3b37182fe..6c9d8caa2 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1431,6 +1431,8 @@ int detect_mf_magic(bool is_mfc) { case MAGIC_NTAG21X: PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x")); break; + case MAGIC_QL88: + PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("QL88")); default: break; } diff --git a/client/src/nfc/ndef.c b/client/src/nfc/ndef.c index 40cfe7113..e03913fbc 100644 --- a/client/src/nfc/ndef.c +++ b/client/src/nfc/ndef.c @@ -927,7 +927,7 @@ static int ndefDecodeExternal_record(NDEFHeader_t *ndef) { print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32); // do a character check? - if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:2", ndef->TypeLen)) { + if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:", ndef->TypeLen - 1)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode..."); asn1_print(ndef->Payload, ndef->PayloadLen, " "); diff --git a/client/src/pm3line_vocabulory.h b/client/src/pm3line_vocabulory.h index ffe9c66ff..ffad57057 100644 --- a/client/src/pm3line_vocabulory.h +++ b/client/src/pm3line_vocabulory.h @@ -367,17 +367,21 @@ const static vocabulory_t vocabulory[] = { { 0, "hf mf ndefread" }, { 0, "hf mf ndefwrite" }, { 1, "hf mfp help" }, - { 0, "hf mfp info" }, - { 0, "hf mfp wrp" }, - { 0, "hf mfp initp" }, - { 0, "hf mfp commitp" }, + { 1, "hf mfp list" }, { 0, "hf mfp auth" }, + { 0, "hf mfp chk" }, + { 0, "hf mfp dump" }, + { 0, "hf mfp info" }, + { 0, "hf mfp mad" }, { 0, "hf mfp rdbl" }, { 0, "hf mfp rdsc" }, { 0, "hf mfp wrbl" }, - { 0, "hf mfp chk" }, - { 0, "hf mfp mad" }, + { 0, "hf mfp commitp" }, + { 0, "hf mfp initp" }, + { 0, "hf mfp wrp" }, + { 0, "hf mfp ndefformat" }, { 0, "hf mfp ndefread" }, + { 0, "hf mfp ndefwrite" }, { 1, "hf mfu help" }, { 1, "hf mfu keygen" }, { 1, "hf mfu pwdgen" }, @@ -461,14 +465,14 @@ const static vocabulory_t vocabulory[] = { { 1, "hf thinfilm list" }, { 0, "hf thinfilm sim" }, { 1, "hf topaz help" }, - { 0, "hf topaz dump" }, { 1, "hf topaz list" }, + { 0, "hf topaz dump" }, { 0, "hf topaz info" }, + { 0, "hf topaz raw" }, + { 0, "hf topaz rdbl" }, { 0, "hf topaz reader" }, { 0, "hf topaz sim" }, { 0, "hf topaz sniff" }, - { 0, "hf topaz raw" }, - { 0, "hf topaz rdbl" }, { 1, "hf topaz view" }, { 0, "hf topaz wrbl" }, { 1, "hf xerox help" }, diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index 86d76317b..c64d85db6 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -189,6 +189,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { free(sp); return INVALID_SERIAL_PORT; } + int sfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sfd == -1) { PrintAndLogEx(ERR, "Error opening Bluetooth socket"); @@ -196,6 +197,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { free(sp); return INVALID_SERIAL_PORT; } + if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { PrintAndLogEx(ERR, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr); close(sfd); diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index e63040a19..f88c8f759 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -730,7 +730,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool pr static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) { memset(card, 0, sizeof(wiegand_card_t)); - if (packed->Length != 36) return false; // Wrong length? Stop here. + + if (packed->Length != 36) + return false; // Wrong length? Stop here. card->OEM = get_linear_field(packed, 1, 10); card->FacilityCode = get_linear_field(packed, 11, 8); @@ -976,8 +978,10 @@ static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed, bool pr packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6))) << 14; packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C))); packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF))) << 15; + if (preamble) return add_HID_header(packed); + return true; } diff --git a/common/crc16.c b/common/crc16.c index d402977b9..812cd3481 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -354,4 +354,4 @@ uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc) { uint16_t crc16_philips(uint8_t const *d, size_t n) { return crc16_fast(d, n, 0x49A3, false, false); -} \ No newline at end of file +} diff --git a/doc/commands.json b/doc/commands.json index efb03edd2..6523703da 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -95,14 +95,6 @@ ], "usage": "analyse freq [-h] [-F ] [-L ] [-C ]" }, - "analyse help": { - "command": "analyse help", - "description": "help This help lcr Generate final byte for XOR LRC crc Stub method for CRC evaluations chksum Checksum with adding, masking and one's complement dates Look for datestamps in a given array of bytes lfsr LFSR tests a num bits test nuid create NUID from 7byte UID demodbuff Load binary string to DemodBuffer freq Calc wave lengths foo muxer units convert ETU <> US <> SSP_CLK (3.39MHz)", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "analyse lcr": { "command": "analyse lcr", "description": "Specifying the bytes of a UID with a known LRC will find the last byte value needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX.", @@ -332,8 +324,7 @@ "data diff -a fileA -b fileB", "data diff -a fileA --eb", "data diff --fa fileA -b fileB", - "data diff --fa fileA --fb fileB", - "data diff --ea --cb" + "data diff --fa fileA --fb fileB" ], "offline": true, "options": [ @@ -404,14 +395,6 @@ ], "usage": "data grid [-h] [-x ] [-y ]" }, - "data help": { - "command": "data help", - "description": "help This help ----------- ------------------------- Modulation------------------------- biphaserawdecode Biphase decode bin stream in DemodBuffer detectclock Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer fsktonrz Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk) manrawdecode Manchester decode binary stream in DemodBuffer modulation Identify LF signal for clock and modulation rawdemod Demodulate the data in the GraphBuffer and output binary ----------- ------------------------- Graph------------------------- askedgedetect Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave autocorr Autocorrelation over window dirthreshold Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev. decimate Decimate samples undecimate Un-decimate samples hide Hide graph window hpf Remove DC offset from trace iir Apply IIR buttersworth filter on plot data grid overlay grid on graph window ltrim Trim samples from left of trace mtrim Trim out samples from the specified start to the specified stop norm Normalize max/min to +/-128 plot Show graph window rtrim Trim samples from right of trace setgraphmarkers Set blue and orange marker in graph window shiftgraphzero Shift 0 for Graphed wave + or - shift value timescale Set a timescale to get a differential reading between the yellow and purple markers as time duration zerocrossings Count time between zero-crossings convertbitstream Convert GraphBuffer's 0/1 values to 127 / -127 getbitstream Convert GraphBuffer's >=1 values to 1 and <1 to 0 ----------- ------------------------- General------------------------- asn1 asn1 decoder bin2hex Converts binary to hexadecimal clear Clears bigbuf on deviceside and graph window diff diff of input files hex2bin Converts hexadecimal to binary load Load contents of file into graph window num Converts dec/hex/bin print Print the data in the DemodBuffer save Save signal trace data (from graph window) setdebugmode Set Debugging Level on client side", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "data hex2bin": { "command": "data hex2bin", "description": "This function converts hexadecimal to binary. It will ignore all non-hexadecimal characters but stop reading on whitespace", @@ -854,14 +837,6 @@ ], "usage": "emv gpo [-hkpmatw] []..." }, - "emv help": { - "command": "emv help", - "description": "help This help test Crypto logic test list List ISO7816 history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "emv intauth": { "command": "emv intauth", "description": "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format . Needs a EMV applet to be selected and GPO to be executed.", @@ -1047,14 +1022,6 @@ ], "usage": "quit [-h]" }, - "help": { - "command": "help", - "description": "help Use ` help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf 14a antifuzz": { "command": "hf 14a antifuzz", "description": "Tries to fuzz the ISO14443a anticollision phase", @@ -1131,21 +1098,18 @@ ], "usage": "hf 14a chaining [-h10]" }, - "hf 14a config": { - "command": "hf 14a config", - "description": "--------------------------------------------------------------------------------------- hf 14a cuids available offline: no", - "notes": [], + "hf 14a cuids": { + "command": "hf 14a cuids", + "description": "Collect n>0 ISO14443-a UIDs in one go", + "notes": [ + "hf 14a cuids -n 5 -> Collect 5 UIDs" + ], "offline": false, - "options": [], - "usage": "" - }, - "hf 14a help": { - "command": "hf 14a help", - "description": "----------- ----------------------- General ----------------------- help This help list List ISO 14443-a history", - "notes": [], - "offline": true, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-n, --num Number of UIDs to collect" + ], + "usage": "hf 14a cuids [-h] [-n ]" }, "hf 14a info": { "command": "hf 14a info", @@ -1359,14 +1323,6 @@ ], "usage": "hf 14b dump [-h] [-f ] [--ns]" }, - "hf 14b help": { - "command": "hf 14b help", - "description": "help This help list List ISO-14443-B history view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf 14b info": { "command": "hf 14b info", "description": "Tag information for ISO/IEC 14443 type B based tags", @@ -1628,14 +1584,6 @@ ], "usage": "hf 15 findafi [-h]" }, - "hf 15 help": { - "command": "hf 15 help", - "description": "----------- --------------------- General --------------------- help This help list List ISO-15693 history demod Demodulate ISO-15693 from tag", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf 15 info": { "command": "hf 15 info", "description": "Uses the optional command `get_systeminfo` 0x2B to try and extract information", @@ -2126,14 +2074,6 @@ ], "usage": "hf cipurse formatall [-hav] [-n ] [-k ] [--sreq ] [--sresp ] [--no-auth]" }, - "hf cipurse help": { - "command": "hf cipurse help", - "description": "help This help. test Regression tests", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf cipurse info": { "command": "hf cipurse info", "description": "Get info from CIPURSE tags", @@ -2305,14 +2245,6 @@ ], "usage": "hf emrtd dump [-h] [-n ] [-d ] [-e ] [-m <[0-9A-Z<]>] [--dir ]" }, - "hf emrtd help": { - "command": "hf emrtd help", - "description": "help This help info Display info about an eMRTD list List ISO 14443A/7816 history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf emrtd info": { "command": "hf emrtd info", "description": "Display info about an eMRTD", @@ -2370,14 +2302,6 @@ ], "usage": "hf epa cnonces [-h] --size --num -d " }, - "hf epa help": { - "command": "hf epa help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf epa replay": { "command": "hf epa replay", "description": "Perform PACE protocol by replaying given APDUs", @@ -2449,14 +2373,6 @@ ], "usage": "hf felica auth2 [-hv] [-i ] [-c ] [-k ]" }, - "hf felica help": { - "command": "hf felica help", - "description": "help This help ----------- ----------------------- General ----------------------- list List ISO 18092/FeliCa history ----------- ----------------------- FeliCa Standard ----------------------- ----------- ----------------------- FeliCa Light -----------------------", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf felica info": { "command": "hf felica info", "description": "Reader for FeliCa based tags", @@ -2537,11 +2453,25 @@ }, "hf felica rdbl": { "command": "hf felica rdbl", - "description": "Use this command to read block data from authentication-not-required Service.", - "notes": [], + "description": "Use this command to read block data from authentication-not-required Service. - Mode shall be Mode0. - Successful == block data - Unsuccessful == Status Flag1 and Flag2", + "notes": [ + "hf felica rdbl --sn 01 --scl 8B00 --bn 01 --ble 8000", + "hf felica rdbl --sn 01 --scl 4B18 --bn 01 --ble 8000 -b", + "hf felica rdbl -i 01100910c11bc407 --sn 01 --scl 8B00 --bn 01 --ble 8000" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-b get all block list elements 00 -> FF", + "-i set custom IDm", + "-l, --long use 3 byte block list element block number", + "--sn number of service", + "--scl service code list", + "--bn number of block", + "--ble block list element (def 2|3 bytes)", + "-v, --verbose verbose output" + ], + "usage": "hf felica rdbl [-hblv] [-i ] [--sn ] [--scl ] [--bn ] [--ble ]" }, "hf felica reader": { "command": "hf felica reader", @@ -2665,11 +2595,23 @@ }, "hf felica wrbl": { "command": "hf felica wrbl", - "description": "Use this command to write block data to authentication-not-required Service.", - "notes": [], + "description": "Use this command to write block data to authentication-not-required Service. - Mode shall be Mode0. - Un-/Ssuccessful == Status Flag1 and Flag2", + "notes": [ + "hf felica wrbl --sn 01 --scl CB10 --bn 01 --ble 8001 -d 0102030405060708090A0B0C0D0E0F10", + "hf felica wrbl -i 01100910c11bc407 --sn 01 --scl CB10 --bn 01 --ble 8001 -d 0102030405060708090A0B0C0D0E0F10" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-d, --data data, 16 hex bytes", + "-i set custom IDm", + "--sn number of service", + "--scl service code list", + "--bn number of block", + "--ble block list element (def 2|3 bytes)", + "-v, --verbose verbose output" + ], + "usage": "hf felica wrbl [-hv] [-d ] [-i ] [--sn ] [--scl ] [--bn ] [--ble ]" }, "hf fido assert": { "command": "hf fido assert", @@ -2717,14 +2659,6 @@ ], "usage": "hf fido auth [-havuc] default mode: [-f ] [-k ] [--kh ] [--cp ] [--ap ] [--cpx ] [--apx ]" }, - "hf fido help": { - "command": "hf fido help", - "description": "help This help. list List ISO 14443A history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf fido info": { "command": "hf fido info", "description": "Get info from Fido tags", @@ -2812,14 +2746,6 @@ ], "usage": "hf fudan dump [-h] [-f ]" }, - "hf fudan help": { - "command": "hf fudan help", - "description": "help This help view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf fudan rdbl": { "command": "hf fudan rdbl", "description": "Read fudan block", @@ -2868,7 +2794,7 @@ "command": "hf fudan wrbl", "description": "Write fudan block with 4 hex bytes of data", "notes": [ - "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304" + "hf fudan wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304" ], "offline": false, "options": [ @@ -2954,14 +2880,6 @@ ], "usage": "hf gallagher diversify [-h] --aid [--keynum ] [--uid ] [--sitekey ] [--apdu]" }, - "hf gallagher help": { - "command": "hf gallagher help", - "description": "help This help diversifykey Diversify Gallagher key decode Decode Gallagher credential block", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf gallagher reader": { "command": "hf gallagher reader", "description": "Read a Gallagher DESFire tag from the Card Application Directory, CAD Specify site key is required if using non-default key", @@ -2980,14 +2898,6 @@ ], "usage": "hf gallagher reader [-h@v] [--aid ] [--sitekey ] [--apdu]" }, - "hf help": { - "command": "hf help", - "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } jooki { Jooki RFIDs... } iclass { ICLASS RFIDs... } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } xerox { Fuji/Xerox cartridge RFIDs... } waveshare { Waveshare NFC ePaper... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf iclass calcnewkey": { "command": "hf iclass calcnewkey", "description": "Calculate new keys for updating (blocks 3 & 4)", @@ -3049,11 +2959,23 @@ }, "hf iclass decrypt": { "command": "hf iclass decrypt", - "description": "3DES decrypt data This is a naive implementation, it tries to decrypt every block after block 6. Correct behaviour would be to decrypt only the application areas where the key is valid, which is defined by the configuration block.", - "notes": [], + "description": "3DES decrypt data This is a naive implementation, it tries to decrypt every block after block 6. Correct behaviour would be to decrypt only the application areas where the key is valid, which is defined by the configuration block. OBS! In order to use this function, the file `iclass_decryptionkey.bin` must reside in the resources directory. The file should be 16 bytes binary data or... make sure your cardhelper is placed in the sim module", + "notes": [ + "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin", + "hf iclass decrypt -f hf-iclass-AA162D30F8FF12F1-dump.bin -k 000102030405060708090a0b0c0d0e0f", + "hf iclass decrypt -d 1122334455667788 -k 000102030405060708090a0b0c0d0e0f" + ], "offline": true, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-f, --file filename of dump file (bin/eml/json)", + "-d, --data 3DES encrypted data", + "-k, --key 3DES transport key", + "-v, --verbose verbose output", + "--d6 decode as block 6", + "-z, --dense dense dump output style" + ], + "usage": "hf iclass decrypt [-hvz] [-f ] [-d ] [-k ] [--d6]" }, "hf iclass dump": { "command": "hf iclass dump", @@ -3171,14 +3093,6 @@ ], "usage": "hf iclass eview [-hvz] [-s <256|2048>]" }, - "hf iclass help": { - "command": "hf iclass help", - "description": "----------- --------------------- operations --------------------- help This help info Tag information list List iclass history ----------- --------------------- recovery --------------------- loclass Use loclass to perform bruteforce reader attack lookup Uses authentication trace to check for key in dictionary file ----------- --------------------- simulation --------------------- ----------- --------------------- utils --------------------- configcard Reader configuration card calcnewkey Calc diversified keys (blocks 3 & 4) to write new keys encode Encode binary wiegand to block 7 encrypt Encrypt given block data decrypt Decrypt given block data or tag dump file managekeys Manage keys to use with iclass commands permutekey Permute function from 'heart of darkness' paper view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf iclass info": { "command": "hf iclass info", "description": "Act as a iCLASS reader. Reads / fingerprints a iCLASS tag.", @@ -3484,14 +3398,6 @@ ], "usage": "hf jooki encode [-hrtv] [-u ] [--dragon] [--fox] [--ghost] [--knight] [--whale] [--blackdragon] [--blackfox] [--blackknight] [--blackwhale] [--whitedragon] [--whitefox] [--whiteknight] [--whitewhale] [--tid ] [--fid ]" }, - "hf jooki help": { - "command": "hf jooki help", - "description": "help This help decode Decode Jooki token encode Encode Jooki token", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf jooki sim": { "command": "hf jooki sim", "description": "Simulate a Jooki token. Either `hf mfu eload` before or use `-d` param", @@ -3520,14 +3426,6 @@ ], "usage": "hf ksx6924 balance [-hka]" }, - "hf ksx6924 help": { - "command": "hf ksx6924 help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf ksx6924 info": { "command": "hf ksx6924 info", "description": "Get info about a KS X 6924 transit card. This application is used by T-Money (South Korea) and Snapper+ (Wellington, New Zealand).", @@ -3677,14 +3575,6 @@ ], "usage": "hf legic eview [-h] [--22] [--256] [--1024]" }, - "hf legic help": { - "command": "hf legic help", - "description": "----------- --------------------- operations --------------------- help This help list List LEGIC history ----------- --------------------- simulation --------------------- ----------- --------------------- utils --------------------- crc Calculate Legic CRC over given bytes view Display deobfuscated and decoded content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf legic info": { "command": "hf legic info", "description": "Gets information from a LEGIC Prime tag like systemarea, user areas, etc", @@ -3853,14 +3743,6 @@ ], "usage": "hf lto dump [-h] [-f ]" }, - "hf lto help": { - "command": "hf lto help", - "description": "help This help list List LTO-CM history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf lto info": { "command": "hf lto info", "description": "Get info from LTO tags", @@ -3966,14 +3848,16 @@ "command": "hf mf auth4", "description": "Executes AES authentication command in ISO14443-4", "notes": [ - "hf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication", - "hf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication" + "hf mf auth4 -n 4000 -k 000102030405060708090a0b0c0d0e0f -> executes authentication", + "hf mf auth4 -n 9003 -k FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication" ], "offline": false, "options": [ - "-h, --help This help" + "-h, --help This help", + "-n key num, 2 hex bytes", + "-k, --key key, 16 hex bytes" ], - "usage": "hf mf auth4 [-h] " + "usage": "hf mf auth4 [-h] -n -k " }, "hf mf autopwn": { "command": "hf mf autopwn", @@ -4449,19 +4333,32 @@ }, "hf mf gen3blk": { "command": "hf mf gen3blk", - "description": "Overwrite full manufacturer block for magic Gen3 card - You can specify part of manufacturer block as 4/7-bytes for UID change only", - "notes": [], + "description": "Overwrite full manufacturer block for magic Gen3 card - You can specify part of manufacturer block as 4/7-bytes for UID change only NOTE: BCC, SAK, ATQA will be calculated automatically", + "notes": [ + "hf mf gen3blk -> print current data", + "hf mf gen3blk -d 01020304 -> set 4 byte uid", + "hf mf gen3blk -d 01020304050607 -> set 7 byte uid", + "hf mf gen3blk -d 01020304FFFFFFFF0102030405060708" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-d, --data manufacturer block data up to 16 hex bytes" + ], + "usage": "hf mf gen3blk [-h] [-d ]" }, "hf mf gen3freeze": { "command": "hf mf gen3freeze", - "description": "Perma lock further UID changes. No more UID changes available after operation completed", - "notes": [], + "description": "Perma lock further UID changes. No more UID changes available after operation completed Note: operation is ! irreversible !", + "notes": [ + "hf mf gen3freeze -y" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-y, --yes confirm UID lock operation" + ], + "usage": "hf mf gen3freeze -y[h]" }, "hf mf gen3uid": { "command": "hf mf gen3uid", @@ -4614,14 +4511,6 @@ ], "usage": "hf mf hardnested [-habrstw] [-k ] [--blk ] [--tblk ] [--ta] [--tb] [--tk ] [-u ] [-f ] [--in] [--im] [--is] [--ia] [--i2] [--i5]" }, - "hf mf help": { - "command": "hf mf help", - "description": "help This help list List MIFARE history hardnested Nested attack for hardened MIFARE Classic cards decrypt [nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace acl Decode and print MIFARE Classic access rights bytes mad Checks and prints MAD value Value blocks view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf mf list": { "command": "hf mf list", "description": "Alias of `trace list -t mf` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", @@ -4655,14 +4544,14 @@ "options": [ "-h, --help This help", "-v, --verbose show technical data", - "--aid print all sectors with specified aid", - "-k, --key key for printing sectors", + "--aid print all sectors with specified aid", + "-k, --key key for printing sectors", "-b, --keyb use key B for access printing sectors (by default: key A)", "--be (optional, BigEndian)", "--dch decode Card Holder information", "-f, --file load dump file and decode MAD" ], - "usage": "hf mf mad [-hvb] [--aid ] [-k ] [--be] [--dch] [-f ]" + "usage": "hf mf mad [-hvb] [--aid ] [-k ] [--be] [--dch] [-f ]" }, "hf mf nack": { "command": "hf mf nack", @@ -4679,11 +4568,22 @@ }, "hf mf ndefformat": { "command": "hf mf ndefformat", - "description": "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write.", - "notes": [], + "description": "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write. If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", + "notes": [ + "hf mf ndefformat", + "hf mf ndefformat --1k -> MIFARE Classic 1k", + "hf mf ndefformat --keys hf-mf-01020304-key.bin -> MIFARE 1k with keys from specified file" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-k, --keys filename of keys", + "--mini MIFARE Classic Mini / S20", + "--1k MIFARE Classic 1k / S50 (def)", + "--2k MIFARE Classic/Plus 2k", + "--4k MIFARE Classic 4k / S70" + ], + "usage": "hf mf ndefformat [-h] [-k ] [--mini] [--1k] [--2k] [--4k]" }, "hf mf ndefread": { "command": "hf mf ndefread", @@ -4784,7 +4684,8 @@ "command": "hf mf rdbl", "description": "Read MIFARE Classic block", "notes": [ - "hf mf rdbl --blk 0 -k FFFFFFFFFFFF", + "hf mf rdbl --blk 0", + "hf mf rdbl --blk 0 -k A0A1A2A3A4A5", "hf mf rdbl --blk 3 -v -> get block 3, decode sector trailer" ], "offline": false, @@ -4802,7 +4703,8 @@ "command": "hf mf rdsc", "description": "Read MIFARE Classic sector", "notes": [ - "hf mf rdsc -s 0 -k FFFFFFFFFFFF" + "hf mf rdsc -s 0", + "hf mf rdsc -s 0 -k A0A1A2A3A4A5" ], "offline": false, "options": [ @@ -4817,11 +4719,27 @@ }, "hf mf restore": { "command": "hf mf restore", - "description": "Restore MIFARE Classic dump file to tag.", - "notes": [], + "description": "Restore MIFARE Classic dump file to tag. The key file and dump file will program the card sector trailers. By default we authenticate to card with key 0xFFFFFFFFFFFF. If access rights in dump file is all zeros, it will be replaced with default values `--uid` param is used for filename templates `hf-mf--dump.bin` and `hf-mf--key.bin. if not specified, it will read the card uid instead. `--ka` param you can indicate that the key file should be used for authentication instead. if so we also try both B/A keys `--force` param is used to override warnings and allow bad ACL block writes. if not specified, it will skip blocks with bad ACL.", + "notes": [ + "hf mf restore", + "hf mf restore --1k --uid 04010203", + "hf mf restore --1k --uid 04010203 -k hf-mf-AABBCCDD-key.bin", + "hf mf restore --4k" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "--mini MIFARE Classic Mini / S20", + "--1k MIFARE Classic 1k / S50 (def)", + "--2k MIFARE Classic/Plus 2k", + "--4k MIFARE Classic 4k / S70", + "-u, --uid uid, (4|7|10 hex bytes)", + "-f, --file specify dump filename (bin/eml/json)", + "-k, --kfn key filename", + "--ka use specified keyfile to authenticate", + "--force override warnings" + ], + "usage": "hf mf restore [-h] [--mini] [--1k] [--2k] [--4k] [-u ] [-f ] [-k ] [--ka] [--force]" }, "hf mf setmod": { "command": "hf mf setmod", @@ -4906,9 +4824,10 @@ "options": [ "-h, --help This help", "-r, --reset Reset card", - "-u, --uid New UID (4 hex bytes)" + "-u, --uid New UID (4 hex bytes)", + "--furui Furui detection card" ], - "usage": "hf mf supercard [-hr] [-u ]" + "usage": "hf mf supercard [-hr] [-u ] [--furui]" }, "hf mf value": { "command": "hf mf value", @@ -4976,7 +4895,8 @@ "command": "hf mf wrbl", "description": "Write MIFARE Classic block with 16 hex bytes of data Sector 0 / Block 0 - Manufacturer block When writing to block 0 you must use a VALID block 0 data (UID, BCC, SAK, ATQA) Writing an invalid block 0 means rendering your Magic GEN2 card undetectable. Look in the magic_cards_notes.md file for help to resolve it. `--force` param is used to override warnings like bad ACL and BLOCK 0 writes. if not specified, it will exit if detected", "notes": [ - "hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 000102030405060708090a0b0c0d0e0f" + "hf mf wrbl --blk 1 -d 000102030405060708090a0b0c0d0e0f", + "hf mf wrbl --blk 1 -k A0A1A2A3A4A5 -d 000102030405060708090a0b0c0d0e0f" ], "offline": false, "options": [ @@ -5791,14 +5711,6 @@ ], "usage": "hf mfdes getuid [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ]" }, - "hf mfdes help": { - "command": "hf mfdes help", - "description": "help This help list List DESFire (ISO 14443A) history test Regression crypto tests", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf mfdes info": { "command": "hf mfdes info", "description": "Get info from MIFARE DESfire tags", @@ -6126,7 +6038,7 @@ }, "hf mfp auth": { "command": "hf mfp auth", - "description": "Executes AES authentication command for Mifare Plus card", + "description": "Executes AES authentication command for MIFARE Plus card", "notes": [ "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication", "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data" @@ -6145,9 +6057,9 @@ "description": "Checks keys on MIFARE Plus card", "notes": [ "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B", - "hf mfp chk -s 2 -a -> check default key list on sector 2, key A", + "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A", "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6", - "hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json", + "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file", "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00" ], "offline": false, @@ -6162,10 +6074,10 @@ "--pattern1b Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)", "--pattern2b Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)", "--startp2b Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)", - "-j, --json Json filename to save keys", + "--dump Dump found keys to JSON file", "-v, --verbose Verbose mode" ], - "usage": "hf mfp chk [-habv] [-s <0..255>] [-e <0..255>] [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [-j ]" + "usage": "hf mfp chk [-habv] [-s <0..255>] [-e <0..255>] [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [--dump]" }, "hf mfp commitp": { "command": "hf mfp commitp", @@ -6180,13 +6092,22 @@ ], "usage": "hf mfp commitp [-hv]" }, - "hf mfp help": { - "command": "hf mfp help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" + "hf mfp dump": { + "command": "hf mfp dump", + "description": "Dump MIFARE Plus tag to binary file If no given, UID will be used as filename", + "notes": [ + "hf mfp dump", + "hf mfp dump --keys hf-mf-066C8B78-key.bin -> MIFARE Plus with keys from specified file" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-f, --file filename of dump", + "-k, --keys filename of keys", + "--ns no save to file", + "-v, --verbose Verbose mode" + ], + "usage": "hf mfp dump [-hv] [-f ] [-k ] [--ns]" }, "hf mfp info": { "command": "hf mfp info", @@ -6215,9 +6136,30 @@ ], "usage": "hf mfp initp [-hv] [-k ]" }, + "hf mfp list": { + "command": "hf mfp list", + "description": "Alias of `trace list -t mf` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "notes": [ + "hf mf list --frame -> show frame delay times", + "hf mf list -1 -> use trace buffer" + ], + "offline": true, + "options": [ + "-h, --help This help", + "-1, --buffer use data from trace buffer", + "--frame show frame delay times", + "-c mark CRC bytes", + "-r show relative times (gap and duration)", + "-u display times in microseconds instead of clock cycles", + "-x show hexdump to convert to pcap(ng)", + "or to import into Wireshark using encapsulation type \"ISO 14443\"", + "-f, --file filename of dictionary" + ], + "usage": "hf mf list [-h1crux] [--frame] [-f ]" + }, "hf mfp mad": { "command": "hf mfp mad", - "description": "Checks and prints Mifare Application Directory (MAD)", + "description": "Checks and prints MIFARE Application Directory (MAD)", "notes": [ "hf mfp mad", "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid" @@ -6234,6 +6176,20 @@ ], "usage": "hf mfp mad [-hvb] [--aid ] [-k ] [--be] [--dch]" }, + "hf mfp ndefformat": { + "command": "hf mfp ndefformat", + "description": "format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write. If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", + "notes": [ + "hf mfp ndefformat", + "hf mfp ndefformat --keys hf-mf-01020304-key.bin -> with keys from specified file" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-k, --keys filename of keys" + ], + "usage": "hf mfp ndefformat [-h] [-k ]" + }, "hf mfp ndefread": { "command": "hf mfp ndefread", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -6254,9 +6210,27 @@ ], "usage": "hf mfp ndefread [-hvb] [--aid ] [-k ] [-f ]" }, + "hf mfp ndefwrite": { + "command": "hf mfp ndefwrite", + "description": "Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.", + "notes": [ + "hf mfp ndefwrite -d 0300FE -> write empty record to tag", + "hf mfp ndefwrite -f myfilename", + "hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031" + ], + "offline": false, + "options": [ + "-h, --help This help", + "-d raw NDEF hex bytes", + "-f, --file write raw NDEF file to tag", + "-p fix NDEF record headers / terminator block if missing", + "-v, --verbose verbose output" + ], + "usage": "hf mfp ndefwrite [-hpv] [-d ] [-f ]" + }, "hf mfp rdbl": { "command": "hf mfp rdbl", - "description": "Reads several blocks from Mifare Plus card", + "description": "Reads blocks from MIFARE Plus card", "notes": [ "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data", "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF" @@ -6293,7 +6267,7 @@ }, "hf mfp wrbl": { "command": "hf mfp wrbl", - "description": "Writes one block to Mifare Plus card", + "description": "Writes one block to MIFARE Plus card", "notes": [ "hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data", "hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF" @@ -6408,14 +6382,6 @@ ], "usage": "hf mfu eview [-h] [-e ]" }, - "hf mfu help": { - "command": "hf mfu help", - "description": "help This help keygen Generate 3DES MIFARE diversified keys pwdgen Generate pwd from known algos view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf mfu info": { "command": "hf mfu info", "description": "Get info about MIFARE Ultralight Family styled tag. Sometimes the tags are locked down, and you may need a key to be able to read the information", @@ -6639,14 +6605,6 @@ ], "usage": "hf mfu wrbl [-hl] [-k ] -b -d [--force]" }, - "hf ntag424 help": { - "command": "hf ntag424 help", - "description": "help This help view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf ntag424 info": { "command": "hf ntag424 info", "description": "Get info about NXP NTAG424 DNA Family styled tag.", @@ -6711,14 +6669,6 @@ ], "usage": "hf search [-hv]" }, - "hf seos help": { - "command": "hf seos help", - "description": "help This help list List SEOS history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf seos info": { "command": "hf seos info", "description": "Get info from SEOS tags", @@ -6769,14 +6719,6 @@ ], "usage": "hf sniff [-h] [--sp ] [--st ] [--smode [none|drop|min|max|avg]] [--sratio ]" }, - "hf st25ta help": { - "command": "hf st25ta help", - "description": "help This help list List ISO 14443A/7816 history ndefread read NDEF file on tag", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf st25ta info": { "command": "hf st25ta info", "description": "Get info about ST25TA tag", @@ -6874,14 +6816,6 @@ ], "usage": "hf st25ta sim [-h] -u " }, - "hf tesla help": { - "command": "hf tesla help", - "description": "help This help list List ISO 14443A/7816 history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf tesla info": { "command": "hf tesla info", "description": "Get info about TESLA Key tag", @@ -6915,14 +6849,6 @@ ], "usage": "hf tesla list [-h1crux] [--frame] [-f ]" }, - "hf texkom help": { - "command": "hf texkom help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf texkom reader": { "command": "hf texkom reader", "description": "Read a texkom tag", @@ -6960,14 +6886,6 @@ ], "usage": "hf texkom sim [-hvt] [--raw ] [--id ] [--timeout ]" }, - "hf thinfilm help": { - "command": "hf thinfilm help", - "description": "help This help list List NFC Barcode / Thinfilm history - not correct", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf thinfilm info": { "command": "hf thinfilm info", "description": "Get info from Thinfilm tags", @@ -7024,17 +6942,10 @@ "offline": false, "options": [ "-h, --help This help", - "-f, --file filename of dump" + "-f, --file filename of dump", + "--ns no save to file" ], - "usage": "hf topaz dump [-h] [-f ]" - }, - "hf topaz help": { - "command": "hf topaz help", - "description": "help This help list List Topaz history view Display content from tag dump file", - "notes": [], - "offline": true, - "options": [], - "usage": "" + "usage": "hf topaz dump [-h] [-f ] [--ns]" }, "hf topaz info": { "command": "hf topaz info", @@ -7086,16 +6997,16 @@ }, "hf topaz rdbl": { "command": "hf topaz rdbl", - "description": "Read a block", + "description": "Read Topaz block", "notes": [ - "hf topaz rdbl -b 7" + "hf topaz rdbl --blk 7" ], "offline": false, "options": [ "-h, --help This help", - "-b, --block Block number to write" + "--blk Block number" ], - "usage": "hf topaz rdbl [-h] -b " + "usage": "hf topaz rdbl [-h] --blk " }, "hf topaz reader": { "command": "hf topaz reader", @@ -7151,17 +7062,17 @@ }, "hf topaz wrbl": { "command": "hf topaz wrbl", - "description": "Write a block", + "description": "Write Topaz block with 8 hex bytes of data", "notes": [ - "hf topaz wrbl -b 7 -d 1122334455667788" + "hf topaz wrbl --blk 7 -d 1122334455667788" ], "offline": false, "options": [ "-h, --help This help", - "-b, --block Block number to write", + "--blk Block number", "-d, --data Block data (8 hex bytes)" ], - "usage": "hf topaz wrbl [-h] -b -d " + "usage": "hf topaz wrbl [-h] --blk -d " }, "hf tune": { "command": "hf tune", @@ -7180,14 +7091,6 @@ ], "usage": "hf tune [-h] [-n ] [--bar] [--mix] [--value]" }, - "hf waveshare help": { - "command": "hf waveshare help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf waveshare loadbmp": { "command": "hf waveshare loadbmp", "description": "Load BMP file to Waveshare NFC ePaper.", @@ -7224,14 +7127,6 @@ ], "usage": "hf xerox dump [-hd] [-f ]" }, - "hf xerox help": { - "command": "hf xerox help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hf xerox info": { "command": "hf xerox info", "description": "Tag information for ISO/IEC 14443 type B / XEROX based tags", @@ -7346,14 +7241,6 @@ ], "usage": "hw fpgaoff [-h]" }, - "hw help": { - "command": "hw help", - "description": "------------- ----------------------- Hardware ----------------------- help This help connect Connect Proxmark3 to serial port version Show version information about the client and the connected Proxmark3, if any", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "hw lcd": { "command": "hw lcd", "description": "Send command/data to LCD", @@ -7579,14 +7466,6 @@ ], "usage": "lf awid demod [-h]" }, - "lf awid help": { - "command": "lf awid help", - "description": "help this help demod demodulate an AWID FSK tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf awid reader": { "command": "lf awid reader", "description": "read a AWID Prox tag", @@ -7655,11 +7534,29 @@ }, "lf config": { "command": "lf config", - "description": "Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle.", - "notes": [], + "description": "Get/Set config for LF sampling, bit/sample, decimation, frequency These changes are temporary, will be reset after a power cycle. - use `lf read` performs a read (active field) - use `lf sniff` performs a sniff (no active field)", + "notes": [ + "lf config -> shows current config", + "lf config -b 8 --125 -> samples at 125 kHz, 8 bps", + "lf config -b 4 --134 --dec 3 -> samples at 134 kHz, averages three samples into one, stored with a resolution of 4 bits per sample", + "lf config --trig 20 -s 10000 -> trigger sampling when above 20, skip 10 000 first samples after triggered", + "lf config --reset -> reset back to default values" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "--125 125 kHz frequency", + "--134 134 kHz frequency", + "-a, --avg <0|1> averaging - if set, will average the stored sample value when decimating (default 1)", + "-b, --bps <1-8> sets resolution of bits per sample (default 8)", + "--dec <1-8> sets decimation. A value of N saves only 1 in N samples (default 1)", + "--divisor <19-255> Manually set freq divisor. 88 -> 134 kHz, 95 -> 125 kHz", + "-f, --freq <47-600> manually set frequency in kHz", + "-r, --reset reset values to defaults", + "-s, --skip sets a number of samples to skip before capture (default 0)", + "-t, --trig <0-128> sets trigger threshold. 0 means no threshold" + ], + "usage": "lf config [-hr] [--125] [--134] [-a <0|1>] [-b <1-8>] [--dec <1-8>] [--divisor <19-255>] [-f <47-600>] [-s ] [-t <0-128>]" }, "lf cotag demod": { "command": "lf cotag demod", @@ -7673,14 +7570,6 @@ ], "usage": "lf cotag demod [-h]" }, - "lf cotag help": { - "command": "lf cotag help", - "description": "help This help demod demodulate an COTAG tag", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf cotag reader": { "command": "lf cotag reader", "description": "read a COTAG tag, the current support for COTAG is limited.", @@ -7725,14 +7614,6 @@ ], "usage": "lf destron demod [-h]" }, - "lf destron help": { - "command": "lf destron help", - "description": "help This help demod demodulate an Destron tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf destron reader": { "command": "lf destron reader", "description": "read a Destron tag", @@ -7816,14 +7697,6 @@ ], "usage": "lf em 410x demod [-hia] [--clk ] [--err ] [--len ]" }, - "lf em 410x help": { - "command": "lf em 410x help", - "description": "help This help demod demodulate a EM410x tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf em 410x reader": { "command": "lf em 410x reader", "description": "read EM 410x tag", @@ -7950,14 +7823,6 @@ ], "usage": "lf em 4x05 dump [-h] [-p ] [-f ]" }, - "lf em 4x05 help": { - "command": "lf em 4x05 help", - "description": "help This help demod demodulate a EM4x05/EM4x69 tag from the GraphBuffer sniff Attempt to recover em4x05 commands from sample buffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf em 4x05 info": { "command": "lf em 4x05 info", "description": "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.", @@ -8147,14 +8012,6 @@ ], "usage": "lf em 4x50 eview [-h]" }, - "lf em 4x50 help": { - "command": "lf em 4x50 help", - "description": "help This help ----------- --------------------- operations --------------------- ----------- --------------------- simulation ---------------------", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf em 4x50 info": { "command": "lf em 4x50 info", "description": "Tag information EM4x50.", @@ -8320,14 +8177,6 @@ ], "usage": "lf em 4x70 brute [-h] [--par] -b --rnd --frn [-s ]" }, - "lf em 4x70 help": { - "command": "lf em 4x70 help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf em 4x70 info": { "command": "lf em 4x70 info", "description": "Tag Information EM4x70 Tag variants include ID48 automotive transponder. ID48 does not use command parity (default). V4070 and EM4170 do require parity bit.", @@ -8402,14 +8251,6 @@ ], "usage": "lf em 4x70 writepin [-h] [--par] -p " }, - "lf em help": { - "command": "lf em help", - "description": "help This help 410x { EM 4102 commands... } 4x05 { EM 4205 / 4305 / 4369 / 4469 commands... } 4x50 { EM 4350 / 4450 commands... } 4x70 { EM 4070 / 4170 commands... }", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf fdxb clone": { "command": "lf fdxb clone", "description": "clone a FDX-B tag to a T55x7, Q5/T5555 or EM4305/4469 tag.", @@ -8443,14 +8284,6 @@ ], "usage": "lf fdxb demod [-h]" }, - "lf fdxb help": { - "command": "lf fdxb help", - "description": "help this help demod demodulate a FDX-B ISO11784/85 tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf fdxb reader": { "command": "lf fdxb reader", "description": "read a FDX-B animal tag Note that the continuous mode is less verbose", @@ -8515,14 +8348,6 @@ ], "usage": "lf gallagher demod [-h]" }, - "lf gallagher help": { - "command": "lf gallagher help", - "description": "help This help demod demodulate an GALLAGHER tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf gallagher reader": { "command": "lf gallagher reader", "description": "read a GALLAGHER tag", @@ -8588,14 +8413,6 @@ ], "usage": "lf gproxii demod [-h] [-r ]" }, - "lf gproxii help": { - "command": "lf gproxii help", - "description": "help this help demod demodulate a G Prox II tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf gproxii reader": { "command": "lf gproxii reader", "description": "read a Guardall tag", @@ -8625,14 +8442,6 @@ ], "usage": "lf gproxii sim [-h] --xor --fmt --fc --cn " }, - "lf help": { - "command": "lf help", - "description": "help This help ----------- -------------- Low Frequency -------------- awid { AWID RFIDs... } cotag { COTAG CHIPs... } destron { FDX-A Destron RFIDs... } em { EM CHIPs & RFIDs... } fdxb { FDX-B RFIDs... } gallagher { GALLAGHER RFIDs... } gproxii { Guardall Prox II RFIDs... } hid { HID Prox RFIDs... } hitag { Hitag CHIPs... } idteck { Idteck RFIDs... } indala { Indala RFIDs... } io { ioProx RFIDs... } jablotron { Jablotron RFIDs... } keri { KERI RFIDs... } motorola { Motorola RFIDs... } nedap { Nedap RFIDs... } nexwatch { NexWatch RFIDs... } noralsy { Noralsy RFIDs... } pac { PAC/Stanley RFIDs... } paradox { Paradox RFIDs... } pcf7931 { PCF7931 CHIPs... } presco { Presco RFIDs... } pyramid { Farpointe/Pyramid RFIDs... } securakey { Securakey RFIDs... } ti { TI CHIPs... } t55xx { T55xx CHIPs... } viking { Viking RFIDs... } visa2000 { Visa2000 RFIDs... } ----------- --------------------- General --------------------- search Read and Search for valid known tag", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf hid brute": { "command": "lf hid brute", "description": "Enables bruteforce of HID readers with specified facility code or card number. This is an attack against the reader. If the field being bruteforced is provided, it starts with it and goes up / down one step while maintaining other supplied values. If the field being bruteforced is not provided, it will iterate through the full range while maintaining other supplied values.", @@ -8697,14 +8506,6 @@ ], "usage": "lf hid demod [-h]" }, - "lf hid help": { - "command": "lf hid help", - "description": "help this help demod demodulate HID Prox tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf hid reader": { "command": "lf hid reader", "description": "read a HID Prox tag", @@ -8798,14 +8599,6 @@ ], "usage": "lf hitag eload [-h12sm] -f " }, - "lf hitag help": { - "command": "lf hitag help", - "description": "help This help list List Hitag trace history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf hitag info": { "command": "lf hitag info", "description": "Hitag2 tag information", @@ -8946,14 +8739,6 @@ ], "usage": "lf idteck demod [-h]" }, - "lf idteck help": { - "command": "lf idteck help", - "description": "help This help demod demodulate an Idteck tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf idteck reader": { "command": "lf idteck reader", "description": "read a Idteck tag", @@ -9018,11 +8803,26 @@ }, "lf indala clone": { "command": "lf indala clone", - "description": "clone Indala UID to T55x7 or Q5/T5555 tag using different known formats", - "notes": [], + "description": "clone Indala UID to T55x7 or Q5/T5555 tag using different known formats Warning, encoding with FC/CN doesn't always work", + "notes": [ + "lf indala clone --heden 888", + "lf indala clone --fc 123 --cn 1337", + "lf indala clone --fc 123 --cn 1337 --4041x", + "lf indala clone -r a0000000a0002021", + "lf indala clone -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-r, --raw raw bytes", + "--heden Card number for Heden 2L format", + "--fc Facility code (26 bit H10301 format)", + "--cn Card number (26 bit H10301 format)", + "--q5 Optional - specify writing to Q5/T5555 tag", + "--em Optional - specify writing to EM4305/4469 tag", + "--4041x Optional - specify Indala 4041X format, must use with fc and cn" + ], + "usage": "lf indala clone [-h] [-r ] [--heden ] [--fc ] [--cn ] [--q5] [--em] [--4041x]" }, "lf indala demod": { "command": "lf indala demod", @@ -9042,14 +8842,6 @@ ], "usage": "lf indala demod [-hi] [--clock ] [--maxerr ]" }, - "lf indala help": { - "command": "lf indala help", - "description": "help This help demod Demodulate an Indala tag (PSK1) from the GraphBuffer altdemod Alternative method to demodulate samples for Indala 64 bit UID (option '224' for 224 bit)", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf indala reader": { "command": "lf indala reader", "description": "read a Indala tag", @@ -9116,14 +8908,6 @@ ], "usage": "lf io demod [-h]" }, - "lf io help": { - "command": "lf io help", - "description": "help this help demod demodulate an ioProx tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf io reader": { "command": "lf io reader", "description": "read a ioProx tag", @@ -9193,14 +8977,6 @@ ], "usage": "lf jablotron demod [-h]" }, - "lf jablotron help": { - "command": "lf jablotron help", - "description": "help This help demod demodulate an Jablotron tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf jablotron reader": { "command": "lf jablotron reader", "description": "read a jablotron tag", @@ -9257,14 +9033,6 @@ ], "usage": "lf keri demod [-h]" }, - "lf keri help": { - "command": "lf keri help", - "description": "help This help demod demodulate an KERI tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf keri reader": { "command": "lf keri reader", "description": "read a keri tag", @@ -9320,14 +9088,6 @@ ], "usage": "lf motorola demod [-h]" }, - "lf motorola help": { - "command": "lf motorola help", - "description": "help This help demod demodulate an MOTOROLA tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf motorola reader": { "command": "lf motorola reader", "description": "read a Motorola tag", @@ -9383,14 +9143,6 @@ ], "usage": "lf nedap demod [-h]" }, - "lf nedap help": { - "command": "lf nedap help", - "description": "help This help demod demodulate Nedap tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf nedap reader": { "command": "lf nedap reader", "description": "read a Nedap tag", @@ -9457,14 +9209,6 @@ ], "usage": "lf nexwatch demod [-h]" }, - "lf nexwatch help": { - "command": "lf nexwatch help", - "description": "help This help demod demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf nexwatch reader": { "command": "lf nexwatch reader", "description": "read a Nexwatch tag", @@ -9531,14 +9275,6 @@ ], "usage": "lf noralsy demod [-h]" }, - "lf noralsy help": { - "command": "lf noralsy help", - "description": "help This help demod demodulate an Noralsy tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf noralsy reader": { "command": "lf noralsy reader", "description": "read a Noralsy tag", @@ -9598,14 +9334,6 @@ ], "usage": "lf pac demod [-h]" }, - "lf pac help": { - "command": "lf pac help", - "description": "help This help demod demodulate a PAC tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf pac reader": { "command": "lf pac reader", "description": "read a PAC/Stanley tag", @@ -9667,14 +9395,6 @@ ], "usage": "lf paradox demod [-h] [--old]" }, - "lf paradox help": { - "command": "lf paradox help", - "description": "help This help demod demodulate a Paradox FSK tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf paradox reader": { "command": "lf paradox reader", "description": "read a Paradox tag", @@ -9725,14 +9445,6 @@ ], "usage": "lf pcf7931 config [-hr] [-p ] [-d ] [--lw ] [--lp ]" }, - "lf pcf7931 help": { - "command": "lf pcf7931 help", - "description": "help This help config Configure the password, the tags initialization delay and time offsets (optional)", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf pcf7931 reader": { "command": "lf pcf7931 reader", "description": "read a PCF7931 tag", @@ -9791,14 +9503,6 @@ ], "usage": "lf presco demod [-h]" }, - "lf presco help": { - "command": "lf presco help", - "description": "help This help demod demodulate Presco tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf presco reader": { "command": "lf presco reader", "description": "read a presco tag", @@ -9858,14 +9562,6 @@ ], "usage": "lf pyramid demod [-h]" }, - "lf pyramid help": { - "command": "lf pyramid help", - "description": "help this help demod demodulate a Pyramid FSK tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf pyramid reader": { "command": "lf pyramid reader", "description": "read a Farpointe/Pyramid tag", @@ -9958,14 +9654,6 @@ ], "usage": "lf securakey demod [-h]" }, - "lf securakey help": { - "command": "lf securakey help", - "description": "help This help demod demodulate an Securakey tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf securakey reader": { "command": "lf securakey reader", "description": "read a Securakey tag", @@ -10044,11 +9732,27 @@ }, "lf simfsk": { "command": "lf simfsk", - "description": "Simulate FSK tag from DemodBuffer or input. There are about four FSK modulations to know of. FSK1 - where fc/8 = high and fc/5 = low FSK1a - is inverted FSK1, ie: fc/5 = high and fc/8 = low FSK2 - where fc/10 = high and fc/8 = low FSK2a - is inverted FSK2, ie: fc/10 = high and fc/8 = low", - "notes": [], + "description": "Simulate FSK tag from DemodBuffer or input. There are about four FSK modulations to know of. FSK1 - where fc/8 = high and fc/5 = low FSK1a - is inverted FSK1, ie: fc/5 = high and fc/8 = low FSK2 - where fc/10 = high and fc/8 = low FSK2a - is inverted FSK2, ie: fc/10 = high and fc/8 = low NOTE: if you set one clock manually set them all manually", + "notes": [ + "lf simfsk -c 40 --high 8 --low 5 -d 010203 -> FSK1 rf/40 data 010203", + "lf simfsk -c 40 --high 5 --low 8 -d 010203 -> FSK1a rf/40 data 010203", + "lf simfsk -c 64 --high 10 --low 8 -d 010203 -> FSK2 rf/64 data 010203", + "lf simfsk -c 64 --high 8 --low 10 -d 010203 -> FSK2a rf/64 data 010203", + "", + "lf simfsk -c 50 --high 10 --low 8 -d 1D5559555569A9A555A59569 -> simulate HID Prox tag manually", + "lf simfsk -c 50 --high 10 --low 8 --stt -d 011DB2487E8D811111111111 -> simulate AWID tag manually" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-c, --clk manually set clock - can autodetect if using DemodBuffer (default 64)", + "--low manually set larger Field Clock", + "--high manually set smaller Field Clock", + "--stt TBD! - STT to enable a gap between playback repetitions (default: no gap)", + "-d, --data data to sim - omit to use DemodBuffer", + "-v, --verbose verbose output" + ], + "usage": "lf simfsk [-hv] [-c ] [--low ] [--high ] [--stt] [-d ]" }, "lf simpsk": { "command": "lf simpsk", @@ -10074,19 +9778,38 @@ }, "lf sniff": { "command": "lf sniff", - "description": "Sniff low frequency signal. You need to configure the LF part on the Proxmark3 device manually. Usually a trigger and skip samples is a good thing to set before doing a low frequency sniff.", - "notes": [], + "description": "Sniff low frequency signal. You need to configure the LF part on the Proxmark3 device manually. Usually a trigger and skip samples is a good thing to set before doing a low frequency sniff. - use `lf config` to set parameters. - use `data plot` to look at sniff signal. - use `lf search -1` to see if signal can be automatic decoded", + "notes": [ + "lf sniff -v", + "lf sniff -s 3000 -@ -> oscilloscope style" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-s, --samples number of samples to collect", + "-v, --verbose verbose output", + "-@ continuous sniffing mode" + ], + "usage": "lf sniff [-hv@] [-s ]" }, "lf t55xx bruteforce": { "command": "lf t55xx bruteforce", - "description": "This command uses bruteforce to scan a number range. Try reading Page 0, block 7 before.", - "notes": [], + "description": "This command uses bruteforce to scan a number range. Try reading Page 0, block 7 before. WARNING this may brick non-password protected chips!", + "notes": [ + "lf t55xx bruteforce --r2 -s aaaaaa77 -e aaaaaa99" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-s, --start search start password (4 hex bytes)", + "-e, --end search end password (4 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes (def)" + ], + "usage": "lf t55xx bruteforce [-h] -s -e [--r0] [--r1] [--r2] [--r3] [--all]" }, "lf t55xx chk": { "command": "lf t55xx chk", @@ -10241,14 +9964,6 @@ ], "usage": "lf t55xx dump [-ho] [-f ] [-p ] [--ns] [--r0] [--r1] [--r2] [--r3]" }, - "lf t55xx help": { - "command": "lf t55xx help", - "description": "----------- ---------------------------- notice ----------------------------- Remember to run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- --------------------- operations --------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) ----------- --------------------- recovery --------------------- sniff Attempt to recover T55xx commands from sample buffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf t55xx info": { "command": "lf t55xx info", "description": "Show T55x7 configuration data (page 0/ blk 0) from reading the configuration block from tag. Use `-c` to specify a config block data to be used instead of reading tag.", @@ -10315,19 +10030,45 @@ }, "lf t55xx read": { "command": "lf t55xx read", - "description": "Read T55xx block data. This commands defaults to page 0.", - "notes": [], + "description": "Read T55xx block data. This commands defaults to page 0. * * * WARNING * * * Use of read with password on a tag not configured for a password can damage the tag * * * * * * * * * *", + "notes": [ + "lf t55xx read -b 0 -> read data from block 0", + "lf t55xx read -b 0 --pwd 01020304 -> read data from block 0, pwd 01020304", + "lf t55xx read -b 0 --pwd 01020304 -o -> read data from block 0, pwd 01020304, override" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-b, --blk <0-7> block number to read", + "-p, --pwd password (4 hex bytes)", + "-o, --override override safety check", + "--pg1 read page 1", + "--r0 downlink - fixed bit length (detected def)", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference" + ], + "usage": "lf t55xx read [-ho] -b <0-7> [-p ] [--pg1] [--r0] [--r1] [--r2] [--r3]" }, "lf t55xx recoverpw": { "command": "lf t55xx recoverpw", - "description": "This command uses a few tricks to try to recover mangled password. Try reading Page 0, block 7 before.", - "notes": [], + "description": "This command uses a few tricks to try to recover mangled password. Try reading Page 0, block 7 before. WARNING this may brick non-password protected chips!", + "notes": [ + "lf t55xx recoverpw", + "lf t55xx recoverpw -p 11223344", + "lf t55xx recoverpw -p 11223344 --r3" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-p, --pwd password (4 hex bytes)", + "--r0 downlink - fixed bit length", + "--r1 downlink - long leading reference", + "--r2 downlink - leading zero", + "--r3 downlink - 1 of 4 coding reference", + "--all try all downlink modes (def)" + ], + "usage": "lf t55xx recoverpw [-h] [-p ] [--r0] [--r1] [--r2] [--r3] [--all]" }, "lf t55xx resetread": { "command": "lf t55xx resetread", @@ -10483,14 +10224,6 @@ ], "usage": "lf ti demod [-h]" }, - "lf ti help": { - "command": "lf ti help", - "description": "help This help demod Demodulate raw bits for TI LF tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf ti reader": { "command": "lf ti reader", "description": "read a TI tag", @@ -10567,14 +10300,6 @@ ], "usage": "lf viking demod [-h]" }, - "lf viking help": { - "command": "lf viking help", - "description": "help This help demod demodulate a Viking tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf viking reader": { "command": "lf viking reader", "description": "read a Viking AM tag", @@ -10630,14 +10355,6 @@ ], "usage": "lf visa2000 demod [-h]" }, - "lf visa2000 help": { - "command": "lf visa2000 help", - "description": "help This help demod demodulate an VISA2000 tag from the GraphBuffer", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "lf visa2000 reader": { "command": "lf visa2000 reader", "description": "read a visa2000 tag", @@ -10696,14 +10413,6 @@ ], "usage": "mem dump [-hv] [-o ] [-l ] [-f ] [-c ]" }, - "mem help": { - "command": "mem help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "mem info": { "command": "mem info", "description": "Collect signature and verify it from flash memory", @@ -10783,14 +10492,6 @@ ], "usage": "mem spiffs dump [-he] -s [-d ]" }, - "mem spiffs help": { - "command": "mem spiffs help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "mem spiffs info": { "command": "mem spiffs info", "description": "Print file system info and usage statistics", @@ -10944,14 +10645,6 @@ ], "usage": "msleep [-h] [-t ]" }, - "nfc barcode help": { - "command": "nfc barcode help", - "description": "-------- ------------------ NFC Barcode -------------------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc barcode read": { "command": "nfc barcode read", "description": "Get info from Thinfilm tags", @@ -10995,21 +10688,24 @@ ], "usage": "nfc decode [-hv] [-d ] [-f ]" }, - "nfc help": { - "command": "nfc help", - "description": "-------- --------------------- NFC Tags -------------------- type1 { NFC Forum Tag Type 1... } type2 { NFC Forum Tag Type 2... } type4a { NFC Forum Tag Type 4 ISO14443A... } type4b { NFC Forum Tag Type 4 ISO14443B... } mf { NFC Type MIFARE Classic/Plus Tag... } barcode { NFC Barcode Tag... } -------- --------------------- General --------------------- help This help decode Decode NDEF records", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc mf cformat": { "command": "nfc mf cformat", - "description": "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write.", - "notes": [], + "description": "format MIFARE Classic Tag as a NFC tag with Data Exchange Format (NDEF) If no given, UID will be used as filename. It will try default keys and MAD keys to detect if tag is already formatted in order to write. If not, it will try finding a key file based on your UID. ie, if you ran autopwn before", + "notes": [ + "hf mf ndefformat", + "hf mf ndefformat --1k -> MIFARE Classic 1k", + "hf mf ndefformat --keys hf-mf-01020304-key.bin -> MIFARE 1k with keys from specified file" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help", + "-k, --keys filename of keys", + "--mini MIFARE Classic Mini / S20", + "--1k MIFARE Classic 1k / S50 (def)", + "--2k MIFARE Classic/Plus 2k", + "--4k MIFARE Classic 4k / S70" + ], + "usage": "hf mf ndefformat [-h] [-k ] [--mini] [--1k] [--2k] [--4k]" }, "nfc mf cread": { "command": "nfc mf cread", @@ -11053,14 +10749,6 @@ ], "usage": "hf mf ndefwrite [-hpv] [-d ] [-f ] [--mini] [--1k] [--2k] [--4k]" }, - "nfc mf help": { - "command": "nfc mf help", - "description": "-------- --------- NFC Type MIFARE Classic/Plus Tag -------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc mf pread": { "command": "nfc mf pread", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -11081,14 +10769,6 @@ ], "usage": "hf mfp ndefread [-hvb] [--aid ] [-k ] [-f ]" }, - "nfc type1 help": { - "command": "nfc type1 help", - "description": "-------- -------------- NFC Forum Tag Type 1 --------------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc type1 read": { "command": "nfc type1 read", "description": "Get info from Topaz tags", @@ -11104,14 +10784,6 @@ ], "usage": "hf topaz info [-hv] [-f ]" }, - "nfc type2 help": { - "command": "nfc type2 help", - "description": "-------- -------------- NFC Forum Tag Type 2 --------------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc type2 read": { "command": "nfc type2 read", "description": "Prints NFC Data Exchange Format (NDEF)", @@ -11142,14 +10814,6 @@ ], "usage": "hf 14a ndefformat [-hv]" }, - "nfc type4a help": { - "command": "nfc type4a help", - "description": "-------- --------- NFC Forum Tag Type 4 ISO14443A ---------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc type4a read": { "command": "nfc type4a read", "description": "Read NFC Data Exchange Format (NDEF) file on Type 4 NDEF tag", @@ -11199,14 +10863,6 @@ ], "usage": "hf 14a ndefwrite [-hpv] [-d ] [-f ]" }, - "nfc type4b help": { - "command": "nfc type4b help", - "description": "-------- --------- NFC Forum Tag Type 4 ISO14443B ------------- -------- --------------------- General --------------------- help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "nfc type4b read": { "command": "nfc type4b read", "description": "Print NFC Data Exchange Format (NDEF)", @@ -11263,14 +10919,6 @@ ], "usage": "piv getdata [-hskatw] [--aid ] " }, - "piv help": { - "command": "piv help", - "description": "help This help list List ISO7816 history", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "piv list": { "command": "piv list", "description": "Alias of `trace list -t 7816` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", @@ -11438,14 +11086,6 @@ ], "usage": "prefs get savepaths [-h]" }, - "prefs help": { - "command": "prefs help", - "description": "help This help get { Get a preference } set { Set a preference } show Show all preferences", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "prefs set barmode": { "command": "prefs set barmode", "description": "Set persistent preference of HF/LF tune command styled output in the client", @@ -11520,14 +11160,6 @@ ], "usage": "prefs set emoji [-h] [--alias] [--emoji] [--alttext] [--none]" }, - "prefs set help": { - "command": "prefs set help", - "description": "help This help barmode Set bar mode clientdebug Set client debug level clientdelay Set client execution delay color Set color support emoji Set emoji display hints Set hint display savepaths ... to be adjusted next ... output Set dump output style plotsliders Set plot slider display", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "prefs set hints": { "command": "prefs set hints", "description": "Set persistent preference of showing hint messages in the client", @@ -11625,13 +11257,17 @@ ], "usage": "rem [-h] []..." }, - "script help": { - "command": "script help", - "description": "This is a feature to run Lua/Cmd scripts. You can place scripts within the luascripts/cmdscripts folders. --------------------------------------------------------------------------------------- script list available offline: yes", - "notes": [], + "script list": { + "command": "script list", + "description": "List available Lua, Cmd and Python scripts", + "notes": [ + "script list" + ], "offline": true, - "options": [], - "usage": "" + "options": [ + "-h, --help This help" + ], + "usage": "script list [-h]" }, "script run": { "command": "script run", @@ -11660,14 +11296,6 @@ ], "usage": "smart brute [-ht]" }, - "smart help": { - "command": "smart help", - "description": "help This help list List ISO 7816 history upgrade Upgrade sim module firmware", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "smart info": { "command": "smart info", "description": "Extract more detailed information from smart card.", @@ -11752,14 +11380,6 @@ ], "usage": "smart setclock [-h] [--16mhz] [--8mhz] [--4mhz]" }, - "smart upgrade": { - "command": "smart upgrade", - "description": "[=] ------------------------------------------------------------------- [!] WARNING - sim module firmware upgrade [!] A dangerous command, do wrong and you could brick the sim module [=] -------------------------------------------------------------------", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "trace extract": { "command": "trace extract", "description": "Extracts protocol authentication challenges from trace buffer", @@ -11774,14 +11394,6 @@ ], "usage": "trace extract [-h1]" }, - "trace help": { - "command": "trace help", - "description": "help This help extract Extract authentication challenges found in trace list List protocol data in trace buffer load Load trace from file save Save trace buffer to file", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "trace list": { "command": "trace list", "description": "Annotate trace buffer with selected protocol data You can load a trace from file (see `trace load -h`) or it be downloaded from device by default", @@ -11854,11 +11466,15 @@ }, "usart btfactory": { "command": "usart btfactory", - "description": "Reset BT add-on to factory settings This requires 1) BTpower to be turned ON 2) BT add-on to NOT be connected => the add-on blue LED must blink", - "notes": [], + "description": "Reset BT add-on to factory settings This requires 1) BTpower to be turned ON 2) BT add-on to NOT be connected => the add-on blue LED must blink WARNING: process only if strictly needed!", + "notes": [ + "usart btfactory" + ], "offline": false, - "options": [], - "usage": "" + "options": [ + "-h, --help This help" + ], + "usage": "usart btfactory [-h]" }, "usart btpin": { "command": "usart btpin", @@ -11891,14 +11507,6 @@ ], "usage": "usart config [-hNEO] [-b ]" }, - "usart help": { - "command": "usart help", - "description": "help This help", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "usart rx": { "command": "usart rx", "description": "Receive string over USART. WARNING: it will have side-effects if used in USART HOST mode!", @@ -12000,14 +11608,6 @@ ], "usage": "wiegand encode [-h] [--fc ] --cn [--issue ] [--oem ] [-w ] [--pre]" }, - "wiegand help": { - "command": "wiegand help", - "description": "help This help list List available wiegand formats encode Encode to wiegand raw hex (currently for HID Prox) decode Convert raw hex to decoded wiegand format (currently for HID Prox)", - "notes": [], - "offline": true, - "options": [], - "usage": "" - }, "wiegand list": { "command": "wiegand list", "description": "List available wiegand formats", @@ -12022,9 +11622,8 @@ } }, "metadata": { - "commands_extracted": 755, + "commands_extracted": 675, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2023-06-04T15:36:56" - + "extracted_on": "2023-06-27T13:20:13" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 938413fa8..a27cf6964 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -538,17 +538,21 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf mfp help `|Y |`This help` -|`hf mfp info `|N |`Info about Mifare Plus tag` -|`hf mfp wrp `|N |`Write Perso command` -|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode` -|`hf mfp commitp `|N |`Move card to SL1 or SL3 mode` +|`hf mfp list `|Y |`List MIFARE Plus history` |`hf mfp auth `|N |`Authentication` -|`hf mfp rdbl `|N |`Read blocks` -|`hf mfp rdsc `|N |`Read sectors` -|`hf mfp wrbl `|N |`Write blocks` |`hf mfp chk `|N |`Check keys` +|`hf mfp dump `|N |`Dump MIFARE Plus tag to binary file` +|`hf mfp info `|N |`Info about MIFARE Plus tag` |`hf mfp mad `|N |`Check and print MAD` +|`hf mfp rdbl `|N |`Read blocks from card` +|`hf mfp rdsc `|N |`Read sectors from card` +|`hf mfp wrbl `|N |`Write block to card` +|`hf mfp commitp `|N |`Configure security layer (SL1/SL3 mode)` +|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode` +|`hf mfp wrp `|N |`Write Perso command` +|`hf mfp ndefformat `|N |`Format MIFARE Plus Tag as NFC Tag` |`hf mfp ndefread `|N |`Read and print NDEF records from card` +|`hf mfp ndefwrite `|N |`Write NDEF records to card` ### hf mfu @@ -704,14 +708,14 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf topaz help `|Y |`This help` -|`hf topaz dump `|N |`Dump TOPAZ family tag to file` |`hf topaz list `|Y |`List Topaz history` +|`hf topaz dump `|N |`Dump TOPAZ family tag to file` |`hf topaz info `|N |`Tag information` +|`hf topaz raw `|N |`Send raw hex data to tag` +|`hf topaz rdbl `|N |`Read block` |`hf topaz reader `|N |`Act like a Topaz reader` |`hf topaz sim `|N |`Simulate Topaz tag` |`hf topaz sniff `|N |`Sniff Topaz reader-tag communication` -|`hf topaz raw `|N |`Send raw hex data to tag` -|`hf topaz rdbl `|N |`Read block` |`hf topaz view `|Y |`Display content from tag dump file` |`hf topaz wrbl `|N |`Write block` diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 7a19e6dbe..0983ee2e1 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -621,6 +621,7 @@ typedef struct { #define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613 #define CMD_HF_MIFARE_ACQ_NONCES 0x0614 #define CMD_HF_MIFARE_STATIC_NESTED 0x0615 +#define CMD_HF_MIFARE_STATIC_ENC 0x0616 #define CMD_HF_MIFARE_READBL 0x0620 #define CMD_HF_MIFAREU_READBL 0x0720 diff --git a/include/protocols.h b/include/protocols.h index f67ae1798..0183f9f0d 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -263,6 +263,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define MAGIC_GEN_3 9 #define MAGIC_GEN_4GTU 10 #define MAGIC_GEN_4GDM 11 +#define MAGIC_QL88 12 + // Commands for configuration of Gen4 GTU cards. // see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md diff --git a/tools/mfd_aes_brute/Makefile b/tools/mfd_aes_brute/Makefile index cf2c457c6..d0df682f6 100644 --- a/tools/mfd_aes_brute/Makefile +++ b/tools/mfd_aes_brute/Makefile @@ -9,6 +9,9 @@ MYLDLIBS = -lcrypto cpu_arch = $(shell uname -m) ifneq ($(findstring arm64, $(cpu_arch)), ) MYCFLAGS += -mcpu=native +# iOS 'fun' +else ifneq ($(findstring iP, $(cpu_arch)), ) + MYCFLAGS += -mcpu=native else MYCFLAGS += -march=native endif diff --git a/tools/mfd_aes_brute/mfd_aes_brute.c b/tools/mfd_aes_brute/mfd_aes_brute.c index 19bb54ce5..53a984421 100644 --- a/tools/mfd_aes_brute/mfd_aes_brute.c +++ b/tools/mfd_aes_brute/mfd_aes_brute.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "util_posix.h" #define AEND "\x1b[0m" diff --git a/tools/mfd_aes_brute/mfd_multi_brute.c b/tools/mfd_aes_brute/mfd_multi_brute.c index 226fd9f7f..b097c77d7 100644 --- a/tools/mfd_aes_brute/mfd_multi_brute.c +++ b/tools/mfd_aes_brute/mfd_multi_brute.c @@ -35,6 +35,7 @@ #include #include #include +#include //#include #include "util_posix.h" #include "randoms.h" diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index 3320d9866..a8ed2a196 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -437,8 +437,7 @@ while true; do if ! CheckExecute slow "lf T55 hid_48 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_hid_48.pm3; lf hid demod'" \ "HID Corporate 1000 48-bit"; then break; fi if ! CheckExecute slow "lf T55 indala_hedem test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf search -1'" "Indala ID found"; then break; fi - if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" \ - "Heden-2L \| 888"; then break; fi + if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" "Heden-2L...... 888"; then break; fi if ! CheckExecute slow "lf T55 indala test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf search -1'" "Indala ID found"; then break; fi if ! CheckExecute slow "lf T55 indala test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf indala demod'" \ "Fmt 26 FC: 123 Card: 1337 Parity: 11"; then break; fi