mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-13 13:09:49 +04:00
bruteforce sfi 2-3 records 1-5
This commit is contained in:
@@ -28,7 +28,7 @@ const NfcDeviceBase nfc_device_emv = {
|
||||
EmvData* emv_alloc() {
|
||||
EmvData* data = malloc(sizeof(EmvData));
|
||||
data->iso14443_4a_data = iso14443_4a_alloc();
|
||||
data->emv_application.pin_attempts_counter = 0xff;
|
||||
data->emv_application.pin_try_counter = 0xff;
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -76,6 +76,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) {
|
||||
|
||||
EmvApplication* app = &data->emv_application;
|
||||
|
||||
flipper_format_read_string(ff, "Cardholder name", temp_str);
|
||||
strcpy(app->cardholder_name, furi_string_get_cstr(temp_str));
|
||||
|
||||
flipper_format_read_string(ff, "Application name", temp_str);
|
||||
strcpy(app->application_name, furi_string_get_cstr(temp_str));
|
||||
|
||||
@@ -107,9 +110,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) {
|
||||
if(!flipper_format_read_hex(ff, "Effective month", &app->effective_month, 1)) break;
|
||||
if(!flipper_format_read_hex(ff, "Effective day", &app->effective_day, 1)) break;
|
||||
|
||||
uint32_t pin_attempts_counter;
|
||||
if(!flipper_format_read_uint32(ff, "PIN attempts left", &pin_attempts_counter, 1)) break;
|
||||
app->pin_attempts_counter = pin_attempts_counter;
|
||||
uint32_t pin_try_counter;
|
||||
if(!flipper_format_read_uint32(ff, "PIN try counter", &pin_try_counter, 1)) break;
|
||||
app->pin_try_counter = pin_try_counter;
|
||||
|
||||
parsed = true;
|
||||
} while(false);
|
||||
@@ -131,6 +134,8 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) {
|
||||
|
||||
if(!flipper_format_write_comment_cstr(ff, "EMV specific data:\n")) break;
|
||||
|
||||
if(!flipper_format_write_string_cstr(ff, "Cardholder name", app.cardholder_name)) break;
|
||||
|
||||
if(!flipper_format_write_string_cstr(ff, "Application name", app.application_name)) break;
|
||||
|
||||
if(!flipper_format_write_string_cstr(ff, "Application label", app.application_label))
|
||||
@@ -160,8 +165,7 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) {
|
||||
break;
|
||||
if(!flipper_format_write_hex(ff, "Effective day", (uint8_t*)&app.effective_day, 1)) break;
|
||||
|
||||
if(!flipper_format_write_uint32(
|
||||
ff, "PIN attempts left", (uint32_t*)&app.pin_attempts_counter, 1))
|
||||
if(!flipper_format_write_uint32(ff, "PIN try counter", (uint32_t*)&app.pin_try_counter, 1))
|
||||
break;
|
||||
|
||||
saved = true;
|
||||
|
||||
@@ -16,7 +16,7 @@ extern "C" {
|
||||
#define EMV_TAG_APPL_LABEL 0x50
|
||||
#define EMV_TAG_APPL_NAME 0x9F12
|
||||
#define EMV_TAG_APPL_EFFECTIVE 0x5F25
|
||||
#define EMV_TAG_PIN_ATTEMPTS_COUNTER 0x9F17
|
||||
#define EMV_TAG_PIN_TRY_COUNTER 0x9F17
|
||||
#define EMV_TAG_LOG_ENTRY 0x9F4D
|
||||
#define EMV_TAG_LOG_FMT 0x9F4F
|
||||
|
||||
@@ -36,6 +36,7 @@ extern "C" {
|
||||
#define EMV_TAG_COUNTRY_CODE 0x5F28
|
||||
#define EMV_TAG_CURRENCY_CODE 0x9F42
|
||||
#define EMV_TAG_CARDHOLDER_NAME 0x5F20
|
||||
#define EMV_TAG_CARDHOLDER_NAME_EXTENDED 0x9F0B
|
||||
#define EMV_TAG_TRACK_2_DATA 0x9F6B
|
||||
#define EMV_TAG_GPO_FMT1 0x80
|
||||
|
||||
@@ -91,7 +92,7 @@ typedef struct {
|
||||
uint8_t effective_year;
|
||||
uint16_t country_code;
|
||||
uint16_t currency_code;
|
||||
uint8_t pin_attempts_counter;
|
||||
uint8_t pin_try_counter;
|
||||
uint16_t transaction_counter;
|
||||
uint16_t last_online_atc;
|
||||
APDU pdol;
|
||||
|
||||
@@ -108,7 +108,7 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) {
|
||||
|
||||
static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) {
|
||||
emv_poller_get_last_online_atc(instance);
|
||||
emv_poller_get_pin_attempts_counter(instance);
|
||||
emv_poller_get_pin_try_counter(instance);
|
||||
|
||||
instance->state = EmvPollerStateReadSuccess;
|
||||
return NfcCommandContinue;
|
||||
|
||||
@@ -50,7 +50,7 @@ EmvError emv_poller_read_afl(EmvPoller* instance);
|
||||
|
||||
EmvError emv_poller_read_log_entry(EmvPoller* instance);
|
||||
|
||||
EmvError emv_poller_get_pin_attempts_counter(EmvPoller* instance);
|
||||
EmvError emv_poller_get_pin_try_counter(EmvPoller* instance);
|
||||
|
||||
EmvError emv_poller_get_last_online_atc(EmvPoller* instance);
|
||||
|
||||
|
||||
@@ -193,6 +193,14 @@ static bool
|
||||
if(strlen(app->cardholder_name) > tlen) break;
|
||||
memcpy(app->cardholder_name, &buff[i], tlen);
|
||||
app->cardholder_name[tlen] = '\0';
|
||||
|
||||
// use space char as terminator
|
||||
for(size_t i = 0; i < tlen; i++)
|
||||
if(app->cardholder_name[i] == 0x20) {
|
||||
app->cardholder_name[i] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
success = true;
|
||||
FURI_LOG_T(TAG, "found EMV_TAG_CARDHOLDER_NAME %x: %s", tag, app->cardholder_name);
|
||||
break;
|
||||
@@ -262,11 +270,10 @@ static bool
|
||||
memcpy(&app->trans[app->active_tr].time, &buff[i], tlen);
|
||||
success = true;
|
||||
break;
|
||||
case EMV_TAG_PIN_ATTEMPTS_COUNTER:
|
||||
app->pin_attempts_counter = buff[i];
|
||||
case EMV_TAG_PIN_TRY_COUNTER:
|
||||
app->pin_try_counter = buff[i];
|
||||
success = true;
|
||||
FURI_LOG_T(
|
||||
TAG, "found EMV_TAG_PIN_ATTEMPTS_COUNTER %x: %d", tag, app->pin_attempts_counter);
|
||||
FURI_LOG_T(TAG, "found EMV_TAG_PIN_TRY_COUNTER %x: %d", tag, app->pin_try_counter);
|
||||
break;
|
||||
}
|
||||
return success;
|
||||
@@ -615,6 +622,8 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
|
||||
|
||||
FURI_LOG_D(TAG, "Search PAN in SFI");
|
||||
|
||||
bool pan_fetched = (instance->data->emv_application.pan_len);
|
||||
|
||||
// Iterate through all files
|
||||
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
|
||||
uint8_t sfi = afl->data[i] >> 3;
|
||||
@@ -633,15 +642,32 @@ EmvError emv_poller_read_afl(EmvPoller* instance) {
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
}
|
||||
|
||||
// Some READ RECORD returns 1 byte response 0x12/0x13 (IDK WTF),
|
||||
// then poller return Timeout to all subsequent requests.
|
||||
// TODO: remove below lines when it was fixed
|
||||
if(instance->data->emv_application.pan_len != 0)
|
||||
return EmvErrorNone; // Card number fetched
|
||||
if(instance->data->emv_application.pan_len) pan_fetched = true; // Card number fetched
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
// Bruteforse files 2-3
|
||||
FURI_LOG_T(TAG, "Bruteforce files 2-3");
|
||||
for(size_t sfi = 2; sfi <= 3; sfi++) {
|
||||
// Iterate through records 1-5 in file
|
||||
for(size_t record = 1; record <= 5; record++) {
|
||||
if(strlen(instance->data->emv_application.cardholder_name)) return EmvErrorNone;
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pan_fetched)
|
||||
return EmvErrorNone;
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) {
|
||||
@@ -684,8 +710,8 @@ static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) {
|
||||
return error;
|
||||
}
|
||||
|
||||
EmvError emv_poller_get_pin_attempts_counter(EmvPoller* instance) {
|
||||
return emv_poller_req_get_data(instance, EMV_TAG_PIN_ATTEMPTS_COUNTER);
|
||||
EmvError emv_poller_get_pin_try_counter(EmvPoller* instance) {
|
||||
return emv_poller_req_get_data(instance, EMV_TAG_PIN_TRY_COUNTER);
|
||||
}
|
||||
|
||||
EmvError emv_poller_get_last_online_atc(EmvPoller* instance) {
|
||||
|
||||
Reference in New Issue
Block a user