mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
FIX: 'hf iclass sim 2'
FIX: 'hf iclass sim 4' FIX: 'hf iclass loclass' - this fixes the bug where loclass assumes the epurse value is all zeros, while it now should save the epurse value during the simulation if it is updated/read. I assume a empty valid epurse, while an all zero epurse is too much easy to detect as a anomaly.
This commit is contained in:
parent
7c8de64c57
commit
dc25f9212f
5 changed files with 69 additions and 65 deletions
|
@ -1159,19 +1159,20 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
// In this mode, a number of csns are within datain. We'll simulate each one, one at a time
|
||||
// in order to collect MAC's from the reader. This can later be used in an offlne-attack
|
||||
// in order to obtain the keys, as in the "dismantling iclass"-paper.
|
||||
#define EPURSE_MAC_SIZE 16
|
||||
int i = 0;
|
||||
for (; i < numberOfCSNS && i*8 + 8 < USB_CMD_DATA_SIZE; i++) {
|
||||
for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < USB_CMD_DATA_SIZE; i++) {
|
||||
// The usb data is 512 bytes, fitting 65 8-byte CSNs in there.
|
||||
|
||||
memcpy(emulator, datain + (i*8), 8);
|
||||
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses+i*8)) {
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses+i * EPURSE_MAC_SIZE)) {
|
||||
// Button pressed
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8);
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8);
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i * EPURSE_MAC_SIZE);
|
||||
|
||||
} else if (simType == 3){
|
||||
//This is 'full sim' mode, where we use the emulator storage for data.
|
||||
|
@ -1192,26 +1193,26 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
// attack below is same as SIM 2, but we run the CSN twice to collected the mac for both keys.
|
||||
int i = 0;
|
||||
// The usb data is 512 bytes, fitting 65 8-byte CSNs in there. iceman fork uses 9 CSNS
|
||||
for (; i < numberOfCSNS && i*8 + 8 < USB_CMD_DATA_SIZE; i++) {
|
||||
for (; i < numberOfCSNS && i * EPURSE_MAC_SIZE + 8 < USB_CMD_DATA_SIZE; i++) {
|
||||
|
||||
memcpy(emulator, datain + (i*8), 8);
|
||||
|
||||
// keyroll 1
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i*8 )) {
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * 8 * 2);
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + i * EPURSE_MAC_SIZE )) {
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2);
|
||||
// Button pressed
|
||||
goto out;
|
||||
}
|
||||
|
||||
// keyroll 2
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * 8 )) {
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * 8 * 2);
|
||||
if (doIClassSimulation(MODE_EXIT_AFTER_MAC, mac_responses + (i + numberOfCSNS) * EPURSE_MAC_SIZE )) {
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE* 2);
|
||||
// Button pressed
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
// double the amount of collected data.
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * 8 * 2 );
|
||||
cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i*2, 0, mac_responses, i * EPURSE_MAC_SIZE * 2 );
|
||||
|
||||
} else {
|
||||
// We may want a mode here where we hardcode the csns to use (from proxclone).
|
||||
|
@ -1255,6 +1256,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
|
|||
uint8_t diversified_key[8] = { 0 };
|
||||
// e-Purse
|
||||
uint8_t card_challenge_data[8] = { 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff };
|
||||
//uint8_t card_challenge_data[8] = { 0 };
|
||||
if (simulationMode == MODE_FULLSIM) {
|
||||
//The diversified key should be stored on block 3
|
||||
//Get the diversified key from emulator memory
|
||||
|
@ -1265,6 +1267,10 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
|
|||
//Precalculate the cipher state, feeding it the CC
|
||||
cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key);
|
||||
}
|
||||
// set epurse of sim2,4 attack
|
||||
if (reader_mac_buf != NULL) {
|
||||
memcpy(reader_mac_buf, card_challenge_data, 8);
|
||||
}
|
||||
|
||||
int exitLoop = 0;
|
||||
// Reader 0a
|
||||
|
@ -1320,50 +1326,26 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
|
|||
// First card answer: SOF
|
||||
CodeIClassTagSOF();
|
||||
memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("SOF");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
// Anticollision CSN
|
||||
CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data));
|
||||
memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("ANTI COLL CSN");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
// CSN
|
||||
CodeIClassTagAnswer(csn_data, sizeof(csn_data));
|
||||
memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("CSN");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
// Configuration
|
||||
CodeIClassTagAnswer(conf_data, sizeof(conf_data));
|
||||
memcpy(resp_conf, ToSend, ToSendMax); resp_conf_len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("Configuration");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
// e-Purse
|
||||
CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data));
|
||||
memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("e-Purse");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
// Application Issuer Area
|
||||
CodeIClassTagAnswer(aia_data, sizeof(aia_data));
|
||||
memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax;
|
||||
// if ( MF_DBGLEVEL == MF_DBG_EXTENDED) {
|
||||
// DbpString("Application Issuer Data");
|
||||
// PrintToSendBuffer();
|
||||
// }
|
||||
|
||||
//This is used for responding to READ-block commands or other data which is dynamically generated
|
||||
//First the 'trace'-data, not encoded for FPGA
|
||||
|
@ -1435,6 +1417,10 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
|
|||
modulated_response = resp_cc; modulated_response_size = resp_cc_len;
|
||||
trace_data = card_challenge_data;
|
||||
trace_data_size = sizeof(card_challenge_data);
|
||||
// set epurse of sim2,4 attack
|
||||
if (reader_mac_buf != NULL) {
|
||||
memcpy(reader_mac_buf, card_challenge_data, 8);
|
||||
}
|
||||
break;
|
||||
case 5:// Application Issuer Area (0c 05)
|
||||
modulated_response = resp_aia; modulated_response_size = resp_aia_len;
|
||||
|
@ -1498,7 +1484,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) {
|
|||
Dbprintf("[+] CSN: %02x .... %02x OK", csn[0], csn[7]);
|
||||
}
|
||||
if (reader_mac_buf != NULL) {
|
||||
memcpy(reader_mac_buf, receivedCmd+1, 8);
|
||||
memcpy(reader_mac_buf + 8, receivedCmd+1, 8);
|
||||
}
|
||||
exitLoop = true;
|
||||
}
|
||||
|
|
|
@ -238,8 +238,11 @@ int usage_hf_iclass_lookup(void) {
|
|||
PrintAndLog(" u CSN");
|
||||
PrintAndLog(" p EPURSE");
|
||||
PrintAndLog(" m macs");
|
||||
PrintAndLog(" r raw");
|
||||
PrintAndLog(" e elite");
|
||||
PrintAndLog("Samples:");
|
||||
PrintAndLog(" hf iclass lookup u 9655a400f8ff12e0 p f0ffffffffffffff m 0000000089cb984b f default_iclass_keys.dic");
|
||||
PrintAndLog(" hf iclass lookup u 9655a400f8ff12e0 p f0ffffffffffffff m 0000000089cb984b f default_iclass_keys.dic e");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -360,7 +363,7 @@ int CmdHFiClassSim(const char *Cmd) {
|
|||
PrintAndLog("[+] press keyboard to cancel");
|
||||
UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, NUM_CSNS}};
|
||||
UsbCommand resp = {0};
|
||||
memcpy(c.d.asBytes, csns, 8*NUM_CSNS);
|
||||
memcpy(c.d.asBytes, csns, 8 * NUM_CSNS);
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
|
||||
|
@ -390,13 +393,16 @@ int CmdHFiClassSim(const char *Cmd) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
memset(dump, 0, datalen);//<-- Need zeroes for the CC-field
|
||||
memset(dump, 0, datalen);//<-- Need zeroes for the EPURSE - field (offical)
|
||||
|
||||
uint8_t i = 0;
|
||||
for (i = 0 ; i < NUM_CSNS ; i++) {
|
||||
//copy CSN
|
||||
memcpy(dump + i*24, csns + i*8, 8);
|
||||
//8 zero bytes here then comes NR_MAC (eight bytes from the response) ( 8b csn + 8 empty== 16)
|
||||
memcpy(dump + i*24 + 16, resp.d.asBytes + i*8, 8);
|
||||
//copy epurse
|
||||
memcpy(dump + i*24 + 8, resp.d.asBytes + i*16, 8);
|
||||
// NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
|
||||
memcpy(dump + i*24 + 16, resp.d.asBytes + i*16 + 8, 8);
|
||||
}
|
||||
/** Now, save to dumpfile **/
|
||||
saveFile("iclass_mac_attack", "bin", dump, datalen);
|
||||
|
@ -445,10 +451,12 @@ int CmdHFiClassSim(const char *Cmd) {
|
|||
//Need zeroes for the CC-field
|
||||
memset(dump, 0, datalen);
|
||||
for (uint8_t i = 0; i < NUM_CSNS ; i++) {
|
||||
// Copy CSN
|
||||
// copy CSN
|
||||
memcpy(dump + i*MAC_ITEM_SIZE, csns + i*8, 8); //CSN
|
||||
//8 zero bytes here then comes NR_MAC (eight bytes from the response) ( 8b csn + 8 empty== 16)
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 16, resp.d.asBytes + i*8, 8);
|
||||
// copy EPURSE
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 8, resp.d.asBytes + i * 16, 8);
|
||||
// copy NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 16, resp.d.asBytes + i * 16 + 8, 8);
|
||||
}
|
||||
saveFile("iclass_mac_attack_keyroll_A", "bin", dump, datalen);
|
||||
|
||||
|
@ -456,11 +464,13 @@ int CmdHFiClassSim(const char *Cmd) {
|
|||
memset(dump, 0, datalen);
|
||||
uint8_t resp_index = 0;
|
||||
for (uint8_t i = 0; i < NUM_CSNS; i++) {
|
||||
resp_index = (i + NUM_CSNS) * 8;
|
||||
resp_index = (i + NUM_CSNS) * 16;
|
||||
// Copy CSN
|
||||
memcpy(dump + i*MAC_ITEM_SIZE, csns + i*8, 8);
|
||||
//8 zero bytes here then comes NR_MAC (eight bytes from the response) ( 8b csn + 8 empty== 16)
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 16, resp.d.asBytes + resp_index, 8);
|
||||
// copy EPURSE
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 8, resp.d.asBytes + resp_index, 8);
|
||||
// copy NR_MAC (eight bytes from the response) ( 8b csn + 8 epurse == 16)
|
||||
memcpy(dump + i*MAC_ITEM_SIZE + 16, resp.d.asBytes + resp_index + 8, 8);
|
||||
resp_index++;
|
||||
}
|
||||
saveFile("iclass_mac_attack_keyroll_B", "bin", dump, datalen);
|
||||
|
@ -800,9 +810,9 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
|
|||
if (CCNR != NULL)
|
||||
memcpy(CCNR, data+16, 8);
|
||||
|
||||
// if (isOK > 0) {
|
||||
// if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8));
|
||||
// }
|
||||
if (isOK > 0) {
|
||||
PrintAndLog("CCNR: %s MISSING NCN",sprint_hex(CCNR, 8));
|
||||
}
|
||||
|
||||
if (isOK <= 1){
|
||||
PrintAndLog("(%d) Failed to obtain CC! Aborting...", isOK);
|
||||
|
@ -1926,6 +1936,8 @@ int CmdHFiClassCheckKeys(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLog("[+] Generating diversified keys and MAC");
|
||||
PrintAndLog("[+] CSN | %s", sprint_hex( CSN, sizeof(CSN) ));
|
||||
PrintAndLog("[+] CCNR | %s", sprint_hex( CCNR, sizeof(CCNR) ));
|
||||
res = GenerateMacFromKeyFile( CSN, CCNR, use_raw, use_elite, keyBlock, keycnt, pre );
|
||||
if ( res > 0) {
|
||||
free(keyBlock);
|
||||
|
@ -2039,6 +2051,7 @@ int CmdHFiClassLookUp(const char *Cmd) {
|
|||
uint8_t CSN[8];
|
||||
uint8_t EPURSE[8];
|
||||
uint8_t MACS[8];
|
||||
uint8_t CCNR[12];
|
||||
uint8_t MAC_TAG[4] = {0x00,0x00,0x00,0x00};
|
||||
|
||||
// elite key, raw key, standard key
|
||||
|
@ -2122,10 +2135,15 @@ int CmdHFiClassLookUp(const char *Cmd) {
|
|||
|
||||
if (errors) return usage_hf_iclass_lookup();
|
||||
|
||||
PrintAndLog("[+] CSN %s", sprint_hex( CSN, sizeof(CSN) ));
|
||||
PrintAndLog("[+] Epurse %s", sprint_hex( EPURSE, sizeof(EPURSE) ));
|
||||
PrintAndLog("[+] MACS %s", sprint_hex( MACS, sizeof(MACS) ));
|
||||
PrintAndLog("[+] MAC_TAG %s", sprint_hex( MAC_TAG, sizeof(MAC_TAG) ));
|
||||
// stupid copy.. CCNR is a combo of epurse and reader nonce
|
||||
memcpy(CCNR, EPURSE, 8);
|
||||
memcpy(CCNR+8, MACS, 4);
|
||||
|
||||
PrintAndLog("[+] CSN | %s", sprint_hex( CSN, sizeof(CSN) ));
|
||||
PrintAndLog("[+] Epurse | %s", sprint_hex( EPURSE, sizeof(EPURSE) ));
|
||||
PrintAndLog("[+] MACS | %s", sprint_hex( MACS, sizeof(MACS) ));
|
||||
PrintAndLog("[+] CCNR | %s", sprint_hex( CCNR, sizeof(CCNR) ));
|
||||
PrintAndLog("[+] MAC_TAG | %s", sprint_hex( MAC_TAG, sizeof(MAC_TAG) ));
|
||||
|
||||
int res = LoadDictionaryKeyFile( filename, &keyBlock, &keycnt);
|
||||
if ( res > 0) {
|
||||
|
@ -2140,7 +2158,7 @@ int CmdHFiClassLookUp(const char *Cmd) {
|
|||
}
|
||||
|
||||
PrintAndLog("[-] Generating diversified keys and MAC");
|
||||
res = GenerateFromKeyFile( CSN, EPURSE, use_raw, use_elite, keyBlock, keycnt, prekey );
|
||||
res = GenerateFromKeyFile( CSN, CCNR, use_raw, use_elite, keyBlock, keycnt, prekey );
|
||||
if ( res > 0) {
|
||||
free(keyBlock);
|
||||
free(prekey);
|
||||
|
|
|
@ -226,17 +226,17 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4])
|
|||
uint8_t div_key[8];
|
||||
//cc_nr=(uint8_t*)malloc(length+1);
|
||||
|
||||
memcpy(cc_nr,cc_nr_p,12);
|
||||
memcpy(div_key,div_key_p,8);
|
||||
memcpy(cc_nr, cc_nr_p, 12);
|
||||
memcpy(div_key, div_key_p, 8);
|
||||
|
||||
reverse_arraybytes(cc_nr,12);
|
||||
BitstreamIn bitstream = {cc_nr,12 * 8,0};
|
||||
reverse_arraybytes(cc_nr, 12);
|
||||
BitstreamIn bitstream = {cc_nr, 12 * 8, 0};
|
||||
uint8_t dest []= {0,0,0,0,0,0,0,0};
|
||||
BitstreamOut out = { dest, sizeof(dest)*8, 0 };
|
||||
MAC(div_key,bitstream, out);
|
||||
//The output MAC must also be reversed
|
||||
reverse_arraybytes(dest, sizeof(dest));
|
||||
memcpy(mac,dest,4);
|
||||
memcpy(mac, dest, 4);
|
||||
//free(cc_nr);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -271,9 +271,9 @@ int _readFromDump(uint8_t dump[], dumpdata* item, uint8_t i) {
|
|||
memcpy(item, dump+i*itemsize, itemsize);
|
||||
|
||||
if (true) {
|
||||
printvar("csn", item->csn,8);
|
||||
printvar("cc_nr", item->cc_nr,12);
|
||||
printvar("mac", item->mac,4);
|
||||
printvar("csn", item->csn, sizeof(item->csn));
|
||||
printvar("cc_nr", item->cc_nr, sizeof(item->cc_nr));
|
||||
printvar("mac", item->mac, sizeof(item->mac));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -355,6 +355,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
prnlog("[+] Bruteforcing byte %d", bytes_to_recover[i]);
|
||||
|
||||
while (!found && !(brute & endmask)) {
|
||||
|
||||
//Update the keytable with the brute-values
|
||||
for (i=0; i < numbytes_to_recover; i++) {
|
||||
keytable[bytes_to_recover[i]] &= 0xFF00;
|
||||
|
@ -380,7 +381,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) {
|
|||
|
||||
// success
|
||||
if (memcmp(calculated_MAC, item.mac, 4) == 0) {
|
||||
//printf("\r\n");
|
||||
printf("\r\n");
|
||||
for (i =0 ; i < numbytes_to_recover; i++) {
|
||||
prnlog("[=] %d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]);
|
||||
}
|
||||
|
|
|
@ -84,8 +84,7 @@ typedef struct {
|
|||
uint8_t csn[8];
|
||||
uint8_t cc_nr[12];
|
||||
uint8_t mac[4];
|
||||
|
||||
}dumpdata;
|
||||
} dumpdata;
|
||||
|
||||
/**
|
||||
* @brief Performs brute force attack against a dump-data item, containing csn, cc_nr and mac.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue