mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-25 03:29:58 -07:00
FM11RF08S backdoor detection
This commit is contained in:
@@ -6,14 +6,16 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U)
|
||||
#define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U)
|
||||
#define MF_CLASSIC_CMD_READ_BLOCK (0x30U)
|
||||
#define MF_CLASSIC_CMD_WRITE_BLOCK (0xA0U)
|
||||
#define MF_CLASSIC_CMD_VALUE_DEC (0xC0U)
|
||||
#define MF_CLASSIC_CMD_VALUE_INC (0xC1U)
|
||||
#define MF_CLASSIC_CMD_VALUE_RESTORE (0xC2U)
|
||||
#define MF_CLASSIC_CMD_VALUE_TRANSFER (0xB0U)
|
||||
#define MF_CLASSIC_CMD_AUTH_KEY_A (0x60U)
|
||||
#define MF_CLASSIC_CMD_AUTH_KEY_B (0x61U)
|
||||
#define MF_CLASSIC_CMD_SE_BACKDOOR_AUTH_KEY_A (0x64U)
|
||||
#define MF_CLASSIC_CMD_SE_BACKDOOR_AUTH_KEY_B (0x65U)
|
||||
#define MF_CLASSIC_CMD_READ_BLOCK (0x30U)
|
||||
#define MF_CLASSIC_CMD_WRITE_BLOCK (0xA0U)
|
||||
#define MF_CLASSIC_CMD_VALUE_DEC (0xC0U)
|
||||
#define MF_CLASSIC_CMD_VALUE_INC (0xC1U)
|
||||
#define MF_CLASSIC_CMD_VALUE_RESTORE (0xC2U)
|
||||
#define MF_CLASSIC_CMD_VALUE_TRANSFER (0xB0U)
|
||||
|
||||
#define MF_CLASSIC_CMD_HALT_MSB (0x50)
|
||||
#define MF_CLASSIC_CMD_HALT_LSB (0x00)
|
||||
|
||||
@@ -891,32 +891,69 @@ NfcCommand mf_classic_poller_handler_nested_analyze_prng(MfClassicPoller* instan
|
||||
}
|
||||
|
||||
NfcCommand mf_classic_poller_handler_nested_analyze_backdoor(MfClassicPoller* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx;
|
||||
// TODO: Check for Fudan backdoor
|
||||
// Can use on more than S variant as a free key for Nested
|
||||
/*
|
||||
do {
|
||||
uint8_t auth_type = (key_type == MfClassicKeyTypeB) ? MF_CLASSIC_CMD_AUTH_KEY_B :
|
||||
MF_CLASSIC_CMD_AUTH_KEY_A;
|
||||
uint8_t auth_cmd[2] = {auth_type, block_num};
|
||||
bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd));
|
||||
NfcCommand command = NfcCommandReset;
|
||||
MfClassicPollerDictAttackContext* dict_attack_ctx = &instance->mode_ctx.dict_attack_ctx;
|
||||
|
||||
if(is_nested) {
|
||||
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
|
||||
crypto1_encrypt(
|
||||
instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
|
||||
error = iso14443_3a_poller_txrx_custom_parity(
|
||||
instance->iso14443_3a_poller,
|
||||
instance->tx_encrypted_buffer,
|
||||
instance->rx_plain_buffer, // NT gets decrypted by mf_classic_async_auth
|
||||
MF_CLASSIC_FWT_FC);
|
||||
if(error != Iso14443_3aErrorNone) {
|
||||
ret = mf_classic_process_error(error);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
dict_attack_ctx->backdoor = MfClassicBackdoorNone;
|
||||
uint8_t block = mf_classic_get_first_block_num_of_sector(dict_attack_ctx->reuse_key_sector);
|
||||
uint32_t cuid = iso14443_3a_get_cuid(instance->data->iso14443_3a_data);
|
||||
|
||||
MfClassicAuthContext auth_ctx = {};
|
||||
MfClassicNt nt = {};
|
||||
MfClassicKey fm11rf08s_backdoor_key = {.data = {0xa3, 0x96, 0xef, 0xa4, 0xe2, 0x4f}};
|
||||
MfClassicError error;
|
||||
Iso14443_3aError iso_error;
|
||||
bool backdoor_found = false;
|
||||
|
||||
do {
|
||||
// Step 1: Perform full authentication once
|
||||
error = mf_classic_poller_auth(
|
||||
instance,
|
||||
block,
|
||||
&dict_attack_ctx->current_key,
|
||||
dict_attack_ctx->current_key_type,
|
||||
&auth_ctx);
|
||||
|
||||
if(error != MfClassicErrorNone) {
|
||||
FURI_LOG_E(TAG, "Failed to perform full authentication");
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_E(TAG, "Full authentication successful");
|
||||
|
||||
// Step 2: Attempt backdoor authentication
|
||||
uint8_t auth_type = (dict_attack_ctx->current_key_type == MfClassicKeyTypeB) ?
|
||||
MF_CLASSIC_CMD_SE_BACKDOOR_AUTH_KEY_B :
|
||||
MF_CLASSIC_CMD_SE_BACKDOOR_AUTH_KEY_A;
|
||||
uint8_t auth_cmd[2] = {auth_type, block};
|
||||
bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd));
|
||||
iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer);
|
||||
crypto1_encrypt(
|
||||
instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer);
|
||||
iso_error = iso14443_3a_poller_txrx_custom_parity(
|
||||
instance->iso14443_3a_poller,
|
||||
instance->tx_encrypted_buffer,
|
||||
instance->rx_plain_buffer,
|
||||
MF_CLASSIC_FWT_FC);
|
||||
if(iso_error != Iso14443_3aErrorNone) {
|
||||
FURI_LOG_E(TAG, "Error during nested authentication");
|
||||
break;
|
||||
}
|
||||
if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) {
|
||||
break;
|
||||
}
|
||||
bit_buffer_write_bytes(instance->rx_plain_buffer, nt.data, sizeof(MfClassicNt));
|
||||
uint32_t nt_enc = bit_lib_bytes_to_num_be(nt.data, sizeof(MfClassicNt));
|
||||
// Ensure the encrypted nt can be generated by the backdoor
|
||||
uint32_t decrypted_nt_enc = decrypt_nt_enc(cuid, nt_enc, fm11rf08s_backdoor_key);
|
||||
backdoor_found = is_weak_prng_nonce(decrypted_nt_enc);
|
||||
} while(false);
|
||||
if(backdoor_found) {
|
||||
FURI_LOG_E(TAG, "Backdoor identified");
|
||||
dict_attack_ctx->backdoor = MfClassicBackdoorFM11RF08S;
|
||||
} else {
|
||||
dict_attack_ctx->backdoor = MfClassicBackdoorNone;
|
||||
}
|
||||
instance->state = MfClassicPollerStateNestedController;
|
||||
return command;
|
||||
}
|
||||
@@ -1041,6 +1078,7 @@ NfcCommand mf_classic_poller_handler_nested_calibrate(MfClassicPoller* instance)
|
||||
bool found = false;
|
||||
uint32_t decrypted_nt_enc =
|
||||
decrypt_nt_enc(cuid, nt_enc_temp_arr[collection_cycle], dict_attack_ctx->current_key);
|
||||
// TODO: Make sure we're not off-by-one here
|
||||
for(int i = 0; i < 65535; i++) {
|
||||
uint32_t nth_successor = prng_successor(nt_prev, i);
|
||||
if(nth_successor != decrypted_nt_enc) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "mf_classic_poller.h"
|
||||
#include <lib/nfc/protocols/iso14443_3a/iso14443_3a_poller_i.h>
|
||||
#include <bit_lib/bit_lib.h>
|
||||
#include "nfc/helpers/iso14443_crc.h"
|
||||
#include <nfc/helpers/crypto1.h>
|
||||
#include <stream/stream.h>
|
||||
#include <stream/buffered_file_stream.h>
|
||||
|
||||
Reference in New Issue
Block a user