Initial structure for UL-C dictionary attacks

This commit is contained in:
noproto
2024-10-28 19:56:28 -04:00
parent 3f34537b5b
commit 60e0a697fa
9 changed files with 330 additions and 11 deletions

View File

@@ -181,6 +181,10 @@ MfUltralightPoller* mf_ultralight_poller_alloc(Iso14443_3aPoller* iso14443_3a_po
instance->general_event.protocol = NfcProtocolMfUltralight;
instance->general_event.event_data = &instance->mfu_event;
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);
return instance;
}
@@ -521,7 +525,7 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
} else {
if(instance->data->type == MfUltralightTypeMfulC &&
!mf_ultralight_3des_key_valid(instance->data)) {
instance->state = MfUltralightPollerStateCheckMfulCAuthStatus;
instance->state = MfUltralightPollerStateDictAttack;
} else {
FURI_LOG_D(TAG, "Read page %d failed", instance->pages_read);
if(instance->pages_read) {
@@ -730,6 +734,63 @@ static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller*
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
mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = {
[MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle,
@@ -755,6 +816,7 @@ static const MfUltralightPollerReadHandler
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
[MfUltralightPollerStateDictAttack] = mf_ultralight_poller_handler_dict_attack,
};

View File

@@ -27,6 +27,7 @@ typedef enum {
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
MfUltralightPollerEventTypeRequestKey, /**< Poller requests key for dict attack. */
} MfUltralightPollerEventType;
/**
@@ -35,6 +36,7 @@ typedef enum {
typedef enum {
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
MfUltralightPollerModeDictAttack, /**< Poller will perform dictionary attack against card. */
} MfUltralightPollerMode;
/**
@@ -42,20 +44,29 @@ typedef enum {
*/
typedef struct {
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
MfUltralightC3DesAuthKey tdes_key;
MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */
MfUltralightC3DesAuthKey tdes_key; /**< 3DES key to be used for authentication. */
MfUltralightAuthPack pack; /**< Pack received on successful authentication. */
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
} MfUltralightPollerAuthContext;
/**
* @brief MfUltralight poller key request data.
*/
typedef struct {
MfUltralightC3DesAuthKey key; /**< Key to try. */
bool key_provided; /**< Set to true if key was provided, false to stop attack. */
} MfUltralightPollerKeyRequestData;
/**
* @brief MfUltralight poller event data.
*/
typedef union {
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
MfUltralightError error; /**< Error code indicating reading fail reason. */
const MfUltralightData* write_data;
MfUltralightPollerMode poller_mode;
const MfUltralightData* write_data; /**< Data to be written to card. */
MfUltralightPollerMode poller_mode; /**< Mode to operate in. */
MfUltralightPollerKeyRequestData key_request_data; /**< Key request data. */
} MfUltralightPollerEventData;
/**
@@ -64,7 +75,7 @@ typedef union {
* Upon emission of an event, an instance of this struct will be passed to the callback.
*/
typedef struct {
MfUltralightPollerEventType type; /**< Type of emmitted event. */
MfUltralightPollerEventType type; /**< Type of emitted event. */
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
} MfUltralightPollerEvent;

View File

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