diff --git a/armsrc/util.c b/armsrc/util.c index 028a8fdb28..0df89352d2 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -397,7 +397,7 @@ uint32_t get_flash_size(void) { } // Combined function to convert an unsigned int to an array of hex values corresponding to the last three bits of k1 -void convertToHexArray(uint8_t num, uint8_t *partialkey) { +void convertToHexArray(uint32_t num, uint8_t *partialkey) { char binaryStr[25]; // 24 bits for binary representation + 1 for null terminator binaryStr[24] = '\0'; // Null-terminate the string @@ -409,8 +409,8 @@ void convertToHexArray(uint8_t num, uint8_t *partialkey) { // Split the binary string into groups of 3 and convert to hex for (int i = 0; i < 8 ; i++) { - char group[4]; - strncpy(group, binaryStr + i * 3, 3); + char group[4] = {'0', '0', '0', '\0'}; // Ensure group is initialized correctly + memcpy(group, binaryStr + i * 3, 3); // Use memcpy to copy exactly 3 characters group[3] = '\0'; // Null-terminate the group string partialkey[i] = (uint8_t)strtoul(group, NULL, 2); } diff --git a/armsrc/util.h b/armsrc/util.h index 96ae692d09..fd99ac73ea 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -88,7 +88,7 @@ int hex2binarray(char *target, const char *source); int hex2binarray_n(char *target, const char *source, int sourcelen); int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex); -void convertToHexArray(uint8_t num, uint8_t *partialkey); +void convertToHexArray(uint32_t num, uint8_t *partialkey); void LED(int led, int ms); void LEDsoff(void); diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index b6bd0ffa6c..79c325baac 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3849,45 +3849,74 @@ void picopass_elite_nextKey(uint8_t *key) { memcpy(key, key_state, 8); } -static int CmdHFiClassRecover(uint8_t key[8]) { - - uint32_t payload_size = sizeof(iclass_recover_req_t); - uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0}; - memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE); - iclass_recover_req_t *payload = calloc(1, payload_size); - payload->req.use_raw = true; - payload->req.use_elite = false; - payload->req.use_credit_key = false; - payload->req.use_replay = true; - payload->req.send_reply = true; - payload->req.do_auth = true; - payload->req.shallow_mod = false; - payload->req2.use_raw = false; - payload->req2.use_elite = false; - payload->req2.use_credit_key = true; - payload->req2.use_replay = false; - payload->req2.send_reply = true; - payload->req2.do_auth = true; - payload->req2.shallow_mod = false; - memcpy(payload->req.key, key, 8); - memcpy(payload->req2.key, aa2_standard_key, 8); +static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool allnight) { + + int runs = 1; + int cycle = 1; + bool repeat = true; + if(allnight){ + runs = 10; + } + + while (repeat == true){ + uint32_t payload_size = sizeof(iclass_recover_req_t); + uint8_t aa2_standard_key[PICOPASS_BLOCK_SIZE] = {0}; + memcpy(aa2_standard_key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE); + iclass_recover_req_t *payload = calloc(1, payload_size); + payload->req.use_raw = true; + payload->req.use_elite = false; + payload->req.use_credit_key = false; + payload->req.use_replay = true; + payload->req.send_reply = true; + payload->req.do_auth = true; + payload->req.shallow_mod = false; + payload->req2.use_raw = false; + payload->req2.use_elite = false; + payload->req2.use_credit_key = true; + payload->req2.use_replay = false; + payload->req2.send_reply = true; + payload->req2.do_auth = true; + payload->req2.shallow_mod = false; + payload->index = index_start; + payload->loop = loop; + payload->debug = debug; + payload->test = test; + memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE); + memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE); + memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE); + + PrintAndLogEx(INFO, "Recover started..."); - PrintAndLogEx(INFO, "Recover started..."); - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size); + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_ICLASS_RECOVER, (uint8_t *)payload, payload_size); - WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp); + WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp); - if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery " _GREEN_("successful")); - } else { - PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery " _RED_("failed")); + if (resp.status == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery: " _GREEN_("completed!")); + repeat = false; + } else if (resp.status == PM3_ESOFT){ + PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery: " _RED_("failed/errors")); + repeat = false; + } else if (resp.status == PM3_EINVARG){ + if(allnight){ + if(runs <= cycle){ + repeat = false; + }else{ + index_start = index_start+loop; + cycle++; + } + }else{ + repeat = false; + } + } + free(payload); + if(!repeat){ + return resp.status; + } } - - free(payload); - return resp.status; + return PM3_SUCCESS; } void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uint8_t *keyBlock) { @@ -3912,84 +3941,60 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass legbrute", "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.", - "hf iclass legbrute --csn 8D7BD711FEFF12E0 --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225" + "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225" ); void *argtable[] = { arg_param_begin, - arg_str1(NULL, "csn", "", "Specify CSN as 8 hex bytes"), arg_str1(NULL, "epurse", "", "Specify ePurse as 8 hex bytes"), arg_str1(NULL, "macs1", "", "MACs captured from the reader"), arg_str1(NULL, "macs2", "", "MACs captured from the reader, different than the first set (with the same csn and epurse value)"), arg_str1(NULL, "pk", "", "Partial Key from legrec or starting key of keyblock from legbrute"), - arg_int0(NULL, "index", "", "Where to start from to retrieve the key, default 0"), + arg_int0(NULL, "index", "", "Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - int csn_len = 0; - uint8_t csn[8] = {0}; - CLIGetHexWithReturn(ctx, 1, csn, &csn_len); - - if (csn_len > 0) { - if (csn_len != 8) { - PrintAndLogEx(ERR, "CSN is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } - int epurse_len = 0; - uint8_t epurse[8] = {0}; - CLIGetHexWithReturn(ctx, 2, epurse, &epurse_len); - - if (epurse_len > 0) { - if (epurse_len != 8) { - PrintAndLogEx(ERR, "ePurse is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } + uint8_t epurse[PICOPASS_BLOCK_SIZE] = {0}; + CLIGetHexWithReturn(ctx, 1, epurse, &epurse_len); int macs_len = 0; - uint8_t macs[8] = {0}; - CLIGetHexWithReturn(ctx, 3, macs, &macs_len); - - if (macs_len > 0) { - if (macs_len != 8) { - PrintAndLogEx(ERR, "MAC1 is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } + uint8_t macs[PICOPASS_BLOCK_SIZE] = {0}; + CLIGetHexWithReturn(ctx, 2, macs, &macs_len); int macs2_len = 0; - uint8_t macs2[8] = {0}; - CLIGetHexWithReturn(ctx, 4, macs2, &macs2_len); - - if (macs2_len > 0) { - if (macs2_len != 8) { - PrintAndLogEx(ERR, "MAC2 is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } + uint8_t macs2[PICOPASS_BLOCK_SIZE] = {0}; + CLIGetHexWithReturn(ctx, 3, macs2, &macs2_len); int startingkey_len = 0; - uint8_t startingKey[8] = {0}; - CLIGetHexWithReturn(ctx, 5, startingKey, &startingkey_len); - - if (startingkey_len > 0) { - if (startingkey_len != 8) { - PrintAndLogEx(ERR, "Partial Key is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } + uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0}; + CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len); uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits + index = index * 1000000; CLIParserFree(ctx); + + if (epurse_len && epurse_len != PICOPASS_BLOCK_SIZE) { + PrintAndLogEx(ERR, "ePurse is incorrect length"); + return PM3_EINVARG; + } + + if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) { + PrintAndLogEx(ERR, "MAC1 is incorrect length"); + return PM3_EINVARG; + } + + if (macs2_len && macs2_len != PICOPASS_BLOCK_SIZE) { + PrintAndLogEx(ERR, "MAC2 is incorrect length"); + return PM3_EINVARG; + } + + if (startingkey_len && startingkey_len != PICOPASS_BLOCK_SIZE) { + PrintAndLogEx(ERR, "Partial Key is incorrect length"); + return PM3_EINVARG; + } //Standalone Command End uint8_t CCNR[12]; @@ -4005,7 +4010,6 @@ static int CmdHFiClassLegRecLookUp(const char *Cmd) { memcpy(MAC_TAG, macs + 4, 4); memcpy(MAC_TAG2, macs2 + 4, 4); - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(csn, 8)); PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, 8)); PrintAndLogEx(SUCCESS, " MACS1: %s", sprint_hex(macs, 8)); PrintAndLogEx(SUCCESS, " MACS2: %s", sprint_hex(macs2, 8)); @@ -4072,34 +4076,66 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass legrec", - "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!", - "hf iclass legrec --macs 0000000089cb984b" + "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!", + "hf iclass legrec --macs 0000000089cb984b\n" + "hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest" ); void *argtable[] = { arg_param_begin, - arg_str1(NULL, "macs", "", "MACs"), + arg_str1(NULL, "macs", "", "AA1 Authentication MACs"), + arg_int0(NULL, "index", "", "Where to start from to retrieve the key, default 0"), + arg_int0(NULL, "loop", "", "The number of key retrieval cycles to perform, max 10000, default 100"), + arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."), + arg_lit0(NULL, "notest", "Perform real writes on the card!"), + arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); int macs_len = 0; - uint8_t macs[8] = {0}; + uint8_t macs[PICOPASS_BLOCK_SIZE] = {0}; CLIGetHexWithReturn(ctx, 1, macs, &macs_len); + uint32_t index = arg_get_int_def(ctx, 2, 0); + uint32_t loop = arg_get_int_def(ctx, 3, 100); + uint8_t no_first_auth[PICOPASS_BLOCK_SIZE] = {0}; + bool debug = arg_get_lit(ctx, 4); + bool test = true; + bool no_test = arg_get_lit(ctx, 5); + bool allnight = arg_get_lit(ctx, 6); - if (macs_len > 0) { - if (macs_len != 8) { - PrintAndLogEx(ERR, "MAC is incorrect length"); - CLIParserFree(ctx); - return PM3_EINVARG; - } + if(no_test){ + test=false; } + if(loop > 10000){ + PrintAndLogEx(ERR, "Too many loops, arm prone to crashes. For safety specify a number lower than 10000"); + CLIParserFree(ctx); + return PM3_EINVARG; + }else if (debug || test){ + loop = 1; + } + + uint8_t csn[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t new_div_key[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + if (select_only(csn, CCNR, true, false) == false) { + DropField(); + return PM3_ESOFT; + } + HFiClassCalcDivKey(csn, iClass_Key_Table[1], new_div_key, false); + memcpy(no_first_auth,new_div_key,PICOPASS_BLOCK_SIZE); + CLIParserFree(ctx); - CmdHFiClassRecover(macs); + if (macs_len && macs_len != PICOPASS_BLOCK_SIZE) { + PrintAndLogEx(ERR, "MAC is incorrect length"); + return PM3_EINVARG; + } + + iclass_recover(macs,index,loop,no_first_auth,debug,test,allnight); - PrintAndLogEx(WARNING, _YELLOW_("If the process completed, you can now run 'hf iclass legrecbrute' with the partial key found.")); + PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found.")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index bb7b6193a4..01550169a3 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -108,6 +108,11 @@ typedef struct { typedef struct { iclass_auth_req_t req; iclass_auth_req_t req2; + uint32_t index; + uint32_t loop; + uint8_t nfa[8]; + bool debug; + bool test; } PACKED iclass_recover_req_t; typedef struct iclass_premac {