nfc: make dict attack more interactive (#1462)
* nfc: deduplify dict attack worker code * nfc: make dict attack more interactive Co-authored-by: gornekich <n.gorbadey@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									284c56718b
								
							
						
					
					
						commit
						3ee93e1a82
					
				| @ -1,5 +1,7 @@ | ||||
| #include "../nfc_i.h" | ||||
| 
 | ||||
| #define TAG "NfcMfClassicDictAttack" | ||||
| 
 | ||||
| typedef enum { | ||||
|     DictAttackStateIdle, | ||||
|     DictAttackStateUserDictInProgress, | ||||
| @ -32,7 +34,9 @@ static void nfc_scene_mf_classic_dict_attack_update_view(Nfc* nfc) { | ||||
| 
 | ||||
| static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackState state) { | ||||
|     MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; | ||||
|     NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; | ||||
|     NfcWorkerState worker_state = NfcWorkerStateReady; | ||||
|     MfClassicDict* dict = NULL; | ||||
| 
 | ||||
|     // Identify scene state
 | ||||
|     if(state == DictAttackStateIdle) { | ||||
| @ -47,16 +51,36 @@ static void nfc_scene_mf_classic_dict_attack_prepare_view(Nfc* nfc, DictAttackSt | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     if(state == DictAttackStateUserDictInProgress) { | ||||
|         worker_state = NfcWorkerStateMfClassicUserDictAttack; | ||||
|         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic User Dict."); | ||||
|     } else if(state == DictAttackStateFlipperDictInProgress) { | ||||
|         worker_state = NfcWorkerStateMfClassicFlipperDictAttack; | ||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); | ||||
|         dict = mf_classic_dict_alloc(MfClassicDictTypeUser); | ||||
| 
 | ||||
|         // If failed to load user dictionary - try flipper dictionary
 | ||||
|         if(!dict) { | ||||
|             FURI_LOG_E(TAG, "User dictionary not found"); | ||||
|             state = DictAttackStateFlipperDictInProgress; | ||||
|         } | ||||
|     } | ||||
|     if(state == DictAttackStateFlipperDictInProgress) { | ||||
|         worker_state = NfcWorkerStateMfClassicDictAttack; | ||||
|         dict_attack_set_header(nfc->dict_attack, "Mf Classic Flipper Dict."); | ||||
|         dict = mf_classic_dict_alloc(MfClassicDictTypeFlipper); | ||||
|         if(!dict) { | ||||
|             FURI_LOG_E(TAG, "Flipper dictionary not found"); | ||||
|             // Pass through to let worker handle the failure
 | ||||
|         } | ||||
|     } | ||||
|     // Free previous dictionary
 | ||||
|     if(dict_attack_data->dict) { | ||||
|         mf_classic_dict_free(dict_attack_data->dict); | ||||
|     } | ||||
|     dict_attack_data->dict = dict; | ||||
|     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicDictAttack, state); | ||||
|     dict_attack_set_callback(nfc->dict_attack, nfc_dict_attack_dict_attack_result_callback, nfc); | ||||
|     dict_attack_set_current_sector(nfc->dict_attack, 0); | ||||
|     dict_attack_set_card_detected(nfc->dict_attack, data->type); | ||||
|     dict_attack_set_total_dict_keys( | ||||
|         nfc->dict_attack, dict ? mf_classic_dict_get_total_keys(dict) : 0); | ||||
|     nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||
|     nfc_worker_start( | ||||
|         nfc->worker, worker_state, &nfc->dev->dev_data, nfc_dict_attack_worker_callback, nfc); | ||||
| @ -112,6 +136,10 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | ||||
|             nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||
|             dict_attack_inc_current_sector(nfc->dict_attack); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcWorkerEventNewDictKeyBatch) { | ||||
|             nfc_scene_mf_classic_dict_attack_update_view(nfc); | ||||
|             dict_attack_inc_current_dict_key(nfc->dict_attack, NFC_DICT_KEY_BATCH_SIZE); | ||||
|             consumed = true; | ||||
|         } else if(event.event == NfcCustomEventDictAttackSkip) { | ||||
|             if(state == DictAttackStateUserDictInProgress) { | ||||
|                 nfc_worker_stop(nfc->worker); | ||||
| @ -130,8 +158,13 @@ bool nfc_scene_mf_classic_dict_attack_on_event(void* context, SceneManagerEvent | ||||
| 
 | ||||
| void nfc_scene_mf_classic_dict_attack_on_exit(void* context) { | ||||
|     Nfc* nfc = context; | ||||
|     NfcMfClassicDictAttackData* dict_attack_data = &nfc->dev->dev_data.mf_classic_dict_attack_data; | ||||
|     // Stop worker
 | ||||
|     nfc_worker_stop(nfc->worker); | ||||
|     if(dict_attack_data->dict) { | ||||
|         mf_classic_dict_free(dict_attack_data->dict); | ||||
|         dict_attack_data->dict = NULL; | ||||
|     } | ||||
|     dict_attack_reset(nfc->dict_attack); | ||||
|     nfc_blink_stop(nfc); | ||||
| } | ||||
|  | ||||
| @ -23,6 +23,8 @@ typedef struct { | ||||
|     uint8_t sector_current; | ||||
|     uint8_t keys_total; | ||||
|     uint8_t keys_found; | ||||
|     uint16_t dict_keys_total; | ||||
|     uint16_t dict_keys_current; | ||||
| } DictAttackViewModel; | ||||
| 
 | ||||
| static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
| @ -38,8 +40,15 @@ static void dict_attack_draw_callback(Canvas* canvas, void* model) { | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, string_get_cstr(m->header)); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         float progress = | ||||
|             m->sectors_total == 0 ? 0 : (float)(m->sector_current) / (float)(m->sectors_total); | ||||
|         float dict_progress = m->dict_keys_total == 0 ? | ||||
|                                   0 : | ||||
|                                   (float)(m->dict_keys_current) / (float)(m->dict_keys_total); | ||||
|         float progress = m->sectors_total == 0 ? 0 : | ||||
|                                                  ((float)(m->sector_current) + dict_progress) / | ||||
|                                                      (float)(m->sectors_total); | ||||
|         if(progress > 1.0) { | ||||
|             progress = 1.0; | ||||
|         } | ||||
|         elements_progress_bar(canvas, 5, 15, 120, progress); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         snprintf(draw_str, sizeof(draw_str), "Keys found: %d/%d", m->keys_found, m->keys_total); | ||||
| @ -100,6 +109,8 @@ void dict_attack_reset(DictAttack* dict_attack) { | ||||
|             model->sector_current = 0; | ||||
|             model->keys_total = 0; | ||||
|             model->keys_found = 0; | ||||
|             model->dict_keys_total = 0; | ||||
|             model->dict_keys_current = 0; | ||||
|             string_reset(model->header); | ||||
|             return false; | ||||
|         }); | ||||
| @ -171,6 +182,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             model->sector_current = curr_sec; | ||||
|             model->dict_keys_current = 0; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| @ -181,6 +193,7 @@ void dict_attack_inc_current_sector(DictAttack* dict_attack) { | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             if(model->sector_current < model->sectors_total) { | ||||
|                 model->sector_current++; | ||||
|                 model->dict_keys_current = 0; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| @ -196,3 +209,23 @@ void dict_attack_inc_keys_found(DictAttack* dict_attack) { | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             model->dict_keys_total = dict_keys_total; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { | ||||
|     furi_assert(dict_attack); | ||||
|     with_view_model( | ||||
|         dict_attack->view, (DictAttackViewModel * model) { | ||||
|             if(model->dict_keys_current + keys_tried < model->dict_keys_total) { | ||||
|                 model->dict_keys_current += keys_tried; | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
|  | ||||
| @ -34,3 +34,7 @@ void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec); | ||||
| void dict_attack_inc_current_sector(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_inc_keys_found(DictAttack* dict_attack); | ||||
| 
 | ||||
| void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total); | ||||
| 
 | ||||
| void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried); | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <dialogs/dialogs.h> | ||||
| 
 | ||||
| #include <furi_hal_nfc.h> | ||||
| #include <lib/nfc/helpers/mf_classic_dict.h> | ||||
| #include <lib/nfc/protocols/emv.h> | ||||
| #include <lib/nfc/protocols/mifare_ultralight.h> | ||||
| #include <lib/nfc/protocols/mifare_classic.h> | ||||
| @ -13,6 +14,7 @@ | ||||
| 
 | ||||
| #define NFC_DEV_NAME_MAX_LEN 22 | ||||
| #define NFC_READER_DATA_MAX_SIZE 64 | ||||
| #define NFC_DICT_KEY_BATCH_SIZE 50 | ||||
| 
 | ||||
| #define NFC_APP_FOLDER ANY_PATH("nfc") | ||||
| #define NFC_APP_EXTENSION ".nfc" | ||||
| @ -41,10 +43,17 @@ typedef struct { | ||||
|     uint16_t size; | ||||
| } NfcReaderRequestData; | ||||
| 
 | ||||
| typedef struct { | ||||
|     MfClassicDict* dict; | ||||
| } NfcMfClassicDictAttackData; | ||||
| 
 | ||||
| typedef struct { | ||||
|     FuriHalNfcDevData nfc_data; | ||||
|     NfcProtocol protocol; | ||||
|     NfcReaderRequestData reader_data; | ||||
|     union { | ||||
|         NfcReaderRequestData reader_data; | ||||
|         NfcMfClassicDictAttackData mf_classic_dict_attack_data; | ||||
|     }; | ||||
|     union { | ||||
|         EmvData emv_data; | ||||
|         MfUltralightData mf_ul_data; | ||||
|  | ||||
| @ -101,10 +101,8 @@ int32_t nfc_worker_task(void* context) { | ||||
|         nfc_worker_emulate_mf_ultralight(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateMfClassicEmulate) { | ||||
|         nfc_worker_emulate_mf_classic(nfc_worker); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) { | ||||
|         nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeUser); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack) { | ||||
|         nfc_worker_mf_classic_dict_attack(nfc_worker, MfClassicDictTypeFlipper); | ||||
|     } else if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { | ||||
|         nfc_worker_mf_classic_dict_attack(nfc_worker); | ||||
|     } | ||||
|     furi_hal_nfc_sleep(); | ||||
|     nfc_worker_change_state(nfc_worker, NfcWorkerStateReady); | ||||
| @ -397,11 +395,13 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type) { | ||||
| void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker) { | ||||
|     furi_assert(nfc_worker); | ||||
|     furi_assert(nfc_worker->callback); | ||||
| 
 | ||||
|     MfClassicData* data = &nfc_worker->dev_data->mf_classic_data; | ||||
|     NfcMfClassicDictAttackData* dict_attack_data = | ||||
|         &nfc_worker->dev_data->mf_classic_dict_attack_data; | ||||
|     uint32_t total_sectors = mf_classic_get_total_sectors_num(data->type); | ||||
|     uint64_t key = 0; | ||||
|     FuriHalNfcTxRxContext tx_rx = {}; | ||||
| @ -409,15 +409,17 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType | ||||
|     bool card_removed_notified = false; | ||||
| 
 | ||||
|     // Load dictionary
 | ||||
|     MfClassicDict* dict = mf_classic_dict_alloc(type); | ||||
|     MfClassicDict* dict = dict_attack_data->dict; | ||||
|     if(!dict) { | ||||
|         FURI_LOG_E(TAG, "Dictionary not found"); | ||||
|         nfc_worker->callback(NfcWorkerEventNoDictFound, nfc_worker->context); | ||||
|         mf_classic_dict_free(dict); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     FURI_LOG_D(TAG, "Start Dictionary attack"); | ||||
|     FURI_LOG_D( | ||||
|         TAG, | ||||
|         "Start Dictionary attack, Key Count %d", | ||||
|         mf_classic_dict_get_total_keys(dict)); | ||||
|     for(size_t i = 0; i < total_sectors; i++) { | ||||
|         FURI_LOG_I(TAG, "Sector %d", i); | ||||
|         nfc_worker->callback(NfcWorkerEventNewSector, nfc_worker->context); | ||||
| @ -425,7 +427,11 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType | ||||
|         if(mf_classic_is_sector_read(data, i)) continue; | ||||
|         bool is_key_a_found = mf_classic_is_key_found(data, i, MfClassicKeyA); | ||||
|         bool is_key_b_found = mf_classic_is_key_found(data, i, MfClassicKeyB); | ||||
|         uint16_t key_index = 0; | ||||
|         while(mf_classic_dict_get_next_key(dict, &key)) { | ||||
|             if(++key_index % NFC_DICT_KEY_BATCH_SIZE == 0) { | ||||
|                 nfc_worker->callback(NfcWorkerEventNewDictKeyBatch, nfc_worker->context); | ||||
|             } | ||||
|             furi_hal_nfc_sleep(); | ||||
|             if(furi_hal_nfc_activate_nfca(200, NULL)) { | ||||
|                 furi_hal_nfc_sleep(); | ||||
| @ -456,8 +462,7 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType | ||||
|                     } | ||||
|                 } | ||||
|                 if(is_key_a_found && is_key_b_found) break; | ||||
|                 if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || | ||||
|                      (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) | ||||
|                 if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) | ||||
|                     break; | ||||
|             } else { | ||||
|                 if(!card_removed_notified) { | ||||
| @ -465,20 +470,16 @@ void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType | ||||
|                     card_removed_notified = true; | ||||
|                     card_found_notified = false; | ||||
|                 } | ||||
|                 if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || | ||||
|                      (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) | ||||
|                 if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|         if(!((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || | ||||
|              (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack))) | ||||
|         if(nfc_worker->state != NfcWorkerStateMfClassicDictAttack) | ||||
|             break; | ||||
|         mf_classic_read_sector(&tx_rx, data, i); | ||||
|         mf_classic_dict_rewind(dict); | ||||
|     } | ||||
|     mf_classic_dict_free(dict); | ||||
|     if((nfc_worker->state == NfcWorkerStateMfClassicUserDictAttack) || | ||||
|        (nfc_worker->state == NfcWorkerStateMfClassicFlipperDictAttack)) { | ||||
|     if(nfc_worker->state == NfcWorkerStateMfClassicDictAttack) { | ||||
|         nfc_worker->callback(NfcWorkerEventSuccess, nfc_worker->context); | ||||
|     } else { | ||||
|         nfc_worker->callback(NfcWorkerEventAborted, nfc_worker->context); | ||||
|  | ||||
| @ -14,8 +14,7 @@ typedef enum { | ||||
|     NfcWorkerStateUidEmulate, | ||||
|     NfcWorkerStateMfUltralightEmulate, | ||||
|     NfcWorkerStateMfClassicEmulate, | ||||
|     NfcWorkerStateMfClassicUserDictAttack, | ||||
|     NfcWorkerStateMfClassicFlipperDictAttack, | ||||
|     NfcWorkerStateMfClassicDictAttack, | ||||
|     // Debug
 | ||||
|     NfcWorkerStateEmulateApdu, | ||||
|     NfcWorkerStateField, | ||||
| @ -49,6 +48,7 @@ typedef enum { | ||||
|     // Mifare Classic events
 | ||||
|     NfcWorkerEventNoDictFound, | ||||
|     NfcWorkerEventNewSector, | ||||
|     NfcWorkerEventNewDictKeyBatch, | ||||
|     NfcWorkerEventFoundKeyA, | ||||
|     NfcWorkerEventFoundKeyB, | ||||
| } NfcWorkerEvent; | ||||
|  | ||||
| @ -13,7 +13,6 @@ | ||||
| #include <lib/nfc/protocols/mifare_desfire.h> | ||||
| #include <lib/nfc/protocols/nfca.h> | ||||
| 
 | ||||
| #include "helpers/mf_classic_dict.h" | ||||
| #include "helpers/nfc_debug_pcap.h" | ||||
| 
 | ||||
| struct NfcWorker { | ||||
| @ -43,6 +42,6 @@ void nfc_worker_emulate_mf_ultralight(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_emulate_mf_classic(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker, MfClassicDictType type); | ||||
| void nfc_worker_mf_classic_dict_attack(NfcWorker* nfc_worker); | ||||
| 
 | ||||
| void nfc_worker_emulate_apdu(NfcWorker* nfc_worker); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Fedor Indutny
						Fedor Indutny