1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Update FlipperNested

https://github.com/AloneLiberty/FlipperNested
This commit is contained in:
MX
2023-05-30 17:14:27 +03:00
parent 5db3d1ed7c
commit 4609d7ed93
12 changed files with 178 additions and 62 deletions

View File

@@ -21,5 +21,5 @@ App(
fap_author="AloneLiberty", fap_author="AloneLiberty",
fap_description="Recover Mifare Classic keys", fap_description="Recover Mifare Classic keys",
fap_weburl="https://github.com/AloneLiberty/FlipperNested", fap_weburl="https://github.com/AloneLiberty/FlipperNested",
fap_version=(1, 4) fap_version="1.5.0"
) )

View File

@@ -5,28 +5,6 @@
#include "../../lib/crypto1/crypto1.h" #include "../../lib/crypto1/crypto1.h"
#define TAG "Nested" #define TAG "Nested"
void nfc_util_num2bytes(uint64_t src, uint8_t len, uint8_t* dest) {
furi_assert(dest);
furi_assert(len <= 8);
while(len--) {
dest[len] = (uint8_t)src;
src >>= 8;
}
}
uint64_t nfc_util_bytes2num(const uint8_t* src, uint8_t len) {
furi_assert(src);
furi_assert(len <= 8);
uint64_t res = 0;
while(len--) {
res = (res << 8) | (*src);
src++;
}
return res;
}
uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) { uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len) {
uint16_t crc = 0x6363; // NFCA_CRC_INIT uint16_t crc = 0x6363; // NFCA_CRC_INIT
uint8_t byte = 0; uint8_t byte = 0;

View File

@@ -396,6 +396,7 @@ void mifare_nested_blink_stop(MifareNested* mifare_nested) {
int32_t mifare_nested_app(void* p) { int32_t mifare_nested_app(void* p) {
UNUSED(p); UNUSED(p);
MifareNested* mifare_nested = mifare_nested_alloc(); MifareNested* mifare_nested = mifare_nested_alloc();
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart); scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneStart);

View File

@@ -21,7 +21,7 @@
#include <gui/modules/variable_item_list.h> #include <gui/modules/variable_item_list.h>
#include "mifare_nested_icons.h" #include "mifare_nested_icons.h"
#define NESTED_VERSION_APP "1.4.6" #define NESTED_VERSION_APP "1.5.0"
#define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested" #define NESTED_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNested"
#define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery" #define NESTED_RECOVER_KEYS_GITHUB_LINK "https://github.com/AloneLiberty/FlipperNestedRecovery"
#define NESTED_NONCE_FORMAT_VERSION "3" #define NESTED_NONCE_FORMAT_VERSION "3"
@@ -99,6 +99,7 @@ struct MifareNested {
NestedState* nested_state; NestedState* nested_state;
CheckKeysState* keys_state; CheckKeysState* keys_state;
SaveNoncesResult_t* save_state;
MifareNestedWorkerState collecting_type; MifareNestedWorkerState collecting_type;

View File

@@ -296,7 +296,7 @@ uint32_t mifare_nested_worker_predict_delay(
} }
// This part of attack is my attempt to implement it on Flipper. // This part of attack is my attempt to implement it on Flipper.
// Proxmark can do this in 2 fucking steps, but idk how. // Check README.md for more info
// First, we find RPNG rounds per 1000 us // First, we find RPNG rounds per 1000 us
for(uint32_t rtr = 0; rtr < 25; rtr++) { for(uint32_t rtr = 0; rtr < 25; rtr++) {
@@ -448,7 +448,7 @@ uint32_t mifare_nested_worker_predict_delay(
return 1; return 1;
} }
void mifare_nested_worker_write_nonces( SaveNoncesResult_t* mifare_nested_worker_write_nonces(
FuriHalNfcDevData* data, FuriHalNfcDevData* data,
Storage* storage, Storage* storage,
NonceList_t* nonces, NonceList_t* nonces,
@@ -459,6 +459,11 @@ void mifare_nested_worker_write_nonces(
uint32_t distance) { uint32_t distance) {
FuriString* path = furi_string_alloc(); FuriString* path = furi_string_alloc();
Stream* file_stream = file_stream_alloc(storage); Stream* file_stream = file_stream_alloc(storage);
SaveNoncesResult_t* result = malloc(sizeof(SaveNoncesResult_t));
result->saved = 0;
result->invalid = 0;
result->skipped = 0;
mifare_nested_worker_get_nonces_file_path(data, path); mifare_nested_worker_get_nonces_file_path(data, path);
file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS); file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
@@ -472,23 +477,26 @@ void mifare_nested_worker_write_nonces(
for(uint8_t tries = 0; tries < tries_count; tries++) { for(uint8_t tries = 0; tries < tries_count; tries++) {
for(uint8_t sector = 0; sector < sector_count; sector++) { for(uint8_t sector = 0; sector < sector_count; sector++) {
for(uint8_t key_type = 0; key_type < 2; key_type++) { for(uint8_t key_type = 0; key_type < 2; key_type++) {
if(nonces->nonces[sector][key_type][tries]->collected && if(nonces->nonces[sector][key_type][tries]->invalid) {
!nonces->nonces[sector][key_type][tries]->skipped) { result->invalid++;
} else if(nonces->nonces[sector][key_type][tries]->skipped) {
result->skipped++;
} else if(nonces->nonces[sector][key_type][tries]->collected) {
if(nonces->nonces[sector][key_type][tries]->hardnested) { if(nonces->nonces[sector][key_type][tries]->hardnested) {
FuriString* path = furi_string_alloc(); FuriString* hardnested_path = furi_string_alloc();
mifare_nested_worker_get_hardnested_file_path( mifare_nested_worker_get_hardnested_file_path(
data, path, sector, key_type); data, hardnested_path, sector, key_type);
FuriString* str = furi_string_alloc_printf( FuriString* str = furi_string_alloc_printf(
"HardNested: Key %c cuid 0x%08lx file %s sec %u\n", "HardNested: Key %c cuid 0x%08lx file %s sec %u\n",
!key_type ? 'A' : 'B', !key_type ? 'A' : 'B',
nonces->cuid, nonces->cuid,
furi_string_get_cstr(path), furi_string_get_cstr(hardnested_path),
sector); sector);
stream_write_string(file_stream, str); stream_write_string(file_stream, str);
furi_string_free(path); furi_string_free(hardnested_path);
furi_string_free(str); furi_string_free(str);
} else { } else {
FuriString* str = furi_string_alloc_printf( FuriString* str = furi_string_alloc_printf(
@@ -515,6 +523,8 @@ void mifare_nested_worker_write_nonces(
stream_write_string(file_stream, str); stream_write_string(file_stream, str);
furi_string_free(str); furi_string_free(str);
} }
result->saved++;
} }
} }
} }
@@ -529,10 +539,20 @@ void mifare_nested_worker_write_nonces(
} }
free_nonces(nonces, sector_count, free_tries_count); free_nonces(nonces, sector_count, free_tries_count);
furi_string_free(path);
file_stream_close(file_stream); file_stream_close(file_stream);
free(file_stream); free(file_stream);
if(!result->saved) {
FURI_LOG_E(TAG, "No nonces collected, removing file...");
if(!storage_simply_remove(storage, furi_string_get_cstr(path))) {
FURI_LOG_E(TAG, "Failed to remove .nonces file");
}
}
furi_string_free(path);
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
return result;
} }
bool mifare_nested_worker_check_initial_keys( bool mifare_nested_worker_check_initial_keys(
@@ -759,7 +779,7 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
mifare_nested_worker_get_block_by_sector(sector), mifare_nested_worker_get_block_by_sector(sector),
key_type); key_type);
info->skipped = true; info->invalid = true;
nonces.nonces[sector][key_type][0] = info; nonces.nonces[sector][key_type][0] = info;
@@ -818,12 +838,20 @@ void mifare_nested_worker_collect_nonces_static(MifareNestedWorker* mifare_neste
break; break;
} }
mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); SaveNoncesResult_t* result =
mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
free(mf_data); free(mf_data);
mifare_nested_worker->callback( if(result->saved) {
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); mifare_nested_worker->callback(
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
} else {
mifare_nested_worker->context->save_state = result;
mifare_nested_worker->callback(
MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
}
nfc_deactivate(); nfc_deactivate();
} }
@@ -930,7 +958,7 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_
mifare_nested_worker_get_block_by_sector(sector), mifare_nested_worker_get_block_by_sector(sector),
key_type); key_type);
info->skipped = true; info->invalid = true;
nonces.nonces[sector][key_type][0] = info; nonces.nonces[sector][key_type][0] = info;
mifare_nested_worker->context->nonces = &nonces; mifare_nested_worker->context->nonces = &nonces;
@@ -1059,12 +1087,20 @@ void mifare_nested_worker_collect_nonces_hard(MifareNestedWorker* mifare_nested_
} }
} }
mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0); SaveNoncesResult_t* result =
mifare_nested_worker_write_nonces(&data, storage, &nonces, 1, 1, sector_count, 0, 0);
free(mf_data); free(mf_data);
mifare_nested_worker->callback( if(result->saved) {
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); mifare_nested_worker->callback(
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
} else {
mifare_nested_worker->context->save_state = result;
mifare_nested_worker->callback(
MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
}
nfc_deactivate(); nfc_deactivate();
} }
@@ -1368,13 +1404,20 @@ void mifare_nested_worker_collect_nonces(MifareNestedWorker* mifare_nested_worke
break; break;
} }
mifare_nested_worker_write_nonces( SaveNoncesResult_t* result = mifare_nested_worker_write_nonces(
&data, storage, &nonces, tries_count, 3, sector_count, delay, distance); &data, storage, &nonces, tries_count, 3, sector_count, delay, distance);
free(mf_data); free(mf_data);
mifare_nested_worker->callback( if(result->saved) {
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context); mifare_nested_worker->callback(
MifareNestedWorkerEventNoncesCollected, mifare_nested_worker->context);
} else {
mifare_nested_worker->context->save_state = result;
mifare_nested_worker->callback(
MifareNestedWorkerEventNoNoncesCollected, mifare_nested_worker->context);
}
nfc_deactivate(); nfc_deactivate();
} }

View File

@@ -22,6 +22,7 @@ typedef enum {
MifareNestedWorkerEventReserved = 1000, MifareNestedWorkerEventReserved = 1000,
MifareNestedWorkerEventNoTagDetected, MifareNestedWorkerEventNoTagDetected,
MifareNestedWorkerEventNoNoncesCollected,
MifareNestedWorkerEventNoncesCollected, MifareNestedWorkerEventNoncesCollected,
MifareNestedWorkerEventCollecting, MifareNestedWorkerEventCollecting,
@@ -64,8 +65,9 @@ typedef struct {
uint32_t target_nt[2]; uint32_t target_nt[2];
uint32_t target_ks[2]; uint32_t target_ks[2];
uint8_t parity[2][4]; uint8_t parity[2][4];
bool collected;
bool skipped; bool skipped;
bool invalid;
bool collected;
bool hardnested; bool hardnested;
} Nonces; } Nonces;
@@ -87,3 +89,9 @@ typedef struct {
uint32_t sector_keys; uint32_t sector_keys;
bool tag_lost; bool tag_lost;
} KeyInfo_t; } KeyInfo_t;
typedef struct {
uint32_t saved;
uint32_t invalid;
uint32_t skipped;
} SaveNoncesResult_t;

View File

@@ -51,7 +51,7 @@ void mifare_nested_scene_about_on_enter(void* context) {
14, 14,
AlignCenter, AlignCenter,
AlignBottom, AlignBottom,
"\e#\e! Flipper (Mifare) Nested \e!\n", "\e#\e! Flipper Nested \e!\n",
false); false);
widget_add_text_scroll_element( widget_add_text_scroll_element(
mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str)); mifare_nested->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));

View File

@@ -56,14 +56,7 @@ bool mifare_nested_scene_check_on_event(void* context, SceneManagerEvent event)
bool consumed = false; bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == MifareNestedWorkerEventNoncesCollected) { if(event.event == MifareNestedWorkerEventCollecting) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventAttackFailed) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed);
consumed = true;
} else if(event.event == MifareNestedWorkerEventCollecting) {
if(mifare_nested->run == NestedRunAttack) { if(mifare_nested->run == NestedRunAttack) {
if(mifare_nested->settings->only_hardnested) { if(mifare_nested->settings->only_hardnested) {
FURI_LOG_I("MifareNested", "Using Hard Nested because user settings"); FURI_LOG_I("MifareNested", "Using Hard Nested because user settings");

View File

@@ -84,13 +84,6 @@ bool mifare_nested_scene_check_keys_on_event(void* context, SceneManagerEvent ev
if(event.event == GuiButtonTypeCenter) { if(event.event == GuiButtonTypeCenter) {
scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0); scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0);
consumed = true; consumed = true;
} else if(event.event == MifareNestedWorkerEventNoncesCollected) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventNeedKey) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneNoKeys);
consumed = true;
} else if(event.event == MifareNestedWorkerEventKeysFound) { } else if(event.event == MifareNestedWorkerEventKeysFound) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys); scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneAddedKeys);
consumed = true; consumed = true;

View File

@@ -120,6 +120,10 @@ bool mifare_nested_scene_collecting_on_event(void* context, SceneManagerEvent ev
scene_manager_next_scene( scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoncesCollected); mifare_nested->scene_manager, MifareNestedSceneNoncesCollected);
consumed = true; consumed = true;
} else if(event.event == MifareNestedWorkerEventNoNoncesCollected) {
scene_manager_next_scene(
mifare_nested->scene_manager, MifareNestedSceneNoNoncesCollected);
consumed = true;
} else if(event.event == MifareNestedWorkerEventAttackFailed) { } else if(event.event == MifareNestedWorkerEventAttackFailed) {
scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed); scene_manager_next_scene(mifare_nested->scene_manager, MifareNestedSceneFailed);
consumed = true; consumed = true;

View File

@@ -10,4 +10,5 @@ ADD_SCENE(mifare_nested, about, About)
ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce) ADD_SCENE(mifare_nested, static_encrypted_nonce, StaticEncryptedNonce)
ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery) ADD_SCENE(mifare_nested, need_key_recovery, NeedKeyRecovery)
ADD_SCENE(mifare_nested, need_collection, NeedCollection) ADD_SCENE(mifare_nested, need_collection, NeedCollection)
ADD_SCENE(mifare_nested, settings, Settings) ADD_SCENE(mifare_nested, settings, Settings)
ADD_SCENE(mifare_nested, no_nonces_collected, NoNoncesCollected)

View File

@@ -0,0 +1,94 @@
#include "../mifare_nested_i.h"
void mifare_nested_scene_no_nonces_collected_widget_callback(
GuiButtonType result,
InputType type,
void* context) {
MifareNested* mifare_nested = context;
if(type == InputTypeShort) {
view_dispatcher_send_custom_event(mifare_nested->view_dispatcher, result);
}
}
void mifare_nested_scene_no_nonces_collected_on_enter(void* context) {
MifareNested* mifare_nested = context;
Widget* widget = mifare_nested->widget;
SaveNoncesResult_t* save_state = mifare_nested->save_state;
notification_message(mifare_nested->notifications, &sequence_error);
widget_add_icon_element(widget, 73, 12, &I_DolphinCry);
widget_add_string_element(
widget, 0, 0, AlignLeft, AlignTop, FontPrimary, "No nonces collected");
uint32_t index = 12;
if(save_state->skipped) {
char append_skipped[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'};
if(save_state->skipped != 1) {
append_skipped[6] = 's';
}
char draw_str[32] = {};
snprintf(
draw_str, sizeof(draw_str), "Skipped: %lu %s", save_state->skipped, append_skipped);
widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str);
widget_add_string_element(
widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(already has keys)");
index += 20;
}
if(save_state->invalid) {
char append_invalid[8] = {'s', 'e', 'c', 't', 'o', 'r', ' ', '\0'};
if(save_state->invalid != 1) {
append_invalid[6] = 's';
}
char draw_str[32] = {};
snprintf(
draw_str, sizeof(draw_str), "Invalid: %lu %s", save_state->invalid, append_invalid);
widget_add_string_element(widget, 0, index, AlignLeft, AlignTop, FontSecondary, draw_str);
widget_add_string_element(
widget, 0, index + 10, AlignLeft, AlignTop, FontSecondary, "(can't auth)");
}
free(save_state);
widget_add_button_element(
widget,
GuiButtonTypeLeft,
"Back",
mifare_nested_scene_no_nonces_collected_widget_callback,
mifare_nested);
// Setup and start worker
view_dispatcher_switch_to_view(mifare_nested->view_dispatcher, MifareNestedViewWidget);
}
bool mifare_nested_scene_no_nonces_collected_on_event(void* context, SceneManagerEvent event) {
MifareNested* mifare_nested = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeCenter || event.event == GuiButtonTypeLeft) {
scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_search_and_switch_to_previous_scene(mifare_nested->scene_manager, 0);
consumed = true;
}
return consumed;
}
void mifare_nested_scene_no_nonces_collected_on_exit(void* context) {
MifareNested* mifare_nested = context;
widget_reset(mifare_nested->widget);
}