mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
MFULC trace: detect when known key is used during auth
This commit is contained in:
parent
0330234aea
commit
e5d7ce61e6
5 changed files with 298 additions and 199 deletions
|
@ -47,6 +47,9 @@ void ClearAuthData(void) {
|
||||||
|
|
||||||
|
|
||||||
static int gs_ntag_i2c_state = 0;
|
static int gs_ntag_i2c_state = 0;
|
||||||
|
static int gs_mfuc_state = 0;
|
||||||
|
static uint8_t gs_mfuc_authdata[3][16] = {0};
|
||||||
|
static uint8_t *gs_mfuc_key = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief iso14443A_CRC_check Checks CRC in command or response
|
* @brief iso14443A_CRC_check Checks CRC in command or response
|
||||||
|
@ -162,8 +165,9 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
|
||||||
|
|
||||||
|
if (! is_response) {
|
||||||
if ((gs_ntag_i2c_state == 1) && (cmdsize == 6) && (memcmp(cmd + 1, "\x00\x00\x00", 3) == 0)) {
|
if ((gs_ntag_i2c_state == 1) && (cmdsize == 6) && (memcmp(cmd + 1, "\x00\x00\x00", 3) == 0)) {
|
||||||
snprintf(exp, size, "SECTOR(%d)", cmd[0]);
|
snprintf(exp, size, "SECTOR(%d)", cmd[0]);
|
||||||
gs_ntag_i2c_state = 0;
|
gs_ntag_i2c_state = 0;
|
||||||
|
@ -171,7 +175,6 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gs_ntag_i2c_state = 0;
|
gs_ntag_i2c_state = 0;
|
||||||
|
|
||||||
switch (cmd[0]) {
|
switch (cmd[0]) {
|
||||||
case ISO14443A_CMD_WUPA:
|
case ISO14443A_CMD_WUPA:
|
||||||
snprintf(exp, size, "WUPA");
|
snprintf(exp, size, "WUPA");
|
||||||
|
@ -281,10 +284,24 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
snprintf(exp, size, "MAGIC WIPEC");
|
snprintf(exp, size, "MAGIC WIPEC");
|
||||||
break;
|
break;
|
||||||
case MIFARE_ULC_AUTH_1:
|
case MIFARE_ULC_AUTH_1:
|
||||||
snprintf(exp, size, "AUTH ");
|
gs_mfuc_state = 1;
|
||||||
|
snprintf(exp, size, "AUTH-1 ");
|
||||||
break;
|
break;
|
||||||
case MIFARE_ULC_AUTH_2:
|
case MIFARE_ULC_AUTH_2:
|
||||||
snprintf(exp, size, "AUTH_ANSW");
|
if ((gs_mfuc_state == 2) && (cmdsize==19)){
|
||||||
|
memcpy(gs_mfuc_authdata[1], &cmd[1], 16);
|
||||||
|
if (trace_mfuc_try_default_3des_keys(&gs_mfuc_key, gs_mfuc_state, gs_mfuc_authdata) == PM3_SUCCESS) {
|
||||||
|
// buffer too small to print the full key,
|
||||||
|
// so we give just a hint that one of the default keys was used
|
||||||
|
// snprintf(exp, size, "AUTH-2 KEY: " _YELLOW_("%s"), sprint_hex(gs_mfuc_key, 16));
|
||||||
|
snprintf(exp, size, "AUTH-2 KEY: " _YELLOW_("%02x%02x%02x%02x..."), gs_mfuc_key[0], gs_mfuc_key[1], gs_mfuc_key[2], gs_mfuc_key[3]);
|
||||||
|
} else {
|
||||||
|
snprintf(exp, size, "AUTH-2");
|
||||||
|
}
|
||||||
|
gs_mfuc_state = 3;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MIFARE_ULEV1_AUTH:
|
case MIFARE_ULEV1_AUTH:
|
||||||
if (cmdsize == 7)
|
if (cmdsize == 7)
|
||||||
|
@ -353,11 +370,35 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (gs_mfuc_state==1) {
|
||||||
|
if ((cmd[0]==0xAF) && (cmdsize==11)) {
|
||||||
|
// register RndB
|
||||||
|
memcpy(gs_mfuc_authdata[0], &cmd[1], 8);
|
||||||
|
gs_mfuc_state=2;
|
||||||
|
} else {
|
||||||
|
gs_mfuc_state=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gs_mfuc_state==3) {
|
||||||
|
if ((cmd[0]==0x00) && (cmdsize==11)) {
|
||||||
|
// register RndA'
|
||||||
|
memcpy(gs_mfuc_authdata[2], &cmd[1], 8);
|
||||||
|
if (trace_mfuc_try_default_3des_keys(&gs_mfuc_key, gs_mfuc_state, gs_mfuc_authdata) == PM3_SUCCESS) {
|
||||||
|
snprintf(exp, size, "AUTH-2 ANSW OK");
|
||||||
|
gs_mfuc_state=0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gs_mfuc_state=0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response) {
|
||||||
applyIso14443a(exp, size, cmd, cmdsize);
|
applyIso14443a(exp, size, cmd, cmdsize, is_response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) {
|
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) {
|
||||||
|
@ -770,7 +811,7 @@ void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
|
|
||||||
// it's basically a ISO14443a tag, so try annotation from there
|
// it's basically a ISO14443a tag, so try annotation from there
|
||||||
if (applyIso14443a(exp, size, cmd, cmdsize) == 0) {
|
if (applyIso14443a(exp, size, cmd, cmdsize, false) == 0) {
|
||||||
|
|
||||||
// S-block 11xxx010
|
// S-block 11xxx010
|
||||||
if ((cmd[0] & 0xC0) && (cmdsize == 3)) {
|
if ((cmd[0] & 0xC0) && (cmdsize == 3)) {
|
||||||
|
@ -1428,8 +1469,8 @@ void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isResponse && ((MifareAuthState == masNone) || (MifareAuthState == masError)))
|
if ((MifareAuthState == masNone) || (MifareAuthState == masError))
|
||||||
annotateIso14443a(exp, size, cmd, cmdsize);
|
annotateIso14443a(exp, size, cmd, cmdsize, isResponse);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ uint8_t mifare_CRC_check(bool isResponse, uint8_t *data, uint8_t len);
|
||||||
uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n);
|
uint8_t iso15693_CRC_check(uint8_t *d, uint8_t n);
|
||||||
uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
||||||
|
|
||||||
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
||||||
|
|
||||||
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse);
|
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse);
|
||||||
void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
|
@ -46,7 +46,7 @@ void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIso7816(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateIso14443b(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIso14443b(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool is_response);
|
||||||
void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, uint8_t paritysize, bool isResponse);
|
void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, uint8_t paritysize, bool isResponse);
|
||||||
void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
|
|
|
@ -255,6 +255,65 @@ static int ulc_authentication(uint8_t *key, bool switch_off_field) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int trace_mfuc_try_key(uint8_t *key, int state, uint8_t (*authdata)[16]) {
|
||||||
|
uint8_t iv[8] = {0};
|
||||||
|
uint8_t RndB[8] = {0};
|
||||||
|
uint8_t RndARndB[16] = {0};
|
||||||
|
uint8_t RndA[8] = {0};
|
||||||
|
mbedtls_des3_context ctx_des3;
|
||||||
|
switch (state) {
|
||||||
|
case 2:
|
||||||
|
mbedtls_des3_set2key_dec(&ctx_des3, key);
|
||||||
|
mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT,
|
||||||
|
8, iv, authdata[0], RndB);
|
||||||
|
mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT,
|
||||||
|
16, iv, authdata[1], RndARndB);
|
||||||
|
if ((memcmp(&RndB[1], &RndARndB[8], 7) == 0) &&
|
||||||
|
(RndB[0] == RndARndB[15])) {
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (key == NULL) {// if no key was found
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
memcpy(iv, authdata[0], 8);
|
||||||
|
mbedtls_des3_set2key_dec(&ctx_des3, key);
|
||||||
|
mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT,
|
||||||
|
16, iv, authdata[1], RndARndB);
|
||||||
|
mbedtls_des3_crypt_cbc(&ctx_des3, MBEDTLS_DES_DECRYPT,
|
||||||
|
8, iv, authdata[2], RndA);
|
||||||
|
if ((memcmp(&RndARndB[1], RndA, 7) == 0) &&
|
||||||
|
(RndARndB[0] == RndA[7])) {
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]) {
|
||||||
|
switch (state) {
|
||||||
|
case 2:
|
||||||
|
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
|
||||||
|
uint8_t *key = default_3des_keys[i];
|
||||||
|
if (trace_mfuc_try_key(key, state, authdata) == PM3_SUCCESS) {
|
||||||
|
*correct_key = key;
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
return trace_mfuc_try_key(*correct_key, state, authdata);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
static int try_default_3des_keys(uint8_t **correct_key) {
|
static int try_default_3des_keys(uint8_t **correct_key) {
|
||||||
PrintAndLogEx(INFO, "Trying some default 3des keys");
|
PrintAndLogEx(INFO, "Trying some default 3des keys");
|
||||||
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
|
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ uint32_t GetHF14AMfU_Type(void);
|
||||||
int ul_print_type(uint32_t tagtype, uint8_t spaces);
|
int ul_print_type(uint32_t tagtype, uint8_t spaces);
|
||||||
void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage);
|
void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage);
|
||||||
int ul_read_uid(uint8_t *uid);
|
int ul_read_uid(uint8_t *uid);
|
||||||
|
int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]);
|
||||||
|
|
||||||
int CmdHFMFUltra(const char *Cmd);
|
int CmdHFMFUltra(const char *Cmd);
|
||||||
int CmdHF14MfuNDEFRead(const char *Cmd);
|
int CmdHF14MfuNDEFRead(const char *Cmd);
|
||||||
|
|
|
@ -334,6 +334,10 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
|
|
||||||
// Always annotate these protocols both reader/tag messages
|
// Always annotate these protocols both reader/tag messages
|
||||||
switch (protocol) {
|
switch (protocol) {
|
||||||
|
case ISO_14443A:
|
||||||
|
case ISO_7816_4:
|
||||||
|
annotateIso14443a(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||||
|
break;
|
||||||
case PROTO_MIFARE:
|
case PROTO_MIFARE:
|
||||||
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, TRACELOG_PARITY_LEN(hdr), hdr->isResponse);
|
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, TRACELOG_PARITY_LEN(hdr), hdr->isResponse);
|
||||||
break;
|
break;
|
||||||
|
@ -359,9 +363,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case LEGIC:
|
case LEGIC:
|
||||||
annotateLegic(explanation, sizeof(explanation), frame, data_len);
|
annotateLegic(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
case ISO_14443A:
|
|
||||||
annotateIso14443a(explanation, sizeof(explanation), frame, data_len);
|
|
||||||
break;
|
|
||||||
case MFDES:
|
case MFDES:
|
||||||
annotateMfDesfire(explanation, sizeof(explanation), frame, data_len);
|
annotateMfDesfire(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
|
@ -372,7 +373,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
annotateTopaz(explanation, sizeof(explanation), frame, data_len);
|
annotateTopaz(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
case ISO_7816_4:
|
case ISO_7816_4:
|
||||||
annotateIso14443a(explanation, sizeof(explanation), frame, data_len);
|
|
||||||
annotateIso7816(explanation, sizeof(explanation), frame, data_len);
|
annotateIso7816(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
case ISO_15693:
|
case ISO_15693:
|
||||||
|
@ -466,9 +466,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
if (protocol == PROTO_MIFARE) {
|
if (protocol == PROTO_MIFARE) {
|
||||||
if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) {
|
if (DecodeMifareData(frame, data_len, parityBytes, hdr->isResponse, mfData, &mfDataLen, mfDicKeys, mfDicKeysCount)) {
|
||||||
memset(explanation, 0x00, sizeof(explanation));
|
memset(explanation, 0x00, sizeof(explanation));
|
||||||
if (hdr->isResponse == false) {
|
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse);
|
||||||
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen);
|
|
||||||
}
|
|
||||||
uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen);
|
uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen);
|
||||||
PrintAndLogEx(NORMAL, " | | * |%-72s | %-4s| %s",
|
PrintAndLogEx(NORMAL, " | | * |%-72s | %-4s| %s",
|
||||||
sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
|
sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue