From b8d5daa77bb96885617ef7f6cd91a8a0aad2e853 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 14:28:59 +0100 Subject: [PATCH 01/14] sam_common: extract payload copy procedures --- armsrc/sam_common.c | 73 +++++++++++++++++++++++++++++++++++++++++ armsrc/sam_common.h | 3 ++ armsrc/sam_seos.c | 79 ++------------------------------------------- 3 files changed, 78 insertions(+), 77 deletions(-) diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index 76ca269e16..ebedfc3b4e 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -371,3 +371,76 @@ void sam_send_ack(void) { BigBuf_free(); } + +/** + * @brief Copies the payload from an NFC buffer to a SAM buffer. + * + * Wraps received data from NFC into an ASN1 tree, so it can be transmitted to the SAM . + * + * @param sam_tx Pointer to the SAM transmit buffer. + * @param nfc_rx Pointer to the NFC receive buffer. + * @param nfc_len Length of the data to be copied from the NFC buffer. + * + * @return Length of SAM APDU to be sent. + */ +uint16_t sam_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len) { + // NFC resp: + // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 + + // SAM req: + // bd 1c + // a0 1a + // a0 18 + // 80 12 + // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 + // 81 02 + // 00 00 + + const uint8_t payload[] = { + 0xbd, 4, + 0xa0, 2, + 0xa0, 0 + }; + + const uint8_t tag81[] = { + 0x00, 0x00 + }; + + memcpy(sam_tx, payload, sizeof(payload)); + + sam_append_asn1_node(sam_tx, sam_tx + 4, 0x80, nfc_rx, nfc_len); + sam_append_asn1_node(sam_tx, sam_tx + 4, 0x81, tag81, sizeof(tag81)); + + return sam_tx[1] + 2; // length of the ASN1 tree +} + +/** + * @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer. + * + * Unpacks data to be transmitted from ASN1 tree in APDU received from SAM. + * + * @param nfc_tx_buf Pointer to the buffer where the NFC transmit data will be stored. + * @param sam_rx_buf Pointer to the buffer containing the data received from the SAM. + * @return Length of NFC APDU to be sent. + */ +uint16_t sam_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf) { + // SAM resp: + // c1 61 c1 00 00 + // a1 10 <- nfc command + // a1 0e <- nfc send + // 80 10 <- data + // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 + // 81 02 <- protocol + // 00 04 + // 82 02 <- timeout + // 01 F4 + // 90 00 + + // NFC req: + // 0C 05 DE 64 + + // copy data out of c1->a1>->a1->80 node + uint16_t nfc_tx_len = (uint8_t) * (sam_rx_buf + 10); + memcpy(nfc_tx_buf, sam_rx_buf + 11, nfc_tx_len); + return nfc_tx_len; +} \ No newline at end of file diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h index 645957a3c8..1c3a88e88a 100644 --- a/armsrc/sam_common.h +++ b/armsrc/sam_common.h @@ -46,4 +46,7 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type void sam_send_ack(void); +uint16_t sam_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len); +uint16_t sam_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf); + #endif diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 2e5c093491..92f2e564c2 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -112,81 +112,6 @@ static int sam_set_card_detected(iso14a_card_select_t *card_select) { return res; } -/** - * @brief Copies the payload from an NFC buffer to a SAM buffer. - * - * Wraps received data from NFC into an ASN1 tree, so it can be transmitted to the SAM . - * - * @param sam_tx Pointer to the SAM transmit buffer. - * @param nfc_rx Pointer to the NFC receive buffer. - * @param nfc_len Length of the data to be copied from the NFC buffer. - * - * @return Length of SAM APDU to be sent. - */ -inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len) { - // NFC resp: - // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 - - // SAM req: - // bd 1c - // a0 1a - // a0 18 - // 80 12 - // 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3 - // 81 02 - // 00 00 - - const uint8_t payload[] = { - 0xbd, 4, - 0xa0, 2, - 0xa0, 0 - }; - - const uint8_t tag81[] = { - 0x00, 0x00 - }; - - memcpy(sam_tx, payload, sizeof(payload)); - - sam_append_asn1_node(sam_tx, sam_tx + 4, 0x80, nfc_rx, nfc_len); - sam_append_asn1_node(sam_tx, sam_tx + 4, 0x81, tag81, sizeof(tag81)); - - return sam_tx[1] + 2; // length of the ASN1 tree -} - -/** - * @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer. - * - * Unpacks data to be transmitted from ASN1 tree in APDU received from SAM. - * - * @param nfc_tx_buf Pointer to the buffer where the NFC transmit data will be stored. - * @param sam_rx_buf Pointer to the buffer containing the data received from the SAM. - * @return Length of NFC APDU to be sent. - */ -inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf) { - // SAM resp: - // c1 61 c1 00 00 - // a1 21 <- nfc command - // a1 1f <- nfc send - // 80 10 <- data - // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 - // 81 02 <- protocol - // 02 02 - // 82 02 <- timeout - // 01 2e - // 85 03 <- format - // 06 c0 00 - // 90 00 - - // NFC req: - // 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00 - - // copy data out of c1->a1>->a1->80 node - uint16_t nfc_tx_len = (uint8_t) * (sam_rx_buf + 10); - memcpy(nfc_tx_buf, sam_rx_buf + 11, nfc_tx_len); - return nfc_tx_len; -} - /** * @brief Sends a request to the SAM and retrieves the response. * @@ -247,7 +172,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r // tag <-> SAM exchange starts here while (sam_rx_buf[1] == 0x61) { switch_clock_to_countsspclk(); - nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); + nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); nfc_rx_len = iso14_apdu( nfc_tx_buf, @@ -259,7 +184,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r ); switch_clock_to_ticks(); - sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len - 2); + sam_tx_len = sam_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len - 2); sam_send_payload( 0x14, 0x0a, 0x14, From 2ae2388cefc08594f538f6e01bc012f43880da82 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 14:30:01 +0100 Subject: [PATCH 02/14] util_hdsio: extract getSioMediaTypeInfo --- client/CMakeLists.txt | 1 + client/Makefile | 1 + client/src/cmdhfseos.c | 28 +--------------------- client/src/cmdhfseos.h | 6 ----- client/src/util_hidsio.c | 51 ++++++++++++++++++++++++++++++++++++++++ client/src/util_hidsio.h | 26 ++++++++++++++++++++ 6 files changed, 80 insertions(+), 33 deletions(-) create mode 100644 client/src/util_hidsio.c create mode 100644 client/src/util_hidsio.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2a74b1500d..dc3d0a21df 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -425,6 +425,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/scripting.c ${PM3_ROOT}/client/src/ui.c ${PM3_ROOT}/client/src/util.c + ${PM3_ROOT}/client/src/util_hidsio.c ${PM3_ROOT}/client/src/wiegand_formats.c ${PM3_ROOT}/client/src/wiegand_formatutils.c ${CMAKE_BINARY_DIR}/version_pm3.c diff --git a/client/Makefile b/client/Makefile index d01e08af0d..523b8b6572 100644 --- a/client/Makefile +++ b/client/Makefile @@ -759,6 +759,7 @@ SRCS = mifare/aiddesfire.c \ scripting.c \ ui.c \ util.c \ + util_hidsio.c \ version_pm3.c \ wiegand_formats.c \ wiegand_formatutils.c diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 02dec90aba..c5fe9d8c18 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -38,6 +38,7 @@ #include "crypto/libpcrypto.h" // AES decrypt #include "commonutil.h" // get_sw #include "protocols.h" // ISO7816 APDU return codes +#include "util_hidsio.h" static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -100,17 +101,6 @@ static const known_algo_t known_algorithm_map[] = { {9, "AES-128_CBC_MODE"}, }; -static const sioMediaTypeName_t sioMediaTypeMapping[] = { - { 0x00, "Unknown"}, - { 0x01, "DESFire"}, - { 0x02, "MIFARE"}, - { 0x03, "iCLASS (PicoPass)"}, - { 0x04, "ISO14443AL4"}, - { 0x06, "MIFARE Plus"}, - { 0x07, "Seos"}, - { 0xFF, "INVALID VALUE"} -}; - static int create_cmac(uint8_t *key, uint8_t *input, uint8_t *out, int input_len, int encryption_algorithm) { uint8_t iv[16] = {0x00}; @@ -1638,22 +1628,6 @@ static int CmdHfSeosList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf seos", "seos -c"); } -// get a SIO media type based on the UID -// uid[8] tag uid -// returns description of the best match -static const char *getSioMediaTypeInfo(uint8_t uid) { - - for (int i = 0; i < ARRAYLEN(sioMediaTypeMapping); ++i) { - if (uid == sioMediaTypeMapping[i].uid) { - return sioMediaTypeMapping[i].desc; - } - } - - //No match, return default - return sioMediaTypeMapping[ARRAYLEN(sioMediaTypeMapping) - 1].desc; -} - - static int CmdHfSeosSAM(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf seos sam", diff --git a/client/src/cmdhfseos.h b/client/src/cmdhfseos.h index f75e070d57..f1dfe99a08 100644 --- a/client/src/cmdhfseos.h +++ b/client/src/cmdhfseos.h @@ -21,12 +21,6 @@ #include "common.h" -// structure and database for uid -> tagtype lookups -typedef struct { - uint8_t uid; - const char *desc; -} sioMediaTypeName_t; - int infoSeos(bool verbose); int CmdHFSeos(const char *Cmd); int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot, diff --git a/client/src/util_hidsio.c b/client/src/util_hidsio.c new file mode 100644 index 0000000000..932999c27d --- /dev/null +++ b/client/src/util_hidsio.c @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// HID Global SIO utilities +//----------------------------------------------------------------------------- +#include "commonutil.h" +#include "util_hidsio.h" + +// structure and database for uid -> tagtype lookups +typedef struct { + uint8_t uid; + const char *desc; +} sioMediaTypeName_t; + +static const sioMediaTypeName_t sioMediaTypeMapping[] = { + { 0x00, "Unknown"}, + { 0x01, "DESFire"}, + { 0x02, "MIFARE"}, + { 0x03, "iCLASS (PicoPass)"}, + { 0x04, "ISO14443AL4"}, + { 0x06, "MIFARE Plus"}, + { 0x07, "Seos"}, + { 0xFF, "INVALID VALUE"} +}; + +// get a SIO media type based on the UID +// uid[8] tag uid +// returns description of the best match +const char *getSioMediaTypeInfo(uint8_t uid) { + + for (int i = 0; i < ARRAYLEN(sioMediaTypeMapping); ++i) { + if (uid == sioMediaTypeMapping[i].uid) { + return sioMediaTypeMapping[i].desc; + } + } + + //No match, return default + return sioMediaTypeMapping[ARRAYLEN(sioMediaTypeMapping) - 1].desc; +} diff --git a/client/src/util_hidsio.h b/client/src/util_hidsio.h new file mode 100644 index 0000000000..5c68f342b6 --- /dev/null +++ b/client/src/util_hidsio.h @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See LICENSE.txt for the text of the license. +//----------------------------------------------------------------------------- +// HID Global SIO utilities +//----------------------------------------------------------------------------- +#ifndef __UTIL_HIDSIO_H_ +#define __UTIL_HIDSIO_H_ + +#include "common.h" +#include "stdint.h" + +const char *getSioMediaTypeInfo(uint8_t uid); + +#endif From f3b831ca3ec08ce6f1e95bc2b84176c5389ebad0 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 14:30:45 +0100 Subject: [PATCH 03/14] sam_seos: rename sam_set_card_detected --- armsrc/sam_seos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 92f2e564c2..0f4a7f2236 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -49,7 +49,7 @@ * @param card_select Pointer to the descriptor of the detected card. * @return Status code indicating success or failure of the operation. */ -static int sam_set_card_detected(iso14a_card_select_t *card_select) { +static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); @@ -296,7 +296,7 @@ int sam_seos_get_pacs(PacketCommandNG *c) { switch_clock_to_ticks(); // step 3: SamCommand CardDetected - sam_set_card_detected(&card_a_info); + sam_set_card_detected_seos(&card_a_info); } // step 3: SamCommand RequestPACS, relay NFC communication From 9696c9763985b3e0ac4b878d34d79a64270be90a Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 14:34:00 +0100 Subject: [PATCH 04/14] sam_picopass: adapt implementation from sam_seos --- armsrc/appmain.c | 2 +- armsrc/sam_picopass.c | 567 ++++++++++++++++----------------------- armsrc/sam_picopass.h | 3 +- client/src/cmdhficlass.c | 85 +++++- 4 files changed, 305 insertions(+), 352 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index a10bdc3347..e9c1fc48d2 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -2258,7 +2258,7 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_HF_SAM_PICOPASS: { - sam_picopass_get_pacs(); + sam_picopass_get_pacs(packet); break; } case CMD_HF_SAM_SEOS: { diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index d396a31c5c..58363de69b 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -30,6 +30,183 @@ #include "protocols.h" #include "optimized_cipher.h" #include "fpgaloader.h" +#include "pm3_cmd.h" + +/** + * @brief Sends a request to the SAM and retrieves the response. + * + * Unpacks request to the SAM and relays ISO15 traffic to the card. + * If no request data provided, sends a request to get PACS data. + * + * @param request Pointer to the buffer containing the request to be sent to the SAM. + * @param request_len Length of the request to be sent to the SAM. + * @param response Pointer to the buffer where the retreived data will be stored. + * @param response_len Pointer to the variable where the length of the retreived data will be stored. + * @return Status code indicating success or failure of the operation. + */ +static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod) { + int res = PM3_SUCCESS; + if (g_dbglevel >= DBG_DEBUG) + DbpString("start sam_send_request_iso14a"); + + uint8_t buf1[ISO7816_MAX_FRAME] = {0}; + uint8_t buf2[ISO7816_MAX_FRAME] = {0}; + + uint8_t *sam_tx_buf = buf1; + uint16_t sam_tx_len; + + uint8_t *sam_rx_buf = buf2; + uint16_t sam_rx_len; + + uint8_t *nfc_tx_buf = buf1; + uint16_t nfc_tx_len; + + uint8_t *nfc_rx_buf = buf2; + uint16_t nfc_rx_len; + + if (request_len > 0) { + sam_tx_len = request_len; + memcpy(sam_tx_buf, request, sam_tx_len); + } else { + // send get pacs + static const uint8_t payload[] = { + 0xa0, 19, // <- SAM command + 0xBE, 17, // <- samCommandGetContentElement2 + 0x80, 1, + 0x04, // <- implicitFormatPhysicalAccessBits + 0x84, 12, + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x04 // <- SoRootOID + }; + + sam_tx_len = sizeof(payload); + memcpy(sam_tx_buf, payload, sam_tx_len); + } + + sam_send_payload( + 0x44, 0x0a, 0x44, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + if (sam_rx_buf[1] == 0x61) { // commands to be relayed to card starts with 0x61 + switch_clock_to_countsspclk(); + // tag <-> SAM exchange starts here + + while (sam_rx_buf[1] == 0x61) { + uint32_t start_time = GetCountSspClk(); + uint32_t eof_time = start_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); + + // should consider blocking update(2) commands and simulating answer + // example command: 87 02 C9 FD FF FF FF FF FF FF F4 BF 98 E2 + + if (g_dbglevel >= DBG_INFO) { + DbpString("ISO15 TAG REQUEST: "); + Dbhexdump(nfc_tx_len, nfc_tx_buf, false); + } + + int tries = 3; + nfc_rx_len = 0; + while (tries-- > 0) { + iclass_send_as_reader(nfc_tx_buf, nfc_tx_len, &start_time, &eof_time, shallow_mod); + + // should not always wait for ICLASS_READER_TIMEOUT_UPDATE. It is too long + // check if command in nfc_tx_buf was iclass update command + res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &nfc_rx_len); + if (res == PM3_SUCCESS && nfc_rx_len > 0) { + break; + } + + start_time = eof_time + ((DELAY_ICLASS_VICC_TO_VCD_READER + DELAY_ISO15693_VCD_TO_VICC_READER + (8 * 8 * 8 * 16)) * 2); + } + + + if (res != PM3_SUCCESS ) { + res = PM3_ECARDEXCHANGE; + goto out; + } + + if (g_dbglevel >= DBG_INFO) { + DbpString("ISO15 TAG RESPONSE: "); + Dbhexdump(nfc_rx_len, nfc_rx_buf, false); + } + + + switch_clock_to_ticks(); + sam_tx_len = sam_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len); + + sam_send_payload( + 0x14, 0x0a, 0x14, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + + // last SAM->TAG + // c1 61 c1 00 00 a1 02 >>82<< 00 90 00 + if (sam_rx_buf[7] == 0x82) { + // tag <-> SAM exchange ends here + break; + } + + switch_clock_to_countsspclk(); + + } + + static const uint8_t hfack[] = { + 0xbd, 0x04, 0xa0, 0x02, 0x82, 0x00 + }; + + sam_tx_len = sizeof(hfack); + memcpy(sam_tx_buf, hfack, sam_tx_len); + + sam_send_payload( + 0x14, 0x0a, 0x00, + sam_tx_buf, &sam_tx_len, + sam_rx_buf, &sam_rx_len + ); + } + + // resp for SamCommandGetContentElement: + // c1 64 00 00 00 + // bd 09 + // 8a 07 + // 03 05 <- include tag for pm3 client + // 06 85 80 6d c0 <- decoded PACS data + // 90 00 + + // resp for samCommandGetContentElement2: + // c1 64 00 00 00 + // bd 1e + // b3 1c + // a0 1a + // 80 05 + // 06 85 80 6d c0 + // 81 0e + // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff + // 82 01 + // 07 + // 90 00 + if (request_len == 0) { + if ( + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03) + && + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0) + ) { + if (g_dbglevel >= DBG_ERROR) + Dbprintf("No PACS data in SAM response"); + res = PM3_ESOFT; + } + } + + *response_len = sam_rx_buf[5 + 1] + 2; + memcpy(response, sam_rx_buf + 5, *response_len); + + goto out; + +out: + return res; +} /** @@ -41,7 +218,7 @@ * @param card_select Pointer to the descriptor of the detected card. * @return Status code indicating success or failure of the operation. */ -static int sam_set_card_detected(picopass_hdr_t *card_select) { +static int sam_set_card_detected_picopass(picopass_hdr_t *card_select) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); @@ -107,366 +284,78 @@ static int sam_set_card_detected(picopass_hdr_t *card_select) { return res; } -// using HID SAM to authenticate w PICOPASS -int sam_picopass_get_pacs(void) { - static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; - static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; - static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; - uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; +/** + * @brief Retrieves PACS data from PICOPASS card using SAM. + * + * This function is called by appmain.c + * It sends a request to the SAM to get the PACS data from the PICOPASS card. + * The PACS data is then returned to the PM3 client. + * + * @return Status code indicating success or failure of the operation. + */ +int sam_picopass_get_pacs(PacketCommandNG *c) { + bool disconnectAfter = c->oldarg[0] & 0x01; + bool skipDetect = c->oldarg[1] & 0x01; + bool shallow_mod = false; - picopass_hdr_t hdr = {0}; - // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used - // bit 7: parity. - // if (use_credit_key) - // read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; + uint8_t *cmd = c->data.asBytes; + uint16_t cmd_len = (uint16_t) c->oldarg[2]; - BigBuf_free_keep_EM(); + int res = PM3_EFAILED; clear_trace(); - I2C_Reset_EnterMainProgram(); - StopTicks(); - uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME); + set_tracing(true); + StartTicks(); - bool shallow_mod = false; - uint16_t resp_len = 0; - int res; - uint32_t eof_time = 0; - - // wakeup - Iso15693InitReader(); + // step 1: ping SAM + sam_get_version(); - uint32_t start_time = GetCountSspClk(); - iclass_send_as_reader(act_all, 1, &start_time, &eof_time, shallow_mod); + if (!skipDetect) { + // step 2: get card information + picopass_hdr_t card_a_info; + uint32_t eof_time = 0; - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_ACTALL, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS) { - res = PM3_ECARDEXCHANGE; - goto out; - } + // implicit StartSspClk() happens here + Iso15693InitReader(); + if(!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)){ + goto err; + } - // send Identify - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(identify, 1, &start_time, &eof_time, shallow_mod); + switch_clock_to_ticks(); - // expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 10) { - res = PM3_ECARDEXCHANGE; - goto out; + // step 3: SamCommand CardDetected + sam_set_card_detected_picopass(&card_a_info); } - // copy the Anti-collision CSN to our select-packet - memcpy(&select[1], resp, 8); - - // select the card - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(select, sizeof(select), &start_time, &eof_time, shallow_mod); - - // expect a 10-byte response here, 8 byte CSN and 2 byte CRC - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 10) { - res = PM3_ECARDEXCHANGE; - goto out; - } - - // store CSN - memcpy(hdr.csn, resp, sizeof(hdr.csn)); - - // card selected, now read config (block1) (only 8 bytes no CRC) - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, &eof_time, shallow_mod); - - // expect a 8-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 10) { - res = PM3_ECARDEXCHANGE; - goto out; - } - - // store CONFIG - memcpy((uint8_t *)&hdr.conf, resp, sizeof(hdr.conf)); - - uint8_t pagemap = get_pagemap(&hdr); - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - res = PM3_EWRONGANSWER; - goto out; - } - - // read App Issuer Area block 5 - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, &eof_time, shallow_mod); - - // expect a 10-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 10) { - res = PM3_ECARDEXCHANGE; - goto out; - } - - // store AIA - memcpy(hdr.app_issuer_area, resp, sizeof(hdr.app_issuer_area)); - - // card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); - - // expect a 8-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 8) { - res = PM3_ECARDEXCHANGE; - goto out; - } - - // store EPURSE - memcpy(hdr.epurse, resp, sizeof(hdr.epurse)); - - // ----------------------------------------------------------------------------- - // SAM comms - // ----------------------------------------------------------------------------- - size_t sam_len = 0; - uint8_t *sam_apdu = BigBuf_calloc(ISO7816_MAX_FRAME); - - // ----------------------------------------------------------------------------- - // first - set detected card (0xAD) - switch_clock_to_ticks(); - sam_set_card_detected(&hdr); - - // ----------------------------------------------------------------------------- - // second - get PACS (0xA1) - - // a0 05 - // a1 03 - // 80 01 - // 04 - hexstr_to_byte_array("a005a103800104", sam_apdu, &sam_len); - if (sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, (uint16_t *) &sam_len, resp, &resp_len) != PM3_SUCCESS) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 2", resp, resp_len); - - // TAG response - // -- 0c 05 de64 // read block 5 - // Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4 - - // ----------------------------------------------------------------------------- - // third AIA block 5 (emulated tag <-> SAM exchange starts here) - // a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000 - // picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5 - // picpoasss SE ff ff ff 00 06 ff ff ff f8 8e - hexstr_to_byte_array("a0da02631c140a00000000bd14a012a010800affffff0006fffffff88e81020000", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, hdr.app_issuer_area, sizeof(hdr.app_issuer_area)); - AddCrc(sam_apdu + 19, 8); - - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 3", resp, resp_len); - - // 88 02 -- readcheck (block2 epurse, start of auth) - // Tag|c00a140a000000a10ea10c8002 8802 8102 0004 820201f4 9000 - // 61 16 f5 0a140a000000a10ea10c 8002 8802 8102 0004 820201f4 9000 - - // ----------------------------------------------------------------------------- - // forth EPURSE - // a0da02631a140a00000000bd12a010a00e8008 ffffffffedffffff 81020000 - hexstr_to_byte_array("a0da02631a140a00000000bd12a010a00e8008ffffffffedffffff81020000", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, hdr.epurse, sizeof(hdr.epurse)); - - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 4", resp, resp_len); - - uint8_t nr_mac[9] = {0}; - memcpy(nr_mac, resp + 11, sizeof(nr_mac)); - // resp here hold the whole NR/MAC - // 05 9bcd475e965ee20e // CHECK (w key) - print_dbg("NR/MAC", nr_mac, sizeof(nr_mac)); - - // c00a140a000000a115a1138009 059bcd475e965ee20e 8102 0004 820201f4 9000 - - // pre calc ourself? - // uint8_t cc_nr[] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0}; - uint8_t div_key[8] = {0}; - static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78}; - iclass_calc_div_key(hdr.csn, legacy_aa1_key, div_key, false); - - uint8_t mac[4] = {0}; - if (g_dbglevel == DBG_DEBUG) { - uint8_t wb[16] = {0}; - memcpy(wb, hdr.epurse, sizeof(hdr.epurse)); - memcpy(wb + sizeof(hdr.epurse), nr_mac + 1, 4); - print_dbg("cc_nr...", wb, sizeof(wb)); - doMAC_N(wb, sizeof(wb), div_key, mac); - print_dbg("Calc MAC...", mac, sizeof(mac)); - } - - // start ssp clock again... - switch_clock_to_countsspclk(); - - // NOW we auth against tag - uint8_t cmd_check[9] = { ICLASS_CMD_CHECK }; - memcpy(cmd_check + 1, nr_mac + 1, 8); - - start_time = GetCountSspClk(); - iclass_send_as_reader(cmd_check, sizeof(cmd_check), &start_time, &eof_time, shallow_mod); - - // expect a 10-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 4) { - res = PM3_ECARDEXCHANGE; - goto out; - } - // store MAC - memcpy(mac, resp, sizeof(mac)); - print_dbg("Got MAC", mac, sizeof(mac)); - - // ----------------------------------------------------------------------------- - // fifth send received MAC - // A0DA026316140A00000000BD0EA00CA00A8004 311E32E9 81020000 - hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, mac, sizeof(mac)); - - switch_clock_to_ticks(); - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 5", resp, resp_len); - - uint8_t tmp_p1[4] = {0}; - uint8_t tmp_p2[4] = {0}; - - // c161c10000a11aa118800e8702 ffffffff88ffffff 0a914eb981020004820236b09000 - - memcpy(tmp_p1, resp + 13, sizeof(tmp_p1)); - memcpy(tmp_p2, resp + 13 + 4, sizeof(tmp_p2)); - // ----------------------------------------------------------------------------- - // sixth send fake epurse update - // A0DA02631C140A00000000BD14A012A010800A 88FFFFFFFFFFFFFF9DE1 81020000 - hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A88FFFFFFFFFFFFFF9DE181020000", sam_apdu, &sam_len); - - memcpy(sam_apdu + 19, tmp_p2, sizeof(tmp_p1)); - memcpy(sam_apdu + 19 + 4, tmp_p1, sizeof(tmp_p1)); - AddCrc(sam_apdu + 19, 8); - - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 6", resp, resp_len); - // c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00 - - // read block 6 - switch_clock_to_countsspclk(); - start_time = GetCountSspClk(); - iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod); - - // expect a 10-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - if (res != PM3_SUCCESS || resp_len != 10) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("Block 6 from Picopass", resp, resp_len); - - // ----------------------------------------------------------------------------- - // eight send block 6 config to SAM - // A0DA02631C140A00000000BD14A012A010800A 030303030003E0174323 81020000 - hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, resp, resp_len); - - switch_clock_to_ticks(); - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 7", resp, resp_len); - - // c161c10000a110a10e8004 0606455681020004820201f49000 - - // read the credential blocks - switch_clock_to_countsspclk(); - start_time = GetCountSspClk(); - iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod); - - // expect a 10-byte response here - res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + // step 3: SamCommand RequestPACS, relay NFC communication + uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; + uint8_t sam_response_len = 0; + res = sam_send_request_iso15(cmd, cmd_len, sam_response, &sam_response_len, shallow_mod); if (res != PM3_SUCCESS) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("Block 6-9 from Picopass", resp, resp_len); - - // ----------------------------------------------------------------------------- - // nine send credential blocks to SAM - // A0DA026334140A00000000BD2CA02AA0288022 030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C 81020000 - hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, resp, resp_len); - - switch_clock_to_ticks(); - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - print_dbg("-- 8", resp, resp_len); - - - // ----------------------------------------------------------------------------- - // TEN ask for PACS data - // A0 DA 02 63 0C - // 44 0A 00 00 00 00 - // BD 04 - // A0 02 - // 82 00 - - // (emulated tag <-> SAM exchange ends here) - hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu, &sam_len); - memcpy(sam_apdu + 19, resp, resp_len); - - if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) { - res = PM3_ECARDEXCHANGE; - goto out; - } - - print_dbg("-- 9 response", resp, resp_len); - if (memcmp(resp, "\xc1\x64\x00\x00\x00\xbd\x17\x8a\x15", 9) == 0) { - res = PM3_ENOPACS; - goto out; + goto err; } + if (g_dbglevel >= DBG_INFO) + print_result("Response data", sam_response, sam_response_len); - // resp: - // c1 64 00 00 00 - // bd 09 - // 8a 07 - // 03 05 06 95 1f 9a 00 <- decoded PACS data - // 90 00 - uint8_t *pacs = BigBuf_calloc(resp[8]); - memcpy(pacs, resp + 9, resp[8]); - - print_dbg("-- 10 PACS data", pacs, resp[8]); - - reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, pacs, resp[8]); - res = PM3_SUCCESS; + goto out; goto off; -out: +err: + res = PM3_ENOPACS; reply_ng(CMD_HF_SAM_PICOPASS, res, NULL, 0); - + goto off; +out: + reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, sam_response, sam_response_len); + goto off; off: - switch_off(); + if (disconnectAfter) { + switch_off(); + } + set_tracing(false); StopTicks(); BigBuf_free(); return res; } - -// HID SAM <-> MFC -// HID SAM <-> SEOS diff --git a/armsrc/sam_picopass.h b/armsrc/sam_picopass.h index 26d734d397..6711fd678d 100644 --- a/armsrc/sam_picopass.h +++ b/armsrc/sam_picopass.h @@ -18,7 +18,8 @@ #include "common.h" #include "sam_common.h" +#include "pm3_cmd.h" -int sam_picopass_get_pacs(void); +int sam_picopass_get_pacs(PacketCommandNG *c); #endif diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 60c24fb49d..68add842a3 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -42,6 +42,7 @@ #include "generator.h" #include "cmdhf14b.h" #include "cmdhw.h" +#include "util_hidsio.h" #define NUM_CSNS 9 @@ -5403,10 +5404,35 @@ static int CmdHFiClassSAM(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_lit0("v", "verbose", "verbose output"), + arg_lit0("k", "keep", "keep the field active after command executed"), + arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"), + arg_lit0("t", "tlv", "decode TLV"), + arg_strx0("d", "data", "", "DER encoded command to send to SAM"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool verbose = arg_get_lit(ctx, 1); + + bool verbose = false; + if (arg_get_lit(ctx, 1)) { + verbose = true; + } + bool disconnectAfter = true; + if (arg_get_lit(ctx, 2)) { + disconnectAfter = false; + } + bool skipDetect = false; + if (arg_get_lit(ctx, 3)) { + skipDetect = true; + } + bool decodeTLV = false; + if (arg_get_lit(ctx, 4)) { + decodeTLV = true; + } + + uint8_t data[PM3_CMD_DATA_SIZE] = {0}; + int datalen = 0; + CLIGetHexBLessWithReturn(ctx, 5, data, &datalen, 0); + CLIParserFree(ctx); if (IsHIDSamPresent(verbose) == false) { @@ -5414,7 +5440,7 @@ static int CmdHFiClassSAM(const char *Cmd) { } clearCommandBuffer(); - SendCommandNG(CMD_HF_SAM_PICOPASS, NULL, 0); + SendCommandMIX(CMD_HF_SAM_PICOPASS, disconnectAfter, skipDetect, datalen, data, datalen); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) { PrintAndLogEx(WARNING, "SAM timeout"); @@ -5432,16 +5458,53 @@ static int CmdHFiClassSAM(const char *Cmd) { return resp.status; } - // CSN, config, epurse, NR/MAC, AIA - // PACS - // 03 05 - // 06 85 80 6d c0 - // first byte skip - // second byte length - // third padded - // fourth .. uint8_t *d = resp.data.asBytes; - HIDDumpPACSBits(d + 2, d[1], verbose); + // check for standard SamCommandGetContentElement response + // bd 09 + // 8a 07 + // 03 05 <- tag + length + // 06 85 80 6d c0 <- decoded PACS data + if (d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03) { + uint8_t pacs_length = d[5]; + uint8_t *pacs_data = d + 6; + int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); + if (res != PM3_SUCCESS) { + return res; + } + // check for standard samCommandGetContentElement2: + // bd 1e + // b3 1c + // a0 1a + // 80 05 + // 06 85 80 6d c0 + // 81 0e + // 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff + // 82 01 + // 07 + } else if (d[0] == 0xbd && d[2] == 0xb3 && d[4] == 0xa0) { + const uint8_t *pacs = d + 6; + const uint8_t pacs_length = pacs[1]; + const uint8_t *pacs_data = pacs + 2; + int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose); + if (res != PM3_SUCCESS) { + return res; + } + + const uint8_t *oid = pacs + 2 + pacs_length; + const uint8_t oid_length = oid[1]; + const uint8_t *oid_data = oid + 2; + PrintAndLogEx(SUCCESS, "SIO OID.......: " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length)); + + const uint8_t *mediaType = oid + 2 + oid_length; + const uint8_t mediaType_data = mediaType[2]; + PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); + + } else { + print_hex(d, resp.length); + } + if (decodeTLV) { + asn1_print(d, d[1] + 2, " "); + } return PM3_SUCCESS; } From 53b67d19691aa765cdafb0cdae928ec768511926 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 21:30:26 +0100 Subject: [PATCH 05/14] sam_picopass: shorter timeouts --- armsrc/sam_picopass.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 58363de69b..546c480fa8 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -101,6 +101,8 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re // should consider blocking update(2) commands and simulating answer // example command: 87 02 C9 FD FF FF FF FF FF FF F4 BF 98 E2 + bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE; + if (g_dbglevel >= DBG_INFO) { DbpString("ISO15 TAG REQUEST: "); Dbhexdump(nfc_tx_len, nfc_tx_buf, false); @@ -110,10 +112,9 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re nfc_rx_len = 0; while (tries-- > 0) { iclass_send_as_reader(nfc_tx_buf, nfc_tx_len, &start_time, &eof_time, shallow_mod); + uint16_t timeout = is_cmd_update ? ICLASS_READER_TIMEOUT_UPDATE : ICLASS_READER_TIMEOUT_ACTALL; - // should not always wait for ICLASS_READER_TIMEOUT_UPDATE. It is too long - // check if command in nfc_tx_buf was iclass update command - res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &nfc_rx_len); + res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, timeout, &eof_time, false, true, &nfc_rx_len); if (res == PM3_SUCCESS && nfc_rx_len > 0) { break; } From 7b34f462cdea58ed3fbffe1ff7d2d14ab83739b3 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Sun, 26 Jan 2025 23:05:48 +0100 Subject: [PATCH 06/14] sam_picopass: add nr-mac extraction and epurse update prevention modes --- armsrc/sam_picopass.c | 87 +++++++++++++++++++++++++++------------- client/src/cmdhficlass.c | 44 +++++++++++--------- 2 files changed, 84 insertions(+), 47 deletions(-) diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 546c480fa8..e5a75e971d 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -44,7 +44,7 @@ * @param response_len Pointer to the variable where the length of the retreived data will be stored. * @return Status code indicating success or failure of the operation. */ -static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod) { +static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) { int res = PM3_SUCCESS; if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_send_request_iso14a"); @@ -98,39 +98,68 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); - // should consider blocking update(2) commands and simulating answer - // example command: 87 02 C9 FD FF FF FF FF FF FF F4 BF 98 E2 + bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK; + if(is_cmd_check && break_on_nr_mac){ + memcpy(response, nfc_tx_buf, nfc_tx_len); + *response_len = nfc_tx_len; + if (g_dbglevel >= DBG_INFO) { + DbpString("NR-MAC: "); + Dbhexdump((*response_len)-1, response+1, false); + } + res = PM3_SUCCESS; + goto out; + } bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE; + if(is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02){ + // block update(2) command and fake the response to prevent update of epurse - if (g_dbglevel >= DBG_INFO) { - DbpString("ISO15 TAG REQUEST: "); - Dbhexdump(nfc_tx_len, nfc_tx_buf, false); - } + // NFC TX BUFFERS PREPARED BY SAM LOOKS LIKE: + // 87 02 #1(C9 FD FF FF) #2(FF FF FF FF) F4 BF 98 E2 - int tries = 3; - nfc_rx_len = 0; - while (tries-- > 0) { - iclass_send_as_reader(nfc_tx_buf, nfc_tx_len, &start_time, &eof_time, shallow_mod); - uint16_t timeout = is_cmd_update ? ICLASS_READER_TIMEOUT_UPDATE : ICLASS_READER_TIMEOUT_ACTALL; + // NFC RX BUFFERS EXPECTED BY SAM WOULD LOOK LIKE: + // #2(FF FF FF FF) #1(C9 FD FF FF) 3A 47 - res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, timeout, &eof_time, false, true, &nfc_rx_len); - if (res == PM3_SUCCESS && nfc_rx_len > 0) { - break; + memcpy(nfc_rx_buf+0, nfc_tx_buf+6, 4); + memcpy(nfc_rx_buf+4, nfc_tx_buf+0, 4); + AddCrc(nfc_rx_buf, 8); + nfc_rx_len = 10; + + if (g_dbglevel >= DBG_INFO) { + DbpString("FAKE EPURSE UPDATE RESPONSE: "); + Dbhexdump(nfc_rx_len, nfc_rx_buf, false); } - start_time = eof_time + ((DELAY_ICLASS_VICC_TO_VCD_READER + DELAY_ISO15693_VCD_TO_VICC_READER + (8 * 8 * 8 * 16)) * 2); - } + } else { + if (g_dbglevel >= DBG_INFO) { + DbpString("ISO15 TAG REQUEST: "); + Dbhexdump(nfc_tx_len, nfc_tx_buf, false); + } + int tries = 3; + nfc_rx_len = 0; + while (tries-- > 0) { + iclass_send_as_reader(nfc_tx_buf, nfc_tx_len, &start_time, &eof_time, shallow_mod); + uint16_t timeout = is_cmd_update ? ICLASS_READER_TIMEOUT_UPDATE : ICLASS_READER_TIMEOUT_ACTALL; + + res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, timeout, &eof_time, false, true, &nfc_rx_len); + if (res == PM3_SUCCESS && nfc_rx_len > 0) { + break; + } + + start_time = eof_time + ((DELAY_ICLASS_VICC_TO_VCD_READER + DELAY_ISO15693_VCD_TO_VICC_READER + (8 * 8 * 8 * 16)) * 2); + } - if (res != PM3_SUCCESS ) { - res = PM3_ECARDEXCHANGE; - goto out; - } - if (g_dbglevel >= DBG_INFO) { - DbpString("ISO15 TAG RESPONSE: "); - Dbhexdump(nfc_rx_len, nfc_rx_buf, false); + if (res != PM3_SUCCESS ) { + res = PM3_ECARDEXCHANGE; + goto out; + } + + if (g_dbglevel >= DBG_INFO) { + DbpString("ISO15 TAG RESPONSE: "); + Dbhexdump(nfc_rx_len, nfc_rx_buf, false); + } } @@ -296,9 +325,11 @@ static int sam_set_card_detected_picopass(picopass_hdr_t *card_select) { * @return Status code indicating success or failure of the operation. */ int sam_picopass_get_pacs(PacketCommandNG *c) { - bool disconnectAfter = c->oldarg[0] & 0x01; - bool skipDetect = c->oldarg[1] & 0x01; - bool shallow_mod = false; + const bool disconnectAfter = !!(c->oldarg[0] & BITMASK(0)); + const bool skipDetect = !!(c->oldarg[0] & BITMASK(1)); + const bool breakOnNrMac = !!(c->oldarg[0] & BITMASK(2)); + const bool preventEpurseUpdate = !!(c->oldarg[0] & BITMASK(3)); + const bool shallow_mod = !!(c->oldarg[0] & BITMASK(4)); uint8_t *cmd = c->data.asBytes; uint16_t cmd_len = (uint16_t) c->oldarg[2]; @@ -334,7 +365,7 @@ int sam_picopass_get_pacs(PacketCommandNG *c) { // step 3: SamCommand RequestPACS, relay NFC communication uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; uint8_t sam_response_len = 0; - res = sam_send_request_iso15(cmd, cmd_len, sam_response, &sam_response_len, shallow_mod); + res = sam_send_request_iso15(cmd, cmd_len, sam_response, &sam_response_len, shallow_mod, breakOnNrMac, preventEpurseUpdate); if (res != PM3_SUCCESS) { goto err; } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 68add842a3..bcdbee5cb5 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5407,31 +5407,32 @@ static int CmdHFiClassSAM(const char *Cmd) { arg_lit0("k", "keep", "keep the field active after command executed"), arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"), arg_lit0("t", "tlv", "decode TLV"), + arg_lit0(NULL, "break-on-nr-mac", "stop tag interaction on nr-mac"), + arg_lit0("p", "prevent-epurse-update", "fake epurse update"), + arg_lit0(NULL, "shallow", "shallow mod"), arg_strx0("d", "data", "", "DER encoded command to send to SAM"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool verbose = false; - if (arg_get_lit(ctx, 1)) { - verbose = true; - } - bool disconnectAfter = true; - if (arg_get_lit(ctx, 2)) { - disconnectAfter = false; - } - bool skipDetect = false; - if (arg_get_lit(ctx, 3)) { - skipDetect = true; - } - bool decodeTLV = false; - if (arg_get_lit(ctx, 4)) { - decodeTLV = true; - } + bool verbose = arg_get_lit(ctx, 1); + bool disconnectAfter = !arg_get_lit(ctx, 2); + bool skipDetect = arg_get_lit(ctx, 3); + bool decodeTLV = arg_get_lit(ctx, 4); + bool breakOnNrMac = arg_get_lit(ctx, 5); + bool preventEpurseUpdate = arg_get_lit(ctx, 6); + bool shallow_mod = arg_get_lit(ctx, 7); + + uint64_t command_flags = 0; + if (disconnectAfter) command_flags |= BITMASK(0); + if (skipDetect) command_flags |= BITMASK(1); + if (breakOnNrMac) command_flags |= BITMASK(2); + if (preventEpurseUpdate) command_flags |= BITMASK(3); + if (shallow_mod) command_flags |= BITMASK(4); uint8_t data[PM3_CMD_DATA_SIZE] = {0}; int datalen = 0; - CLIGetHexBLessWithReturn(ctx, 5, data, &datalen, 0); + CLIGetHexBLessWithReturn(ctx, 8, data, &datalen, 0); CLIParserFree(ctx); @@ -5440,7 +5441,7 @@ static int CmdHFiClassSAM(const char *Cmd) { } clearCommandBuffer(); - SendCommandMIX(CMD_HF_SAM_PICOPASS, disconnectAfter, skipDetect, datalen, data, datalen); + SendCommandMIX(CMD_HF_SAM_PICOPASS, command_flags, 0, datalen, data, datalen); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) { PrintAndLogEx(WARNING, "SAM timeout"); @@ -5498,7 +5499,12 @@ static int CmdHFiClassSAM(const char *Cmd) { const uint8_t *mediaType = oid + 2 + oid_length; const uint8_t mediaType_data = mediaType[2]; PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); - + } else if(breakOnNrMac && d[0] == 0x05) { + PrintAndLogEx(SUCCESS, "Nr-MAC: " _GREEN_("%s"), sprint_hex_inrow(d+1, 8)); + if(verbose){ + PrintAndLogEx(INFO, "Replay Nr-MAC to dump SIO:"); + PrintAndLogEx(SUCCESS, " hf iclass dump -k \"%s\" --nr", sprint_hex_inrow(d+1, 8)); + } } else { print_hex(d, resp.length); } From e3e9ca504e34e8292ed719eb0ee5f978b0ca8399 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 10:27:47 +0100 Subject: [PATCH 07/14] cmdhfseos less verbose args parsing --- client/src/cmdhfseos.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index c5fe9d8c18..ac9b894456 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1636,8 +1636,6 @@ static int CmdHfSeosSAM(const char *Cmd) { "hd seos sam -d a005a103800104 -> get PACS data\n" ); - - void *argtable[] = { arg_param_begin, arg_lit0("v", "verbose", "verbose output"), @@ -1649,22 +1647,10 @@ static int CmdHfSeosSAM(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool verbose = false; - if (arg_get_lit(ctx, 1)) { - verbose = true; - } - bool disconnectAfter = true; - if (arg_get_lit(ctx, 2)) { - disconnectAfter = false; - } - bool skipDetect = false; - if (arg_get_lit(ctx, 3)) { - skipDetect = true; - } - bool decodeTLV = false; - if (arg_get_lit(ctx, 4)) { - decodeTLV = true; - } + bool verbose = arg_get_lit(ctx, 1); + bool disconnectAfter = !arg_get_lit(ctx, 2); + bool skipDetect = arg_get_lit(ctx, 3); + bool decodeTLV = arg_get_lit(ctx, 4); uint8_t data[PM3_CMD_DATA_SIZE] = {0}; int datalen = 0; From 5750d47ba32e5d0343dab95548e98a7a3c7d024c Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 10:30:10 +0100 Subject: [PATCH 08/14] rename util_hidsio to hidsio --- client/CMakeLists.txt | 2 +- client/Makefile | 2 +- client/src/cmdhficlass.c | 2 +- client/src/cmdhfseos.c | 2 +- client/src/{util_hidsio.c => hidsio.c} | 2 +- client/src/{util_hidsio.h => hidsio.h} | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) rename client/src/{util_hidsio.c => hidsio.c} (98%) rename client/src/{util_hidsio.h => hidsio.h} (95%) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index dc3d0a21df..274024fb75 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -413,6 +413,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/fileutils.c ${PM3_ROOT}/client/src/flash.c ${PM3_ROOT}/client/src/graph.c + ${PM3_ROOT}/client/src/hidsio.c ${PM3_ROOT}/client/src/iso4217.c ${PM3_ROOT}/client/src/jansson_path.c ${PM3_ROOT}/client/src/lua_bitlib.c @@ -425,7 +426,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/scripting.c ${PM3_ROOT}/client/src/ui.c ${PM3_ROOT}/client/src/util.c - ${PM3_ROOT}/client/src/util_hidsio.c ${PM3_ROOT}/client/src/wiegand_formats.c ${PM3_ROOT}/client/src/wiegand_formatutils.c ${CMAKE_BINARY_DIR}/version_pm3.c diff --git a/client/Makefile b/client/Makefile index 523b8b6572..46fa404390 100644 --- a/client/Makefile +++ b/client/Makefile @@ -723,6 +723,7 @@ SRCS = mifare/aiddesfire.c \ flash.c \ generator.c \ graph.c \ + hidsio.c \ jansson_path.c \ iso4217.c \ iso7816/apduinfo.c \ @@ -759,7 +760,6 @@ SRCS = mifare/aiddesfire.c \ scripting.c \ ui.c \ util.c \ - util_hidsio.c \ version_pm3.c \ wiegand_formats.c \ wiegand_formatutils.c diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index bcdbee5cb5..3d3dd9c6c2 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -42,7 +42,7 @@ #include "generator.h" #include "cmdhf14b.h" #include "cmdhw.h" -#include "util_hidsio.h" +#include "hidsio.h" #define NUM_CSNS 9 diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index ac9b894456..d697d1b418 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -38,7 +38,7 @@ #include "crypto/libpcrypto.h" // AES decrypt #include "commonutil.h" // get_sw #include "protocols.h" // ISO7816 APDU return codes -#include "util_hidsio.h" +#include "hidsio.h" static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/client/src/util_hidsio.c b/client/src/hidsio.c similarity index 98% rename from client/src/util_hidsio.c rename to client/src/hidsio.c index 932999c27d..eb2dc11c23 100644 --- a/client/src/util_hidsio.c +++ b/client/src/hidsio.c @@ -16,7 +16,7 @@ // HID Global SIO utilities //----------------------------------------------------------------------------- #include "commonutil.h" -#include "util_hidsio.h" +#include "hidsio.h" // structure and database for uid -> tagtype lookups typedef struct { diff --git a/client/src/util_hidsio.h b/client/src/hidsio.h similarity index 95% rename from client/src/util_hidsio.h rename to client/src/hidsio.h index 5c68f342b6..f99ee9a139 100644 --- a/client/src/util_hidsio.h +++ b/client/src/hidsio.h @@ -15,8 +15,8 @@ //----------------------------------------------------------------------------- // HID Global SIO utilities //----------------------------------------------------------------------------- -#ifndef __UTIL_HIDSIO_H_ -#define __UTIL_HIDSIO_H_ +#ifndef __HIDSIO_H_ +#define __HIDSIO_H_ #include "common.h" #include "stdint.h" From 15aea059ef7a8977461923106c3347d2f9584e1e Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 20:15:23 +0100 Subject: [PATCH 09/14] cmdhficlass: change from SendCommandMix to SendCommandNG --- armsrc/sam_picopass.c | 17 +++++++++-------- client/src/cmdhficlass.c | 20 +++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index e5a75e971d..f493e852b0 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -325,14 +325,15 @@ static int sam_set_card_detected_picopass(picopass_hdr_t *card_select) { * @return Status code indicating success or failure of the operation. */ int sam_picopass_get_pacs(PacketCommandNG *c) { - const bool disconnectAfter = !!(c->oldarg[0] & BITMASK(0)); - const bool skipDetect = !!(c->oldarg[0] & BITMASK(1)); - const bool breakOnNrMac = !!(c->oldarg[0] & BITMASK(2)); - const bool preventEpurseUpdate = !!(c->oldarg[0] & BITMASK(3)); - const bool shallow_mod = !!(c->oldarg[0] & BITMASK(4)); - - uint8_t *cmd = c->data.asBytes; - uint16_t cmd_len = (uint16_t) c->oldarg[2]; + const uint8_t flags = c->data.asBytes[0]; + const bool disconnectAfter = !!(flags & BITMASK(0)); + const bool skipDetect = !!(flags & BITMASK(1)); + const bool breakOnNrMac = !!(flags & BITMASK(2)); + const bool preventEpurseUpdate = !!(flags & BITMASK(3)); + const bool shallow_mod = !!(flags & BITMASK(4)); + + uint8_t *cmd = c->data.asBytes + 1; + uint16_t cmd_len = c->length - 1; int res = PM3_EFAILED; diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3d3dd9c6c2..dbb6cf2656 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5423,16 +5423,18 @@ static int CmdHFiClassSAM(const char *Cmd) { bool preventEpurseUpdate = arg_get_lit(ctx, 6); bool shallow_mod = arg_get_lit(ctx, 7); - uint64_t command_flags = 0; - if (disconnectAfter) command_flags |= BITMASK(0); - if (skipDetect) command_flags |= BITMASK(1); - if (breakOnNrMac) command_flags |= BITMASK(2); - if (preventEpurseUpdate) command_flags |= BITMASK(3); - if (shallow_mod) command_flags |= BITMASK(4); + uint8_t flags = 0; + if (disconnectAfter) flags |= BITMASK(0); + if (skipDetect) flags |= BITMASK(1); + if (breakOnNrMac) flags |= BITMASK(2); + if (preventEpurseUpdate) flags |= BITMASK(3); + if (shallow_mod) flags |= BITMASK(4); uint8_t data[PM3_CMD_DATA_SIZE] = {0}; - int datalen = 0; - CLIGetHexBLessWithReturn(ctx, 8, data, &datalen, 0); + data[0] = flags; + + int cmdlen = 0; + CLIGetHexBLessWithReturn(ctx, 8, data+1, &cmdlen, 0); CLIParserFree(ctx); @@ -5441,7 +5443,7 @@ static int CmdHFiClassSAM(const char *Cmd) { } clearCommandBuffer(); - SendCommandMIX(CMD_HF_SAM_PICOPASS, command_flags, 0, datalen, data, datalen); + SendCommandNG(CMD_HF_SAM_PICOPASS, data, cmdlen+1); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) { PrintAndLogEx(WARNING, "SAM timeout"); From 2464cf60fded1a5899c5ae7c529d5d512199f1aa Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 11:26:08 +0100 Subject: [PATCH 10/14] sam_seos, sam_picopass: switch from static allocation to BigBuf --- armsrc/sam_picopass.c | 9 +++++++-- armsrc/sam_seos.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index f493e852b0..450e462534 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -49,8 +49,12 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_send_request_iso14a"); - uint8_t buf1[ISO7816_MAX_FRAME] = {0}; - uint8_t buf2[ISO7816_MAX_FRAME] = {0}; + uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME); + if(buf1 == NULL || buf2 == NULL){ + res = PM3_EMALLOC; + goto out; + } uint8_t *sam_tx_buf = buf1; uint16_t sam_tx_len; @@ -235,6 +239,7 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re goto out; out: + BigBuf_free(); return res; } diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 0f4a7f2236..492a684a9a 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -129,8 +129,12 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_send_request_iso14a"); - uint8_t buf1[ISO7816_MAX_FRAME] = {0}; - uint8_t buf2[ISO7816_MAX_FRAME] = {0}; + uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME); + if(buf1 == NULL || buf2 == NULL){ + res = PM3_EMALLOC; + goto out; + } uint8_t *sam_tx_buf = buf1; uint16_t sam_tx_len; @@ -253,6 +257,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r goto out; out: + BigBuf_free(); return res; } From e05c36d4eadf739c84d750d30bf46eb8853b96ce Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 20:23:23 +0100 Subject: [PATCH 11/14] cmdhfseos: change from SendCommandMix to SendCommandNG --- armsrc/sam_seos.c | 10 ++++++---- client/src/cmdhfseos.c | 12 +++++++++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 492a684a9a..facdb25459 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -271,11 +271,13 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r * @return Status code indicating success or failure of the operation. */ int sam_seos_get_pacs(PacketCommandNG *c) { - bool disconnectAfter = c->oldarg[0] & 0x01; - bool skipDetect = c->oldarg[1] & 0x01; + const uint8_t flags = c->data.asBytes[0]; + const bool disconnectAfter = !!(flags & BITMASK(0)); + const bool skipDetect = !!(flags & BITMASK(1)); + + uint8_t *cmd = c->data.asBytes + 1; + uint16_t cmd_len = c->length - 1; - uint8_t *cmd = c->data.asBytes; - uint16_t cmd_len = (uint16_t) c->oldarg[2]; int res = PM3_EFAILED; diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index d697d1b418..4d59a19e2c 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1652,9 +1652,15 @@ static int CmdHfSeosSAM(const char *Cmd) { bool skipDetect = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 4); + uint8_t flags = 0; + if (disconnectAfter) flags |= BITMASK(0); + if (skipDetect) flags |= BITMASK(1); + uint8_t data[PM3_CMD_DATA_SIZE] = {0}; - int datalen = 0; - CLIGetHexBLessWithReturn(ctx, 5, data, &datalen, 0); + data[0] = flags; + + int cmdlen = 0; + CLIGetHexBLessWithReturn(ctx, 5, data+1, &cmdlen, 0); CLIParserFree(ctx); @@ -1663,7 +1669,7 @@ static int CmdHfSeosSAM(const char *Cmd) { } clearCommandBuffer(); - SendCommandMIX(CMD_HF_SAM_SEOS, disconnectAfter, skipDetect, datalen, data, datalen); + SendCommandNG(CMD_HF_SAM_SEOS, data, cmdlen+1); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) { PrintAndLogEx(WARNING, "SAM timeout"); From 098e3765c02e44238f5f7a76fadb58833018faf2 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 20:34:52 +0100 Subject: [PATCH 12/14] cmdhfseos: fixed typo --- client/src/cmdhfseos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 4d59a19e2c..dbc903e4da 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1633,7 +1633,7 @@ static int CmdHfSeosSAM(const char *Cmd) { CLIParserInit(&ctx, "hf seos sam", "Extract PACS via a HID SAM\n", "hf seos sam\n" - "hd seos sam -d a005a103800104 -> get PACS data\n" + "hf seos sam -d a005a103800104 -> get PACS data\n" ); void *argtable[] = { From 97aa1ff5984f2c8bd8aa5db7c948fba063226c95 Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 20:38:15 +0100 Subject: [PATCH 13/14] cmdhficlass: expand sam examples --- client/src/cmdhficlass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index dbb6cf2656..3b6b570d83 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5399,6 +5399,8 @@ static int CmdHFiClassSAM(const char *Cmd) { CLIParserInit(&ctx, "hf iclass sam", "Extract PACS via a HID SAM\n", "hf iclass sam\n" + "hf iclass sam -p -d a005a103800104 -> get PACS data, but ensure that epurse will stay unchanged\n" + "hf iclass sam --break-on-nr-mac -> get Nr-MAC for extracting encrypted SIO\n" ); void *argtable[] = { From 550af14502adee67c80d160c1a6b5dc53cd3d4ff Mon Sep 17 00:00:00 2001 From: Jakub Kramarz Date: Mon, 27 Jan 2025 20:57:24 +0100 Subject: [PATCH 14/14] cmdhficlass, cmdhfseos: fixed data argument parsing --- client/src/cmdhficlass.c | 5 ++++- client/src/cmdhfseos.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 3b6b570d83..22b90834e9 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -5436,7 +5436,10 @@ static int CmdHFiClassSAM(const char *Cmd) { data[0] = flags; int cmdlen = 0; - CLIGetHexBLessWithReturn(ctx, 8, data+1, &cmdlen, 0); + if (CLIParamHexToBuf(arg_get_str(ctx, 8), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){ + CLIParserFree(ctx); + return PM3_ESOFT; + } CLIParserFree(ctx); diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index dbc903e4da..99c438ef6c 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -1660,7 +1660,10 @@ static int CmdHfSeosSAM(const char *Cmd) { data[0] = flags; int cmdlen = 0; - CLIGetHexBLessWithReturn(ctx, 5, data+1, &cmdlen, 0); + if (CLIParamHexToBuf(arg_get_str(ctx, 5), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){ + CLIParserFree(ctx); + return PM3_ESOFT; + } CLIParserFree(ctx);