mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-06-07 00:11:46 +00:00
Merge branch 'master' into mfp_write_checker
Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
@@ -64,6 +64,7 @@ cov-int/
|
||||
|
||||
!client/resources/hardnested/*.bin
|
||||
!client/resources/hardnested_tables/*.z
|
||||
!client/resources/felica_system_code_list.json
|
||||
client/src/ui/ui_image.h
|
||||
client/src/ui/ui_overlays.h
|
||||
client/deps/reveng/bmptst
|
||||
|
||||
+5
-4
@@ -3,8 +3,9 @@ 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]
|
||||
- Fixed ACL RO checks on 16-block sectors when using `hf mf wrbl` and `hf mfp wrbl` (@team-orangeBlue)
|
||||
- Fixed `hf mf wrbl` and `hf mfp wrbl` the ACL RO checks on 16-block sectors correct (@team-orangeBlue)
|
||||
- Changed `hf mfp wrbl` command to check for Sector Trailer errors that could potentially lock sectors out (@team-orangeBlue)
|
||||
- Changed `hf felica info` and `hf felica rqsyscode` system code name annotation (@team-orangeBlue)
|
||||
- Added `lf relay` command where it relays between two pm3 devices over internet. Thanks to Moerno for the code! (@iceman1001)
|
||||
- Changed `hf mf acl` command to have more recognized generic configurations (@team-orangeBlue)
|
||||
- Added `hf mfp acl` command (@team-orangeBlue)
|
||||
@@ -15,10 +16,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||
- Added `hf mfdes createdelegateapp` command (@kormax)
|
||||
- Optimized `hf iclass legbrute` throughput: replaced recursive `suc()`/`output()` cipher functions with iterative loops, added 256-entry LUT for the `select()` function eliminating redundant bit arithmetic and halving key lookups per state step, switched successor state to in-place pointer update removing per-call struct copies, added `doMAC_brute()` with byte-wise LSB-first processing and direct output bit packing eliminating all bitstream struct overhead and output reversal calls per key candidate, and replaced per-iteration 64-bit modulo progress check with a countdown counter (@antiklesys)
|
||||
- Improved `hf iclass legbrute` fixed multithreaded key-range partitioning so threads cover non-overlapping slices of the 40-bit keyspace, added ETA display, keyboard abort with resume hint, `_Atomic` correctness for shared state, `pthread_create` error handling, and thread count capped at available CPUs (@antiklesys)
|
||||
- Added wildcard support to `hf secc sim` payloads (@antiklesys)
|
||||
- Changed `hf secc sim` it nows supports wildcard to payloads (@antiklesys)
|
||||
- Added `hf secc` to build a base for simulating basic function of iclass SE config cards (@antiklesys)
|
||||
- Improved SIO parsing for `hf iclass view` based on Iceman's "Dismantling the SEOS Protocol" talk (@antiklesys)
|
||||
- Added live fc/cn update to `hf iclass tagsim` refreshing the csn with each update (@antiklesys)
|
||||
- Changed `hf iclass view` , improved SIO parsing for based on @Iceman1001's "Dismantling the SEOS Protocol" talk (@antiklesys)
|
||||
- Changed `hf iclass tagsim` added live fc/cn update to refreshing the csn with each update (@antiklesys)
|
||||
- Added `--live` option to `hf iclass lookup` command to perform a live recovery of the reader's key by simulating a tag and running the lookup command against both standard and elite dictionaries (@antiklesys)
|
||||
- Added `hf iclass tagsim` command to quickly simulate an iclass card based on facility code and card number(@antiklesys)
|
||||
- Added `-f` parameter to `hf iclass sam` command to use the sam to parse a card dump (@antiklesys)
|
||||
|
||||
@@ -362,6 +362,8 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/mifare/desfiretest.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghercore.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghertest.c
|
||||
${PM3_ROOT}/client/src/relay/relay_posix.c
|
||||
${PM3_ROOT}/client/src/relay/relay_win32.c
|
||||
${PM3_ROOT}/client/src/uart/ringbuffer.c
|
||||
${PM3_ROOT}/client/src/uart/uart_common.c
|
||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
|
||||
@@ -831,6 +831,8 @@ SRCS = mifare/aiddesfire.c \
|
||||
pm3line.c \
|
||||
proxmark3.c \
|
||||
scandir.c \
|
||||
relay/relay_posix.c \
|
||||
relay/relay_win32.c \
|
||||
uart/ringbuffer.c \
|
||||
uart/uart_common.c \
|
||||
uart/uart_posix.c \
|
||||
|
||||
@@ -282,6 +282,8 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/mifare/desfiretest.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghercore.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghertest.c
|
||||
${PM3_ROOT}/client/src/relay/relay_posix.c
|
||||
${PM3_ROOT}/client/src/relay/relay_win32.c
|
||||
${PM3_ROOT}/client/src/uart/ringbuffer.c
|
||||
${PM3_ROOT}/client/src/uart/uart_common.c
|
||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"code": "0003",
|
||||
"name": "CJRC Standard",
|
||||
"region": "Japan",
|
||||
"type": "transit",
|
||||
"description": "Used by Mutual Use transit cards"
|
||||
},
|
||||
{
|
||||
"code": "0102",
|
||||
"name": "EZLink",
|
||||
"region": "Singapore",
|
||||
"type": "transit",
|
||||
"description": "Used by legacy EZ-Link transit cards"
|
||||
},
|
||||
{
|
||||
"code": "04C7",
|
||||
"name": "nanaco",
|
||||
"region": "Japan",
|
||||
"type": "payment",
|
||||
"description": "nanaco e-money system"
|
||||
},
|
||||
{
|
||||
"code": "12FC",
|
||||
"name": "NDEF Type 3 Tag",
|
||||
"region": "Global",
|
||||
"type": "ndef",
|
||||
"description": "NFC Forum Type 3 Tag system code"
|
||||
},
|
||||
{
|
||||
"code": "8005",
|
||||
"name": "Shenzhen Tong",
|
||||
"region": "China",
|
||||
"type": "transit",
|
||||
"description": "Used by legacy Shenzen Tong cards"
|
||||
},
|
||||
{
|
||||
"code": "8008",
|
||||
"name": "Octopus",
|
||||
"region": "Hong Kong",
|
||||
"type": "transit",
|
||||
"description": "Used by Octopus transit cards"
|
||||
},
|
||||
{
|
||||
"code": "852B",
|
||||
"name": "WAON",
|
||||
"region": "Japan",
|
||||
"type": "payment",
|
||||
"description": "Can be found on some WAON cards"
|
||||
},
|
||||
{
|
||||
"code": "8592",
|
||||
"name": "PASPY",
|
||||
"region": "Japan",
|
||||
"type": "transit",
|
||||
"description": "PASPY transit card system"
|
||||
},
|
||||
{
|
||||
"code": "86A7",
|
||||
"name": "Suica",
|
||||
"region": "Japan",
|
||||
"type": "transit",
|
||||
"description": "JR East Suica and related transit cards"
|
||||
},
|
||||
{
|
||||
"code": "88B4",
|
||||
"name": "FeliCa Lite",
|
||||
"region": "Global",
|
||||
"type": "common",
|
||||
"description": "Default system code used by FeliCa Lite/Lite-S tags"
|
||||
},
|
||||
{
|
||||
"code": "90B7",
|
||||
"name": "Kartu Multi Trip Commet",
|
||||
"region": "Indonesia",
|
||||
"type": "transit",
|
||||
"description": "Used on Kartu Multi Trip Commet cards"
|
||||
},
|
||||
{
|
||||
"code": "9373",
|
||||
"name": "Kartu Multi Trip Jelajah",
|
||||
"region": "Indonesia",
|
||||
"type": "transit",
|
||||
"description": "Used on Kartu Multi Trip Jelajah cards"
|
||||
},
|
||||
{
|
||||
"code": "9450",
|
||||
"name": "HCMC",
|
||||
"region": "Vietnam",
|
||||
"type": "transit",
|
||||
"description": "Used with Ho Chi Minh City Metro transit cards"
|
||||
},
|
||||
{
|
||||
"code": "FE00",
|
||||
"name": "FeliCa Networks Common Area",
|
||||
"region": "Japan",
|
||||
"type": "common",
|
||||
"description": "Common area for FeliCa Networks services"
|
||||
},
|
||||
{
|
||||
"code": "FE0F",
|
||||
"name": "Osaifu Keitai Container",
|
||||
"region": "Japan",
|
||||
"type": "mobile",
|
||||
"description": "Container system used by devices with Osaifu-Keitai"
|
||||
},
|
||||
{
|
||||
"code": "FFFF",
|
||||
"name": "Unfused system",
|
||||
"region": "Global",
|
||||
"type": "unfused",
|
||||
"description": "Default unfused/pre-personalization system"
|
||||
}
|
||||
]
|
||||
+194
-22
@@ -26,6 +26,7 @@
|
||||
#include "cmdtrace.h"
|
||||
#include "crc16.h"
|
||||
#include "util.h"
|
||||
#include "fileutils.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "ui.h"
|
||||
#include "iso18.h" // felica_card_select_t struct
|
||||
@@ -60,6 +61,8 @@
|
||||
#define FELICA_SEAC_POLL_TIMEOUT_MS 200U
|
||||
#define FELICA_SEAC_POLL_RETRY_COUNT 5U
|
||||
#define FELICA_SEAC_POLL_FRAME_LEN 5U
|
||||
#define FELICA_SYSTEM_CODE_MAX_COUNT 16U
|
||||
#define FELICA_SYSTEM_LIST_JSON "felica_system_code_list"
|
||||
|
||||
#define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001)
|
||||
#define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010)
|
||||
@@ -253,6 +256,8 @@ static const char *felica_node_discovery_method_display_name(felica_node_discove
|
||||
static void felica_print_node_discovery_method_used(felica_node_discovery_method_t method);
|
||||
static int felica_compare_discovered_nodes(const void *lhs, const void *rhs);
|
||||
static felica_card_select_t last_known_card;
|
||||
static json_t *felica_system_list = NULL;
|
||||
static bool felica_system_list_loaded = false;
|
||||
|
||||
static void set_last_known_card(felica_card_select_t card) {
|
||||
last_known_card = card;
|
||||
@@ -568,6 +573,161 @@ static void print_platform_information(const uint8_t *platform_information_data,
|
||||
sprint_hex_inrow(platform_information_data, platform_information_data_len));
|
||||
}
|
||||
|
||||
static json_t *felica_get_system_list(void) {
|
||||
if (felica_system_list_loaded) {
|
||||
return felica_system_list;
|
||||
}
|
||||
|
||||
felica_system_list_loaded = true;
|
||||
|
||||
char *path = NULL;
|
||||
if (searchFile(&path, RESOURCES_SUBDIR, FELICA_SYSTEM_LIST_JSON, ".json", true) != PM3_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
json_error_t error;
|
||||
json_t *root = json_load_file(path, 0, &error);
|
||||
if (root == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to parse `%s` line %d: %s", path, error.line, error.text);
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (json_is_array(root) == false) {
|
||||
PrintAndLogEx(WARNING, "Invalid `%s` format, expected array root", path);
|
||||
json_decref(root);
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
felica_system_list = root;
|
||||
free(path);
|
||||
return felica_system_list;
|
||||
}
|
||||
|
||||
static const char *felica_get_json_string(const json_t *obj, const char *key) {
|
||||
json_t *value = json_object_get(obj, key);
|
||||
if (json_is_string(value) == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *str = json_string_value(value);
|
||||
if (str == NULL || str[0] == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static const json_t *felica_find_system_annotation(uint16_t system_code) {
|
||||
json_t *system_list = felica_get_system_list();
|
||||
if (system_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char code_hex[5] = {0};
|
||||
snprintf(code_hex, sizeof(code_hex), "%04X", system_code);
|
||||
|
||||
size_t index = 0;
|
||||
json_t *entry = NULL;
|
||||
json_array_foreach(system_list, index, entry) {
|
||||
if (json_is_object(entry) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *entry_code = felica_get_json_string(entry, "code");
|
||||
if (entry_code && strcmp(entry_code, code_hex) == 0) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void felica_print_system_code_annotation(int level, const uint8_t *system_code_bytes) {
|
||||
if (system_code_bytes == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t system_code = ((uint16_t)system_code_bytes[0] << 8) | system_code_bytes[1];
|
||||
char code_hex[5] = {0};
|
||||
snprintf(code_hex, sizeof(code_hex), "%04X", system_code);
|
||||
|
||||
const json_t *entry = felica_find_system_annotation(system_code);
|
||||
if (entry == NULL) {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. UNKNOWN (" _RED_("Report to Iceman!") ")", code_hex);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *name = felica_get_json_string(entry, "name");
|
||||
const char *region = felica_get_json_string(entry, "region");
|
||||
const char *card_type = felica_get_json_string(entry, "type");
|
||||
|
||||
if (name == NULL) {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. UNKNOWN (" _RED_("Report to Iceman!") ")", code_hex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (region && card_type) {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s, %s") ")", code_hex, name, region, card_type);
|
||||
} else if (region) {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s") ")", code_hex, name, region);
|
||||
} else if (card_type) {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s (" _YELLOW_("%s") ")", code_hex, name, card_type);
|
||||
} else {
|
||||
PrintAndLogEx(level, " " _YELLOW_("%s") "............. %s", code_hex, name);
|
||||
}
|
||||
}
|
||||
|
||||
static int send_request_system_code(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose,
|
||||
uint32_t timeout_ms, uint32_t retries, bool logging,
|
||||
felica_syscode_response_t *system_code_response) {
|
||||
if (system_code_response == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
memset(system_code_response, 0, sizeof(*system_code_response));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (send_felica_payload_with_retries(flags, datalen, data, verbose,
|
||||
FELICA_REQSYSCODE_ACK,
|
||||
timeout_ms, retries,
|
||||
0, logging, &resp, "request system code") != PM3_SUCCESS) {
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
if (resp.length < (sizeof(felica_frame_response_t) + 1 + 2)) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
const size_t payload_length = resp.length - 2;
|
||||
const size_t number_of_systems_offset = sizeof(felica_frame_response_t);
|
||||
if (payload_length < (number_of_systems_offset + 1)) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t reported_system_count = resp.data.asBytes[number_of_systems_offset];
|
||||
const size_t available_system_count = (payload_length - number_of_systems_offset - 1) / 2;
|
||||
if (reported_system_count > available_system_count) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (reported_system_count > FELICA_SYSTEM_CODE_MAX_COUNT) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (reported_system_count == 0) {
|
||||
memcpy(system_code_response, resp.data.asBytes, sizeof(felica_frame_response_t) + 1);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
memcpy(system_code_response, resp.data.asBytes, sizeof(felica_frame_response_t) + 1);
|
||||
memcpy(system_code_response->system_code_list,
|
||||
resp.data.asBytes + number_of_systems_offset + 1,
|
||||
(size_t)reported_system_count * 2U);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for response from pm3 or timeout.
|
||||
* Checks if receveid bytes have a valid CRC.
|
||||
@@ -1047,7 +1207,7 @@ static int info_felica(bool verbose) {
|
||||
memcpy(&card, (felica_card_select_t *)resp.data.asBytes, sizeof(felica_card_select_t));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "IDm............ " _YELLOW_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
|
||||
PrintAndLogEx(INFO, "Primary IDm.... " _YELLOW_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
|
||||
PrintAndLogEx(INFO, " Code......... " _GREEN_("%s"), sprint_hex_inrow(card.code, sizeof(card.code)));
|
||||
PrintAndLogEx(INFO, " NFCID2....... " _GREEN_("%s"), sprint_hex_inrow(card.uid, sizeof(card.uid)));
|
||||
PrintAndLogEx(INFO, "PMM............ " _YELLOW_("%s"), sprint_hex_inrow(card.PMm, sizeof(card.PMm)));
|
||||
@@ -1160,6 +1320,24 @@ static int info_felica(bool verbose) {
|
||||
}
|
||||
}
|
||||
|
||||
felica_request_system_code_request_t request_system_code_request;
|
||||
memset(&request_system_code_request, 0, sizeof(request_system_code_request));
|
||||
request_system_code_request.length[0] = sizeof(request_system_code_request);
|
||||
request_system_code_request.command_code[0] = FELICA_REQSYSCODE_REQ;
|
||||
memcpy(request_system_code_request.IDm, card.IDm, sizeof(request_system_code_request.IDm));
|
||||
|
||||
felica_syscode_response_t system_code_response;
|
||||
if (send_request_system_code(optional_flags,
|
||||
sizeof(request_system_code_request), (uint8_t *)&request_system_code_request,
|
||||
false, FELICA_OPTIONAL_CMD_TIMEOUT_MS, FELICA_OPTIONAL_CMD_RETRIES, false,
|
||||
&system_code_response) == PM3_SUCCESS &&
|
||||
system_code_response.number_of_systems[0] > 0) {
|
||||
PrintAndLogEx(INFO, "System codes.... " _GREEN_("%u"), system_code_response.number_of_systems[0]);
|
||||
for (size_t i = 0; i < system_code_response.number_of_systems[0]; i++) {
|
||||
felica_print_system_code_annotation(INFO, system_code_response.system_code_list + (i * 2));
|
||||
}
|
||||
}
|
||||
|
||||
DropField();
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
@@ -3391,38 +3569,32 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
||||
uint8_t data[PM3_CMD_DATA_SIZE];
|
||||
memset(data, 0, sizeof(data));
|
||||
data[0] = 0x0A; // Static length
|
||||
data[1] = 0x0C; // Command ID
|
||||
felica_request_system_code_request_t request_system_code_request;
|
||||
memset(&request_system_code_request, 0, sizeof(request_system_code_request));
|
||||
request_system_code_request.length[0] = sizeof(request_system_code_request);
|
||||
request_system_code_request.command_code[0] = FELICA_REQSYSCODE_REQ;
|
||||
|
||||
uint16_t datalen = 10; // Length (1), Command ID (1), IDm (8)
|
||||
res = felica_ensure_target_present(idm, (size_t)ilen, FELICA_IDM_RESOLVE_STANDALONE, data + 2);
|
||||
res = felica_ensure_target_present(idm, (size_t)ilen, FELICA_IDM_RESOLVE_STANDALONE, request_system_code_request.IDm);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t flags = (FELICA_APPEND_CRC | FELICA_RAW);
|
||||
|
||||
clear_and_send_command(flags, datalen, data, 0);
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (waitCmdFelica(false, &resp, true) == false) {
|
||||
felica_syscode_response_t system_code_response;
|
||||
if (send_request_system_code(flags,
|
||||
sizeof(request_system_code_request), (uint8_t *)&request_system_code_request,
|
||||
false,
|
||||
FELICA_DEFAULT_TIMEOUT_MS, FELICA_DEFAULT_RETRY_COUNT, true,
|
||||
&system_code_response) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Got no response from card");
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
felica_syscode_response_t rq_syscode_response;
|
||||
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t));
|
||||
if (system_code_response.frame_response.IDm[0] != 0) {
|
||||
PrintAndLogEx(INFO, "Systems........ " _GREEN_("%u"), system_code_response.number_of_systems[0]);
|
||||
|
||||
if (rq_syscode_response.frame_response.IDm[0] != 0) {
|
||||
PrintAndLogEx(SUCCESS, "Request Response");
|
||||
PrintAndLogEx(SUCCESS, "IDm... %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm)));
|
||||
PrintAndLogEx(SUCCESS, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems)));
|
||||
PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0.");
|
||||
|
||||
for (int i = 0; i < rq_syscode_response.number_of_systems[0]; i++) {
|
||||
PrintAndLogEx(SUCCESS, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, 2));
|
||||
for (size_t i = 0; i < system_code_response.number_of_systems[0]; i++) {
|
||||
felica_print_system_code_annotation(INFO, system_code_response.system_code_list + (i * 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+73
-117
@@ -24,17 +24,7 @@
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include "relay/relay.h"
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
@@ -1722,33 +1712,9 @@ static int check_autocorrelate(const char *prefix, int clock) {
|
||||
|
||||
static int lf_relay_tag(uint64_t samples, uint16_t port) {
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket");
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr.s_addr = INADDR_ANY };
|
||||
int opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u"), port);
|
||||
close(sock);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (listen(sock, 1) < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to listen on socket");
|
||||
close(sock);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
|
||||
|
||||
int client = accept(sock, NULL, NULL);
|
||||
if (client < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to accept connection");
|
||||
close(sock);
|
||||
relay_socket_t listen_sock = RELAY_SOCKET_INVALID;
|
||||
relay_socket_t client = relay_listen_accept(port, &listen_sock);
|
||||
if (client == RELAY_SOCKET_INVALID) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
@@ -1763,49 +1729,32 @@ static int lf_relay_tag(uint64_t samples, uint16_t port) {
|
||||
|
||||
lf_read_internal(false, false, samples);
|
||||
|
||||
if (g_GraphTraceLen > 1000 && !getSignalProperties()->isnoise) {
|
||||
if ((g_GraphTraceLen > 1000) && (getSignalProperties()->isnoise == false)) {
|
||||
|
||||
PrintAndLogEx(INFO, "Tag detected! Sending %zu samples to Client...", g_GraphTraceLen);
|
||||
|
||||
|
||||
uint32_t len = (uint32_t)g_GraphTraceLen;
|
||||
if (send(client, &len, sizeof(len), 0) < 0) {
|
||||
if (relay_send_all(client, &len, sizeof(len)) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (send(client, g_GraphBuffer, len * sizeof(int32_t), 0) < 0) {
|
||||
|
||||
if (relay_send_all(client, g_GraphBuffer, len * sizeof(int32_t)) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(500);
|
||||
}
|
||||
|
||||
}
|
||||
close(client);
|
||||
close(sock);
|
||||
|
||||
relay_close(client);
|
||||
relay_close(listen_sock);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int lf_relay_rdr(const char *ip, uint16_t port) {
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket");
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr = {0};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
|
||||
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
|
||||
close(sock);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
PrintAndLogEx(ERR, "Connection error to %s:%u", ip, port);
|
||||
close(sock);
|
||||
relay_socket_t sock = relay_connect(ip, port);
|
||||
if (sock == RELAY_SOCKET_INVALID) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
@@ -1814,9 +1763,9 @@ static int lf_relay_rdr(const char *ip, uint16_t port) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
int n = 0;
|
||||
do {
|
||||
|
||||
bool running = true;
|
||||
while (running) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
PrintAndLogEx(DEBUG, "\naborted via keyboard!");
|
||||
@@ -1825,67 +1774,74 @@ static int lf_relay_rdr(const char *ip, uint16_t port) {
|
||||
}
|
||||
|
||||
uint32_t incoming_len = 0;
|
||||
|
||||
n = recv(sock, &incoming_len, sizeof(incoming_len), MSG_WAITALL);
|
||||
|
||||
if (n > 0 && incoming_len > 0) {
|
||||
|
||||
if (incoming_len > MAX_GRAPH_TRACE_LEN) {
|
||||
PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, MAX_GRAPH_TRACE_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len);
|
||||
ssize_t rx = recv(sock, g_GraphBuffer, incoming_len * sizeof(int32_t), MSG_WAITALL);
|
||||
|
||||
if (rx != (ssize_t)(incoming_len * sizeof(int32_t))) {
|
||||
PrintAndLogEx(ERR, "Short read: expected %u bytes, got %zd", incoming_len * (uint32_t)sizeof(int32_t), rx);
|
||||
break;
|
||||
}
|
||||
|
||||
// if previous simulation running, we need to break it.
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
msleep(300);
|
||||
|
||||
g_GraphTraceLen = incoming_len;
|
||||
lf_chk_bitstream();
|
||||
lfsim_upload_gb();
|
||||
struct {
|
||||
uint16_t len;
|
||||
uint16_t gap;
|
||||
} PACKED payload;
|
||||
payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen;
|
||||
payload.gap = 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulation active.");
|
||||
int n = relay_recv_all(sock, &incoming_len, sizeof(incoming_len));
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (n > 0);
|
||||
if (incoming_len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
|
||||
if (incoming_len > MAX_GRAPH_TRACE_LEN) {
|
||||
PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, (uint32_t)MAX_GRAPH_TRACE_LEN);
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len);
|
||||
|
||||
int rx = relay_recv_all(sock, g_GraphBuffer, incoming_len * sizeof(int32_t));
|
||||
if (rx < 0) {
|
||||
PrintAndLogEx(ERR, "Short read receiving sample data");
|
||||
break;
|
||||
}
|
||||
|
||||
// if previous simulation running, we need to break it.
|
||||
SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
|
||||
msleep(300);
|
||||
|
||||
g_GraphTraceLen = incoming_len;
|
||||
lf_chk_bitstream();
|
||||
lfsim_upload_gb();
|
||||
|
||||
struct {
|
||||
uint16_t len;
|
||||
uint16_t gap;
|
||||
} PACKED payload;
|
||||
payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen;
|
||||
payload.gap = 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulation active.");
|
||||
}
|
||||
|
||||
relay_close(sock);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFRelay(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf relay",
|
||||
"Relay LF signal between two Proxmark3 devices over TCP.\n"
|
||||
"By default it uses PORT 8000.\n"
|
||||
"One device acts as a Tag Proxy, the other as a Reader Client.",
|
||||
"lf relay --tag -s 7000\n"
|
||||
"lf relay --rdr --ip 192.168.1.141"
|
||||
);
|
||||
"Relay LF signal between two Proxmark3 devices over TCP.\n"
|
||||
"By default it uses PORT 8000 and uses 40000 samples from Graphbuffer\n"
|
||||
" --rdr : Reading device, act as IP client and reads LF tag and sends data\n"
|
||||
" --tag : Simulation device, act as IP server and simulates relayed data\n",
|
||||
_WHITE_("Device A, reading LF tag, client") "\n"
|
||||
"lf relay --rdr --ip 192.168.1.141 -> Client, connect to IP 192.168.1.141:8000\n"
|
||||
"lf relay --rdr --ip 192.168.1.141 -p 18111 -> Client, connect to IP 192.168.1.141:18111 \n\n"
|
||||
_WHITE_("Device B, simulate LF tag, server") "\n"
|
||||
"lf relay --tag -p 8111 -> Server listening port 8111, recv 40000 samples\n"
|
||||
"lf relay --tag -s 10000 -> Server listening port 8000, recv 10000 samples\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0(NULL, "tag", "Act as Tag Proxy (Server)"),
|
||||
arg_lit0(NULL, "rdr", "Act as Reader Client (Connects to Proxy)"),
|
||||
arg_str0("i", "ip", "<i>", "Target IP address for Reader mode"),
|
||||
arg_u64_0("s", "samples", "<dec>", "Number of samples to collect (default 40000)"),
|
||||
arg_lit0(NULL, "tag", "Simulation device, act as Server"),
|
||||
arg_lit0(NULL, "rdr", "Sniffing device, act as client"),
|
||||
arg_str0("i", "ip", "<ipaddr>", "Target IPv4 address to send data to. Used with `--rdr`"),
|
||||
arg_u64_0("s", "samples", "<dec>", "Number of samples to collect (def: 40000)"),
|
||||
arg_u64_0("p", "port", "<dec>", "Port number (def: 8000)"),
|
||||
arg_param_end
|
||||
};
|
||||
|
||||
@@ -293,6 +293,7 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "hf gst info" },
|
||||
{ 0, "hf gst read" },
|
||||
{ 1, "hf secc help" },
|
||||
{ 0, "hf secc info" },
|
||||
{ 0, "hf secc sim" },
|
||||
{ 0, "hf secc sniff" },
|
||||
{ 1, "hf iclass help" },
|
||||
@@ -435,6 +436,7 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "hf mf encodehid" },
|
||||
{ 1, "hf mfp help" },
|
||||
{ 1, "hf mfp list" },
|
||||
{ 1, "hf mfp acl" },
|
||||
{ 0, "hf mfp auth" },
|
||||
{ 0, "hf mfp chk" },
|
||||
{ 0, "hf mfp dump" },
|
||||
@@ -620,6 +622,7 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "lf config" },
|
||||
{ 0, "lf cmdread" },
|
||||
{ 0, "lf read" },
|
||||
{ 0, "lf relay" },
|
||||
{ 1, "lf search" },
|
||||
{ 0, "lf sim" },
|
||||
{ 0, "lf simask" },
|
||||
@@ -1024,10 +1027,10 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "script run hf_ntag_bruteforce.lua" },
|
||||
{ 0, "script run hf_ntag_dt.lua" },
|
||||
{ 0, "script run init_rdv4.lua" },
|
||||
{ 0, "script run kybercrystals.lua" },
|
||||
{ 0, "script run lf_awid_bulkclone.lua" },
|
||||
{ 0, "script run lf_electra.lua" },
|
||||
{ 0, "script run lf_em4100_bulk.lua" },
|
||||
{ 0, "script run lf_em4x05_kybercrystals.lua" },
|
||||
{ 0, "script run lf_em_tearoff.lua" },
|
||||
{ 0, "script run lf_em_tearoff_protect.lua" },
|
||||
{ 0, "script run lf_hid_bulkclone.lua" },
|
||||
@@ -1046,7 +1049,6 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "script run ntag_clean.lua" },
|
||||
{ 0, "script run ntag_getsig.lua" },
|
||||
{ 0, "script run ntag_hammertime.lua" },
|
||||
{ 0, "script run paxton_clone.lua" },
|
||||
{ 0, "script run data_tracetest.lua" },
|
||||
{ 0, "script run hf_read.lua" },
|
||||
{ 0, "script run lf_t55xx_defaultask.lua" },
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// TCP relay socket abstraction layer
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef RELAY_H__
|
||||
#define RELAY_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
typedef SOCKET relay_socket_t;
|
||||
#define RELAY_SOCKET_INVALID INVALID_SOCKET
|
||||
#else
|
||||
typedef int relay_socket_t;
|
||||
#define RELAY_SOCKET_INVALID (-1)
|
||||
#endif
|
||||
|
||||
// Initialize relay subsystem (call once at startup).
|
||||
// On Win32 this calls WSAStartup; on POSIX it is a no-op.
|
||||
int relay_init(void);
|
||||
|
||||
// Tear down relay subsystem (call once at shutdown).
|
||||
// On Win32 this calls WSACleanup; on POSIX it is a no-op.
|
||||
void relay_cleanup(void);
|
||||
|
||||
// Create a TCP server socket bound to INADDR_ANY:<port>, listen, and
|
||||
// block until one client connects. Returns the *client* fd/SOCKET.
|
||||
// On error, returns RELAY_SOCKET_INVALID. Caller owns both sockets;
|
||||
// the listening socket is written to *listen_sock so it can be closed.
|
||||
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock);
|
||||
|
||||
// Connect to a TCP server at ip:port.
|
||||
// Returns the connected socket or RELAY_SOCKET_INVALID on error.
|
||||
relay_socket_t relay_connect(const char *ip, uint16_t port);
|
||||
|
||||
// Send exactly `len` bytes from `buf`.
|
||||
// Returns 0 on success, -1 on error.
|
||||
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len);
|
||||
|
||||
// Receive exactly `len` bytes into `buf`.
|
||||
// Returns number of bytes received, or -1 on error / disconnect.
|
||||
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len);
|
||||
|
||||
// Close a relay socket.
|
||||
void relay_close(relay_socket_t sock);
|
||||
|
||||
#endif // RELAY_H__
|
||||
@@ -0,0 +1,148 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// TCP relay socket abstraction — POSIX implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include "relay.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
int relay_init(void) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void relay_cleanup(void) {
|
||||
}
|
||||
|
||||
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) {
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno));
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
struct sockaddr_in addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(port),
|
||||
.sin_addr.s_addr = INADDR_ANY
|
||||
};
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (%s)", port, strerror(errno));
|
||||
close(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (listen(sock, 1) < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to listen on socket (%s)", strerror(errno));
|
||||
close(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
|
||||
|
||||
int client = accept(sock, NULL, NULL);
|
||||
if (client < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to accept connection (%s)", strerror(errno));
|
||||
close(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (listen_sock != NULL) {
|
||||
*listen_sock = sock;
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
relay_socket_t relay_connect(const char *ip, uint16_t port) {
|
||||
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno));
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr = {0};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
|
||||
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
|
||||
close(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
PrintAndLogEx(ERR, "Connection error to %s:%u (%s)", ip, port, strerror(errno));
|
||||
close(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) {
|
||||
const uint8_t *p = (const uint8_t *)buf;
|
||||
uint32_t remaining = len;
|
||||
|
||||
while (remaining > 0) {
|
||||
ssize_t n = send(sock, p, remaining, 0);
|
||||
if (n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
p += n;
|
||||
remaining -= (uint32_t)n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) {
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
uint32_t remaining = len;
|
||||
|
||||
while (remaining > 0) {
|
||||
ssize_t n = recv(sock, p, remaining, 0);
|
||||
if (n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
p += n;
|
||||
remaining -= (uint32_t)n;
|
||||
}
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
void relay_close(relay_socket_t sock) {
|
||||
if (sock != RELAY_SOCKET_INVALID) {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
@@ -0,0 +1,175 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// TCP relay socket abstraction — Win32 implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "relay.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
static bool g_wsa_initialized = false;
|
||||
|
||||
int relay_init(void) {
|
||||
if (g_wsa_initialized) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
WSADATA wsa;
|
||||
int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
|
||||
if (ret != 0) {
|
||||
PrintAndLogEx(ERR, "WSAStartup failed with error %d", ret);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
g_wsa_initialized = true;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void relay_cleanup(void) {
|
||||
if (g_wsa_initialized) {
|
||||
WSACleanup();
|
||||
g_wsa_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) {
|
||||
|
||||
if (relay_init() != PM3_SUCCESS) {
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError());
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||
PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (WSA %d)", port, WSAGetLastError());
|
||||
closesocket(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (listen(sock, 1) == SOCKET_ERROR) {
|
||||
PrintAndLogEx(ERR, "Failed to listen on socket (WSA %d)", WSAGetLastError());
|
||||
closesocket(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port);
|
||||
|
||||
SOCKET client = accept(sock, NULL, NULL);
|
||||
if (client == INVALID_SOCKET) {
|
||||
PrintAndLogEx(ERR, "Failed to accept connection (WSA %d)", WSAGetLastError());
|
||||
closesocket(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (listen_sock != NULL) {
|
||||
*listen_sock = sock;
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
relay_socket_t relay_connect(const char *ip, uint16_t port) {
|
||||
|
||||
if (relay_init() != PM3_SUCCESS) {
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError());
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) {
|
||||
PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port);
|
||||
closesocket(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||
PrintAndLogEx(ERR, "Connection error to %s:%u (WSA %d)", ip, port, WSAGetLastError());
|
||||
closesocket(sock);
|
||||
return RELAY_SOCKET_INVALID;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) {
|
||||
const char *p = (const char *)buf;
|
||||
uint32_t remaining = len;
|
||||
|
||||
while (remaining > 0) {
|
||||
int n = send(sock, p, (int)remaining, 0);
|
||||
if (n == SOCKET_ERROR || n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
p += n;
|
||||
remaining -= (uint32_t)n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) {
|
||||
char *p = (char *)buf;
|
||||
uint32_t remaining = len;
|
||||
|
||||
while (remaining > 0) {
|
||||
int n = recv(sock, p, (int)remaining, 0);
|
||||
if (n == SOCKET_ERROR || n <= 0) {
|
||||
return -1;
|
||||
}
|
||||
p += n;
|
||||
remaining -= (uint32_t)n;
|
||||
}
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
void relay_close(relay_socket_t sock) {
|
||||
if (sock != INVALID_SOCKET) {
|
||||
closesocket(sock);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
+169
-17
@@ -3523,7 +3523,7 @@
|
||||
"--ki <dec> Key index to select key from memory 'hf iclass managekeys'",
|
||||
"--credit key is assumed to be the credit key",
|
||||
"-s <dec> tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us",
|
||||
"-i <dec> tearoff delay increment (in us) - default 10",
|
||||
"-i <dec> tearoff delay increment (in us) - default 5",
|
||||
"-e <dec> tearoff delay end (in us) must be a higher value than the start delay",
|
||||
"-o, --otp <hex> Custom OTP value as 2 hex bytes",
|
||||
"--dns Do not stabilize the bits, and return the raw dump of the block after tearoff",
|
||||
@@ -3805,7 +3805,7 @@
|
||||
},
|
||||
"hf iclass legbrute": {
|
||||
"command": "hf iclass legbrute",
|
||||
"description": "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key. Complete 40 bit keyspace is 1'099'511'627'776 and command is locked down to max 16 threads currently. A possible worst case scenario on 16 threads estimates XXX days YYY hours MMM minutes.",
|
||||
"description": "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key. Complete 40 bit keyspace is 1'099'511'627'776.",
|
||||
"notes": [
|
||||
"hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"
|
||||
],
|
||||
@@ -3817,13 +3817,14 @@
|
||||
"--macs2 <hex> MACs captured from the reader, different than the first set (with the same csn and epurse value)",
|
||||
"--pk <hex> Partial Key from legrec or starting key of keyblock from legbrute",
|
||||
"--index <dec> Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million",
|
||||
"--threads <dec> Number of threads to use, by default it uses the cpu's max threads (max 16)."
|
||||
"--threads <dec> Number of threads to use, by default it uses the cpu's max threads.",
|
||||
"--dbg Print first 2 key candidates and midpoint per thread, then exit (use to verify thread partitioning)"
|
||||
],
|
||||
"usage": "hf iclass legbrute [-h] --epurse <hex> --macs1 <hex> --macs2 <hex> --pk <hex> [--index <dec>] [--threads <dec>]"
|
||||
"usage": "hf iclass legbrute [-h] --epurse <hex> --macs1 <hex> --macs2 <hex> --pk <hex> [--index <dec>] [--threads <dec>] [--dbg]"
|
||||
},
|
||||
"hf iclass legrec": {
|
||||
"command": "hf iclass legrec",
|
||||
"description": "Attempts to recover the diversified key of a specific iCLASS card. This may take several days. The card must remain be on the PM3 antenna during the whole process. ! Warning ! This process may brick the card! ! Warning !",
|
||||
"description": "Attempts to recover the diversified key of a specific iCLASS card. This may take several days. The card must remain on the PM3 antenna during the whole process. ! Warning ! This process may brick the card! ! Warning !",
|
||||
"notes": [
|
||||
"hf iclass legrec --macs 0000000089cb984b",
|
||||
"hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest"
|
||||
@@ -3839,10 +3840,9 @@
|
||||
"--allnight Loops the loop for 10 times, recommended loop value of 5000",
|
||||
"--fast Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card",
|
||||
"--sl Lower card comms delay times, further speeds increases, may cause more errors",
|
||||
"--est Estimates the key updates based on the card's CSN assuming standard key, can be used with --credit option",
|
||||
"--credit EXPERIMENTAL : Recover the credit key using KD 0"
|
||||
"--est Estimates the key updates based on the card's CSN assuming standard key, can be used with --credit option"
|
||||
],
|
||||
"usage": "hf iclass legrec [-h] --macs <hex> [--index <dec>] [--loop <dec>] [--debug] [--notest] [--allnight] [--fast] [--sl] [--est] [--credit]"
|
||||
"usage": "hf iclass legrec [-h] [--macs <hex>] [--index <dec>] [--loop <dec>] [--debug] [--notest] [--allnight] [--fast] [--sl] [--est]"
|
||||
},
|
||||
"hf iclass loclass": {
|
||||
"command": "hf iclass loclass",
|
||||
@@ -6045,6 +6045,35 @@
|
||||
],
|
||||
"usage": "hf mfdes bruteaid [-h] [--start <hex>] [--end <hex>] [-i <dec>] [--preset <full|ascii|numbers|letters|dictionary|mad>]"
|
||||
},
|
||||
"hf mfdes brutedamslot": {
|
||||
"command": "hf mfdes brutedamslot",
|
||||
"description": "Recover DAM slot to delegated AID mappings by bruteforce. WARNING: This command takes a loooong time",
|
||||
"notes": [
|
||||
"hf mfdes brutedamslot -> bruteforce all DAM slots",
|
||||
"hf mfdes brutedamslot --start 0000 --end 00ff -> bruteforce specific DAM slot range",
|
||||
"hf mfdes brutedamslot --step 16 -> bruteforce DAM slots with step 16",
|
||||
"hf mfdes brutedamslot --no-auth -> execute without authentication"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-a, --apdu Show APDU requests and responses",
|
||||
"-v, --verbose Verbose output",
|
||||
"-n, --keyno <dec> Key number (default: 0 / PICC key)",
|
||||
"-t, --algo <DES|2TDEA|3TDEA|AES> Crypt algo",
|
||||
"-k, --key <hex> Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)",
|
||||
"--kdf <none|AN10922|gallagher> Key Derivation Function (KDF)",
|
||||
"-i, --kdfi <hex> KDF input (1-31 hex bytes)",
|
||||
"-m, --cmode <plain|mac|encrypt> Communicaton mode",
|
||||
"-c, --ccset <native|niso|iso> Communicaton command set",
|
||||
"--schann <d40|ev1|ev2|lrp> Secure channel",
|
||||
"--start <hex> Starting DAM slot (2 hex bytes, little endian on card)",
|
||||
"--end <hex> Last DAM slot (2 hex bytes, little endian on card)",
|
||||
"--step <dec> Increment step when bruteforcing DAM slots",
|
||||
"--no-auth Execute without authentication"
|
||||
],
|
||||
"usage": "hf mfdes brutedamslot [-hav] [-n <dec>] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--start <hex>] [--end <hex>] [--step <dec>] [--no-auth]"
|
||||
},
|
||||
"hf mfdes bruteisofid": {
|
||||
"command": "hf mfdes bruteisofid",
|
||||
"description": "Recover ISO file IDs by bruteforce. WARNING: This command takes a loooong time",
|
||||
@@ -6281,6 +6310,49 @@
|
||||
],
|
||||
"usage": "hf mfdes createapp [-hav] [-n <dec>] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--rawdata <hex>] [--aid <hex>] [--fid <hex>] [--dfname <str>] [--dfhex <hex>] [--ks1 <hex>] [--ks2 <hex>] [--dstalgo <DES|2TDEA|3TDEA|AES>] [--numkeys <dec>] [--no-auth]"
|
||||
},
|
||||
"hf mfdes createdelegateapp": {
|
||||
"command": "hf mfdes createdelegateapp",
|
||||
"description": "Create delegated application (CreateDelegatedApplication / 0xC9). Master key needs to be provided.",
|
||||
"notes": [
|
||||
"Command is built from fields and sends two frames: C9 + AF continuation.",
|
||||
"Authentication is always performed with DAM key number 0x10.",
|
||||
"EncK and DAMMAC are calculated from supplied key material.",
|
||||
"",
|
||||
"Structured mode examples:",
|
||||
"hf mfdes createdelegateapp --aid 123456 --damslot 0001 --damslotver 00 --quota 0010 --ks1 0F --ks2 AE --algo 2TDEA --key 00000000000000000000000000000000 --damenckey 00112233445566778899AABBCCDDEEFF --dammackey 8899AABBCCDDEEFF0011223344556677 --dstkey 00112233445566778899AABBCCDDEEFF --dstkeyver 00",
|
||||
"hf mfdes createdelegateapp --aid 123456 --damslot 0001 --quota 0010 --ks1 0F --dstalgo aes --numkeys 14 --ks3 01 --fid E110 --dfname D2760000850101 --algo 2TDEA --key 00000000000000000000000000000000 --damenckey 00112233445566778899AABBCCDDEEFF --dammackey 8899AABBCCDDEEFF0011223344556677 --dstkey 00112233445566778899AABBCCDDEEFF --dstkeyver 00"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-a, --apdu Show APDU requests and responses",
|
||||
"-v, --verbose Verbose output",
|
||||
"-t, --algo <DES|2TDEA|3TDEA|AES> Crypt algo",
|
||||
"-k, --key <hex> Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)",
|
||||
"--kdf <none|AN10922|gallagher> Key Derivation Function (KDF)",
|
||||
"-i, --kdfi <hex> KDF input (1-31 hex bytes)",
|
||||
"-m, --cmode <plain|mac|encrypt> Communicaton mode",
|
||||
"-c, --ccset <native|niso|iso> Communicaton command set",
|
||||
"--schann <d40|ev1|ev2|lrp> Secure channel",
|
||||
"--aid <hex> Application ID for create. Mandatory in structured mode. (3 hex bytes, big endian)",
|
||||
"--damslot <hex> DAM slot number (2 hex bytes, little endian on card)",
|
||||
"--damslotver <hex> DAM slot version (1 hex byte, def: 00)",
|
||||
"--quota <hex> Quota in blocks (2 hex bytes, little endian on card, def: 0000)",
|
||||
"--ks1 <hex> Key settings 1 (1 hex byte, def: 0x0F)",
|
||||
"--ks2 <hex> Key settings 2 (1 hex byte, def: 0x0E)",
|
||||
"--ks3 <hex> Key settings 3 (1 hex byte, optional)",
|
||||
"--fid <hex> ISO file ID (2 hex bytes, big endian), optional",
|
||||
"--dfname <hex> ISO DF Name (1..16 bytes, hex), optional",
|
||||
"--dstalgo <DES|2TDEA|3TDEA|AES> Application key crypt algo (used when ks2 omitted, def: DES)",
|
||||
"--numkeys <dec> Number of keys 0x01..0x0e (used when ks2 omitted, def: 0x01)",
|
||||
"--damenckey <hex> DAM ENC key (16 bytes for AES/2TDEA, 24 bytes for 3TDEA)",
|
||||
"--dammackey <hex> DAM MAC key (16 bytes for AES/2TDEA, 24 bytes for 3TDEA)",
|
||||
"--dstkey <hex> Initial delegated-app key (16 bytes for 2TDEA/AES, 24 bytes for 3TDEA)",
|
||||
"--dstkeyver <hex> Initial delegated-app key version (1 hex byte, def: 00)",
|
||||
"--no-auth Execute without authentication"
|
||||
],
|
||||
"usage": "hf mfdes createdelegateapp [-hav] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--aid <hex>] [--damslot <hex>] [--damslotver <hex>] [--quota <hex>] [--ks1 <hex>] [--ks2 <hex>] [--ks3 <hex>] [--fid <hex>] [--dfname <hex>] [--dstalgo <DES|2TDEA|3TDEA|AES>] [--numkeys <dec>] [--damenckey <hex>] [--dammackey <hex>] [--dstkey <hex>] [--dstkeyver <hex>] [--no-auth]"
|
||||
},
|
||||
"hf mfdes createfile": {
|
||||
"command": "hf mfdes createfile",
|
||||
"description": "Create Standard/Backup file in the application. Application master key needs to be provided or flag --no-auth set (depend on application settings).",
|
||||
@@ -6664,6 +6736,33 @@
|
||||
],
|
||||
"usage": "hf mfdes getappnames [-hav] [-n <dec>] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--no-auth]"
|
||||
},
|
||||
"hf mfdes getdelegateappinfo": {
|
||||
"command": "hf mfdes getdelegateappinfo",
|
||||
"description": "Get delegated application information for DAM slot (GetDelegatedInfo / 0x69).",
|
||||
"notes": [
|
||||
"By default authentication is performed with PICC key number 0x00.",
|
||||
"Use --keyno to pick another key number, or --no-auth to skip authentication.",
|
||||
"hf mfdes getdelegateappinfo --damslot 0001 --algo 2TDEA --key 00000000000000000000000000000000",
|
||||
"hf mfdes getdelegateappinfo --damslot 0001 --no-auth"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-a, --apdu Show APDU requests and responses",
|
||||
"-v, --verbose Verbose output",
|
||||
"-n, --keyno <dec> Key number (default: 0 / PICC key)",
|
||||
"-t, --algo <DES|2TDEA|3TDEA|AES> Crypt algo",
|
||||
"-k, --key <hex> Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)",
|
||||
"--kdf <none|AN10922|gallagher> Key Derivation Function (KDF)",
|
||||
"-i, --kdfi <hex> KDF input (1-31 hex bytes)",
|
||||
"-m, --cmode <plain|mac|encrypt> Communicaton mode",
|
||||
"-c, --ccset <native|niso|iso> Communicaton command set",
|
||||
"--schann <d40|ev1|ev2|lrp> Secure channel",
|
||||
"--damslot <hex> DAM slot number (2 hex bytes, little endian on card)",
|
||||
"--no-auth Execute without authentication"
|
||||
],
|
||||
"usage": "hf mfdes getdelegateappinfo [-hav] [-n <dec>] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--damslot <hex>] [--no-auth]"
|
||||
},
|
||||
"hf mfdes getfileids": {
|
||||
"command": "hf mfdes getfileids",
|
||||
"description": "Get File IDs list from card. Master key needs to be provided or flag --no-auth set.",
|
||||
@@ -7185,6 +7284,20 @@
|
||||
],
|
||||
"usage": "hf mfdes write [-hav] [-n <dec>] [-t <DES|2TDEA|3TDEA|AES>] [-k <hex>] [--kdf <none|AN10922|gallagher>] [-i <hex>] [-m <plain|mac|encrypt>] [-c <native|niso|iso>] [--schann <d40|ev1|ev2|lrp>] [--aid <hex>] [--fid <hex>] [--no-auth] [--type <auto|data|value|record|mac>] [-o <hex>] [-d <hex>] [--debit] [--commit] [--updaterec <dec>] [--isoid <hex>] [--fileisoid <hex>] [--readerid <hex>] [--trkey <hex>]"
|
||||
},
|
||||
"hf mfp acl": {
|
||||
"command": "hf mfp acl",
|
||||
"description": "Print decoded MIFARE Plus access rights (ACL), A = key A B = key B AB = both key A and B ACCESS = access bytes inside sector trailer block Increment, decrement, transfer, restore is for value blocks",
|
||||
"notes": [
|
||||
"hf mf acl",
|
||||
"hf mf acl -d FF0780"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-d, --data <hex> ACL bytes specified as 4 hex bytes"
|
||||
],
|
||||
"usage": "hf mfp acl [-h] -d <hex>"
|
||||
},
|
||||
"hf mfp auth": {
|
||||
"command": "hf mfp auth",
|
||||
"description": "Executes AES authentication command for MIFARE Plus card",
|
||||
@@ -7311,7 +7424,7 @@
|
||||
},
|
||||
"hf mfp help": {
|
||||
"command": "hf mfp help",
|
||||
"description": "help This help list List MIFARE Plus history --------------------------------------------------------------------------------------- hf mfp list available offline: yes Alias of `trace list -t mfp -c` 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",
|
||||
"description": "help This help list List MIFARE Plus history acl Decode ACL values for Mifare Plus --------------------------------------------------------------------------------------- hf mfp list available offline: yes Alias of `trace list -t mfp -c` 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 mfp list --frame -> show frame delay times",
|
||||
"hf mfp list -1 -> use trace buffer"
|
||||
@@ -8320,12 +8433,24 @@
|
||||
},
|
||||
"hf secc help": {
|
||||
"command": "hf secc help",
|
||||
"description": "-------- ----------- HID Config Card ----------- help This help --------------------------------------------------------------------------------------- hf secc sim available offline: no Simulate a HID iCLASS SE Config Card (JCOP / GlobalPlatform SCP02). Responds to SELECT AID (0013/0017), A0 D4, INITIALIZE UPDATE, and EXTERNAL AUTH. Load card parameters (UID, AID, SCP02Key) from a JSON file.",
|
||||
"description": "-------- ----------- HID Config Card ----------- help This help --------------------------------------------------------------------------------------- hf secc info available offline: no Read and decode Card Recognition Data from a GlobalPlatform card. Sends GET DATA (80 CA 00 66 00) and parses the Card Recognition Template (tag 73) to identify platform, SCP type, and chip family.",
|
||||
"notes": [
|
||||
"hf secc info"
|
||||
],
|
||||
"offline": true,
|
||||
"options": [
|
||||
"-h, --help This help"
|
||||
],
|
||||
"usage": "hf secc info [-h]"
|
||||
},
|
||||
"hf secc sim": {
|
||||
"command": "hf secc sim",
|
||||
"description": "Simulate a HID iCLASS SE Config Card (JCOP / GlobalPlatform SCP02). APDUs are matched against the JSON APDUResponses table; INITIALIZE UPDATE and EXTERNAL AUTH are handled by the built-in SCP02 crypto. Anything else falls through to the JSON DefaultResponse (or 9000 if none is set).",
|
||||
"notes": [
|
||||
"hf secc sim -f hidconfig_sample",
|
||||
"hf secc sim -f hidconfig_sample -n 5 -> stop after 5 reader interactions"
|
||||
],
|
||||
"offline": true,
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"-f, --file <fn> JSON file with UID, AID, SCP02Key (without .json extension)",
|
||||
@@ -8335,11 +8460,13 @@
|
||||
},
|
||||
"hf secc sniff": {
|
||||
"command": "hf secc sniff",
|
||||
"description": "Sniff the communication between a HID Config Card reader and card. Use `hf 14a list` to view collected data.",
|
||||
"description": "Sniff the communication between a HID Config Card reader and card. Use `hf seos list` to view collected data. With -j and no -d, jams responses to APDU A0 D4 00 00 00. With -j -d <hex> jams responses to the specified APDU. Use -r <hex> to override the jam response payload (default: 00009000).",
|
||||
"notes": [
|
||||
"hf secc sniff",
|
||||
"hf secc sniff -j -> jam A0 D4 00 00 00, respond 00 00 90 00",
|
||||
"hf secc sniff -c -r -> trigger on card or reader data"
|
||||
"hf secc sniff -j -d A0D4000000 -> same, APDU specified explicitly",
|
||||
"hf secc sniff -j -d A0D4000000 -r 9000 -> jam A0D4000000, respond 90 00",
|
||||
"hf secc sniff -c -i -> trigger on card data, interactive"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
@@ -8347,9 +8474,11 @@
|
||||
"-c, --card triggered by first data from card",
|
||||
"-r, --reader triggered by first 7-bit request from reader (REQ, WUP)",
|
||||
"-i, --interactive console will not be returned until sniff finishes or is aborted",
|
||||
"-j, --jam jam APDU A0 D4 00 00 00, respond with 00 00 90 00"
|
||||
"-j, --jam jam responses to a specific APDU (see -d/-a)",
|
||||
"-d, --apdu <hex> APDU bytes to jam (default: A0D4000000)",
|
||||
"-a, --resp <hex> response payload when jamming (default: 00009000)"
|
||||
],
|
||||
"usage": "hf secc sniff [-hcrij]"
|
||||
"usage": "hf secc sniff [-hcrij] [-d <hex>] [-a <hex>]"
|
||||
},
|
||||
"hf seos adf": {
|
||||
"command": "hf seos adf",
|
||||
@@ -12092,6 +12221,29 @@
|
||||
],
|
||||
"usage": "lf read [-hv@] [-s <dec>]"
|
||||
},
|
||||
"lf relay": {
|
||||
"command": "lf relay",
|
||||
"description": "Relay LF signal between two Proxmark3 devices over TCP. By default it uses PORT 8000 and uses 40000 samples from Graphbuffer --rdr : Reading device, act as IP client and reads LF tag and sends data --tag : Simulation device, act as IP server and simulates relayed data",
|
||||
"notes": [
|
||||
"Device A, reading LF tag, client",
|
||||
"lf relay --rdr --ip 192.168.1.141 -> Client, connect to IP 192.168.1.141:8000",
|
||||
"lf relay --rdr --ip 192.168.1.141 -p 18111 -> Client, connect to IP 192.168.1.141:18111",
|
||||
"",
|
||||
"Device B, simulate LF tag, server",
|
||||
"lf relay --tag -p 8111 -> Server listening port 8111, recv 40000 samples",
|
||||
"lf relay --tag -s 10000 -> Server listening port 8000, recv 10000 samples"
|
||||
],
|
||||
"offline": false,
|
||||
"options": [
|
||||
"-h, --help This help",
|
||||
"--tag Simulation device, act as Server",
|
||||
"--rdr Sniffing device, act as client",
|
||||
"-i, --ip <ipaddr> Target IPv4 address to send data to. Used with `--rdr`",
|
||||
"-s, --samples <dec> Number of samples to collect (def: 40000)",
|
||||
"-p, --port <dec> Port number (def: 8000)"
|
||||
],
|
||||
"usage": "lf relay [-h] [--tag] [--rdr] [-i <ipaddr>] [-s <dec>] [-p <dec>]"
|
||||
},
|
||||
"lf search": {
|
||||
"command": "lf search",
|
||||
"description": "Read and search for valid known tag. For offline mode, you can `data load` first then search.",
|
||||
@@ -14286,8 +14438,8 @@
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"commands_extracted": 813,
|
||||
"commands_extracted": 819,
|
||||
"extracted_by": "PM3Help2JSON v1.00",
|
||||
"extracted_on": "2026-04-02T12:42:42"
|
||||
"extracted_on": "2026-04-11T02:04:09"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,6 +432,7 @@ Check column "offline" for their availability.
|
||||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf secc help `|Y |`This help`
|
||||
|`hf secc info `|N |`Read and decode Card Recognition Data (GP tag 0066)`
|
||||
|`hf secc sim `|N |`Simulate HID iCLASS SE Config Card`
|
||||
|`hf secc sniff `|N |`Sniff reader<->card, jam A0 D4 APDU`
|
||||
|
||||
@@ -638,6 +639,7 @@ Check column "offline" for their availability.
|
||||
|------- |------- |-----------
|
||||
|`hf mfp help `|Y |`This help`
|
||||
|`hf mfp list `|Y |`List MIFARE Plus history`
|
||||
|`hf mfp acl `|Y |`Decode ACL values for Mifare Plus`
|
||||
|`hf mfp auth `|N |`Authentication`
|
||||
|`hf mfp chk `|N |`Check keys`
|
||||
|`hf mfp dump `|N |`Dump MIFARE Plus tag to file`
|
||||
@@ -713,7 +715,10 @@ Check column "offline" for their availability.
|
||||
|`hf mfdes getaids `|N |`Get Application IDs list`
|
||||
|`hf mfdes getappnames `|N |`Get Applications list`
|
||||
|`hf mfdes bruteaid `|N |`Recover AIDs by bruteforce`
|
||||
|`hf mfdes brutedamslot `|N |`Recover DAM slots to delegated AIDs by bruteforce`
|
||||
|`hf mfdes createapp `|N |`Create Application`
|
||||
|`hf mfdes createdelegateapp`|N |`Create Delegated Application`
|
||||
|`hf mfdes getdelegateappinfo`|N |`Get Delegated Application info by DAM slot`
|
||||
|`hf mfdes deleteapp `|N |`Delete Application`
|
||||
|`hf mfdes selectapp `|N |`Select Application ID`
|
||||
|`hf mfdes selectisofid `|N |`Select file by ISO ID`
|
||||
@@ -940,6 +945,7 @@ Check column "offline" for their availability.
|
||||
|`lf config `|N |`Get/Set config for LF sampling, bit/sample, decimation, frequency`
|
||||
|`lf cmdread `|N |`Modulate LF reader field to send command before read`
|
||||
|`lf read `|N |`Read LF tag`
|
||||
|`lf relay `|N |`LF relay between two pm3 devices (tag/rdr mode)`
|
||||
|`lf search `|Y |`Read and Search for valid known tag`
|
||||
|`lf sim `|N |`Simulate LF tag from buffer`
|
||||
|`lf simask `|N |`Simulate ASK tag`
|
||||
|
||||
@@ -175,6 +175,12 @@ typedef struct {
|
||||
felica_status_flags_t status_flags;
|
||||
} PACKED felica_status_response_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t length[1];
|
||||
uint8_t command_code[1];
|
||||
uint8_t IDm[8];
|
||||
} PACKED felica_request_system_code_request_t;
|
||||
|
||||
typedef struct {
|
||||
felica_frame_response_t frame_response;
|
||||
uint8_t number_of_systems[1];
|
||||
|
||||
Reference in New Issue
Block a user