mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
Updated hf iclass legrec
Updated hf iclass legrec: 1- Fixed communication timing inconsistencies by moving away from iclass_writeblock_ext to iclass_writeblock_sp which supports start_time and end_time 2- Reduced number of debug messages being printed Overall this reduces slightly the speed of the process, but it should make it more stable as the timings are now all correctly being accounted for.
This commit is contained in:
parent
be65279475
commit
23d9783b26
1 changed files with 77 additions and 39 deletions
116
armsrc/iclass.c
116
armsrc/iclass.c
|
@ -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: "));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue