diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ae35b2f8..46dfc8d0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Use proxmark3 as a generic smartcard reader with other software with `smart relay` (@gm3197) - Added `tools\mfkeys\staticnested` - program to recover static nested keys (@iceman1001) - Added `pm3_gen_dictionary.py` - python script to extract and save all keys from MFC dump files. (@iceman1001) - Changed `hf mfu info` - now detect MIFARE Ultralight AES (@iceman1001) diff --git a/client/deps/mbedtls.cmake b/client/deps/mbedtls.cmake index 58b9aae23..c1ab8d880 100644 --- a/client/deps/mbedtls.cmake +++ b/client/deps/mbedtls.cmake @@ -43,6 +43,7 @@ add_library(pm3rrg_rdv4_mbedtls STATIC ../../common/mbedtls/x509.c ../../common/mbedtls/x509_crl.c ../../common/mbedtls/x509_crt.c + ../../common/mbedtls/net_sockets.c ) target_include_directories(pm3rrg_rdv4_mbedtls PRIVATE ../../common) diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index 1e825bbaf..2d6ed052a 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -20,6 +20,7 @@ #include #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN +#include "iso7816/iso7816core.h" #include "protocols.h" #include "cmdtrace.h" #include "proxmark3.h" @@ -32,6 +33,11 @@ #include "crc16.h" // crc #include "cliparser.h" // cliparsing #include "atrs.h" // ATR lookup +#include "mbedtls/net_sockets.h" +#include "mifare.h" +#include "util_posix.h" +#include "cmdhf14a.h" +#include "cmdhf14b.h" static int CmdHelp(const char *Cmd); @@ -1158,10 +1164,201 @@ static int CmdSmartBruteforceSFI(const char *Cmd) { return PM3_SUCCESS; } +static void atsToEmulatedAtr(uint8_t *ats, uint8_t *atr, int *atrLen) { + int historicalLen = 0; + int offset = 2; + + if (ats[0] < 2) { + historicalLen = 0; + } else { + + if ((ats[1] & 64) != 0) { + offset++; + } + if ((ats[1] & 32) != 0) { + offset++; + } + if ((ats[1] & 16) != 0) { + offset++; + } + + if (offset >= ats[0]) { + historicalLen = 0; + } else { + historicalLen = ats[0] - offset; + } + } + + atr[0] = 0x3B; + atr[1] = 0x80 | historicalLen; + atr[2] = 0x80; + atr[3] = 0x01; + + uint8_t tck = atr[1] ^ atr[2] ^ atr[3]; + for (int i = 0; i < historicalLen; ++i) { + atr[4 + i] = ats[offset + i]; + tck = tck ^ ats[offset + i]; + } + atr[4 + historicalLen] = tck; + + *atrLen = 5 + historicalLen; +} + +static void atqbToEmulatedAtr(uint8_t *atqb, uint8_t cid, uint8_t *atr, int *atrLen) { + atr[0] = 0x3B; + atr[1] = 0x80 | 8; + atr[2] = 0x80; + atr[3] = 0x01; + + memcpy(atr + 4, atqb, 7); + atr[11] = cid >> 4; + + uint8_t tck = 0; + for (int i = 1; i < 12; ++i) { + tck = tck ^ atr[i]; + } + atr[12] = tck; + + *atrLen = 13; +} + +static int CmdRelay(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "smart relay", + "Make pm3 available to host OS smartcard driver via vpcd to enable use with other software such as GlobalPlatform Pro", + "Requires the virtual smartcard daemon to be installed and running, see https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html" + ); + + void *argtable[] = { + arg_param_begin, + arg_str0(NULL, "host", "", "vpcd socket host (default: localhost)"), + arg_str0("p", "port", "", "vpcd socket port (default: 35963)"), + arg_lit0("v", "verbose", "display APDU transactions between OS and card"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + + uint8_t host[100] = {0}; + int hostLen = sizeof(host); + CLIGetStrWithReturn(ctx, 1, host, &hostLen); + if (hostLen == 0) { + strcpy((char *) host, "localhost"); + } + + uint8_t port[6] = {0}; + int portLen = sizeof(port); + CLIGetStrWithReturn(ctx, 2, port, &portLen); + if (portLen == 0) { + strcpy((char *) port, "35963"); + } + + bool verbose = arg_get_lit(ctx, 3); + + CLIParserFree(ctx); + + mbedtls_net_context netCtx; + mbedtls_net_init(&netCtx); + + PrintAndLogEx(INFO, "Relaying pm3 to host OS pcsc daemon. Press " _GREEN_("Enter") " to exit"); + + uint8_t cmdbuf[512] = {0}; + iso14a_card_select_t selectedCard14a; + iso14b_card_select_t selectedCard14b; + isodep_state_t cardType = ISODEP_INACTIVE; + bool fieldActivated = false; + + do { + if (cardType != ISODEP_INACTIVE) { + int bytesRead = mbedtls_net_recv_timeout(&netCtx, cmdbuf, sizeof(cmdbuf), 100); + + if (bytesRead == MBEDTLS_ERR_SSL_TIMEOUT || bytesRead == MBEDTLS_ERR_SSL_WANT_READ) { + continue; + } + + if (bytesRead > 0) { + if (cmdbuf[1] == 0x01 && cmdbuf[2] == 0x04) { // vpcd GET ATR + uint8_t atr[20] = {0}; + int atrLen = 0; + + if (cardType == ISODEP_NFCA) { + atsToEmulatedAtr(selectedCard14a.ats, atr, &atrLen); + } else if (cardType == ISODEP_NFCB) { + atqbToEmulatedAtr(selectedCard14b.atqb, selectedCard14b.cid, atr, &atrLen); + } + + uint8_t res[22] = {0}; + res[1] = atrLen; + memcpy(res + 2, atr, atrLen); + mbedtls_net_send(&netCtx, res, 2 + atrLen); + } else if (cmdbuf[1] != 0x01) { // vpcd APDU + int apduLen = (cmdbuf[0] << 8) + cmdbuf[1]; + + uint8_t apduRes[APDU_RES_LEN] = {0}; + int apduResLen = 0; + + if (verbose) { + PrintAndLogEx(INFO, ">> %s", sprint_hex(cmdbuf + 2, apduLen)); + } + + if (cardType == ISODEP_NFCA) { + if (ExchangeAPDU14a(cmdbuf + 2, apduLen, !fieldActivated, true, apduRes, sizeof(apduRes), &apduResLen) != PM3_SUCCESS) { + cardType = ISODEP_INACTIVE; + mbedtls_net_close(&netCtx); + continue; + } + } else if (cardType == ISODEP_NFCB) { + if (exchange_14b_apdu(cmdbuf + 2, apduLen, !fieldActivated, true, apduRes, sizeof(apduRes), &apduResLen, 0)) { + cardType = ISODEP_INACTIVE; + mbedtls_net_close(&netCtx); + continue; + } + } + + fieldActivated = true; + + if (verbose) { + PrintAndLogEx(INFO, "<< %s", sprint_hex(apduRes, apduResLen)); + } + + uint8_t res[APDU_RES_LEN + 2] = {0}; + res[0] = (apduResLen >> 8) & 0xFF; + res[1] = apduResLen & 0xFF; + memcpy(res + 2, apduRes, apduResLen); + mbedtls_net_send(&netCtx, res, 2 + apduResLen); + } + } + } else { + if (IfPm3Iso14443a() && SelectCard14443A_4(false, false, &selectedCard14a) == PM3_SUCCESS) { + cardType = ISODEP_NFCA; + } else if (IfPm3Iso14443b() && select_card_14443b_4(false, &selectedCard14b) == PM3_SUCCESS) { + cardType = ISODEP_NFCB; + } + if (cardType != ISODEP_INACTIVE) { + fieldActivated = false; + if (mbedtls_net_connect(&netCtx, (char *) host, (char *) port, MBEDTLS_NET_PROTO_TCP)) { + PrintAndLogEx(FAILED, "Failed to connect to vpcd socket. Ensure you have vpcd installed and running"); + mbedtls_net_close(&netCtx); + mbedtls_net_free(&netCtx); + DropField(); + return PM3_EINVARG; + } + } + msleep(300); + } + } while (!kbd_enter_pressed()); + + mbedtls_net_close(&netCtx); + mbedtls_net_free(&netCtx); + DropField(); + + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdSmartList, AlwaysAvailable, "List ISO 7816 history"}, {"info", CmdSmartInfo, IfPm3Smartcard, "Tag information"}, + {"relay", CmdRelay, IfPm3Iso14443a, "Turn pm3 into pcsc reader and relay to host OS via vpcd"}, {"reader", CmdSmartReader, IfPm3Smartcard, "Act like an IS07816 reader"}, {"raw", CmdSmartRaw, IfPm3Smartcard, "Send raw hex data to tag"}, {"upgrade", CmdSmartUpgrade, AlwaysAvailable, "Upgrade sim module firmware"}, diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index 46c33389d..48a2ecb91 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -791,6 +791,7 @@ const static vocabulary_t vocabulary[] = { { 1, "smart help" }, { 1, "smart list" }, { 0, "smart info" }, + { 0, "smart relay" }, { 0, "smart reader" }, { 0, "smart raw" }, { 1, "smart upgrade" }, diff --git a/common/mbedtls/Makefile b/common/mbedtls/Makefile index ebd2d5dcf..0413bdff7 100644 --- a/common/mbedtls/Makefile +++ b/common/mbedtls/Makefile @@ -46,7 +46,8 @@ MYSRCS = \ threading.c \ x509.c \ x509_crl.c \ - x509_crt.c + x509_crt.c \ + net_sockets.c LIB_A = libmbedtls.a diff --git a/common/mbedtls/config.h b/common/mbedtls/config.h index 7c739cfd0..a3faef146 100644 --- a/common/mbedtls/config.h +++ b/common/mbedtls/config.h @@ -2979,7 +2979,7 @@ * * This module provides networking routines. */ -//#define MBEDTLS_NET_C +#define MBEDTLS_NET_C /** * \def MBEDTLS_OID_C diff --git a/doc/commands.json b/doc/commands.json index 03751cbe2..3320a9c5d 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -11790,6 +11790,21 @@ ], "usage": "smart reader [-hv]" }, + "smart relay": { + "command": "smart relay", + "description": "Make pm3 available to host OS smartcard driver via vpcd to enable use with other software such as GlobalPlatform Pro", + "notes": [ + "Requires the virtual smartcard daemon to be installed and running, see https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html" + ], + "offline": false, + "options": [ + "-h, --help This help", + "--host vpcd socket host (default: localhost)", + "-p, --port vpcd socket port (default: 35963)", + "-v, --verbose display APDU transactions between OS and card" + ], + "usage": "smart relay [-hv] [--host ] [-p ]" + }, "smart setclock": { "command": "smart setclock", "description": "Set clock speed for smart card interface.", @@ -12049,8 +12064,8 @@ } }, "metadata": { - "commands_extracted": 698, + "commands_extracted": 699, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2023-11-09T16:29:08" + "extracted_on": "2023-11-11T20:31:02" } } \ No newline at end of file diff --git a/doc/commands.md b/doc/commands.md index 94c3aa8ee..ef9dac251 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -1424,6 +1424,7 @@ Check column "offline" for their availability. |`smart help `|Y |`This help` |`smart list `|Y |`List ISO 7816 history` |`smart info `|N |`Tag information` +|`smart relay `|N |`Turn pm3 into pcsc reader and relay to host OS via vpcd` |`smart reader `|N |`Act like an IS07816 reader` |`smart raw `|N |`Send raw hex data to tag` |`smart upgrade `|Y |`Upgrade sim module firmware` diff --git a/tools/mf_nonce_brute/mf_nonce_brute.c b/tools/mf_nonce_brute/mf_nonce_brute.c index 63572da0d..1c00f4eef 100644 --- a/tools/mf_nonce_brute/mf_nonce_brute.c +++ b/tools/mf_nonce_brute/mf_nonce_brute.c @@ -525,7 +525,7 @@ static void *brute_thread(void *arguments) { free(revstate); continue; } - + // lock this section to avoid interlacing prints from different threats pthread_mutex_lock(&print_lock); if (args->ev1) { @@ -533,11 +533,11 @@ static void *brute_thread(void *arguments) { } #if 0 - printf("thread #%d idx %d %s\n", args->thread, args->idx, (args->ev1) ? "(Ev1)" : ""); - printf("current nt(%08x) ar_enc(%08x) at_enc(%08x)\n", nt, ar_enc, at_enc); - printf("ks2:%08x\n", ks2); - printf("ks3:%08x\n", ks3); - printf("ks4:%08x\n", ks4); + printf("thread #%d idx %d %s\n", args->thread, args->idx, (args->ev1) ? "(Ev1)" : ""); + printf("current nt(%08x) ar_enc(%08x) at_enc(%08x)\n", nt, ar_enc, at_enc); + printf("ks2:%08x\n", ks2); + printf("ks3:%08x\n", ks3); + printf("ks4:%08x\n", ks4); #endif if (cmd_enc) { uint32_t decrypted = ks4 ^ cmd_enc; @@ -681,7 +681,7 @@ int main(int argc, const char *argv[]) { // next encrypted command + a full read/write int enc_len = 0; - uint8_t enc[ENC_LEN] = {0}; + uint8_t enc[ENC_LEN] = {0}; if (argc > 9) { param_gethex_to_eol(argv[9], 0, enc, sizeof(enc), &enc_len); cmd_enc = (enc[0] << 24 | enc[1] << 16 | enc[2] << 8 | enc[3]); diff --git a/tools/mfkey/nested_util.c b/tools/mfkey/nested_util.c index 239fe5d88..4b2b86c4c 100644 --- a/tools/mfkey/nested_util.c +++ b/tools/mfkey/nested_util.c @@ -235,7 +235,7 @@ uint64_t *nested(NtpKs1 *pNK, uint32_t sizePNK, uint32_t authuid, uint32_t *keyC free(pRPs); return NULL; } - + for (i = 0; i < TRY_KEYS; i++) { // We don't known this key, try to break it // This key can be found here two or more times diff --git a/tools/mfkey/nested_util.h b/tools/mfkey/nested_util.h index fa0e1552d..140d99414 100644 --- a/tools/mfkey/nested_util.h +++ b/tools/mfkey/nested_util.h @@ -12,4 +12,4 @@ typedef struct { uint8_t valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity); uint64_t *nested(NtpKs1 *pNK, uint32_t sizePNK, uint32_t authuid, uint32_t *keyCount); -#endif \ No newline at end of file +#endif diff --git a/tools/mfkey/staticnested.c b/tools/mfkey/staticnested.c index 70bade540..164dcaaa1 100644 --- a/tools/mfkey/staticnested.c +++ b/tools/mfkey/staticnested.c @@ -233,4 +233,4 @@ int main(int argc, char *const argv[]) { exit(EXIT_SUCCESS); error: exit(EXIT_FAILURE); -} \ No newline at end of file +}