mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
nfc mf classic upgrades
by noproto
This commit is contained in:
@@ -163,11 +163,14 @@ NfcCommand mf_classic_poller_handler_start(MfClassicPoller* instance) {
|
||||
instance->mfc_event.type = MfClassicPollerEventTypeRequestMode;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackStandard) {
|
||||
if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackStandard ||
|
||||
instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackCUID) {
|
||||
mf_classic_copy(instance->data, instance->mfc_event_data.poller_mode.data);
|
||||
instance->mode_ctx.dict_attack_ctx.mode = instance->mfc_event_data.poller_mode.mode;
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeDictAttackEnhanced) {
|
||||
mf_classic_copy(instance->data, instance->mfc_event_data.poller_mode.data);
|
||||
instance->mode_ctx.dict_attack_ctx.mode = instance->mfc_event_data.poller_mode.mode;
|
||||
instance->state = MfClassicPollerStateAnalyzeBackdoor;
|
||||
} else if(instance->mfc_event_data.poller_mode.mode == MfClassicPollerModeRead) {
|
||||
instance->state = MfClassicPollerStateRequestReadSector;
|
||||
@@ -590,7 +593,22 @@ NfcCommand mf_classic_poller_handler_analyze_backdoor(MfClassicPoller* instance)
|
||||
(error == MfClassicErrorProtocol || error == MfClassicErrorTimeout)) {
|
||||
FURI_LOG_D(TAG, "No backdoor identified");
|
||||
dict_attack_ctx->backdoor = MfClassicBackdoorNone;
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
|
||||
// Check if any keys were cached - if so, go directly to nested attack
|
||||
bool has_cached_keys = false;
|
||||
for(uint8_t sector = 0; sector < instance->sectors_total; sector++) {
|
||||
if(mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeA) ||
|
||||
mf_classic_is_key_found(instance->data, sector, MfClassicKeyTypeB)) {
|
||||
has_cached_keys = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(has_cached_keys) {
|
||||
instance->state = MfClassicPollerStateNestedController;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
}
|
||||
} else if(error == MfClassicErrorNone) {
|
||||
FURI_LOG_I(TAG, "Backdoor identified: v%d", backdoor_version);
|
||||
dict_attack_ctx->backdoor = mf_classic_backdoor_keys[next_key_index].type;
|
||||
@@ -687,7 +705,15 @@ NfcCommand mf_classic_poller_handler_request_key(MfClassicPoller* instance) {
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(instance->mfc_event_data.key_request_data.key_provided) {
|
||||
dict_attack_ctx->current_key = instance->mfc_event_data.key_request_data.key;
|
||||
instance->state = MfClassicPollerStateAuthKeyA;
|
||||
dict_attack_ctx->requested_key_type = instance->mfc_event_data.key_request_data.key_type;
|
||||
|
||||
// In CUID mode, go directly to the appropriate Auth state based on key_type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID &&
|
||||
dict_attack_ctx->requested_key_type == MfClassicKeyTypeB) {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyA;
|
||||
}
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateNextSector;
|
||||
}
|
||||
@@ -701,7 +727,12 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
||||
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
// In CUID mode, skip directly to RequestKey since we test keys by specific type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
}
|
||||
} else {
|
||||
uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->current_sector);
|
||||
uint64_t key =
|
||||
@@ -722,7 +753,12 @@ NfcCommand mf_classic_poller_handler_auth_a(MfClassicPoller* instance) {
|
||||
instance->state = MfClassicPollerStateReadSector;
|
||||
} else {
|
||||
mf_classic_poller_halt(instance);
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
// In CUID mode, skip directly to RequestKey since we test keys by specific type
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateAuthKeyB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,8 +771,11 @@ NfcCommand mf_classic_poller_handler_auth_b(MfClassicPoller* instance) {
|
||||
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeB)) {
|
||||
if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
// In CUID mode, just request next key since we iterate by key_idx
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
} else if(mf_classic_is_key_found(
|
||||
instance->data, dict_attack_ctx->current_sector, MfClassicKeyTypeA)) {
|
||||
instance->state = MfClassicPollerStateNextSector;
|
||||
} else {
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
@@ -774,12 +813,20 @@ NfcCommand mf_classic_poller_handler_next_sector(MfClassicPoller* instance) {
|
||||
MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx;
|
||||
|
||||
dict_attack_ctx->current_sector++;
|
||||
|
||||
if(dict_attack_ctx->current_sector == instance->sectors_total) {
|
||||
instance->state = MfClassicPollerStateSuccess;
|
||||
} else {
|
||||
instance->mfc_event.type = MfClassicPollerEventTypeNextSector;
|
||||
instance->mfc_event_data.next_sector_data.current_sector = dict_attack_ctx->current_sector;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
|
||||
// In CUID mode, NFC app manages sector based on key_idx - read it back
|
||||
if(dict_attack_ctx->mode == MfClassicPollerModeDictAttackCUID) {
|
||||
dict_attack_ctx->current_sector =
|
||||
instance->mfc_event_data.next_sector_data.current_sector;
|
||||
}
|
||||
|
||||
instance->state = MfClassicPollerStateRequestKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef enum {
|
||||
MfClassicPollerModeRead, /**< Poller reading mode. */
|
||||
MfClassicPollerModeWrite, /**< Poller writing mode. */
|
||||
MfClassicPollerModeDictAttackStandard, /**< Poller dictionary attack mode. */
|
||||
MfClassicPollerModeDictAttackCUID, /**< Poller CUID dictionary attack mode. */
|
||||
MfClassicPollerModeDictAttackEnhanced, /**< Poller enhanced dictionary attack mode. */
|
||||
} MfClassicPollerMode;
|
||||
|
||||
@@ -129,6 +130,7 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
MfClassicKey key; /**< Key to be used by poller. */
|
||||
MfClassicKeyType key_type; /**< Key type (A or B) for CUID dict attack mode. */
|
||||
bool key_provided; /**< Flag indicating if key is provided. */
|
||||
} MfClassicPollerEventDataKeyRequest;
|
||||
|
||||
|
||||
@@ -128,10 +128,12 @@ typedef struct {
|
||||
uint8_t current_sector;
|
||||
MfClassicKey current_key;
|
||||
MfClassicKeyType current_key_type;
|
||||
MfClassicKeyType requested_key_type; // Key type requested from app (for CUID mode)
|
||||
bool auth_passed;
|
||||
uint16_t current_block;
|
||||
uint8_t reuse_key_sector;
|
||||
MfClassicBackdoor backdoor;
|
||||
MfClassicPollerMode mode; // Current attack mode
|
||||
// Enhanced dictionary attack and nested nonce collection
|
||||
bool enhanced_dict;
|
||||
MfClassicNestedPhase nested_phase;
|
||||
|
||||
Reference in New Issue
Block a user