diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 6c6bc48e0..8823ea2d9 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -3219,39 +3219,87 @@ int CmdHF14AMfMAD(const char *cmd) { CLIParserInit("hf mf mad", "Checks and prints Mifare Application Directory (MAD)", - "Usage:\n\thf mf mad -> shows MAD if exists\n"); + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k d3f7d3f7d3f7 -> shows NDEF data if exists\n"); void* argtable[] = { arg_param_begin, arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); CLIParserFree(); - uint8_t sector[16 * 4] = {0}; - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector)) { + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); return 2; } if (verbose) { for(int i = 0; i < 4; i ++) - PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or[i * 16], 16)); + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); } bool haveMAD2 = false; - MAD1DecodeAndPrint(sector, verbose, &haveMAD2); + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector)) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); return 2; } - MAD2DecodeAndPrint(sector, verbose); + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for(int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } } return 0; diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 43c8d645d..725dbca04 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -643,20 +643,38 @@ int CmdHFMFPMAD(const char *cmd) { CLIParserInit("hf mfp mad", "Checks and prints Mifare Application Directory (MAD)", - "Usage:\n\thf mfp mad -> shows MAD if exists\n"); + "Usage:\n\thf mfp mad -> shows MAD if exists\n" + "\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n"); void* argtable[] = { arg_param_begin, arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[16] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } - uint8_t sector[16 * 4] = {0}; - if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector, verbose)) { + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + + if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); return 2; @@ -664,20 +682,52 @@ int CmdHFMFPMAD(const char *cmd) { if (verbose) { for(int i = 0; i < 4; i ++) - PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or[i * 16], 16)); + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); } bool haveMAD2 = false; - MAD1DecodeAndPrint(sector, verbose, &haveMAD2); + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); if (haveMAD2) { - if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector, verbose)) { + if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); return 2; } - MAD2DecodeAndPrint(sector, verbose); + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[16] = {0}; + memcpy(akey, g_mifarep_ndef_key, 16); + if (keylen == 16) { + memcpy(akey, key, 16); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector, false)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for(int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } } return 0; diff --git a/client/mifare/mad.c b/client/mifare/mad.c index ff6991f22..34ea50cfc 100644 --- a/client/mifare/mad.c +++ b/client/mifare/mad.c @@ -134,10 +134,13 @@ uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) { return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]); } -int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { +int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) { + if (!sector0) + return 1; - uint8_t GPB = sector[3 * 16 + 9]; - PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB); + uint8_t GPB = sector0[3 * 16 + 9]; + if (verbose) + PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB); // DA (MAD available) if (!(GPB & 0x80)) { @@ -146,13 +149,16 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { } // MA (multi-application card) - if (GPB & 0x40) - PrintAndLogEx(NORMAL, "Multi application card."); - else - PrintAndLogEx(NORMAL, "Single application card."); + if (verbose) { + if (GPB & 0x40) + PrintAndLogEx(NORMAL, "Multi application card."); + else + PrintAndLogEx(NORMAL, "Single application card."); + } uint8_t MADVer = GPB & 0x03; - PrintAndLogEx(NORMAL, "MAD version: %d", MADVer); + if (verbose) + PrintAndLogEx(NORMAL, "MAD version: %d", MADVer); // MAD version if ((MADVer != 0x01) && (MADVer != 0x02)) { @@ -163,7 +169,56 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { if (haveMAD2) *haveMAD2 = (MADVer == 2); - int res = madCRCCheck(sector, true, 1); + int res = madCRCCheck(sector0, true, 1); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD1 OK."); + + if (MADVer == 2 && sector10) { + int res = madCRCCheck(sector10, true, 2); + if (res) + return res; + + if (verbose) + PrintAndLogEx(NORMAL, "CRC8-MAD2 OK."); + } + + return 0; +} + +int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen) { + *madlen = 0; + bool haveMAD2 = false; + int res = MADCheck(sector0, sector10, false, &haveMAD2); + if (res) + return res; + + for (int i = 1; i < 16; i++) { + mad[*madlen] = madGetAID(sector0, 1, i); + (*madlen)++; + } + + if (haveMAD2) { + // mad2 sector (0x10 == 16dec) here + mad[*madlen] = 0x0005; + (*madlen)++; + + for (int i = 1; i < 24; i++) { + mad[*madlen] = madGetAID(sector10, 2, i); + (*madlen)++; + } + } + + return 0; +} + + +int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { + + // check MAD1 only + int res = MADCheck(sector, NULL, verbose, haveMAD2); if (res) return res; diff --git a/client/mifare/mad.h b/client/mifare/mad.h index dc2b2e3c0..ee362adb6 100644 --- a/client/mifare/mad.h +++ b/client/mifare/mad.h @@ -19,8 +19,10 @@ typedef struct { const char *Description; } madAIDDescr; -int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2); -int MAD2DecodeAndPrint(uint8_t *sector, bool verbose); +extern int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2); +extern int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen); +extern int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2); +extern int MAD2DecodeAndPrint(uint8_t *sector, bool verbose); #endif // _MAD_H_ diff --git a/client/mifare/mifare4.c b/client/mifare/mifare4.c index 3fe67077f..c95529a84 100644 --- a/client/mifare/mifare4.c +++ b/client/mifare/mifare4.c @@ -302,7 +302,8 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF memmove(session->Kmac, kmac, 16); } - PrintAndLogEx(INFO, "Authentication OK"); + if (verbose) + PrintAndLogEx(INFO, "Authentication OK"); return 0; } diff --git a/client/mifare/mifaredefault.h b/client/mifare/mifaredefault.h index e7218cbe7..b12a57c03 100644 --- a/client/mifare/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -42,8 +42,9 @@ static const uint64_t g_mifare_default_keys[] = 0x96a301bce267 }; -static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; +static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; -static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; +static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; +static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; #endif