From 508151ee3a33624f0b1fc9e06548fd3d93050cf1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 19 Aug 2020 21:51:10 +0200 Subject: [PATCH] hf iclass list - now tries to recovery key --- client/src/cmdhficlass.c | 60 ++++++++++++----- client/src/cmdhficlass.h | 4 ++ client/src/cmdhflist.c | 141 +++++++++++++++++++++++++-------------- client/src/cmdhflist.h | 2 +- client/src/cmdtrace.c | 6 +- 5 files changed, 141 insertions(+), 72 deletions(-) diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 526b14765..c766769cb 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -362,6 +362,46 @@ static int usage_hf_iclass_permutekey(void) { return PM3_SUCCESS; } +static int cmp_uint32(const void *a, const void *b) { + + const iclass_prekey_t *x = (const iclass_prekey_t *)a; + const iclass_prekey_t *y = (const iclass_prekey_t *)b; + + uint32_t mx = bytes_to_num((uint8_t *)x->mac, 4); + uint32_t my = bytes_to_num((uint8_t *)y->mac, 4); + + if (mx < my) + return -1; + else + return mx > my; +} + +bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key) { + + iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX, sizeof(iclass_prekey_t)); + if (prekey == false) { + return PM3_EMALLOC; + } + + uint8_t ccnr[12]; + memcpy(ccnr, epurse, 8); + memcpy(ccnr + 8, rmac, 4); + + GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t*)iClass_Key_Table, ICLASS_KEYS_MAX, prekey); + qsort(prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); + + iclass_prekey_t lookup; + memcpy(lookup.mac, tmac, 4); + + // binsearch + iclass_prekey_t * item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32); + if (item != NULL) { + memcpy(key, item->key, 8); + return true; + } + return false; +} + typedef enum { None = 0, DES, @@ -415,7 +455,7 @@ static uint8_t notset(uint8_t val, uint8_t mask) { return !(val & mask); } -static uint8_t get_pagemap(const picopass_hdr *hdr) { +uint8_t get_pagemap(const picopass_hdr *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; } @@ -2926,9 +2966,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0}; uint8_t fileNameLen = 0; - iclass_premac_t *pre = NULL; - // time uint64_t t1 = msclock(); while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -2973,7 +3011,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { return res; } - pre = calloc(keycount, sizeof(iclass_premac_t)); + iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); if (!pre) { free(keyBlock); return PM3_EMALLOC; @@ -3116,20 +3154,6 @@ out: return PM3_SUCCESS; } -static int cmp_uint32(const void *a, const void *b) { - - const iclass_prekey_t *x = (const iclass_prekey_t *)a; - const iclass_prekey_t *y = (const iclass_prekey_t *)b; - - uint32_t mx = bytes_to_num((uint8_t *)x->mac, 4); - uint32_t my = bytes_to_num((uint8_t *)y->mac, 4); - - if (mx < my) - return -1; - else - return mx > my; -} - // this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in. // Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work. static int CmdHFiClassLookUp(const char *Cmd) { diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index 50152fd6c..afc612c33 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -13,6 +13,7 @@ #include "common.h" #include "fileutils.h" +#include "pm3_cmd.h" typedef struct iclass_block { uint8_t d[8]; @@ -38,4 +39,7 @@ void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, uint8_t *keys, uint32_t keycnt, iclass_prekey_t *list); void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list); void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt); + +uint8_t get_pagemap(const picopass_hdr *hdr); +bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key); #endif diff --git a/client/src/cmdhflist.c b/client/src/cmdhflist.c index 02abfef20..0e2b40a50 100644 --- a/client/src/cmdhflist.c +++ b/client/src/cmdhflist.c @@ -23,6 +23,7 @@ #include "crc16.h" #include "crapto1/crapto1.h" #include "protocols.h" +#include "cmdhficlass.h" enum MifareAuthSeq { masNone, @@ -326,59 +327,99 @@ void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { applyIso14443a(exp, size, cmd, cmdsize); } -void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { - uint8_t c = cmd[0] & 0x0F; - uint8_t parity = 0; - for (uint8_t i = 0; i < 7; i++) { - parity ^= (cmd[0] >> i) & 1; - } +void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) { - switch (c) { - case ICLASS_CMD_HALT: - snprintf(exp, size, "HALT"); - break; - case ICLASS_CMD_SELECT: - snprintf(exp, size, "SELECT"); - break; - case ICLASS_CMD_ACTALL: - snprintf(exp, size, "ACTALL"); - break; - case ICLASS_CMD_DETECT: - snprintf(exp, size, "DETECT"); - break; - case ICLASS_CMD_CHECK: - snprintf(exp, size, "CHECK"); - break; - case ICLASS_CMD_READ4: - snprintf(exp, size, "READ4(%d)", cmd[1]); - break; - case ICLASS_CMD_READ_OR_IDENTIFY: { - if (cmdsize > 1) { - snprintf(exp, size, "READ(%d)", cmd[1]); - } else { - snprintf(exp, size, "IDENTIFY"); - } - break; + enum pico_state {PICO_NONE, PICO_SELECT, PICO_AUTH_EPURSE, PICO_AUTH_MACS }; + static enum pico_state curr_state = PICO_NONE; + static uint8_t csn[8]; + static uint8_t epurse[8]; + static uint8_t rmac[4]; + static uint8_t tmac[4]; + + if ( isResponse == false ) { + uint8_t c = cmd[0] & 0x0F; + uint8_t parity = 0; + for (uint8_t i = 0; i < 7; i++) { + parity ^= (cmd[0] >> i) & 1; } - case ICLASS_CMD_PAGESEL: - snprintf(exp, size, "PAGESEL(%d)", cmd[1]); - break; - case ICLASS_CMD_UPDATE: - snprintf(exp, size, "UPDATE(%d)", cmd[1]); - break; - case ICLASS_CMD_READCHECK: - if (ICLASS_CREDIT(cmd[0])) { - snprintf(exp, size, "READCHECK[Kc](%d)", cmd[1]); - } else { - snprintf(exp, size, "READCHECK[Kd](%d)", cmd[1]); + + switch (c) { + case ICLASS_CMD_HALT: + snprintf(exp, size, "HALT"); + curr_state = PICO_NONE; + break; + case ICLASS_CMD_SELECT: + snprintf(exp, size, "SELECT"); + curr_state = PICO_SELECT; + break; + case ICLASS_CMD_ACTALL: + snprintf(exp, size, "ACTALL"); + curr_state = PICO_NONE; + break; + case ICLASS_CMD_DETECT: + snprintf(exp, size, "DETECT"); + curr_state = PICO_NONE; + break; + case ICLASS_CMD_CHECK: + snprintf(exp, size, "CHECK"); + curr_state = PICO_AUTH_MACS; + memcpy(rmac, cmd + 1, 4); + memcpy(tmac, cmd + 5, 4); + break; + case ICLASS_CMD_READ4: + snprintf(exp, size, "READ4(%d)", cmd[1]); + break; + case ICLASS_CMD_READ_OR_IDENTIFY: { + + if (cmdsize > 1) { + snprintf(exp, size, "READ(%d)", cmd[1]); + } else { + snprintf(exp, size, "IDENTIFY"); + } + break; } - break; - case ICLASS_CMD_ACT: - snprintf(exp, size, "ACT"); - break; - default: - snprintf(exp, size, "?"); - break; + case ICLASS_CMD_PAGESEL: + snprintf(exp, size, "PAGESEL(%d)", cmd[1]); + curr_state = PICO_NONE; + break; + case ICLASS_CMD_UPDATE: + snprintf(exp, size, "UPDATE(%d)", cmd[1]); + curr_state = PICO_NONE; + break; + case ICLASS_CMD_READCHECK: + if (ICLASS_CREDIT(cmd[0])) { + snprintf(exp, size, "READCHECK[Kc](%d)", cmd[1]); + curr_state = PICO_AUTH_EPURSE; + } else { + snprintf(exp, size, "READCHECK[Kd](%d)", cmd[1]); + curr_state = PICO_AUTH_EPURSE; + } + break; + case ICLASS_CMD_ACT: + snprintf(exp, size, "ACT"); + curr_state = PICO_NONE; + break; + default: + snprintf(exp, size, "?"); + curr_state = PICO_NONE; + break; + } + + } else { + + if (curr_state == PICO_SELECT) { + memcpy(csn, cmd, 8); + curr_state = PICO_NONE; + } else if (curr_state == PICO_AUTH_EPURSE) { + memcpy(epurse, cmd, 8); + } else if ( curr_state == PICO_AUTH_MACS) { + + uint8_t key[8]; + if (check_known_default(csn, epurse, rmac, tmac, key)) { + snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8) ); + } + curr_state = PICO_NONE; + } } return; } diff --git a/client/src/cmdhflist.h b/client/src/cmdhflist.h index 6a7a60bbe..f12f2a61d 100644 --- a/client/src/cmdhflist.h +++ b/client/src/cmdhflist.h @@ -38,7 +38,7 @@ 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); -void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); +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 annotateTopaz(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index aad064289..04bb64f95 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -387,6 +387,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case PROTO_HITAGS: annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); break; + case ICLASS: + annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse); + break; default: break; } @@ -397,9 +400,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case LEGIC: annotateLegic(explanation, sizeof(explanation), frame, data_len); break; - case ICLASS: - annotateIclass(explanation, sizeof(explanation), frame, data_len); - break; case ISO_14443A: annotateIso14443a(explanation, sizeof(explanation), frame, data_len); break;