From cd9090b6c898f481f76196014c54e29369a295d6 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Mon, 3 May 2021 20:01:12 +0200 Subject: [PATCH] hf iclass chk - now uses NG --- armsrc/appmain.c | 4 +- armsrc/iclass.c | 24 +++++------- armsrc/iclass.h | 2 +- armsrc/mifaresim.c | 28 +++++-------- client/src/cmdhficlass.c | 85 ++++++++++++++++++++++++++-------------- client/src/cmdhficlass.h | 4 -- client/src/cmdhfmf.c | 4 ++ include/pm3_cmd.h | 13 ++++++ 8 files changed, 96 insertions(+), 68 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 05ea84aa8..c75ef861d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1695,14 +1695,14 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_CHKKEYS: { - iClass_Authentication_fast(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); + iClass_Authentication_fast((iclass_chk_t*)packet->data.asBytes); break; } case CMD_HF_ICLASS_DUMP: { iClass_Dump(packet->data.asBytes); break; } - case CMD_HF_ICLASS_RESTORE: { + case CMD_HF_ICLASS_RESTORE: { iClass_Restore((iclass_restore_req_t *)packet->data.asBytes); break; } diff --git a/armsrc/iclass.c b/armsrc/iclass.c index b75355af2..111aa1c56 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1512,9 +1512,6 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, ui return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time); } -typedef struct iclass_premac { - uint8_t mac[4]; -} iclass_premac_t; /* this function works on the following assumptions. * - one select first, to get CSN / CC (e-purse) @@ -1523,36 +1520,35 @@ typedef struct iclass_premac { * - key loop only test one type of authtication key. Ie two calls needed * to cover debit and credit key. (AA1/AA2) */ -void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { - -// uint8_t lastChunk = ((arg0 >> 8) & 0xFF); - bool use_credit_key = ((arg0 >> 16) & 0xFF); - uint8_t keyCount = arg1 & 0xFF; +void iClass_Authentication_fast(iclass_chk_t *p) { + // sanitation + if (p == NULL) { + reply_ng(CMD_HF_ICLASS_CHKKEYS, PM3_ESOFT, NULL, 0); + return; + } uint8_t check[9] = { ICLASS_CMD_CHECK }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; uint8_t readcheck_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; - if (use_credit_key) + if (p->use_credit_key) readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; // select card / e-purse picopass_hdr_t hdr = {0}; - - iclass_premac_t *keys = (iclass_premac_t *)datain; + iclass_premac_t *keys = p->items; LED_A_ON(); // fresh start switch_off(); SpinDelay(20); - Iso15693InitReader(); bool isOK = false; uint32_t start_time = 0, eof_time = 0; - if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false) + if (select_iclass_tag(&hdr, p->use_credit_key, &eof_time) == false) goto out; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1562,7 +1558,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { // Keychunk loop uint8_t i = 0; - for (i = 0; i < keyCount; i++) { + for (i = 0; i < p->count; i++) { // Allow button press / usb cmd to interrupt device if (checked == 1000) { diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 83d6df302..958382256 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -28,7 +28,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen); -void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain); +void iClass_Authentication_fast(iclass_chk_t *p); bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out); void iClass_ReadBlock(uint8_t *msg); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index ee8560994..e6810f8e9 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -449,19 +449,10 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint16_t atqa, uint8_t sak) { tag_response_info_t *responses; uint8_t cardSTATE = MFEMUL_NOFIELD; - uint8_t uid_len = 0; // 4,7, 10 - uint32_t cuid = 0; - -// int vHf = 0; // in mV - - uint32_t selTimer = 0; - uint32_t authTimer = 0; - + uint8_t uid_len = 0; // 4, 7, 10 + uint32_t cuid = 0, selTimer = 0, authTimer = 0; + uint32_t nr, ar; uint8_t blockNo; - - uint32_t nr; - uint32_t ar; - bool encrypted_data; uint8_t cardWRBL = 0; @@ -469,9 +460,9 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication uint32_t cardRr = 0; uint32_t ans = 0; - uint32_t cardINTREG = 0; uint8_t cardINTBLOCK = 0; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; @@ -849,7 +840,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); FpgaDisableTracing(); - if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); + if (DBGLEVEL >= DBG_ERROR) + Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); break; } } @@ -883,20 +875,20 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // Check if selected Block is a Sector Trailer if (IsSectorTrailer(blockNo)) { - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYA_READ)) { + if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYA_READ) == false) { memset(response, 0x00, 6); // keyA can never be read if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyA can never be read - block %d (0x%02x)", blockNo, blockNo); } - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) { + if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ) == false) { memset(response + 10, 0x00, 6); // keyB cannot be read if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsSectorTrailer] keyB cannot be read - block %d (0x%02x)", blockNo, blockNo); } - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) { + if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ) == false) { memset(response + 6, 0x00, 4); // AC bits cannot be read if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] AC bits cannot be read - block %d (0x%02x)", blockNo, blockNo); } } else { - if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) { + if (IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ) == false) { memset(response, 0x00, 16); // datablock cannot be read if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK - IsAccessAllowed] Data block %d (0x%02x) cannot be read", blockNo, blockNo); } diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 33dd97404..c55e78490 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -2970,39 +2970,47 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - bool found_key = false; - //bool found_credit = false; - bool got_csn = false; - uint64_t t1 = msclock(); + // load keys uint8_t *keyBlock = NULL; uint32_t keycount = 0; - - // load keys int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); if (res != PM3_SUCCESS || keycount == 0) { free(keyBlock); return res; } + // limit size of keys that can be held in memory + if (keycount > 100000) { + PrintAndLogEx(FAILED, "File contains more than 100 000 keys, aborting..."); + free(keyBlock); + return PM3_EFILE; + } + // Get CSN / UID and CCNR PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); - for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { + + bool got_csn = false; + for (uint8_t i = 0; i < ICLASS_AUTH_RETRY; i++) { got_csn = select_only(CSN, CCNR, false); if (got_csn == false) PrintAndLogEx(WARNING, "one more try"); + else + break; } if (got_csn == false) { - PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); + PrintAndLogEx(WARNING, "Tried %d times. Can't select card, aborting...", ICLASS_AUTH_RETRY); free(keyBlock); DropField(); return PM3_ESOFT; } + // allocate memory for the pre calculated macs iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); if (pre == NULL) { + PrintAndLogEx(WARNING, "failed to allocate memory"); return PM3_EMALLOC; } @@ -3019,19 +3027,28 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); - - // max 42 keys inside USB_COMMAND. 512/4 = 103 mac - uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; - bool lastChunk = false; + // USB_COMMAND. 512/4 = 103 mac + uint32_t max_chunk_size = 0; + if (keycount > ((PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4)) + max_chunk_size = (PM3_CMD_DATA_SIZE - sizeof(iclass_chk_t)) / 4; + else + max_chunk_size = keycount; // fast push mode conn.block_after_ACK = true; // keep track of position of found key + uint32_t chunk_offset = 0; uint8_t found_offset = 0; - uint32_t key_offset = 0; + bool found_key = false; + + // We have + // - a list of keys. + // - a list of precalculated macs that corresponds to the key list + // We send a chunk of macs to the device each time + // main keychunk loop - for (key_offset = 0; key_offset < keycount && (found_key == false); key_offset += chunksize) { + for (chunk_offset = 0; chunk_offset < keycount; chunk_offset += max_chunk_size) { if (kbd_enter_pressed()) { PrintAndLogEx(NORMAL, ""); @@ -3039,31 +3056,40 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { goto out; } - uint32_t keys = ((keycount - key_offset) > chunksize) ? chunksize : keycount - key_offset; + uint32_t curr_chunk_cnt = keycount - chunk_offset; + if ((keycount - chunk_offset) > max_chunk_size) { + curr_chunk_cnt = max_chunk_size; + } // last chunk? - if (keys == keycount - key_offset) { - lastChunk = true; + if (curr_chunk_cnt == keycount - chunk_offset) { // Disable fast mode on last command conn.block_after_ACK = false; } - uint32_t flags = lastChunk << 8; - // bit 16 - // - 1 indicates credit key - // - 0 indicates debit key (default) - flags |= (use_credit_key << 16); + + uint32_t tmp_plen = sizeof(iclass_chk_t) + (4 * curr_chunk_cnt); + iclass_chk_t *packet = calloc(tmp_plen, sizeof(uint8_t) ); + if (packet == NULL) { + + } + packet->use_credit_key = use_credit_key; + packet->count = curr_chunk_cnt; + // copy chunk of pre calculated macs to packet + memcpy(packet->items, (pre + chunk_offset), (4 * curr_chunk_cnt)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys); - PacketResponseNG resp; + SendCommandNG(CMD_HF_ICLASS_CHKKEYS, (uint8_t*)packet, tmp_plen); + free(packet); bool looped = false; uint8_t timeout = 0; + + PacketResponseNG resp; while (WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000) == false) { timeout++; PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 10) { - PrintAndLogEx(WARNING, "\nno response from device, aborting..."); + PrintAndLogEx(WARNING, "\ncommand execute timeout, aborting..."); goto out; } looped = true; @@ -3078,10 +3104,11 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s") - , sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8) + , sprint_hex(keyBlock + (chunk_offset + found_offset) * 8, 8) ); + break; } else { - PrintAndLogEx(INPLACE, "Chunk [%d/%d]", key_offset, keycount); + PrintAndLogEx(INPLACE, "Chunk [%d/%d]", chunk_offset, keycount); fflush(stdout); } } @@ -3090,11 +3117,11 @@ out: t1 = msclock() - t1; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0); + PrintAndLogEx(SUCCESS, "time in iclass chk " _YELLOW_("%.1f") " seconds", (float)t1 / 1000.0); DropField(); if (found_key) { - uint8_t *key = keyBlock + (key_offset + found_offset) * 8; + uint8_t *key = keyBlock + (chunk_offset + found_offset) * 8; add_key(key); } diff --git a/client/src/cmdhficlass.h b/client/src/cmdhficlass.h index f96c9b1b2..73d34df0b 100644 --- a/client/src/cmdhficlass.h +++ b/client/src/cmdhficlass.h @@ -19,10 +19,6 @@ typedef struct iclass_block { uint8_t d[8]; } iclass_block_t; -typedef struct iclass_premac { - uint8_t mac[4]; -} iclass_premac_t; - typedef struct iclass_prekey { uint8_t mac[4]; uint8_t key[8]; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index f99c28955..7007fdcef 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -3288,6 +3288,7 @@ static int CmdHF14AMfSim(const char *Cmd) { arg_lit0("x", NULL, "Performs the 'reader attack', nr/ar attack against a reader"), arg_lit0("e", "emukeys", "Fill simulator keys from found keys"), arg_lit0("v", "verbose", "verbose output"), + arg_lit0(NULL, "cve", "trigger CVE 2021_0430"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3345,6 +3346,9 @@ static int CmdHF14AMfSim(const char *Cmd) { bool setEmulatorMem = arg_get_lit(ctx, 11); bool verbose = arg_get_lit(ctx, 12); + if (arg_get_lit(ctx, 13)) { + flags |= FLAG_CVE21_0430; + } CLIParserFree(ctx); nonces_t data[1]; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index d65e457c5..aefc36339 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -348,6 +348,16 @@ typedef struct { iclass_restore_item_t blocks[]; } PACKED iclass_restore_req_t; +typedef struct iclass_premac { + uint8_t mac[4]; +} iclass_premac_t; + +typedef struct { + bool use_credit_key; + uint8_t count; + iclass_premac_t items[]; +} PACKED iclass_chk_t; + // iclass / picopass chip config structures and shared routines typedef struct { @@ -593,6 +603,7 @@ typedef struct { #define CMD_HF_ISO15693_COMMAND 0x0313 #define CMD_HF_ISO15693_FINDAFI 0x0315 #define CMD_HF_ISO15693_CSETUID 0x0316 +#define CMD_HF_ISO15693_SLIX_L_DISABLE_PRIVACY 0x0317 #define CMD_LF_SNIFF_RAW_ADC 0x0360 @@ -756,6 +767,8 @@ typedef struct { #define FLAG_MF_4K 0x400 #define FLAG_FORCED_ATQA 0x800 #define FLAG_FORCED_SAK 0x1000 +#define FLAG_CVE21_0430 0x2000 + // iCLASS reader flags #define FLAG_ICLASS_READER_INIT 0x01