Merge pull request #2870 from Antiklesys/master

Updated hf iclass legrec
This commit is contained in:
Iceman 2025-05-30 20:33:43 +02:00 committed by GitHub
commit 359469c0a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1795,6 +1795,28 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
return true; return true;
} }
static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, bool shallow_mod, uint32_t *start_time, uint32_t *eof_time) {
// write command: cmd, 1 blockno, 8 data, 4 mac
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno };
uint8_t write_len = 14;
memcpy(write + 2, data, 8);
memcpy(write + 10, mac, 4);
uint8_t resp[10] = {0};
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE, eof_time, shallow_mod);
if (isOK == false) {
return false;
}
// check response. All other updates return unchanged data
if (memcmp(data, resp, PICOPASS_BLOCK_SIZE)) {
return false;
}
return true;
}
// turn off afterwards // turn off afterwards
void iClass_WriteBlock(uint8_t *msg) { void iClass_WriteBlock(uint8_t *msg) {
@ -2657,8 +2679,14 @@ void iClass_Recover(iclass_recover_req_t *msg) {
uint8_t mac2[4] = {0}; uint8_t mac2[4] = {0};
picopass_hdr_t hdr = {0}; picopass_hdr_t hdr = {0};
bool res = false; bool res = false;
int status_message = 0;
while (!card_select || !card_auth) { while (!card_select || !card_auth) {
if (msg->test) {
Dbprintf(_YELLOW_("*Cycled Reader*") " ------------ TEST Index - Loops: "_YELLOW_("%3d / %3d") " *", loops, msg->loop);
} else {
Dbprintf(_YELLOW_("*Cycled Reader*") " ------------ Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " *", index, loops, msg->loop);
}
Iso15693InitReader(); //has to be at the top as it starts tracing Iso15693InitReader(); //has to be at the top as it starts tracing
if (!msg->debug) { if (!msg->debug) {
set_tracing(false); //disable tracing to prevent crashes - set to true for debugging set_tracing(false); //disable tracing to prevent crashes - set to true for debugging
@ -2667,18 +2695,11 @@ void iClass_Recover(iclass_recover_req_t *msg) {
clear_trace(); //if we're debugging better to clear the trace but do it only on the first loop clear_trace(); //if we're debugging better to clear the trace but do it only on the first loop
} }
} }
if (msg->test) {
Dbprintf(_YELLOW_("*Cycled Reader*") " ----------------- TEST Index - Loops: "_YELLOW_("%3d / %3d") " --------------*", loops, msg->loop);
} else {
Dbprintf(_YELLOW_("*Cycled Reader*") " ----------------- Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " --------------*", index, loops, msg->loop);
}
//Step0 Card Select Routine //Step0 Card Select Routine
eof_time = 0; //reset eof time eof_time = 0; //reset eof time
res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod);
if (res == false) { if (res) {
DbpString(_RED_("Unable to select card after reader cycle! Retrying...")); status_message = 1; //card select successful
} else {
DbpString(_GREEN_("Card selected successfully!"));
card_select = true; card_select = true;
} }
@ -2687,10 +2708,8 @@ void iClass_Recover(iclass_recover_req_t *msg) {
memcpy(original_mac, msg->req.key, 8); memcpy(original_mac, msg->req.key, 8);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1);
if (res == false) { if (res) {
DbpString(_RED_("Unable to authenticate on AA1 using macs! Retrying...")); status_message = 2; //authentication with AA1 macs successful
} else {
DbpString(_GREEN_("AA1 authentication with macs successful!"));
card_auth = true; card_auth = true;
} }
} }
@ -2715,10 +2734,9 @@ void iClass_Recover(iclass_recover_req_t *msg) {
// expect a 8-byte response here // expect a 8-byte response here
res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
if (res2 != PM3_SUCCESS || resp_len != 8) { if (res2 != PM3_SUCCESS || resp_len != 8) {
DbpString(_YELLOW_("Privilege Escalation -> ")_RED_("Read failed! Trying again..."));
priv_esc_tries++; priv_esc_tries++;
} else { } else {
DbpString(_YELLOW_("Privilege Escalation -> ")_GREEN_("Response OK!")); status_message = 3; //privilege escalation successful
priv_esc = true; priv_esc = true;
} }
if (priv_esc_tries == 5) { if (priv_esc_tries == 5) {
@ -2740,19 +2758,16 @@ void iClass_Recover(iclass_recover_req_t *msg) {
wb[0] = blockno; wb[0] = blockno;
memcpy(wb + 1, genkeyblock, 8); memcpy(wb + 1, genkeyblock, 8);
doMAC_N(wb, sizeof(wb), div_key2, mac2); doMAC_N(wb, sizeof(wb), div_key2, mac2);
bool use_mac = true;
bool written = false; bool written = false;
bool write_error = false; bool write_error = false;
while (written == false && write_error == false) { while (written == false && write_error == false) {
//Step5 Perform Write //Step5 Perform Write
if (iclass_writeblock_ext(blockno, genkeyblock, mac2, use_mac, shallow_mod)) { if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
DbpString("Wrote key: "); status_message = 4; //wrote new key on the card - unverified
Dbhexdump(8, genkeyblock, false);
} }
//Reset cypher state //Reset cypher state
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
//res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
//try to authenticate with the original mac to verify the write happened //try to authenticate with the original mac to verify the write happened
memcpy(msg->req.key, original_mac, 8); memcpy(msg->req.key, original_mac, 8);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
@ -2768,10 +2783,9 @@ void iClass_Recover(iclass_recover_req_t *msg) {
} }
} else { } else {
if (res) { if (res) {
DbpString("Write Operation : "_RED_("FAILED! Card Key is the Original. Retrying...")); write_error = true; //failed to update the key, the card's key is the original one
write_error = true;
} else { } else {
DbpString("Write Operation : "_GREEN_("VERIFIED! Card Key Updated!")); status_message = 5; //verified the card key was updated to the new one
written = true; written = true;
} }
} }
@ -2782,16 +2796,12 @@ void iClass_Recover(iclass_recover_req_t *msg) {
for (int i = 0; i < 8 ; ++i) { for (int i = 0; i < 8 ; ++i) {
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
//res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
//need to craft the authentication payload accordingly //need to craft the authentication payload accordingly
memcpy(msg->req.key, iclass_mac_table[i], 8); memcpy(msg->req.key, iclass_mac_table[i], 8);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //mac1 here shouldn't matter res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //mac1 here shouldn't matter
if (res == true) { if (res == true) {
bits_found = i; bits_found = i;
DbpString(_RED_("--------------------------------------------------------"));
Dbprintf("Decimal Value of last 3 bits: " _GREEN_("[%3d]"), bits_found);
DbpString(_RED_("--------------------------------------------------------"));
recovered = true; recovered = true;
} }
} }
@ -2805,36 +2815,31 @@ void iClass_Recover(iclass_recover_req_t *msg) {
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
// TODO: check result // TODO: check result
//GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); //GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
DbpString(_YELLOW_("Attempting to restore the original key. ")); if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time)) {
if (iclass_writeblock_ext(blockno, genkeyblock, mac2, use_mac, shallow_mod)) { status_message = 6; //restore of original key successful but unverified
DbpString("Restore of Original Key "_GREEN_("successful."));
} else {
DbpString("Restore of Original Key " _RED_("failed."));
} }
DbpString(_YELLOW_("Verifying Key Restore..."));
//Do a readcheck first to reset the cypher state //Do a readcheck first to reset the cypher state
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod);
// TODO: check result // TODO: check result
//GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); //GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
//need to craft the authentication payload accordingly //need to craft the authentication payload accordingly
memcpy(msg->req.key, original_mac, 8); memcpy(msg->req.key, original_mac, 8);
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1);
if (res == true) { if (res == true) {
DbpString("Restore of Original Key "_GREEN_("VERIFIED! Card is usable again.")); status_message = 7; //restore of original key verified - card usable again
reverted = true; reverted = true;
if (recovered) { if (recovered) {
goto restore; goto restore;
} }
} else {
DbpString("Restore of Original Key "_RED_("VERIFICATION FAILED! Trying again..."));
} }
revert_retries++; revert_retries++;
if (revert_retries >= 7) { //must always be an odd number! if (revert_retries >= 7) { //must always be an odd number!
DbpString("Wrote key: ");
Dbhexdump(8, genkeyblock, false);
Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries);
goto out; goto out;
} }
@ -2842,11 +2847,41 @@ void iClass_Recover(iclass_recover_req_t *msg) {
} }
if(msg->debug || msg->test){
if(status_message >= 1){
DbpString("Card Select:............."_GREEN_("Ok!"));
}
if(status_message >= 2){
DbpString("AA1 macs authentication:."_GREEN_("Ok!"));
}
if(status_message >= 3){
DbpString("Privilege Escalation:...."_GREEN_("Ok!"));
}
if(status_message >= 4){
DbpString("Wrote key: ");
Dbhexdump(8, genkeyblock, false);
}
if(status_message >= 5){
DbpString("Key Update:.............."_GREEN_("Verified!"));
}
if(status_message >= 6){
DbpString("Original Key Restore:...."_GREEN_("Ok!"));
}
if(status_message >= 7){
DbpString("Original Key Restore:...."_GREEN_("Verified!"));
}
}else{
Dbhexdump(8, genkeyblock, false);
}
if (loops >= msg->loop) { if (loops >= msg->loop) {
completed = true; completed = true;
goto out; goto out;
} }
if (!write_error) { //if there was a write error, re-run the loop for the same key index if (write_error && (msg->debug || msg->test)) { //if there was a write error, re-run the loop for the same key index
DbpString("Loop Error: "_RED_("Repeating Loop!"));
}else{
loops++; loops++;
index++; index++;
} }
@ -2862,6 +2897,9 @@ restore:
partialkey[i] = genkeyblock[i] ^ bits_found; partialkey[i] = genkeyblock[i] ^ bits_found;
} }
//Print the bits decimal value
DbpString(_RED_("--------------------------------------------------------"));
Dbprintf("Decimal Value of last 3 bits: " _GREEN_("[%3d]"), bits_found);
//Print the 24 bits found from k1 //Print the 24 bits found from k1
DbpString(_RED_("--------------------------------------------------------")); DbpString(_RED_("--------------------------------------------------------"));
DbpString(_RED_("SUCCESS! Raw Key Partial Bytes: ")); DbpString(_RED_("SUCCESS! Raw Key Partial Bytes: "));