mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
Merge remote-tracking branch 'noproto/nestednonces' into dev
This commit is contained in:
@@ -543,6 +543,22 @@ void mf_classic_set_key_not_found(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MfClassicKey
|
||||||
|
mf_classic_get_key(const MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type) {
|
||||||
|
furi_check(data);
|
||||||
|
furi_check(sector_num < mf_classic_get_total_sectors_num(data->type));
|
||||||
|
furi_check(key_type == MfClassicKeyTypeA || key_type == MfClassicKeyTypeB);
|
||||||
|
|
||||||
|
const MfClassicSectorTrailer* sector_trailer =
|
||||||
|
mf_classic_get_sector_trailer_by_sector(data, sector_num);
|
||||||
|
|
||||||
|
if(key_type == MfClassicKeyTypeA) {
|
||||||
|
return sector_trailer->key_a;
|
||||||
|
} else {
|
||||||
|
return sector_trailer->key_b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num) {
|
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num) {
|
||||||
furi_check(data);
|
furi_check(data);
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,9 @@ void mf_classic_set_key_not_found(
|
|||||||
uint8_t sector_num,
|
uint8_t sector_num,
|
||||||
MfClassicKeyType key_type);
|
MfClassicKeyType key_type);
|
||||||
|
|
||||||
|
MfClassicKey
|
||||||
|
mf_classic_get_key(const MfClassicData* data, uint8_t sector_num, MfClassicKeyType key_type);
|
||||||
|
|
||||||
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num);
|
bool mf_classic_is_block_read(const MfClassicData* data, uint8_t block_num);
|
||||||
|
|
||||||
void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data);
|
void mf_classic_set_block_read(MfClassicData* data, uint8_t block_num, MfClassicBlock* block_data);
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
// TODO: Buffer writes for Hardnested, set state to Log when finished and sum property matches
|
// TODO: Buffer writes for Hardnested, set state to Log when finished and sum property matches
|
||||||
// TODO: Store target key in CUID dictionary
|
// TODO: Store target key in CUID dictionary
|
||||||
// TODO: Fix rare nested_target_key 64 bug
|
|
||||||
// TODO: Dead code for malloc returning NULL?
|
// TODO: Dead code for malloc returning NULL?
|
||||||
// TODO: Auth1 static encrypted exists (rare)
|
// TODO: Auth1 static encrypted exists (rare)
|
||||||
|
// TODO: Use keys found by NFC plugins, cached keys
|
||||||
|
|
||||||
#define MF_CLASSIC_MAX_BUFF_SIZE (64)
|
#define MF_CLASSIC_MAX_BUFF_SIZE (64)
|
||||||
|
|
||||||
@@ -1663,7 +1663,7 @@ NfcCommand mf_classic_poller_handler_nested_dict_attack(MfClassicPoller* instanc
|
|||||||
"Found key candidate %06llx",
|
"Found key candidate %06llx",
|
||||||
bit_lib_bytes_to_num_be(key_candidate->data, sizeof(MfClassicKey)));
|
bit_lib_bytes_to_num_be(key_candidate->data, sizeof(MfClassicKey)));
|
||||||
dict_attack_ctx->current_key = *key_candidate;
|
dict_attack_ctx->current_key = *key_candidate;
|
||||||
dict_attack_ctx->reuse_key_sector = (target_block / 4);
|
dict_attack_ctx->reuse_key_sector = target_sector;
|
||||||
dict_attack_ctx->current_key_type = target_key_type;
|
dict_attack_ctx->current_key_type = target_key_type;
|
||||||
free(key_candidate);
|
free(key_candidate);
|
||||||
break;
|
break;
|
||||||
@@ -1818,12 +1818,13 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
bool initial_dict_attack_iter = false;
|
bool initial_dict_attack_iter = false;
|
||||||
if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseNone) {
|
if(dict_attack_ctx->nested_phase == MfClassicNestedPhaseNone) {
|
||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
dict_attack_ctx->nested_known_key = dict_attack_ctx->current_key;
|
|
||||||
bool backdoor_present = (dict_attack_ctx->backdoor != MfClassicBackdoorNone);
|
bool backdoor_present = (dict_attack_ctx->backdoor != MfClassicBackdoorNone);
|
||||||
if(!(backdoor_present)) {
|
if(!(backdoor_present)) {
|
||||||
for(uint8_t sector = 0; sector < instance->sectors_total; sector++) {
|
for(uint8_t sector = 0; sector < instance->sectors_total; sector++) {
|
||||||
for(uint8_t key_type = 0; key_type < 2; key_type++) {
|
for(uint8_t key_type = 0; key_type < 2; key_type++) {
|
||||||
if(mf_classic_is_key_found(instance->data, sector, key_type)) {
|
if(mf_classic_is_key_found(instance->data, sector, key_type)) {
|
||||||
|
dict_attack_ctx->nested_known_key =
|
||||||
|
mf_classic_get_key(instance->data, sector, key_type);
|
||||||
dict_attack_ctx->nested_known_key_sector = sector;
|
dict_attack_ctx->nested_known_key_sector = sector;
|
||||||
dict_attack_ctx->nested_known_key_type = key_type;
|
dict_attack_ctx->nested_known_key_type = key_type;
|
||||||
break;
|
break;
|
||||||
@@ -1832,6 +1833,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
}
|
}
|
||||||
dict_attack_ctx->nested_phase = MfClassicNestedPhaseAnalyzePRNG;
|
dict_attack_ctx->nested_phase = MfClassicNestedPhaseAnalyzePRNG;
|
||||||
} else {
|
} else {
|
||||||
|
dict_attack_ctx->nested_known_key = dict_attack_ctx->current_key;
|
||||||
dict_attack_ctx->nested_known_key_sector = 0;
|
dict_attack_ctx->nested_known_key_sector = 0;
|
||||||
dict_attack_ctx->nested_known_key_type = MfClassicKeyTypeA;
|
dict_attack_ctx->nested_known_key_type = MfClassicKeyTypeA;
|
||||||
dict_attack_ctx->prng_type = MfClassicPrngTypeWeak;
|
dict_attack_ctx->prng_type = MfClassicPrngTypeWeak;
|
||||||
@@ -2004,9 +2006,7 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
}
|
}
|
||||||
uint16_t nonce_collect_key_max;
|
uint16_t nonce_collect_key_max;
|
||||||
if(dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) {
|
if(dict_attack_ctx->prng_type == MfClassicPrngTypeWeak) {
|
||||||
nonce_collect_key_max = dict_attack_ctx->static_encrypted ?
|
nonce_collect_key_max = instance->sectors_total * 4;
|
||||||
((instance->sectors_total * 4) - 2) :
|
|
||||||
(instance->sectors_total * 4);
|
|
||||||
} else {
|
} else {
|
||||||
nonce_collect_key_max = instance->sectors_total * 2;
|
nonce_collect_key_max = instance->sectors_total * 2;
|
||||||
}
|
}
|
||||||
@@ -2047,30 +2047,6 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
dict_attack_ctx->attempt_count = 0;
|
dict_attack_ctx->attempt_count = 0;
|
||||||
}
|
}
|
||||||
dict_attack_ctx->auth_passed = true;
|
dict_attack_ctx->auth_passed = true;
|
||||||
if(!(dict_attack_ctx->current_key_checked)) {
|
|
||||||
dict_attack_ctx->current_key_checked = true;
|
|
||||||
|
|
||||||
// Check if the nested target key is a known key
|
|
||||||
if(mf_classic_nested_is_target_key_found(instance, false)) {
|
|
||||||
// Continue to next key
|
|
||||||
if(!(dict_attack_ctx->static_encrypted)) {
|
|
||||||
dict_attack_ctx->nested_target_key++;
|
|
||||||
dict_attack_ctx->current_key_checked = false;
|
|
||||||
}
|
|
||||||
instance->state = MfClassicPollerStateNestedController;
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it is not a known key, we'll need to calibrate for static encrypted backdoored tags
|
|
||||||
if((dict_attack_ctx->backdoor == MfClassicBackdoorAuth3) &&
|
|
||||||
(dict_attack_ctx->nested_target_key < nonce_collect_key_max) &&
|
|
||||||
!(recalibrated)) {
|
|
||||||
dict_attack_ctx->calibrated = false;
|
|
||||||
dict_attack_ctx->nested_phase = MfClassicNestedPhaseRecalibrate;
|
|
||||||
instance->state = MfClassicPollerStateNestedController;
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have tried to collect this nonce too many times, skip
|
// If we have tried to collect this nonce too many times, skip
|
||||||
if((is_weak && (dict_attack_ctx->attempt_count >= MF_CLASSIC_NESTED_RETRY_MAXIMUM)) ||
|
if((is_weak && (dict_attack_ctx->attempt_count >= MF_CLASSIC_NESTED_RETRY_MAXIMUM)) ||
|
||||||
@@ -2096,12 +2072,52 @@ NfcCommand mf_classic_poller_handler_nested_controller(MfClassicPoller* instance
|
|||||||
dict_attack_ctx->attempt_count = 0;
|
dict_attack_ctx->attempt_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FURI_LOG_D(
|
||||||
|
TAG,
|
||||||
|
"Nested target key: %u (max: %u)",
|
||||||
|
dict_attack_ctx->nested_target_key,
|
||||||
|
nonce_collect_key_max);
|
||||||
|
|
||||||
|
if(!(dict_attack_ctx->current_key_checked)) {
|
||||||
|
if(dict_attack_ctx->nested_target_key == nonce_collect_key_max) {
|
||||||
|
// All nonces have been collected
|
||||||
|
FURI_LOG_D(TAG, "All nonces collected");
|
||||||
|
instance->state = MfClassicPollerStateNestedController;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
dict_attack_ctx->current_key_checked = true;
|
||||||
|
|
||||||
|
// Check if the nested target key is a known key
|
||||||
|
if(mf_classic_nested_is_target_key_found(instance, false)) {
|
||||||
|
// Continue to next key
|
||||||
|
if(!(dict_attack_ctx->static_encrypted)) {
|
||||||
|
dict_attack_ctx->nested_target_key++;
|
||||||
|
dict_attack_ctx->current_key_checked = false;
|
||||||
|
}
|
||||||
|
instance->state = MfClassicPollerStateNestedController;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it is not a known key, we'll need to calibrate for static encrypted backdoored tags
|
||||||
|
if((dict_attack_ctx->backdoor == MfClassicBackdoorAuth3) &&
|
||||||
|
(dict_attack_ctx->nested_target_key < nonce_collect_key_max) &&
|
||||||
|
!(recalibrated)) {
|
||||||
|
dict_attack_ctx->calibrated = false;
|
||||||
|
dict_attack_ctx->nested_phase = MfClassicNestedPhaseRecalibrate;
|
||||||
|
instance->state = MfClassicPollerStateNestedController;
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FURI_LOG_T(TAG, "Collecting a nonce");
|
||||||
|
|
||||||
// Collect a nonce
|
// Collect a nonce
|
||||||
dict_attack_ctx->auth_passed = false;
|
dict_attack_ctx->auth_passed = false;
|
||||||
instance->state = MfClassicPollerStateNestedCollectNtEnc;
|
instance->state = MfClassicPollerStateNestedCollectNtEnc;
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dict_attack_ctx->nested_target_key = 0;
|
||||||
dict_attack_ctx->nested_phase = MfClassicNestedPhaseFinished;
|
dict_attack_ctx->nested_phase = MfClassicNestedPhaseFinished;
|
||||||
instance->state = MfClassicPollerStateSuccess;
|
instance->state = MfClassicPollerStateSuccess;
|
||||||
return command;
|
return command;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,77.2,,
|
Version,+,77.3,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
Header,+,applications/services/cli/cli.h,,
|
Header,+,applications/services/cli/cli.h,,
|
||||||
|
|||||||
|
@@ -1,5 +1,5 @@
|
|||||||
entry,status,name,type,params
|
entry,status,name,type,params
|
||||||
Version,+,77.2,,
|
Version,+,77.3,,
|
||||||
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||||
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
|
||||||
@@ -2559,6 +2559,7 @@ Function,+,mf_classic_get_base_data,Iso14443_3aData*,const MfClassicData*
|
|||||||
Function,+,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t
|
Function,+,mf_classic_get_blocks_num_in_sector,uint8_t,uint8_t
|
||||||
Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType"
|
Function,+,mf_classic_get_device_name,const char*,"const MfClassicData*, NfcDeviceNameType"
|
||||||
Function,+,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t
|
Function,+,mf_classic_get_first_block_num_of_sector,uint8_t,uint8_t
|
||||||
|
Function,+,mf_classic_get_key,MfClassicKey,"const MfClassicData*, uint8_t, MfClassicKeyType"
|
||||||
Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*"
|
Function,+,mf_classic_get_read_sectors_and_keys,void,"const MfClassicData*, uint8_t*, uint8_t*"
|
||||||
Function,+,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
Function,+,mf_classic_get_sector_by_block,uint8_t,uint8_t
|
||||||
Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t"
|
Function,+,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"const MfClassicData*, uint8_t"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user