diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 6c446c0bb..9296b4612 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -3770,10 +3770,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { CLIGetHexWithReturn(ctx, 1, key, &key_len); int key_nr = arg_get_int_def(ctx, 2, -1); - int blockno = 1; - - uint8_t data[8] = {0x12, 0xFF, 0xFE, 0xFF, 0x7F, 0x1F, 0xFF, 0x2C}; // tearoff payload - uint8_t mac[4] = {0}; + bool use_credit_key = arg_get_lit(ctx, 3); // Start at 1700, end at 1900. // 5 steps increments @@ -3787,18 +3784,18 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { uint8_t otp[2] = {0}; CLIGetHexWithReturn(ctx, 7, otp, &otp_len); + bool rawkey = arg_get_lit(ctx, 8); bool verbose = arg_get_lit(ctx, 9); bool shallow_mod = arg_get_lit(ctx, 10); + CLIParserFree(ctx); + bool elite = false; - bool rawkey = arg_get_lit(ctx, 8); - bool use_replay = false; //not implemented in this mode + bool use_replay = false; // not implemented in this mode bool read_auth = false; - bool use_credit_key = arg_get_lit(ctx, 3); + int tearoff_loop = 1; int tearoff_sleep = 0; - CLIParserFree(ctx); - // Sanity checks if (key_len > 0 && key_nr >= 0) { PrintAndLogEx(ERR, "Please specify key or index, not both"); @@ -3807,7 +3804,7 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { bool auth = false; - if (key_len > 0) { + if (key_len) { auth = true; if (key_len != 8) { @@ -3825,19 +3822,17 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); + PrintAndLogEx(NORMAL, ""); return PM3_EINVARG; } } else { PrintAndLogEx(SUCCESS, "Using Key... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key))); } - if (otp_len > 0) { - if (otp_len != 2) { - PrintAndLogEx(ERR, "OTP is incorrect length"); - return PM3_EINVARG; - } - memcpy(&data[1], otp, 2); //update the otp in the tearoff data value + if (otp_len && otp_len != 2) { + PrintAndLogEx(ERR, "OTP is incorrect length"); PrintAndLogEx(NORMAL, ""); + return PM3_EINVARG; } int loop_count = 0; @@ -3892,8 +3887,8 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { int fail_tolerance = 1; if (memcmp(r->header.hdr.csn + 4, "\xFE\xFF\x12\xE0", 4) == 0) { PrintAndLogEx(SUCCESS, "New silicon detected ( %s )", _GREEN_("ok")); - PrintAndLogEx(INFO, "----------------------------------------"); - PrintAndLogEx(SUCCESS, "CSN.................... %s", sprint_hex_inrow(r->header.hdr.csn, PICOPASS_BLOCK_SIZE)); + PrintAndLogEx(INFO, "---------------------------------------"); + PrintAndLogEx(SUCCESS, "CSN................... %s", sprint_hex_inrow(r->header.hdr.csn, PICOPASS_BLOCK_SIZE)); } else { PrintAndLogEx(ERR, "Old silicon detected ( %s )", _RED_("fail")); PrintAndLogEx(INFO, "Unsupported for this operation"); @@ -3916,14 +3911,12 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { goto out; } + #define TEAR_WRITE_BYTE 0x2C #define TEAR_INITAL 0x3C - #define TEAR_PERSO_ENABLED 0xBC - #define TEAR_PERSO_STABLE 0xBE - #define TEAR_PERSO_STABLE2 0x9C #define TEAR_UNLOCKED 0xAC - #define TEAR_IS_PERSO_SET(x) ((x) & 0x80 == 1) - #define TEAR_BAD(x) ((x) & 0x1 == 0) + #define TEAR_IS_PERSO_SET(x) (((x) & 0x80) == 0x80) + #define TEAR_BAD(x) (((x) & 0x01) == 0) // perform initial read here, repeat if failed or 00s @@ -3934,6 +3927,8 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { bool erase_phase = false; read_auth = false; + + int blockno = 1; int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read_orig, false); while (reread) { @@ -3951,12 +3946,18 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { } } + uint8_t data[8] = { 0 }; // tearoff payload memcpy(data, data_read_orig, sizeof(data)); - data[7] = 0x2C; + data[7] = TEAR_WRITE_BYTE; - PrintAndLogEx(SUCCESS, "Original block data.... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); - PrintAndLogEx(SUCCESS, "New data to write...... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); - PrintAndLogEx(SUCCESS, "Target block........... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); + // add the modified OTP if needed + if (otp_len) { + memcpy(data + 1, otp, sizeof(otp)); // update the otp in the tearoff data value + } + + PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); + PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); + PrintAndLogEx(SUCCESS, "Target block.......... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); // turn off Device side debug messages uint8_t dbg_curr = DBG_NONE; @@ -3971,13 +3972,15 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { // clear trace log SendCommandNG(CMD_BUFF_CLEAR, NULL, 0); - PrintAndLogEx(INFO, "----------------------------------------"); + PrintAndLogEx(INFO, "---------------------------------------"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " ------------------\n"); + PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); // Main loop + uint8_t mac[4] = {0}; + while ((tearoff_start <= tearoff_end) && (read_ok == false)) { if (kbd_enter_pressed()) { @@ -4097,7 +4100,9 @@ static int CmdHFiClass_BlackTears(const char *Cmd) { bool goto_out = false; - if (data_read[0] != data_read_orig[0]) { + // App limit became SMALLER :( + if (data_read[0] > data_read_orig[0]) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]); isok = PM3_SUCCESS; @@ -4205,7 +4210,6 @@ out: read_auth = false; uint8_t data_read[8]= {0}; - uint8_t data_verify[8] = {0}; int res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false); if (res != PM3_SUCCESS) { @@ -4214,41 +4218,15 @@ out: uint8_t b7 = data_read[7]; - switch(b7) { + if ( b7 == TEAR_INITAL) { + PrintAndLogEx(INFO, _YELLOW_("Fuses unchanged. Try again if the OTP is unchanged")); + // check for OTP change? + } else if ( b7 == TEAR_UNLOCKED) { + // don't do anything as this is ok + PrintAndLogEx(SUCCESS, "Detected fuse: " _GREEN_("0x%02X")" _non secure memory_ ( %s )", data_read[7], _GREEN_("ok")); - case TEAR_PERSO_ENABLED: { - - // stabilize 0xBC with write operation to 0xBE - PrintAndLogEx(SUCCESS, "Detected fuse: " _GREEN_("0x%02X") " stabilizing to: " _YELLOW_("0xBE") NOLF, data_read[7]); - - memcpy(data, data_read, PICOPASS_BLOCK_SIZE); - data[7] = TEAR_PERSO_STABLE; - - iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod); - - // verify if it was a succesful write - res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_verify, false); - - if (data_verify[7] == TEAR_PERSO_STABLE) { - - PrintAndLogEx(SUCCESS, " ( %s )", _GREEN_("ok")); - PrintAndLogEx(SUCCESS, "Detected fuse: " _GREEN_("0x%02X") " set non-secure memory: " _YELLOW_("0xAC"), data_read[7]); - - memcpy(data, data_verify, PICOPASS_BLOCK_SIZE); - data[7] = TEAR_UNLOCKED; - - // set non-secure memory with 0xAC, in this state it will always succeed - iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod); - - iclass_read_interesting_data(key, keyType, elite, rawkey, use_replay, verbose, shallow_mod); - } else { - PrintAndLogEx(FAILED, " ( %s )", _RED_("fail")); - } - break; - - } - case TEAR_PERSO_STABLE: - case TEAR_PERSO_STABLE2: { + iclass_read_interesting_data(key, keyType, elite, rawkey, use_replay, verbose, shallow_mod); + } else if (TEAR_IS_PERSO_SET(b7)) { PrintAndLogEx(SUCCESS, "Detected fuse: " _GREEN_("0x%02X") " set non-secure memory: " _YELLOW_("0xAC"), data_read[7]); @@ -4259,27 +4237,12 @@ out: iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod); iclass_read_interesting_data(key, keyType, elite, rawkey, use_replay, verbose, shallow_mod); - break; - } - case TEAR_UNLOCKED: { - - // don't do anything as this is ok - PrintAndLogEx(SUCCESS, "Detected fuse: " _GREEN_("0x%02X")" _non secure memory_ ( %s )", data_read[7], _GREEN_("ok")); - - iclass_read_interesting_data(key, keyType, elite, rawkey, use_replay, verbose, shallow_mod); - break; - } - case TEAR_INITAL: { - PrintAndLogEx(INFO, _YELLOW_("Fuses unchanged. Try again if the OTP is unchanged")); - // check for OTP change? - break; - } - default: { - PrintAndLogEx(INFO, _YELLOW_("Did not detect " _YELLOW_("0xBC") " or " _YELLOW_("0xBE") " or " _YELLOW_("0x9C") " fuse, might need manual intervention!")); - break; - } + } else if (TEAR_BAD(b7)) { + PrintAndLogEx(WARNING, "Bad fuse state detected: " _RED_("0x%02X") ", cannot proceed", b7); + return PM3_EFAILED; + } else { + PrintAndLogEx(INFO, _YELLOW_("Did not detect " _YELLOW_("0xBC") " or " _YELLOW_("0xBE") " or " _YELLOW_("0x9C") " fuse, might need manual intervention!")); } - return isok; }