Dictionary attack functional

This commit is contained in:
noproto
2024-12-20 18:07:18 -05:00
parent 92b9bd039e
commit 948dffadcc
4 changed files with 81 additions and 90 deletions

View File

@@ -15,6 +15,7 @@ enum {
SubmenuIndexUnlockByReader, SubmenuIndexUnlockByReader,
SubmenuIndexUnlockByPassword, SubmenuIndexUnlockByPassword,
SubmenuIndexWrite, SubmenuIndexWrite,
SubmenuIndexDictAttack
}; };
enum { enum {
@@ -150,7 +151,8 @@ static NfcCommand
} }
if(!mf_ultralight_event->data->auth_context.skip_auth) { if(!mf_ultralight_event->data->auth_context.skip_auth) {
mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password; mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password;
mf_ultralight_event->data->auth_context.tdes_key = instance->mf_ul_auth->tdes_key; mf_ultralight_event->data->key_request_data.key = instance->mf_ul_auth->tdes_key;
// TODO: Key provided attribute is not set
} }
} else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) { } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) {
instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack; instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack;
@@ -201,6 +203,14 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc
SubmenuIndexUnlock, SubmenuIndexUnlock,
nfc_protocol_support_common_submenu_callback, nfc_protocol_support_common_submenu_callback,
instance); instance);
if(data->type == MfUltralightTypeMfulC) {
submenu_add_item(
submenu,
"Unlock with Dictionary",
SubmenuIndexDictAttack,
nfc_protocol_support_common_submenu_callback,
instance);
}
} else if( } else if(
data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 || data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 ||
data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 || data->type == MfUltralightTypeNTAG216 || data->type == MfUltralightTypeUL11 ||
@@ -269,6 +279,12 @@ static bool nfc_scene_read_and_saved_menu_on_event_mf_ultralight(
} else if(event.event == SubmenuIndexCommonEdit) { } else if(event.event == SubmenuIndexCommonEdit) {
scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid); scene_manager_next_scene(instance->scene_manager, NfcSceneSetUid);
consumed = true; consumed = true;
} else if(event.event == SubmenuIndexDictAttack) {
if(!scene_manager_search_and_switch_to_previous_scene(
instance->scene_manager, NfcSceneMfUltralightCDictAttack)) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightCDictAttack);
}
consumed = true;
} }
} }
return consumed; return consumed;

View File

@@ -181,10 +181,6 @@ MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_po
instance->general_event.protocol = NfcProtocolMfUltralight; instance->general_event.protocol = NfcProtocolMfUltralight;
instance->general_event.event_data = &instance->mfu_event; instance->general_event.event_data = &instance->mfu_event;
instance->general_event.instance = instance; instance->general_event.instance = instance;
instance->dict_attack_ctx.auth_success = false;
instance->dict_attack_ctx.is_card_present = false;
mbedtls_des3_init(&instance->des_context); mbedtls_des3_init(&instance->des_context);
return instance; return instance;
} }
@@ -255,7 +251,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller*
instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version); instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version);
instance->state = MfUltralightPollerStateGetFeatureSet; instance->state = MfUltralightPollerStateGetFeatureSet;
} else { } else {
FURI_LOG_D(TAG, "Didn't response. Check Ultralight C"); FURI_LOG_D(TAG, "Didn't respond. Check Ultralight C");
iso14443_3a_poller_halt(instance->iso14443_3a_poller); iso14443_3a_poller_halt(instance->iso14443_3a_poller);
instance->state = MfUltralightPollerStateDetectMfulC; instance->state = MfUltralightPollerStateDetectMfulC;
} }
@@ -270,7 +266,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo
instance->data->type = MfUltralightTypeMfulC; instance->data->type = MfUltralightTypeMfulC;
instance->state = MfUltralightPollerStateGetFeatureSet; instance->state = MfUltralightPollerStateGetFeatureSet;
} else { } else {
FURI_LOG_D(TAG, "Didn't response. Check NTAG 203"); FURI_LOG_D(TAG, "Didn't respond. Check NTAG 203");
instance->state = MfUltralightPollerStateDetectNtag203; instance->state = MfUltralightPollerStateDetectNtag203;
} }
iso14443_3a_poller_halt(instance->iso14443_3a_poller); iso14443_3a_poller_halt(instance->iso14443_3a_poller);
@@ -456,7 +452,28 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol
command = instance->callback(instance->general_event, instance->context); command = instance->callback(instance->general_event, instance->context);
if(!instance->mfu_event.data->auth_context.skip_auth) { if(!instance->mfu_event.data->auth_context.skip_auth) {
FURI_LOG_D(TAG, "Trying to authenticate with 3des key"); FURI_LOG_D(TAG, "Trying to authenticate with 3des key");
instance->auth_context.tdes_key = instance->mfu_event.data->auth_context.tdes_key; instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
instance->auth_context.auth_success = false;
// For debugging
FURI_LOG_D(
"TAG",
"Key data: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
instance->auth_context.tdes_key.data[0],
instance->auth_context.tdes_key.data[1],
instance->auth_context.tdes_key.data[2],
instance->auth_context.tdes_key.data[3],
instance->auth_context.tdes_key.data[4],
instance->auth_context.tdes_key.data[5],
instance->auth_context.tdes_key.data[6],
instance->auth_context.tdes_key.data[7],
instance->auth_context.tdes_key.data[8],
instance->auth_context.tdes_key.data[9],
instance->auth_context.tdes_key.data[10],
instance->auth_context.tdes_key.data[11],
instance->auth_context.tdes_key.data[12],
instance->auth_context.tdes_key.data[13],
instance->auth_context.tdes_key.data[14],
instance->auth_context.tdes_key.data[15]);
do { do {
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE]; uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0}; uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
@@ -473,20 +490,41 @@ static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPol
mf_ultralight_3des_shift_data(RndA); mf_ultralight_3des_shift_data(RndA);
instance->auth_context.auth_success = instance->auth_context.auth_success =
(memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0); (memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0);
if(instance->auth_context.auth_success) { if(instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Auth success"); FURI_LOG_E(TAG, "Auth success");
if(instance->mode == MfUltralightPollerModeDictAttack) {
memcpy(
&instance->data->page[44],
instance->auth_context.tdes_key.data,
MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE);
instance->data->pages_read = instance->pages_total;
instance->pages_read = instance->pages_total;
instance->state = MfUltralightPollerStateReadSuccess;
}
} }
} while(false); } while(false);
if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) { if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Auth failed"); FURI_LOG_E(TAG, "Auth failed");
iso14443_3a_poller_halt(instance->iso14443_3a_poller); iso14443_3a_poller_halt(instance->iso14443_3a_poller);
if(instance->mode == MfUltralightPollerModeDictAttack) {
// Not needed? We already do a callback earlier?
instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey;
command = instance->callback(instance->general_event, instance->context);
if(!instance->mfu_event.data->key_request_data.key_provided) {
instance->state = MfUltralightPollerStateReadPages;
} else {
instance->auth_context.tdes_key =
instance->mfu_event.data->key_request_data.key;
instance->state = MfUltralightPollerStateAuthMfulC;
}
}
} }
} }
} }
instance->state = MfUltralightPollerStateReadPages; // Regression review
if(instance->mode != MfUltralightPollerModeDictAttack) {
instance->state = MfUltralightPollerStateReadPages;
}
return command; return command;
} }
@@ -509,12 +547,16 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
instance->error = mf_ultralight_poller_read_page(instance, start_page, &data); instance->error = mf_ultralight_poller_read_page(instance, start_page, &data);
} }
// Regression review
const uint8_t read_cnt = instance->data->type == MfUltralightTypeMfulC ? 1 : 4;
if(instance->error == MfUltralightErrorNone) { if(instance->error == MfUltralightErrorNone) {
if(start_page < instance->pages_total) { for(size_t i = 0; i < read_cnt; i++) {
FURI_LOG_D(TAG, "Read page %d success", start_page); if(start_page + i < instance->pages_total) {
instance->data->page[start_page] = data.page[0]; FURI_LOG_D(TAG, "Read page %d success", start_page + i);
instance->pages_read++; instance->data->page[start_page + i] = data.page[i];
instance->data->pages_read = instance->pages_read; instance->pages_read++;
instance->data->pages_read = instance->pages_read;
}
} }
if(instance->pages_read == instance->pages_total) { if(instance->pages_read == instance->pages_total) {
@@ -523,7 +565,7 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
} else { } else {
if(instance->data->type == MfUltralightTypeMfulC && if(instance->data->type == MfUltralightTypeMfulC &&
!mf_ultralight_3des_key_valid(instance->data)) { !mf_ultralight_3des_key_valid(instance->data)) {
instance->state = MfUltralightPollerStateDictAttack; instance->state = MfUltralightPollerStateCheckMfulCAuthStatus;
} else { } else {
FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read); FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read);
if(instance->pages_read) { if(instance->pages_read) {
@@ -732,63 +774,6 @@ static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller*
return command; return command;
} }
static NfcCommand mf_ultralight_poller_handler_dict_attack(MfUltralightPoller* instance) {
NfcCommand command = NfcCommandContinue;
const MfUltralightData* tag_data = instance->data;
uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type);
FURI_LOG_D(TAG, "Dict Attack");
do {
if(!mf_ultralight_support_feature(features, MfUltralightFeatureSupportAuthenticate)) {
instance->error = MfUltralightErrorProtocol;
instance->state = MfUltralightPollerStateReadFailed;
break;
}
instance->dict_attack_ctx.is_card_present = true;
instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey;
command = instance->callback(instance->general_event, instance->context);
if(!instance->mfu_event.data->key_request_data.key_provided) {
instance->state = MfUltralightPollerStateReadSuccess;
break;
}
FURI_LOG_D(TAG, "Trying next 3DES key");
instance->error = MfUltralightErrorNone;
instance->auth_context.auth_success = false;
instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
do {
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
furi_hal_random_fill_buf(RndA, sizeof(RndA));
instance->error = mf_ultralight_poller_authenticate_start(instance, RndA, output);
if(instance->error != MfUltralightErrorNone) break;
uint8_t decoded_shifted_RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
instance->error = mf_ultralight_poller_authenticate_end(
instance, RndB, output, decoded_shifted_RndA);
if(instance->error != MfUltralightErrorNone) break;
mf_ultralight_3des_shift_data(RndA);
instance->auth_context.auth_success =
(memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0);
if(instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Dict attack success");
instance->state = MfUltralightPollerStateReadPages;
instance->dict_attack_ctx.auth_success = true;
break;
}
} while(false);
if(!instance->auth_context.auth_success) {
FURI_LOG_D(TAG, "Dict attack auth failed");
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
}
} while(false);
return command;
}
static const MfUltralightPollerReadHandler static const MfUltralightPollerReadHandler
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
@@ -814,8 +799,6 @@ static const MfUltralightPollerReadHandler
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages, [MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail, [MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success, [MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
[MfUltralightPollerStateDictAttack] = mf_ultralight_poller_handler_dict_attack,
}; };
static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) { static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) {

View File

@@ -134,7 +134,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start(
uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET; uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
mf_ultralight_3des_decrypt( mf_ultralight_3des_decrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
iv, iv,
encRndB, encRndB,
sizeof(encRndB), sizeof(encRndB),
@@ -145,7 +145,7 @@ MfUltralightError mf_ultralight_poller_authenticate_start(
mf_ultralight_3des_encrypt( mf_ultralight_3des_encrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
encRndB, encRndB,
output, output,
MF_ULTRALIGHT_C_AUTH_DATA_SIZE, MF_ULTRALIGHT_C_AUTH_DATA_SIZE,
@@ -179,7 +179,7 @@ MfUltralightError mf_ultralight_poller_authenticate_end(
mf_ultralight_3des_decrypt( mf_ultralight_3des_decrypt(
&instance->des_context, &instance->des_context,
instance->mfu_event.data->auth_context.tdes_key.data, instance->auth_context.tdes_key.data,
RndB, RndB,
bit_buffer_get_data(instance->rx_buffer) + 1, bit_buffer_get_data(instance->rx_buffer) + 1,
MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE, MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE,

View File

@@ -68,17 +68,10 @@ typedef enum {
MfUltralightPollerStateWritePages, MfUltralightPollerStateWritePages,
MfUltralightPollerStateWriteFail, MfUltralightPollerStateWriteFail,
MfUltralightPollerStateWriteSuccess, MfUltralightPollerStateWriteSuccess,
MfUltralightPollerStateDictAttack,
MfUltralightPollerStateNum, MfUltralightPollerStateNum,
} MfUltralightPollerState; } MfUltralightPollerState;
typedef struct {
uint8_t sectors_total;
bool auth_success;
bool is_card_present;
} MfUltralightPollerDictAttackContext;
struct MfUltralightPoller { struct MfUltralightPoller {
Iso14443_3aPoller* iso14443_3a_poller; Iso14443_3aPoller* iso14443_3a_poller;
MfUltralightPollerState state; MfUltralightPollerState state;
@@ -96,7 +89,6 @@ struct MfUltralightPoller {
uint8_t tearing_flag_total; uint8_t tearing_flag_total;
uint16_t current_page; uint16_t current_page;
MfUltralightError error; MfUltralightError error;
MfUltralightPollerDictAttackContext dict_attack_ctx;
mbedtls_des3_context des_context; mbedtls_des3_context des_context;
NfcGenericEvent general_event; NfcGenericEvent general_event;