mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-15 06:50:00 +00:00
Added support for emulating ST25TA tag (IKEA Rothult) with custom NDEF response
This commit is contained in:
+7
-1
@@ -26,6 +26,9 @@
|
||||
#include "bwm_uart_at32.h"
|
||||
#include "bwm_wifi.h"
|
||||
#endif
|
||||
#include "clocks.h"
|
||||
#include "pm3_cmd.h"
|
||||
#include "usb_cdc.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "dbprint.h"
|
||||
#include "pmflash.h"
|
||||
@@ -2144,13 +2147,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
uint8_t ulauth_1a1[16];
|
||||
uint8_t ulauth_1a2[16];
|
||||
bool ulauth_1a2_mirror;
|
||||
uint16_t st25ta_ndef_len;
|
||||
uint8_t st25ta_ndef[ST25TA_SIM_NDEF_MAX];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SimulateIso14443aTagEx(payload->tagtype, payload->flags, payload->uid,
|
||||
payload->exitAfter, payload->rats, sizeof(payload->rats),
|
||||
payload->ulauth_1a1, payload->ulauth_1a1_len,
|
||||
payload->ulauth_1a2, payload->ulauth_1a2_len,
|
||||
payload->ulauth_1a2_mirror
|
||||
payload->ulauth_1a2_mirror,
|
||||
payload->st25ta_ndef, payload->st25ta_ndef_len
|
||||
); // ## Simulate iso14443a tag - pass tag type & UID
|
||||
break;
|
||||
}
|
||||
|
||||
+22
-6
@@ -19,6 +19,7 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "iso14443a.h"
|
||||
|
||||
#include "pm3_cmd.h"
|
||||
#include "string.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "cmd.h"
|
||||
@@ -1714,14 +1715,15 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data,
|
||||
// 'hf 14a sim'
|
||||
//-----------------------------------------------------------------------------
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads) {
|
||||
SimulateIso14443aTagEx(tagType, flags, useruid, exitAfterNReads, NULL, 0, NULL, 0, NULL, 0, false);
|
||||
SimulateIso14443aTagEx(tagType, flags, useruid, exitAfterNReads, NULL, 0, NULL, 0, NULL, 0, false, NULL, 0);
|
||||
}
|
||||
|
||||
void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads,
|
||||
uint8_t *ats, size_t ats_len,
|
||||
uint8_t *ulauth_1a1, uint8_t ulauth_1a1_len,
|
||||
uint8_t *ulauth_1a2, uint8_t ulauth_1a2_len,
|
||||
bool ulauth_1a2_mirror) {
|
||||
bool ulauth_1a2_mirror,
|
||||
const uint8_t *st25ta_ndef, uint16_t st25ta_ndef_len) {
|
||||
#define ATTACK_KEY_COUNT 16
|
||||
#define ULC_TAG_NONCE "\x01\x02\x03\x04\x05\x06\x07\x08"
|
||||
|
||||
@@ -1754,8 +1756,8 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE (ST25TA_SIM_NDEF_MAX + 4)
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 4096
|
||||
|
||||
uint8_t *dynamic_response_buffer = BigBuf_calloc(DYNAMIC_RESPONSE_BUFFER_SIZE);
|
||||
if (dynamic_response_buffer == NULL) {
|
||||
@@ -2429,10 +2431,24 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
|
||||
if (tagType == 10) {
|
||||
// we replay 90 00 for all commands but the read bin and we deny the verify cmd.
|
||||
|
||||
static const uint8_t default_st25ta_ndef[] = {
|
||||
0x00, 0x1b, 0xd1, 0x01, 0x17, 0x54, 0x02, 0x7a,
|
||||
0x68, 0xa2, 0x34, 0xcb, 0xd0, 0xe2, 0x03, 0xc7,
|
||||
0x3e, 0x62, 0x0b, 0xe8, 0xc6, 0x3c, 0x85, 0x2c,
|
||||
0xc5, 0x31, 0x31, 0x31, 0x32, 0x90, 0x00
|
||||
};
|
||||
const uint8_t *ndef = default_st25ta_ndef;
|
||||
uint16_t ndef_len = sizeof(default_st25ta_ndef);
|
||||
|
||||
if (st25ta_ndef != NULL && st25ta_ndef_len > 0 && st25ta_ndef_len <= ST25TA_SIM_NDEF_MAX) {
|
||||
ndef = st25ta_ndef;
|
||||
ndef_len = st25ta_ndef_len;
|
||||
}
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, "\x00\x1b\xd1\x01\x17\x54\x02\x7a\x68\xa2\x34\xcb\xd0\xe2\x03\xc7\x3e\x62\x0b\xe8\xc6\x3c\x85\x2c\xc5\x31\x31\x31\x32\x90\x00", 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
memcpy(dynamic_response_info.response + 1, ndef, ndef_len);
|
||||
dynamic_response_info.response_n = ndef_len + 1;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
|
||||
+2
-1
@@ -148,7 +148,8 @@ void SimulateIso14443aTagEx(uint8_t tagType, uint16_t flags, uint8_t *useruid, u
|
||||
uint8_t *ats, size_t ats_len,
|
||||
uint8_t *ulauth_1a1, uint8_t ulauth_1a1_len,
|
||||
uint8_t *ulauth_1a2, uint8_t ulauth_1a2_len,
|
||||
bool ulauth_1a2_mirror);
|
||||
bool ulauth_1a2_mirror,
|
||||
const uint8_t *st25ta_ndef, uint16_t st25ta_ndef_len);
|
||||
|
||||
void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid,
|
||||
uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len,
|
||||
|
||||
@@ -1037,8 +1037,11 @@ int CmdHF14ASim(const char *Cmd) {
|
||||
uint8_t ulauth_1a1[16];
|
||||
uint8_t ulauth_1a2[16];
|
||||
bool ulauth_1a2_mirror;
|
||||
uint16_t st25ta_ndef_len;
|
||||
uint8_t st25ta_ndef[ST25TA_SIM_NDEF_MAX];
|
||||
} PACKED payload;
|
||||
|
||||
memset(&payload, 0x00, sizeof(payload));
|
||||
payload.tagtype = tagtype;
|
||||
payload.flags = flags;
|
||||
payload.exitAfter = exitAfterNReads;
|
||||
|
||||
+141
-1
@@ -26,6 +26,7 @@
|
||||
#include "cliparser.h"
|
||||
#include "crc16.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "pm3_cmd.h"
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
@@ -34,6 +35,8 @@
|
||||
#include "protocols.h" // ISO7816 APDU return codes
|
||||
#include "crypto/libpcrypto.h" // ecdsa
|
||||
#include "crypto/originality.h"
|
||||
#include "ui.h"
|
||||
#include "util.h" // kbd_enter_pressed
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
@@ -335,22 +338,122 @@ static int CmdHFST25TAInfo(const char *Cmd) {
|
||||
return infoHFST25TA();
|
||||
}
|
||||
|
||||
static int st25ta_normalize_sim_ndef(const uint8_t *src, size_t src_len, uint8_t *dst, uint16_t *dst_len) {
|
||||
if (src == NULL || src_len == 0 || dst == NULL || dst_len == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (src_len >= 4 && src[src_len - 2] == 0x90 && src[src_len - 1] == 0x00) {
|
||||
if (src_len > ST25TA_SIM_NDEF_MAX) {
|
||||
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_SIM_NDEF_MAX);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
memcpy(dst, src, src_len);
|
||||
*dst_len = src_len;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (src_len >= 2) {
|
||||
uint16_t nlen = (src[0] << 8) | src[1];
|
||||
if (nlen + 2 == src_len) {
|
||||
if (src_len + 2 > ST25TA_SIM_NDEF_MAX) {
|
||||
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_SIM_NDEF_MAX);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
memcpy(dst, src, src_len);
|
||||
dst[src_len] = 0x90;
|
||||
dst[src_len + 1] = 0x00;
|
||||
*dst_len = src_len + 2;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (src_len + 4 > ST25TA_SIM_NDEF_MAX) {
|
||||
PrintAndLogEx(ERR, "NDEF response too large. Max %u bytes", ST25TA_SIM_NDEF_MAX);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
dst[0] = (src_len >> 8) & 0xff;
|
||||
dst[1] = src_len & 0xff;
|
||||
memcpy(dst + 2, src, src_len);
|
||||
dst[src_len + 2] = 0x90;
|
||||
dst[src_len + 3] = 0x00;
|
||||
*dst_len = src_len + 4;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int st25ta_simulate_with_ndef(const uint8_t *uid, const uint8_t *ndef, uint16_t ndef_len) {
|
||||
struct {
|
||||
uint8_t tagtype;
|
||||
uint16_t flags;
|
||||
uint8_t uid[10];
|
||||
uint8_t exitAfter;
|
||||
uint8_t rats[20];
|
||||
uint8_t ulauth_1a1_len;
|
||||
uint8_t ulauth_1a2_len;
|
||||
uint8_t ulauth_1a1[16];
|
||||
uint8_t ulauth_1a2[16];
|
||||
bool ulauth_1a2_mirror;
|
||||
uint16_t st25ta_ndef_len;
|
||||
uint8_t st25ta_ndef[ST25TA_SIM_NDEF_MAX];
|
||||
} PACKED payload;
|
||||
|
||||
memset(&payload, 0x00, sizeof(payload));
|
||||
payload.tagtype = 10;
|
||||
payload.flags = 0;
|
||||
FLAG_SET_UID_IN_DATA(payload.flags, 7);
|
||||
memcpy(payload.uid, uid, 7);
|
||||
|
||||
if (ndef != NULL && ndef_len > 0) {
|
||||
payload.st25ta_ndef_len = ndef_len;
|
||||
memcpy(payload.st25ta_ndef, ndef, ndef_len);
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " or " _GREEN_("<Enter>") " to abort simulation");
|
||||
PacketResponseNG resp = {0};
|
||||
bool keypress = kbd_enter_pressed();
|
||||
while (keypress == false) {
|
||||
keypress = kbd_enter_pressed();
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
static int CmdHFST25TASim(const char *Cmd) {
|
||||
int uidlen = 0;
|
||||
uint8_t uid[7] = {0};
|
||||
int ndef_hex_len = 0;
|
||||
uint8_t ndef_hex[ST25TA_SIM_NDEF_MAX] = {0};
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf st25ta sim",
|
||||
"Emulating ST25TA512B tag with 7 byte UID",
|
||||
"hf st25ta sim -u 02E2007D0FCA4C\n");
|
||||
"hf st25ta sim -u 02E2007D0FCA4C\n"
|
||||
"hf st25ta sim -u 02E2007D0FCA4C --ndef 001BD1011754027A68A234CBD0E203C73E620BE8C63C852CC5313131329000\n"
|
||||
"hf st25ta sim -u 02E2007D0FCA4C -f my-ndef.bin\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("u", "uid", "<hex>", "7 byte UID"),
|
||||
arg_str0(NULL, "ndef", "<hex>", "NDEF data or full READ BINARY response"),
|
||||
arg_str0("f", "file", "<fn>", "load NDEF data or full READ BINARY response from file"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
|
||||
int ndef_res = CLIParamHexToBuf(arg_get_str(ctx, 2), ndef_hex, sizeof(ndef_hex), &ndef_hex_len);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (uidlen != 7) {
|
||||
@@ -358,6 +461,43 @@ static int CmdHFST25TASim(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (ndef_res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Invalid NDEF hex");
|
||||
return ndef_res;
|
||||
}
|
||||
|
||||
if (ndef_hex_len > 0 && fnlen > 0) {
|
||||
PrintAndLogEx(ERR, "Use either --ndef or -f, not both");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
uint8_t ndef[ST25TA_SIM_NDEF_MAX] = {0};
|
||||
uint16_t ndef_len = 0;
|
||||
|
||||
if (ndef_hex_len > 0) {
|
||||
int res = st25ta_normalize_sim_ndef(ndef_hex, ndef_hex_len, ndef, &ndef_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
} else if (fnlen > 0) {
|
||||
uint8_t *file_data = NULL;
|
||||
size_t file_len = 0;
|
||||
int res = loadFile_safe(filename, "", (void **)&file_data, &file_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
res = st25ta_normalize_sim_ndef(file_data, file_len, ndef, &ndef_len);
|
||||
free(file_data);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (ndef_len > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Emulating ST25TA512B with supplied NDEF response (%u bytes)", ndef_len);
|
||||
return st25ta_simulate_with_ndef(uid, ndef, ndef_len);
|
||||
}
|
||||
|
||||
char param[40];
|
||||
snprintf(param, sizeof(param), "-t 10 -u %s", sprint_hex_inrow(uid, uidlen));
|
||||
return CmdHF14ASim(param);
|
||||
|
||||
@@ -974,6 +974,9 @@ typedef struct {
|
||||
|
||||
#define CMD_UNKNOWN 0xFFFF
|
||||
|
||||
// Max NDEF record length for ST25TA simulation
|
||||
#define ST25TA_SIM_NDEF_MAX 256
|
||||
|
||||
// Mifare simulation flags
|
||||
// In interactive mode, we are expected to finish the operation with an ACK
|
||||
#define FLAG_INTERACTIVE 0x0001
|
||||
|
||||
Reference in New Issue
Block a user