mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Merge branch 'master' into master
Signed-off-by: Angel <jeremy_1996@hotmail.com>
This commit is contained in:
commit
2adfc928fc
36 changed files with 724 additions and 269 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -3,6 +3,10 @@ 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...
|
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]
|
## [unreleased][unreleased]
|
||||||
|
- Fixed truncated FPGA upload due to incorrect integer size variable (@d18c7db)
|
||||||
|
- Changed `usart btfactory` - handles the new BT board with version "BT SPP V3.0" (@iceman1001)
|
||||||
|
- Changed `hf mf eview --sk` - now can extract keys and save to file (@iceman1001)
|
||||||
|
- Changed `hf mf view --sk` - now can extract keys and save to file (@iceman1001)
|
||||||
- Changed `hf mf sim` - reduce 6ms threshold to 4ms for reset to idle #1974 (@net147)
|
- Changed `hf mf sim` - reduce 6ms threshold to 4ms for reset to idle #1974 (@net147)
|
||||||
- Rebuilt the Spartan-2 `fpga_*.bit` files to include the `hi_iso14443a.v` update (@d18c7db)
|
- Rebuilt the Spartan-2 `fpga_*.bit` files to include the `hi_iso14443a.v` update (@d18c7db)
|
||||||
- Added minor orphaned change from `hi_iso14443a.v` in `fpga-xc3s100e` to `hi_iso14443a.v` in `fpga-xc2s30` (@d18c7db)
|
- Added minor orphaned change from `hi_iso14443a.v` in `fpga-xc3s100e` to `hi_iso14443a.v` in `fpga-xc2s30` (@d18c7db)
|
||||||
|
@ -22,7 +26,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
|
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
|
||||||
- Added iClass credit key to default iClass key table and reorganized key order (@GuruSteve)
|
- Added iClass credit key to default iClass key table and reorganized key order (@GuruSteve)
|
||||||
- Changed `hf mf value` - ability to use transfer on different block (@AloneLiberty)
|
- Changed `hf mf value` - ability to use transfer on different block (@AloneLiberty)
|
||||||
- Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
|
- Changed `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
|
||||||
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
|
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
|
||||||
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)
|
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)
|
||||||
- Changed magic note to include a section about GDM tags (@iceman1001)
|
- Changed magic note to include a section about GDM tags (@iceman1001)
|
||||||
|
@ -62,13 +66,14 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added `hf legic info` command for other sources (@0xdeb)
|
- Added `hf legic info` command for other sources (@0xdeb)
|
||||||
- Added `hf legic einfo` - views emulator menory (@0xdeb)
|
- Added `hf legic einfo` - views emulator menory (@0xdeb)
|
||||||
- Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb)
|
- Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb)
|
||||||
- Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120)
|
- Changed `script run hf_mf_ultimatecard.lua -u` to support 10bytes UID (@alejandro12120)
|
||||||
- Update documentation for installation on macOS with MacPorts (@linuxgemini)
|
- Updated documentation for installation on macOS with MacPorts (@linuxgemini)
|
||||||
- Added possible Paxton id to hitag2 tag info output
|
- Added possible Paxton id to hitag2 tag info output
|
||||||
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
|
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
|
||||||
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
|
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
|
||||||
- Added `lf paradox sim --fc --cn` - Simulates Paradox fob from facility code and card number (jerji)
|
- Added `lf paradox sim --fc --cn` - Simulates Paradox fob from facility code and card number (jerji)
|
||||||
|
|
||||||
|
|
||||||
## [Nitride.4.16191][2023-01-29]
|
## [Nitride.4.16191][2023-01-29]
|
||||||
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)
|
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)
|
||||||
- Fixed some coverity fixes (@iceman1001)
|
- Fixed some coverity fixes (@iceman1001)
|
||||||
|
|
|
@ -77,7 +77,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(findstring WITH_EM4x50,$(APP_CFLAGS)))
|
ifneq (,$(findstring WITH_EM4x50,$(APP_CFLAGS)))
|
||||||
SRC_EM4x50 = em4x50.c
|
SRC_EM4x50 = em4x50.c bruteforce.c
|
||||||
else
|
else
|
||||||
SRC_EM4x50 =
|
SRC_EM4x50 =
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -2014,11 +2014,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
uint32_t waittime;
|
uint32_t waittime;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) &packet->data.asBytes;
|
struct p *payload = (struct p *) &packet->data.asBytes;
|
||||||
|
|
||||||
uint16_t available;
|
uint16_t available;
|
||||||
uint16_t pre_available = 0;
|
uint16_t pre_available = 0;
|
||||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||||
uint32_t wait = payload->waittime;
|
uint32_t wait = payload->waittime;
|
||||||
|
|
||||||
|
StartTicks();
|
||||||
|
|
||||||
uint32_t ti = GetTickCount();
|
uint32_t ti = GetTickCount();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
WaitMS(50);
|
WaitMS(50);
|
||||||
available = usart_rxdata_available();
|
available = usart_rxdata_available();
|
||||||
|
@ -2039,6 +2044,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
} else {
|
} else {
|
||||||
reply_ng(CMD_USART_RX, PM3_ENODATA, NULL, 0);
|
reply_ng(CMD_USART_RX, PM3_ENODATA, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StopTicks();
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
LED_B_OFF();
|
LED_B_OFF();
|
||||||
break;
|
break;
|
||||||
|
@ -2051,11 +2058,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct p *payload = (struct p *) &packet->data.asBytes;
|
struct p *payload = (struct p *) &packet->data.asBytes;
|
||||||
usart_writebuffer_sync(payload->data, packet->length - sizeof(payload));
|
usart_writebuffer_sync(payload->data, packet->length - sizeof(payload));
|
||||||
|
|
||||||
uint16_t available;
|
uint16_t available;
|
||||||
uint16_t pre_available = 0;
|
uint16_t pre_available = 0;
|
||||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||||
uint32_t wait = payload->waittime;
|
uint32_t wait = payload->waittime;
|
||||||
|
|
||||||
|
StartTicks();
|
||||||
|
|
||||||
uint32_t ti = GetTickCount();
|
uint32_t ti = GetTickCount();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
WaitMS(50);
|
WaitMS(50);
|
||||||
available = usart_rxdata_available();
|
available = usart_rxdata_available();
|
||||||
|
@ -2070,12 +2082,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
if (GetTickCountDelta(ti) > wait)
|
if (GetTickCountDelta(ti) > wait)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available > 0) {
|
if (available > 0) {
|
||||||
uint16_t len = usart_read_ng(dest, available);
|
uint16_t len = usart_read_ng(dest, available);
|
||||||
reply_ng(CMD_USART_TXRX, PM3_SUCCESS, dest, len);
|
reply_ng(CMD_USART_TXRX, PM3_SUCCESS, dest, len);
|
||||||
} else {
|
} else {
|
||||||
reply_ng(CMD_USART_TXRX, PM3_ENODATA, NULL, 0);
|
reply_ng(CMD_USART_TXRX, PM3_ENODATA, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StopTicks();
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
LED_B_OFF();
|
LED_B_OFF();
|
||||||
break;
|
break;
|
||||||
|
@ -2718,9 +2733,6 @@ void __attribute__((noreturn)) AppMain(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_FPC_USART
|
|
||||||
usart_init(USART_BAUD_RATE, USART_PARITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WITH_FLASH
|
#ifdef WITH_FLASH
|
||||||
// If flash is not present, BUSY_TIMEOUT kicks in, let's do it after USB
|
// If flash is not present, BUSY_TIMEOUT kicks in, let's do it after USB
|
||||||
|
@ -2733,6 +2745,10 @@ void __attribute__((noreturn)) AppMain(void) {
|
||||||
rdv40_spiffs_check();
|
rdv40_spiffs_check();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_FPC_USART
|
||||||
|
usart_init(USART_BAUD_RATE, USART_PARITY);
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is made as late as possible to ensure enumeration without timeout
|
// This is made as late as possible to ensure enumeration without timeout
|
||||||
// against device such as http://www.hobbytronics.co.uk/usb-host-board-v2
|
// against device such as http://www.hobbytronics.co.uk/usb-host-board-v2
|
||||||
// In other words, keep the interval between usb_enable() and the main loop as short as possible.
|
// In other words, keep the interval between usb_enable() and the main loop as short as possible.
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "BigBuf.h"
|
#include "BigBuf.h"
|
||||||
#include "spiffs.h"
|
#include "spiffs.h"
|
||||||
#include "appmain.h" // tear
|
#include "appmain.h" // tear
|
||||||
|
#include "bruteforce.h"
|
||||||
|
|
||||||
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
|
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
|
||||||
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
|
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
|
||||||
|
@ -632,12 +633,21 @@ static int login(uint32_t password) {
|
||||||
return PM3_EFAILED;
|
return PM3_EFAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// searching for password in given range
|
// searching for password using chosen bruteforce algorithm
|
||||||
static bool brute(uint32_t start, uint32_t stop, uint32_t *pwd) {
|
static bool brute(em4x50_data_t *etd, uint32_t *pwd) {
|
||||||
|
|
||||||
|
generator_context_t ctx;
|
||||||
bool pwd_found = false;
|
bool pwd_found = false;
|
||||||
|
int generator_ret = 0;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
|
||||||
for (*pwd = start; *pwd <= stop; (*pwd)++) {
|
bf_generator_init(&ctx, etd->bruteforce_mode);
|
||||||
|
|
||||||
|
if (etd->bruteforce_mode == BRUTEFORCE_MODE_CHARSET)
|
||||||
|
bf_generator_set_charset(&ctx, etd->bruteforce_charset);
|
||||||
|
|
||||||
|
while ((generator_ret = bf_generate32(&ctx)) == GENERATOR_NEXT) {
|
||||||
|
*pwd = ctx.current_key32;
|
||||||
|
|
||||||
WDT_HIT();
|
WDT_HIT();
|
||||||
|
|
||||||
|
@ -702,7 +712,7 @@ void em4x50_login(uint32_t *password, bool ledcontrol) {
|
||||||
reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0);
|
reply_ng(CMD_LF_EM4X50_LOGIN, status, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// envoke password search
|
// invoke password search
|
||||||
void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
|
void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
|
||||||
em4x50_setup_read();
|
em4x50_setup_read();
|
||||||
|
|
||||||
|
@ -714,7 +724,7 @@ void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
|
||||||
LED_C_OFF();
|
LED_C_OFF();
|
||||||
LED_D_ON();
|
LED_D_ON();
|
||||||
}
|
}
|
||||||
bsuccess = brute(etd->password1, etd->password2, &pwd);
|
bsuccess = brute(etd, &pwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ledcontrol) LEDsoff();
|
if (ledcontrol) LEDsoff();
|
||||||
|
|
|
@ -393,7 +393,7 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
||||||
while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
|
while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
|
||||||
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||||
numbytes++;
|
numbytes++;
|
||||||
uint16_t current_length = 0;
|
uint32_t current_length = 0;
|
||||||
if (current_name < 'a' || current_name > 'e') {
|
if (current_name < 'a' || current_name > 'e') {
|
||||||
/* Strange section name, abort */
|
/* Strange section name, abort */
|
||||||
break;
|
break;
|
||||||
|
@ -423,7 +423,7 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
|
for (uint32_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
|
||||||
get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||||
numbytes++;
|
numbytes++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,8 @@ void usart_close(void) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint8_t us_inbuf1[USART_BUFFLEN];
|
static uint8_t us_in_a[USART_BUFFLEN];
|
||||||
static uint8_t us_inbuf2[USART_BUFFLEN];
|
static uint8_t us_in_b[USART_BUFFLEN];
|
||||||
static uint8_t *usart_cur_inbuf = NULL;
|
static uint8_t *usart_cur_inbuf = NULL;
|
||||||
static uint16_t usart_cur_inbuf_off = 0;
|
static uint16_t usart_cur_inbuf_off = 0;
|
||||||
static uint8_t us_rxfifo[USART_FIFOLEN];
|
static uint8_t us_rxfifo[USART_FIFOLEN];
|
||||||
|
@ -56,7 +56,9 @@ static size_t us_rxfifo_high = 0;
|
||||||
|
|
||||||
|
|
||||||
static void usart_fill_rxfifo(void) {
|
static void usart_fill_rxfifo(void) {
|
||||||
uint16_t rxfifo_free ;
|
|
||||||
|
uint16_t rxfifo_free = 0;
|
||||||
|
|
||||||
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
||||||
|
|
||||||
if (us_rxfifo_low > us_rxfifo_high)
|
if (us_rxfifo_low > us_rxfifo_high)
|
||||||
|
@ -79,19 +81,22 @@ static void usart_fill_rxfifo(void) {
|
||||||
pUS1->US_RNCR = USART_BUFFLEN;
|
pUS1->US_RNCR = USART_BUFFLEN;
|
||||||
|
|
||||||
// Swap current buff
|
// Swap current buff
|
||||||
if (usart_cur_inbuf == us_inbuf1)
|
if (usart_cur_inbuf == us_in_a)
|
||||||
usart_cur_inbuf = us_inbuf2;
|
usart_cur_inbuf = us_in_b;
|
||||||
else
|
else
|
||||||
usart_cur_inbuf = us_inbuf1;
|
usart_cur_inbuf = us_in_a;
|
||||||
|
|
||||||
usart_cur_inbuf_off = 0;
|
usart_cur_inbuf_off = 0;
|
||||||
} else {
|
} else {
|
||||||
// Take only what we have room for
|
// Take only what we have room for
|
||||||
available = rxfifo_free;
|
available = rxfifo_free;
|
||||||
for (uint16_t i = 0; i < available; i++) {
|
for (uint16_t i = 0; i < available; i++) {
|
||||||
|
|
||||||
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
||||||
if (us_rxfifo_high == sizeof(us_rxfifo))
|
|
||||||
|
if (us_rxfifo_high == sizeof(us_rxfifo)) {
|
||||||
us_rxfifo_high = 0;
|
us_rxfifo_high = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
usart_cur_inbuf_off += available;
|
usart_cur_inbuf_off += available;
|
||||||
return;
|
return;
|
||||||
|
@ -101,18 +106,20 @@ static void usart_fill_rxfifo(void) {
|
||||||
if (pUS1->US_RCR < USART_BUFFLEN - usart_cur_inbuf_off) { // Current buffer partially filled
|
if (pUS1->US_RCR < USART_BUFFLEN - usart_cur_inbuf_off) { // Current buffer partially filled
|
||||||
|
|
||||||
if (us_rxfifo_low > us_rxfifo_high)
|
if (us_rxfifo_low > us_rxfifo_high)
|
||||||
rxfifo_free = us_rxfifo_low - us_rxfifo_high;
|
rxfifo_free = (us_rxfifo_low - us_rxfifo_high);
|
||||||
else
|
else
|
||||||
rxfifo_free = sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low;
|
rxfifo_free = (sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low);
|
||||||
|
|
||||||
uint16_t available = USART_BUFFLEN - pUS1->US_RCR - usart_cur_inbuf_off;
|
uint16_t available = (USART_BUFFLEN - pUS1->US_RCR - usart_cur_inbuf_off);
|
||||||
|
|
||||||
if (available > rxfifo_free)
|
if (available > rxfifo_free)
|
||||||
available = rxfifo_free;
|
available = rxfifo_free;
|
||||||
|
|
||||||
for (uint16_t i = 0; i < available; i++) {
|
for (uint16_t i = 0; i < available; i++) {
|
||||||
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
||||||
if (us_rxfifo_high == sizeof(us_rxfifo))
|
if (us_rxfifo_high == sizeof(us_rxfifo)) {
|
||||||
us_rxfifo_high = 0;
|
us_rxfifo_high = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
usart_cur_inbuf_off += available;
|
usart_cur_inbuf_off += available;
|
||||||
}
|
}
|
||||||
|
@ -121,9 +128,9 @@ static void usart_fill_rxfifo(void) {
|
||||||
uint16_t usart_rxdata_available(void) {
|
uint16_t usart_rxdata_available(void) {
|
||||||
usart_fill_rxfifo();
|
usart_fill_rxfifo();
|
||||||
if (us_rxfifo_low <= us_rxfifo_high)
|
if (us_rxfifo_low <= us_rxfifo_high)
|
||||||
return us_rxfifo_high - us_rxfifo_low;
|
return (us_rxfifo_high - us_rxfifo_low);
|
||||||
else
|
else
|
||||||
return sizeof(us_rxfifo) - us_rxfifo_low + us_rxfifo_high;
|
return (sizeof(us_rxfifo) - us_rxfifo_low + us_rxfifo_high);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
||||||
|
@ -143,9 +150,10 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
||||||
uint32_t maxtry = 10 * (3000000 / USART_BAUD_RATE) + tryconstant;
|
uint32_t maxtry = 10 * (3000000 / USART_BAUD_RATE) + tryconstant;
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
uint32_t available = usart_rxdata_available();
|
|
||||||
|
|
||||||
|
uint32_t available = usart_rxdata_available();
|
||||||
uint32_t packetSize = MIN(available, len);
|
uint32_t packetSize = MIN(available, len);
|
||||||
|
|
||||||
if (available > 0) {
|
if (available > 0) {
|
||||||
// Dbprintf_usb("Dbg USART ask %d bytes, available %d bytes, packetsize %d bytes", len, available, packetSize);
|
// Dbprintf_usb("Dbg USART ask %d bytes, available %d bytes, packetsize %d bytes", len, available, packetSize);
|
||||||
// highest_observed_try = MAX(highest_observed_try, try);
|
// highest_observed_try = MAX(highest_observed_try, try);
|
||||||
|
@ -153,8 +161,9 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
||||||
}
|
}
|
||||||
len -= packetSize;
|
len -= packetSize;
|
||||||
while (packetSize--) {
|
while (packetSize--) {
|
||||||
if (us_rxfifo_low == sizeof(us_rxfifo))
|
if (us_rxfifo_low == sizeof(us_rxfifo)) {
|
||||||
us_rxfifo_low = 0;
|
us_rxfifo_low = 0;
|
||||||
|
}
|
||||||
data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++];
|
data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++];
|
||||||
}
|
}
|
||||||
if (try++ == maxtry) {
|
if (try++ == maxtry) {
|
||||||
|
@ -183,10 +192,13 @@ int usart_writebuffer_sync(uint8_t *data, size_t len) {
|
||||||
|
|
||||||
void usart_init(uint32_t baudrate, uint8_t parity) {
|
void usart_init(uint32_t baudrate, uint8_t parity) {
|
||||||
|
|
||||||
if (baudrate != 0)
|
if (baudrate != 0) {
|
||||||
g_usart_baudrate = baudrate;
|
g_usart_baudrate = baudrate;
|
||||||
if ((parity == 'N') || (parity == 'O') || (parity == 'E'))
|
}
|
||||||
|
|
||||||
|
if ((parity == 'N') || (parity == 'O') || (parity == 'E')) {
|
||||||
g_usart_parity = parity;
|
g_usart_parity = parity;
|
||||||
|
}
|
||||||
|
|
||||||
// For a nice detailed sample, interrupt driven but still relevant.
|
// For a nice detailed sample, interrupt driven but still relevant.
|
||||||
// See https://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf
|
// See https://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf
|
||||||
|
@ -262,11 +274,11 @@ void usart_init(uint32_t baudrate, uint8_t parity) {
|
||||||
pUS1->US_TCR = 0;
|
pUS1->US_TCR = 0;
|
||||||
pUS1->US_TNPR = (uint32_t)0;
|
pUS1->US_TNPR = (uint32_t)0;
|
||||||
pUS1->US_TNCR = 0;
|
pUS1->US_TNCR = 0;
|
||||||
pUS1->US_RPR = (uint32_t)us_inbuf1;
|
pUS1->US_RPR = (uint32_t)us_in_a;
|
||||||
pUS1->US_RCR = USART_BUFFLEN;
|
pUS1->US_RCR = USART_BUFFLEN;
|
||||||
usart_cur_inbuf = us_inbuf1;
|
usart_cur_inbuf = us_in_a;
|
||||||
usart_cur_inbuf_off = 0;
|
usart_cur_inbuf_off = 0;
|
||||||
pUS1->US_RNPR = (uint32_t)us_inbuf2;
|
pUS1->US_RNPR = (uint32_t)us_in_b;
|
||||||
pUS1->US_RNCR = USART_BUFFLEN;
|
pUS1->US_RNCR = USART_BUFFLEN;
|
||||||
|
|
||||||
// Initialize our fifo
|
// Initialize our fifo
|
||||||
|
|
|
@ -586,6 +586,17 @@ if (MINGW)
|
||||||
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
|
# GCC 10 has issues with false positives on stringop-overflow,
|
||||||
|
# let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||||
|
# beware these flags didn't exist for GCC < 7
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
if (GCC_VERSION VERSION_GREATER 10.0 OR GCC_VERSION VERSION_EQUAL 10.0)
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_C_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_CXX_FLAGS}")
|
||||||
|
endif()
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
|
||||||
# link Winsock2
|
# link Winsock2
|
||||||
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
|
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
|
||||||
endif (MINGW)
|
endif (MINGW)
|
||||||
|
|
|
@ -182,7 +182,7 @@ crack_states_thread(void *x) {
|
||||||
} else {
|
} else {
|
||||||
if (!thread_arg->silent) {
|
if (!thread_arg->silent) {
|
||||||
char progress_text[80];
|
char progress_text[80];
|
||||||
snprintf(progress_text, sizeof(progress_text), "Brute force phase: %6.02f%%\t", 100.0 * (float)num_keys_tested / (float)(thread_arg->maximum_states));
|
snprintf(progress_text, sizeof(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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,19 @@ A5A4A3A2A1A0
|
||||||
# MAD access key B
|
# MAD access key B
|
||||||
89ECA97F8C2A
|
89ECA97F8C2A
|
||||||
#
|
#
|
||||||
|
# Mifare 1k EV1 (S50) hidden blocks, Signature data
|
||||||
|
# 16 A
|
||||||
|
5C8FF9990DA2
|
||||||
|
#
|
||||||
|
# 17 A
|
||||||
|
75CCB59C9BED
|
||||||
|
#
|
||||||
|
# 16 B
|
||||||
|
D01AFEEB890A
|
||||||
|
#
|
||||||
|
# 17 B
|
||||||
|
4B791BEA7BCC
|
||||||
|
#
|
||||||
#
|
#
|
||||||
B0B1B2B3B4B5
|
B0B1B2B3B4B5
|
||||||
C0C1C2C3C4C5
|
C0C1C2C3C4C5
|
||||||
|
@ -111,7 +124,7 @@ F1D83F964314
|
||||||
# Access control system
|
# Access control system
|
||||||
605F5E5D5C5B
|
605F5E5D5C5B
|
||||||
#
|
#
|
||||||
#NSP Global keys A and B (uk housing access control)
|
# NSP Global keys A and B (uk housing access control)
|
||||||
199404281970
|
199404281970
|
||||||
199404281998
|
199404281998
|
||||||
#
|
#
|
||||||
|
@ -263,16 +276,25 @@ E3429281EFC1
|
||||||
460722122510
|
460722122510
|
||||||
#
|
#
|
||||||
# 3dprinter
|
# 3dprinter
|
||||||
# EPI Envisionte# 3dprinter
|
# EPI Envisionte
|
||||||
AAFB06045877
|
AAFB06045877
|
||||||
#
|
#
|
||||||
# gym
|
# gym
|
||||||
|
#
|
||||||
# Fysiken A
|
# Fysiken A
|
||||||
3E65E4FB65B3
|
3E65E4FB65B3
|
||||||
#
|
#
|
||||||
# Fysiken B
|
# Fysiken B
|
||||||
25094DF6F148
|
25094DF6F148
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# https://mattionline.de/fitnessstudio-armband-reverse-engineering/
|
||||||
|
# https://mattionline.de/milazycracker/
|
||||||
|
# gym wistband A, same as Fysiken A
|
||||||
|
# gym wistband B
|
||||||
|
81CC25EBBB6A
|
||||||
|
195DC63DB3A3
|
||||||
|
#
|
||||||
# CleverFit
|
# CleverFit
|
||||||
A05DBD98E0FC
|
A05DBD98E0FC
|
||||||
#
|
#
|
||||||
|
@ -280,6 +302,10 @@ A05DBD98E0FC
|
||||||
AA4DDA458EBB
|
AA4DDA458EBB
|
||||||
EAB8066C7479
|
EAB8066C7479
|
||||||
#
|
#
|
||||||
|
# Nordic Wellness A, same as Fysiken A
|
||||||
|
# Nordic Wellness B
|
||||||
|
E5519E1CC92B
|
||||||
|
#
|
||||||
# Hotel KeyCard
|
# Hotel KeyCard
|
||||||
D3B595E9DD63
|
D3B595E9DD63
|
||||||
AFBECD121004
|
AFBECD121004
|
||||||
|
@ -626,19 +652,6 @@ A8844B0BCA06
|
||||||
564C505F4D41
|
564C505F4D41
|
||||||
BA5B895DA162
|
BA5B895DA162
|
||||||
#
|
#
|
||||||
# Vigik mystery Keys Mifare 1k EV1 (S50)
|
|
||||||
# 16 A
|
|
||||||
5C8FF9990DA2
|
|
||||||
#
|
|
||||||
# 17 A
|
|
||||||
75CCB59C9BED
|
|
||||||
#
|
|
||||||
# 16 B
|
|
||||||
D01AFEEB890A
|
|
||||||
#
|
|
||||||
# 17 B
|
|
||||||
4B791BEA7BCC
|
|
||||||
#
|
|
||||||
# BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
|
# BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
|
||||||
021209197591
|
021209197591
|
||||||
#
|
#
|
||||||
|
|
|
@ -585,6 +585,18 @@ if (MINGW)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
|
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
|
# GCC 10 has issues with false positives on stringop-overflow,
|
||||||
|
# let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||||
|
# beware these flags didn't exist for GCC < 7
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||||
|
if (GCC_VERSION VERSION_GREATER 10.0 OR GCC_VERSION VERSION_EQUAL 10.0)
|
||||||
|
set(CMAKE_C_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_C_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_CXX_FLAGS}")
|
||||||
|
endif()
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
|
||||||
endif (MINGW)
|
endif (MINGW)
|
||||||
|
|
||||||
target_include_directories(pm3rrg_rdv4 PRIVATE
|
target_include_directories(pm3rrg_rdv4 PRIVATE
|
||||||
|
|
|
@ -367,5 +367,21 @@
|
||||||
"Name": "University of Ljubljana Student ID",
|
"Name": "University of Ljubljana Student ID",
|
||||||
"Description": "",
|
"Description": "",
|
||||||
"Type": "student"
|
"Type": "student"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "27E178",
|
||||||
|
"Vendor": "Disney",
|
||||||
|
"Country": "US",
|
||||||
|
"Name": "Disney MagicBand",
|
||||||
|
"Description": "",
|
||||||
|
"Type": "payment system"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AID": "44434C",
|
||||||
|
"Vendor": "Disney",
|
||||||
|
"Country": "US",
|
||||||
|
"Name": "Disney MagicBand",
|
||||||
|
"Description": "AID found on MagicBand desfire cards",
|
||||||
|
"Type": "payment system"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -531,7 +531,7 @@ static int CmdFlashMemSpiFFSView(const char *Cmd) {
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("f", "file", "<fn>", "SPIFFS file to view"),
|
arg_str1("f", "file", "<fn>", "SPIFFS file to view"),
|
||||||
arg_int0("c", "cols", "<dec>", "column breaks (def 32)"),
|
arg_int0("c", "cols", "<dec>", "column breaks (def 16)"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -540,7 +540,7 @@ static int CmdFlashMemSpiFFSView(const char *Cmd) {
|
||||||
char fn[32] = {0};
|
char fn[32] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)fn, 32, &fnlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)fn, 32, &fnlen);
|
||||||
|
|
||||||
int breaks = arg_get_int_def(ctx, 2, 32);
|
int breaks = arg_get_int_def(ctx, 2, 16);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t *dump = NULL;
|
uint8_t *dump = NULL;
|
||||||
|
|
|
@ -308,7 +308,6 @@ static int mf_print_keys(uint16_t n, uint8_t *d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint16_t i = 0; i < n; i++) {
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
|
||||||
if (mfIsSectorTrailer(i)) {
|
if (mfIsSectorTrailer(i)) {
|
||||||
e_sector[mfSectorNum(i)].foundKey[0] = 1;
|
e_sector[mfSectorNum(i)].foundKey[0] = 1;
|
||||||
e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE);
|
e_sector[mfSectorNum(i)].Key[0] = bytes_to_num(d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE);
|
||||||
|
@ -321,6 +320,52 @@ static int mf_print_keys(uint16_t n, uint8_t *d) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MFC dump , extract and save the keys to key file
|
||||||
|
static int mf_save_keys_from_arr(uint16_t n, uint8_t *d) {
|
||||||
|
uint8_t sectors = 0;
|
||||||
|
switch (n) {
|
||||||
|
case MIFARE_MINI_MAXBLOCK:
|
||||||
|
sectors = MIFARE_MINI_MAXSECTOR;
|
||||||
|
break;
|
||||||
|
case MIFARE_2K_MAXBLOCK:
|
||||||
|
sectors = MIFARE_2K_MAXSECTOR;
|
||||||
|
break;
|
||||||
|
case MIFARE_4K_MAXBLOCK:
|
||||||
|
sectors = MIFARE_4K_MAXSECTOR;
|
||||||
|
break;
|
||||||
|
case MIFARE_1K_MAXBLOCK:
|
||||||
|
default:
|
||||||
|
sectors = MIFARE_1K_MAXSECTOR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t keysize = 2 * MIFARE_KEY_SIZE * sectors;
|
||||||
|
|
||||||
|
uint8_t *keys = calloc(keysize, sizeof(uint8_t));
|
||||||
|
if (keys == NULL) {
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sector = 0;
|
||||||
|
for (uint16_t i = 0; i < n; i++) {
|
||||||
|
if (mfIsSectorTrailer(i)) {
|
||||||
|
// key A offset in ST block
|
||||||
|
memcpy(keys + (MIFARE_KEY_SIZE * sector), d + (i * MFBLOCK_SIZE), MIFARE_KEY_SIZE);
|
||||||
|
|
||||||
|
// key B offset in ST block
|
||||||
|
memcpy(keys + (MIFARE_KEY_SIZE * sectors) + (MIFARE_KEY_SIZE * sector), d + (i * MFBLOCK_SIZE) + 10, MIFARE_KEY_SIZE);
|
||||||
|
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char fn[FILE_PATH_SIZE] = {0};
|
||||||
|
snprintf(fn, sizeof(fn), "hf-mf-%s-keys", sprint_hex_inrow(d, 4));
|
||||||
|
saveFile(fn, ".bin", keys, keysize);
|
||||||
|
free(keys);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static void mf_print_values(uint16_t n, uint8_t *d) {
|
static void mf_print_values(uint16_t n, uint8_t *d) {
|
||||||
|
|
||||||
|
@ -1211,52 +1256,41 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
||||||
free(fptr);
|
free(fptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *f;
|
//
|
||||||
if ((f = fopen(keyfilename, "rb")) == NULL) {
|
size_t alen = 0, blen = 0;
|
||||||
PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), keyfilename);
|
uint8_t *keyA, *keyB;
|
||||||
return PM3_EFILE;
|
if (loadFileBinaryKey(keyfilename, "", (void **)&keyA, (void **)&keyB, &alen, &blen) != PM3_SUCCESS) {
|
||||||
}
|
if (keyA) {
|
||||||
|
free(keyA);
|
||||||
// key arrays
|
|
||||||
uint8_t keyA[40][6];
|
|
||||||
uint8_t keyB[40][6];
|
|
||||||
|
|
||||||
// read key file
|
|
||||||
size_t bytes_read;
|
|
||||||
for (uint8_t s = 0; s < sectors; s++) {
|
|
||||||
bytes_read = fread(keyA[s], 1, 6, f);
|
|
||||||
if (bytes_read != 6) {
|
|
||||||
PrintAndLogEx(ERR, "File reading error " _YELLOW_("%s"), keyfilename);
|
|
||||||
fclose(f);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
}
|
||||||
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t s = 0; s < sectors; s++) {
|
PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyfilename);
|
||||||
bytes_read = fread(keyB[s], 1, 6, f);
|
|
||||||
if (bytes_read != 6) {
|
|
||||||
PrintAndLogEx(ERR, "File reading error " _YELLOW_("%s"), keyfilename);
|
|
||||||
fclose(f);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
// try reading card uid and create filename
|
// try reading card uid and create filename
|
||||||
if (datafnlen == 0) {
|
if (datafnlen == 0) {
|
||||||
char *fptr = GenerateFilename("hf-mf-", "-dump.bin");
|
char *fptr = GenerateFilename("hf-mf-", "-dump.bin");
|
||||||
if (fptr == NULL)
|
if (fptr == NULL) {
|
||||||
|
if (keyA) {
|
||||||
|
free(keyA);
|
||||||
|
}
|
||||||
|
if (keyB) {
|
||||||
|
free(keyB);
|
||||||
|
}
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
strcpy(datafilename, fptr);
|
strcpy(datafilename, fptr);
|
||||||
free(fptr);
|
free(fptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read dump file
|
// read dump file
|
||||||
uint8_t *dump = NULL;
|
uint8_t *dump = NULL;
|
||||||
bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
int res = pm3_load_dump(datafilename, (void **)&dump, &bytes_read, (MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK));
|
int res = pm3_load_dump(datafilename, (void **)&dump, &bytes_read, (MFBLOCK_SIZE * MIFARE_4K_MAXBLOCK));
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
|
free(keyA);
|
||||||
|
free(keyB);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1281,19 +1315,10 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
||||||
if (mfNumBlocksPerSector(s) - 1 == b) {
|
if (mfNumBlocksPerSector(s) - 1 == b) {
|
||||||
if (use_keyfile_for_auth == false) {
|
if (use_keyfile_for_auth == false) {
|
||||||
// replace KEY A
|
// replace KEY A
|
||||||
bldata[0] = (keyA[s][0]);
|
memcpy(bldata, keyA + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
bldata[1] = (keyA[s][1]);
|
|
||||||
bldata[2] = (keyA[s][2]);
|
|
||||||
bldata[3] = (keyA[s][3]);
|
|
||||||
bldata[4] = (keyA[s][4]);
|
|
||||||
bldata[5] = (keyA[s][5]);
|
|
||||||
// replace KEY B
|
// replace KEY B
|
||||||
bldata[10] = (keyB[s][0]);
|
memcpy(bldata + 10, keyB + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
bldata[11] = (keyB[s][1]);
|
|
||||||
bldata[12] = (keyB[s][2]);
|
|
||||||
bldata[13] = (keyB[s][3]);
|
|
||||||
bldata[14] = (keyB[s][4]);
|
|
||||||
bldata[15] = (keyB[s][5]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure access right isn't messed up.
|
// ensure access right isn't messed up.
|
||||||
|
@ -1327,12 +1352,12 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
||||||
for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
|
for (int8_t kt = MF_KEY_B; kt > -1; kt--) {
|
||||||
if (use_keyfile_for_auth) {
|
if (use_keyfile_for_auth) {
|
||||||
if (kt == MF_KEY_A)
|
if (kt == MF_KEY_A)
|
||||||
memcpy(wdata, keyA[s], 6);
|
memcpy(wdata, keyA + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
else
|
else
|
||||||
memcpy(wdata, keyB[s], 6);
|
memcpy(wdata, keyB + (s * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
} else {
|
} else {
|
||||||
// use default key to authenticate for the write command
|
// use default key to authenticate for the write command
|
||||||
memcpy(wdata, default_key, 6);
|
memcpy(wdata, default_key, MIFARE_KEY_SIZE);
|
||||||
}
|
}
|
||||||
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
|
PrintAndLogEx(INFO, "block %3d: %s", mfFirstBlockOfSector(s) + b, sprint_hex(bldata, sizeof(bldata)));
|
||||||
|
|
||||||
|
@ -1359,6 +1384,8 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
||||||
} // end loop S
|
} // end loop S
|
||||||
|
|
||||||
free(ref_dump);
|
free(ref_dump);
|
||||||
|
free(keyA);
|
||||||
|
free(keyB);
|
||||||
PrintAndLogEx(INFO, "Done!");
|
PrintAndLogEx(INFO, "Done!");
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2155,26 +2182,27 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
|
||||||
|
|
||||||
uint64_t foundkey = 0;
|
uint64_t foundkey = 0;
|
||||||
int16_t isOK = mfnestedhard(blockno, keytype, key, trg_blockno, trg_keytype, known_target_key ? trg_key : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename);
|
int16_t isOK = mfnestedhard(blockno, keytype, key, trg_blockno, trg_keytype, known_target_key ? trg_key : NULL, nonce_file_read, nonce_file_write, slow, tests, &foundkey, filename);
|
||||||
|
switch (isOK) {
|
||||||
|
case PM3_ETIMEOUT :
|
||||||
|
PrintAndLogEx(ERR, "Error: No response from Proxmark3\n");
|
||||||
|
break;
|
||||||
|
case PM3_EOPABORTED:
|
||||||
|
PrintAndLogEx(WARNING, "Button pressed. Aborted\n");
|
||||||
|
break;
|
||||||
|
case PM3_ESTATIC_NONCE:
|
||||||
|
PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n");
|
||||||
|
break;
|
||||||
|
case PM3_EFAILED: {
|
||||||
|
PrintAndLogEx(FAILED, "\nFailed to recover a key...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((tests == 0) && IfPm3Iso14443a()) {
|
if ((tests == 0) && IfPm3Iso14443a()) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOK) {
|
|
||||||
switch (isOK) {
|
|
||||||
case PM3_ETIMEOUT :
|
|
||||||
PrintAndLogEx(ERR, "Error: No response from Proxmark3\n");
|
|
||||||
break;
|
|
||||||
case PM3_EOPABORTED:
|
|
||||||
PrintAndLogEx(WARNING, "Button pressed. Aborted\n");
|
|
||||||
break;
|
|
||||||
case PM3_ESTATIC_NONCE:
|
|
||||||
PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n");
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isOK;
|
return isOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2389,14 +2417,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
|
|
||||||
if (is_ev1) {
|
if (is_ev1) {
|
||||||
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
|
PrintAndLogEx(INFO, "MIFARE Classic EV1 card detected");
|
||||||
// Store the keys
|
|
||||||
e_sector[16].Key[MF_KEY_A] = bytes_to_num((uint8_t *)g_mifare_signature_key_a, sizeof(g_mifare_signature_key_a));
|
|
||||||
e_sector[16].foundKey[MF_KEY_A] = 'D';
|
|
||||||
|
|
||||||
e_sector[17].Key[MF_KEY_A] = bytes_to_num((uint8_t *)g_mifare_signature_key_a, sizeof(g_mifare_signature_key_a));
|
|
||||||
e_sector[17].foundKey[MF_KEY_A] = 'D';
|
|
||||||
e_sector[17].Key[MF_KEY_B] = bytes_to_num((uint8_t *)g_mifare_signature_key_b, sizeof(g_mifare_signature_key_b));
|
|
||||||
e_sector[17].foundKey[MF_KEY_B] = 'D';
|
|
||||||
|
|
||||||
// use found key if not supplied
|
// use found key if not supplied
|
||||||
if (known_key == false) {
|
if (known_key == false) {
|
||||||
|
@ -2431,7 +2451,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), known_key ? "True" : "False");
|
PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), known_key ? "True" : "False");
|
||||||
PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno);
|
PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno);
|
||||||
PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A');
|
PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A');
|
||||||
PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key)));
|
PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex_inrow(key, sizeof(key)));
|
||||||
|
|
||||||
if (has_staticnonce == NONCE_STATIC)
|
if (has_staticnonce == NONCE_STATIC)
|
||||||
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC"));
|
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC"));
|
||||||
|
@ -2458,10 +2478,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mfCheckKeys(mfFirstBlockOfSector(sectorno), keytype, true, 1, key, &key64) == PM3_SUCCESS) {
|
if (mfCheckKeys(mfFirstBlockOfSector(sectorno), keytype, true, 1, key, &key64) == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(INFO, "target sector %3u key type %c -- using valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
PrintAndLogEx(INFO, "target sector %3u key type %c -- using valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
|
||||||
sectorno,
|
sectorno,
|
||||||
(keytype == MF_KEY_B) ? 'B' : 'A',
|
(keytype == MF_KEY_B) ? 'B' : 'A',
|
||||||
sprint_hex(key, sizeof(key))
|
sprint_hex_inrow(key, sizeof(key))
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store the key for the nested / hardnested attack (if supplied by the user)
|
// Store the key for the nested / hardnested attack (if supplied by the user)
|
||||||
|
@ -2474,7 +2494,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector"_RED_("%3d") " key type "_RED_("%c") " key " _RED_("%s"),
|
PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector"_RED_("%3d") " key type "_RED_("%c") " key " _RED_("%s"),
|
||||||
sectorno,
|
sectorno,
|
||||||
(keytype == MF_KEY_B) ? 'B' : 'A',
|
(keytype == MF_KEY_B) ? 'B' : 'A',
|
||||||
sprint_hex(key, sizeof(key))
|
sprint_hex_inrow(key, sizeof(key))
|
||||||
);
|
);
|
||||||
PrintAndLogEx(WARNING, "falling back to dictionary");
|
PrintAndLogEx(WARNING, "falling back to dictionary");
|
||||||
}
|
}
|
||||||
|
@ -2482,31 +2502,34 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
// Check if the user supplied key is used by other sectors
|
// Check if the user supplied key is used by other sectors
|
||||||
for (int i = 0; i < sector_cnt; i++) {
|
for (int i = 0; i < sector_cnt; i++) {
|
||||||
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
||||||
if (e_sector[i].foundKey[j] == 0) {
|
|
||||||
if (mfCheckKeys(mfFirstBlockOfSector(i), j, true, 1, key, &key64) == PM3_SUCCESS) {
|
|
||||||
e_sector[i].Key[j] = bytes_to_num(key, 6);
|
|
||||||
e_sector[i].foundKey[j] = 'U';
|
|
||||||
|
|
||||||
// If the user supplied secctor / keytype was wrong --> just be nice and correct it ;)
|
if (e_sector[i].foundKey[j]) {
|
||||||
if (known_key == false) {
|
continue;
|
||||||
num_to_bytes(e_sector[i].Key[j], 6, key);
|
}
|
||||||
known_key = true;
|
|
||||||
sectorno = i;
|
if (mfCheckKeys(mfFirstBlockOfSector(i), j, true, 1, key, &key64) == PM3_SUCCESS) {
|
||||||
keytype = j;
|
e_sector[i].Key[j] = bytes_to_num(key, 6);
|
||||||
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
|
e_sector[i].foundKey[j] = 'U';
|
||||||
i,
|
|
||||||
(j == MF_KEY_B) ? 'B' : 'A',
|
// If the user supplied secctor / keytype was wrong --> just be nice and correct it ;)
|
||||||
sprint_hex_inrow(key, sizeof(key))
|
if (known_key == false) {
|
||||||
);
|
num_to_bytes(e_sector[i].Key[j], 6, key);
|
||||||
} else {
|
known_key = true;
|
||||||
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
|
sectorno = i;
|
||||||
i,
|
keytype = j;
|
||||||
(j == MF_KEY_B) ? 'B' : 'A',
|
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
|
||||||
sprint_hex_inrow(key, sizeof(key))
|
i,
|
||||||
);
|
(j == MF_KEY_B) ? 'B' : 'A',
|
||||||
}
|
sprint_hex_inrow(key, sizeof(key))
|
||||||
++num_found_keys;
|
);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
|
||||||
|
i,
|
||||||
|
(j == MF_KEY_B) ? 'B' : 'A',
|
||||||
|
sprint_hex_inrow(key, sizeof(key))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
++num_found_keys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2551,7 +2574,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "." NOLF);
|
PrintAndLogEx(INFO, "." NOLF);
|
||||||
// Check all the sectors
|
// Check all the sectors
|
||||||
for (int i = 0; i < sector_cnt; i++) {
|
for (int i = 0; i < sector_cnt; i++) {
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
||||||
// Check if the key is known
|
// Check if the key is known
|
||||||
if (e_sector[i].foundKey[j] == 0) {
|
if (e_sector[i].foundKey[j] == 0) {
|
||||||
for (uint32_t k = 0; k < key_cnt; k++) {
|
for (uint32_t k = 0; k < key_cnt; k++) {
|
||||||
|
@ -2608,28 +2631,30 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
||||||
// Analyse the dictionary attack
|
// Analyse the dictionary attack
|
||||||
for (int i = 0; i < sector_cnt; i++) {
|
for (int i = 0; i < sector_cnt; i++) {
|
||||||
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
for (int j = MF_KEY_A; j <= MF_KEY_B; j++) {
|
||||||
if (e_sector[i].foundKey[j] == 1) {
|
if (e_sector[i].foundKey[j] != 1) {
|
||||||
e_sector[i].foundKey[j] = 'D';
|
continue;
|
||||||
num_to_bytes(e_sector[i].Key[j], 6, tmp_key);
|
}
|
||||||
|
|
||||||
// Store valid credentials for the nested / hardnested attack if none exist
|
e_sector[i].foundKey[j] = 'D';
|
||||||
if (known_key == false) {
|
num_to_bytes(e_sector[i].Key[j], 6, tmp_key);
|
||||||
num_to_bytes(e_sector[i].Key[j], 6, key);
|
|
||||||
known_key = true;
|
// Store valid credentials for the nested / hardnested attack if none exist
|
||||||
sectorno = i;
|
if (known_key == false) {
|
||||||
keytype = j;
|
num_to_bytes(e_sector[i].Key[j], 6, key);
|
||||||
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
|
known_key = true;
|
||||||
i,
|
sectorno = i;
|
||||||
(j == MF_KEY_B) ? 'B' : 'A',
|
keytype = j;
|
||||||
sprint_hex_inrow(tmp_key, sizeof(tmp_key))
|
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)",
|
||||||
);
|
i,
|
||||||
} else {
|
(j == MF_KEY_B) ? 'B' : 'A',
|
||||||
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
|
sprint_hex_inrow(tmp_key, sizeof(tmp_key))
|
||||||
i,
|
);
|
||||||
(j == MF_KEY_B) ? 'B' : 'A',
|
} else {
|
||||||
sprint_hex_inrow(tmp_key, sizeof(tmp_key))
|
PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]",
|
||||||
);
|
i,
|
||||||
}
|
(j == MF_KEY_B) ? 'B' : 'A',
|
||||||
|
sprint_hex_inrow(tmp_key, sizeof(tmp_key))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2690,7 +2715,8 @@ noValidKeyFound:
|
||||||
|
|
||||||
// Iterate over each sector and key(A/B)
|
// Iterate over each sector and key(A/B)
|
||||||
for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) {
|
for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) {
|
||||||
for (current_key_type_i = 0; current_key_type_i < 2; current_key_type_i++) {
|
|
||||||
|
for (current_key_type_i = MF_KEY_A; current_key_type_i <= MF_KEY_B; current_key_type_i++) {
|
||||||
|
|
||||||
// If the key is already known, just skip it
|
// If the key is already known, just skip it
|
||||||
if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) {
|
if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) {
|
||||||
|
@ -2863,7 +2889,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
|
||||||
foundkey = 0;
|
foundkey = 0;
|
||||||
isOK = mfnestedhard(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
|
isOK = mfnestedhard(mfFirstBlockOfSector(sectorno), keytype, key, mfFirstBlockOfSector(current_sector_i), current_key_type_i, NULL, false, false, slow, 0, &foundkey, NULL);
|
||||||
DropField();
|
DropField();
|
||||||
if (isOK) {
|
if (isOK != PM3_SUCCESS) {
|
||||||
switch (isOK) {
|
switch (isOK) {
|
||||||
case PM3_ETIMEOUT: {
|
case PM3_ETIMEOUT: {
|
||||||
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
|
PrintAndLogEx(ERR, "\nError: No response from Proxmark3");
|
||||||
|
@ -2886,6 +2912,10 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PM3_EFAILED: {
|
||||||
|
PrintAndLogEx(FAILED, "\nFailed to recover a key...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4394,6 +4424,7 @@ static int CmdHF14AMfEView(const char *Cmd) {
|
||||||
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
arg_lit0(NULL, "2k", "MIFARE Classic/Plus 2k"),
|
||||||
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
arg_lit0(NULL, "4k", "MIFARE Classic 4k / S70"),
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_lit0(NULL, "sk", "Save extracted keys to file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
@ -4402,6 +4433,7 @@ static int CmdHF14AMfEView(const char *Cmd) {
|
||||||
bool m2 = arg_get_lit(ctx, 3);
|
bool m2 = arg_get_lit(ctx, 3);
|
||||||
bool m4 = arg_get_lit(ctx, 4);
|
bool m4 = arg_get_lit(ctx, 4);
|
||||||
bool verbose = arg_get_lit(ctx, 5);
|
bool verbose = arg_get_lit(ctx, 5);
|
||||||
|
bool save_keys = arg_get_lit(ctx, 6);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// validations
|
// validations
|
||||||
|
@ -4447,6 +4479,11 @@ static int CmdHF14AMfEView(const char *Cmd) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
mf_print_keys(block_cnt, dump);
|
mf_print_keys(block_cnt, dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (save_keys) {
|
||||||
|
mf_save_keys_from_arr(block_cnt, dump);
|
||||||
|
}
|
||||||
|
|
||||||
free(dump);
|
free(dump);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -5864,8 +5901,9 @@ int CmdHFMFNDEFRead(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint16_t ndef_aid = NDEF_MFC_AID;
|
uint16_t ndef_aid = NDEF_MFC_AID;
|
||||||
if (aidlen == 2)
|
if (aidlen == 2) {
|
||||||
ndef_aid = (aid[0] << 8) + aid[1];
|
ndef_aid = (aid[0] << 8) + aid[1];
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ndefkey[6] = {0};
|
uint8_t ndefkey[6] = {0};
|
||||||
memcpy(ndefkey, g_mifare_ndef_key, 6);
|
memcpy(ndefkey, g_mifare_ndef_key, 6);
|
||||||
|
@ -6079,39 +6117,27 @@ int CmdHFMFNDEFFormat(const char *Cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// load key file if exist
|
// load key file if exist
|
||||||
if (strlen(keyFilename)) {
|
if (strlen(keyFilename)) {
|
||||||
|
//
|
||||||
FILE *f;
|
size_t alen = 0, blen = 0;
|
||||||
if ((f = fopen(keyFilename, "rb")) == NULL) {
|
uint8_t *tmpA, *tmpB;
|
||||||
// PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), keyFilename);
|
if (loadFileBinaryKey(keyFilename, "", (void **)&tmpA, (void **)&tmpB, &alen, &blen) != PM3_SUCCESS) {
|
||||||
|
if (tmpA) {
|
||||||
|
free(tmpA);
|
||||||
|
}
|
||||||
goto skipfile;
|
goto skipfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename);
|
PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename);
|
||||||
|
|
||||||
// Read keys A from file
|
for (int i = 0; i < numSectors; i++) {
|
||||||
size_t bytes_read;
|
memcpy(keyA[i], tmpA + (i * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
for (uint8_t i = 0; i < numSectors; i++) {
|
memcpy(keyB[i], tmpB + (i * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE);
|
||||||
bytes_read = fread(keyA[i], 1, MFKEY_SIZE, f);
|
|
||||||
if (bytes_read != MFKEY_SIZE) {
|
|
||||||
PrintAndLogEx(ERR, "File reading error.");
|
|
||||||
fclose(f);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
free(tmpA);
|
||||||
// Read keys B from file
|
free(tmpB);
|
||||||
for (uint8_t i = 0; i < numSectors; i++) {
|
|
||||||
bytes_read = fread(keyB[i], 1, MFKEY_SIZE, f);
|
|
||||||
if (bytes_read != MFKEY_SIZE) {
|
|
||||||
PrintAndLogEx(ERR, "File reading error.");
|
|
||||||
fclose(f);
|
|
||||||
return PM3_EFILE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skipfile:
|
skipfile:
|
||||||
|
@ -6154,7 +6180,6 @@ skipfile:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write to card, try B key first
|
// write to card, try B key first
|
||||||
|
@ -6169,7 +6194,6 @@ skipfile:
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6952,6 +6976,7 @@ static int CmdHF14AMfWipe(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Forcing overwrite of sector 0 / block 0 ");
|
PrintAndLogEx(INFO, "Forcing overwrite of sector 0 / block 0 ");
|
||||||
else
|
else
|
||||||
PrintAndLogEx(INFO, "Skipping sector 0 / block 0");
|
PrintAndLogEx(INFO, "Skipping sector 0 / block 0");
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
||||||
uint8_t zeros[MFBLOCK_SIZE] = {0};
|
uint8_t zeros[MFBLOCK_SIZE] = {0};
|
||||||
|
@ -6963,7 +6988,12 @@ static int CmdHF14AMfWipe(const char *Cmd) {
|
||||||
|
|
||||||
for (uint8_t b = 0; b < mfNumBlocksPerSector(s); b++) {
|
for (uint8_t b = 0; b < mfNumBlocksPerSector(s); b++) {
|
||||||
|
|
||||||
// Skipp write to manufacture block if not enforced
|
if (kbd_enter_pressed()) {
|
||||||
|
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip write to manufacture block if not enforced
|
||||||
if (s == 0 && b == 0 && gen2 == false) {
|
if (s == 0 && b == 0 && gen2 == false) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -7026,6 +7056,7 @@ static int CmdHF14AMfView(const char *Cmd) {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("f", "file", "<fn>", "filename of dump"),
|
arg_str1("f", "file", "<fn>", "filename of dump"),
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_lit0(NULL, "sk", "Save extracted keys to file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
@ -7033,6 +7064,7 @@ static int CmdHF14AMfView(const char *Cmd) {
|
||||||
char filename[FILE_PATH_SIZE];
|
char filename[FILE_PATH_SIZE];
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
bool verbose = arg_get_lit(ctx, 2);
|
bool verbose = arg_get_lit(ctx, 2);
|
||||||
|
bool save_keys = arg_get_lit(ctx, 3);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// read dump file
|
// read dump file
|
||||||
|
@ -7063,6 +7095,10 @@ static int CmdHF14AMfView(const char *Cmd) {
|
||||||
mf_analyse_acl(block_cnt, dump);
|
mf_analyse_acl(block_cnt, dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (save_keys) {
|
||||||
|
mf_save_keys_from_arr(block_cnt, dump);
|
||||||
|
}
|
||||||
|
|
||||||
int sector = DetectHID(dump, 0x4910);
|
int sector = DetectHID(dump, 0x4910);
|
||||||
if (sector > -1) {
|
if (sector > -1) {
|
||||||
// decode it
|
// decode it
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
|
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
#include "comms.h"
|
#include "comms.h"
|
||||||
|
|
||||||
#include "proxmark3.h"
|
#include "proxmark3.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "util_posix.h"
|
#include "util_posix.h"
|
||||||
|
@ -48,7 +47,8 @@
|
||||||
#define NUM_CHECK_BITFLIPS_THREADS (num_CPUs())
|
#define NUM_CHECK_BITFLIPS_THREADS (num_CPUs())
|
||||||
#define NUM_REDUCTION_WORKING_THREADS (num_CPUs())
|
#define NUM_REDUCTION_WORKING_THREADS (num_CPUs())
|
||||||
|
|
||||||
#define IGNORE_BITFLIP_THRESHOLD 0.99 // ignore bitflip arrays which have nearly only valid states
|
// ignore bitflip arrays which have nearly only valid states
|
||||||
|
#define IGNORE_BITFLIP_THRESHOLD 0.9901
|
||||||
|
|
||||||
#define STATE_FILES_DIRECTORY "hardnested_tables/"
|
#define STATE_FILES_DIRECTORY "hardnested_tables/"
|
||||||
#define STATE_FILE_TEMPLATE "bitflip_%d_%03" PRIx16 "_states.bin.bz2"
|
#define STATE_FILE_TEMPLATE "bitflip_%d_%03" PRIx16 "_states.bin.bz2"
|
||||||
|
@ -57,7 +57,11 @@
|
||||||
// #define DEBUG_REDUCTION
|
// #define DEBUG_REDUCTION
|
||||||
|
|
||||||
// possible sum property values
|
// possible sum property values
|
||||||
static uint16_t sums[NUM_SUMS] = {0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256};
|
static uint16_t sums[NUM_SUMS] = {
|
||||||
|
0, 32, 56, 64, 80, 96, 104, 112,
|
||||||
|
120, 128, 136, 144, 152, 160, 176, 192,
|
||||||
|
200, 224, 256
|
||||||
|
};
|
||||||
|
|
||||||
// number of possible partial sum property values
|
// number of possible partial sum property values
|
||||||
#define NUM_PART_SUMS 9
|
#define NUM_PART_SUMS 9
|
||||||
|
@ -505,8 +509,11 @@ static void free_sum_bitarrays(void) {
|
||||||
static char failstr[250] = "";
|
static char failstr[250] = "";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const float p_K0[NUM_SUMS] = { // the probability that a random nonce has a Sum Property K
|
// the probability that a random nonce has a Sum Property K
|
||||||
0.0290, 0.0083, 0.0006, 0.0339, 0.0048, 0.0934, 0.0119, 0.0489, 0.0602, 0.4180, 0.0602, 0.0489, 0.0119, 0.0934, 0.0048, 0.0339, 0.0006, 0.0083, 0.0290
|
static const float p_K0[NUM_SUMS] = {
|
||||||
|
0.0290, 0.0083, 0.0006, 0.0339, 0.0048, 0.0934, 0.0119, 0.0489,
|
||||||
|
0.0602, 0.4180, 0.0602, 0.0489, 0.0119, 0.0934, 0.0048, 0.0339,
|
||||||
|
0.0006, 0.0083, 0.0290
|
||||||
};
|
};
|
||||||
static float my_p_K[NUM_SUMS];
|
static float my_p_K[NUM_SUMS];
|
||||||
static const float *p_K;
|
static const float *p_K;
|
||||||
|
@ -1275,6 +1282,7 @@ static void apply_sum_a0(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void simulate_MFplus_RNG(uint32_t test_cuid, uint64_t test_key, uint32_t *nt_enc, uint8_t *par_enc) {
|
static void simulate_MFplus_RNG(uint32_t test_cuid, uint64_t test_key, uint32_t *nt_enc, uint8_t *par_enc) {
|
||||||
|
|
||||||
struct Crypto1State sim_cs = {0, 0};
|
struct Crypto1State sim_cs = {0, 0};
|
||||||
|
|
||||||
// init cryptostate with key:
|
// init cryptostate with key:
|
||||||
|
@ -1285,12 +1293,20 @@ static void simulate_MFplus_RNG(uint32_t test_cuid, uint64_t test_key, uint32_t
|
||||||
|
|
||||||
*par_enc = 0;
|
*par_enc = 0;
|
||||||
uint32_t nt = (rand() & 0xff) << 24 | (rand() & 0xff) << 16 | (rand() & 0xff) << 8 | (rand() & 0xff);
|
uint32_t nt = (rand() & 0xff) << 24 | (rand() & 0xff) << 16 | (rand() & 0xff) << 8 | (rand() & 0xff);
|
||||||
|
|
||||||
for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) {
|
for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) {
|
||||||
|
|
||||||
uint8_t nt_byte_dec = (nt >> (8 * byte_pos)) & 0xff;
|
uint8_t nt_byte_dec = (nt >> (8 * byte_pos)) & 0xff;
|
||||||
uint8_t nt_byte_enc = crypto1_byte(&sim_cs, nt_byte_dec ^ (test_cuid >> (8 * byte_pos)), false) ^ nt_byte_dec; // encode the nonce byte
|
|
||||||
|
// encode the nonce byte
|
||||||
|
uint8_t nt_byte_enc = crypto1_byte(&sim_cs, nt_byte_dec ^ (test_cuid >> (8 * byte_pos)), false) ^ nt_byte_dec;
|
||||||
*nt_enc = (*nt_enc << 8) | nt_byte_enc;
|
*nt_enc = (*nt_enc << 8) | nt_byte_enc;
|
||||||
uint8_t ks_par = filter(sim_cs.odd); // the keystream bit to encode/decode the parity bit
|
|
||||||
uint8_t nt_byte_par_enc = ks_par ^ oddparity8(nt_byte_dec); // determine the nt byte's parity and encode it
|
// the keystream bit to encode/decode the parity bit
|
||||||
|
uint8_t ks_par = filter(sim_cs.odd);
|
||||||
|
|
||||||
|
// determine the nt byte's parity and encode it
|
||||||
|
uint8_t nt_byte_par_enc = ks_par ^ oddparity8(nt_byte_dec);
|
||||||
*par_enc = (*par_enc << 1) | nt_byte_par_enc;
|
*par_enc = (*par_enc << 1) | nt_byte_par_enc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2460,6 +2476,9 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
|
||||||
free_bitarray(all_bitflips_bitarray[EVEN_STATE]);
|
free_bitarray(all_bitflips_bitarray[EVEN_STATE]);
|
||||||
free_sum_bitarrays();
|
free_sum_bitarrays();
|
||||||
free_part_sum_bitarrays();
|
free_part_sum_bitarrays();
|
||||||
|
|
||||||
|
return (key_found) ? PM3_SUCCESS : PM3_EFAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
#include "cmdlfem4x50.h"
|
#include "cmdlfem4x50.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
#include "cmdparser.h" // command_t
|
#include "cmdparser.h" // command_t
|
||||||
#include "util_posix.h" // msclock
|
#include "util_posix.h" // msclock
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
|
@ -349,54 +350,118 @@ int CmdEM4x50Brute(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "lf em 4x50 brute",
|
CLIParserInit(&ctx, "lf em 4x50 brute",
|
||||||
"Tries to bruteforce the password of a EM4x50 card.\n"
|
"Tries to bruteforce the password of a EM4x50 card.\n"
|
||||||
"Function can be stopped by pressing pm3 button.",
|
"Function can be stopped by pressing pm3 button.\n",
|
||||||
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000\n"
|
|
||||||
|
"lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000\n"
|
||||||
|
"lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1(NULL, "first", "<hex>", "first password (start), 4 bytes, lsb"),
|
arg_str1(NULL, "mode", "<str>", "Bruteforce mode (range|charset)"),
|
||||||
arg_str1(NULL, "last", "<hex>", "last password (stop), 4 bytes, lsb"),
|
arg_str0(NULL, "begin", "<hex>", "Range mode - start of the key range"),
|
||||||
|
arg_str0(NULL, "end", "<hex>", "Range mode - end of the key range"),
|
||||||
|
arg_lit0(NULL, "digits", "Charset mode - include ASCII codes for digits"),
|
||||||
|
arg_lit0(NULL, "uppercase", "Charset mode - include ASCII codes for uppercase letters"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
int first_len = 0;
|
|
||||||
uint8_t first[4] = {0, 0, 0, 0};
|
|
||||||
CLIGetHexWithReturn(ctx, 1, first, &first_len);
|
|
||||||
int last_len = 0;
|
|
||||||
uint8_t last[4] = {0, 0, 0, 0};
|
|
||||||
CLIGetHexWithReturn(ctx, 2, last, &last_len);
|
|
||||||
CLIParserFree(ctx);
|
|
||||||
|
|
||||||
if (first_len != 4) {
|
|
||||||
PrintAndLogEx(FAILED, "password length must be 4 bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
if (last_len != 4) {
|
|
||||||
PrintAndLogEx(FAILED, "password length must be 4 bytes");
|
|
||||||
return PM3_EINVARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
em4x50_data_t etd;
|
em4x50_data_t etd;
|
||||||
etd.password1 = BYTES2UINT32_BE(first);
|
memset(&etd, 0, sizeof(etd));
|
||||||
etd.password2 = BYTES2UINT32_BE(last);
|
|
||||||
|
int mode_len = 64;
|
||||||
|
char mode[64];
|
||||||
|
CLIGetStrWithReturn(ctx, 1, (uint8_t *) mode, &mode_len);
|
||||||
|
PrintAndLogEx(INFO, "Chosen mode: %s", mode);
|
||||||
|
|
||||||
|
if (strcmp(mode, "range") == 0) {
|
||||||
|
etd.bruteforce_mode = BRUTEFORCE_MODE_RANGE;
|
||||||
|
} else if (strcmp(mode, "charset") == 0) {
|
||||||
|
etd.bruteforce_mode = BRUTEFORCE_MODE_CHARSET;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(FAILED, "Unknown bruteforce mode: %s", mode);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE) {
|
||||||
|
int begin_len = 0;
|
||||||
|
uint8_t begin[4] = {0x0};
|
||||||
|
CLIGetHexWithReturn(ctx, 2, begin, &begin_len);
|
||||||
|
|
||||||
|
int end_len = 0;
|
||||||
|
uint8_t end[4] = {0x0};
|
||||||
|
CLIGetHexWithReturn(ctx, 3, end, &end_len);
|
||||||
|
|
||||||
|
if (begin_len != 4) {
|
||||||
|
PrintAndLogEx(FAILED, "'begin' parameter must be 4 bytes");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end_len != 4) {
|
||||||
|
PrintAndLogEx(FAILED, "'end' parameter must be 4 bytes");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
etd.password1 = BYTES2UINT32_BE(begin);
|
||||||
|
etd.password2 = BYTES2UINT32_BE(end);
|
||||||
|
} else if (etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET) {
|
||||||
|
bool enable_digits = arg_get_lit(ctx, 4);
|
||||||
|
bool enable_uppercase = arg_get_lit(ctx, 5);
|
||||||
|
|
||||||
|
if (enable_digits)
|
||||||
|
etd.bruteforce_charset |= CHARSET_DIGITS;
|
||||||
|
if (enable_uppercase)
|
||||||
|
etd.bruteforce_charset |= CHARSET_UPPERCASE;
|
||||||
|
|
||||||
|
if (etd.bruteforce_charset == 0) {
|
||||||
|
PrintAndLogEx(FAILED, "Please enable at least one charset when using charset bruteforce mode.");
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "Enabled charsets: %s%s",
|
||||||
|
enable_digits ? "digits " : "",
|
||||||
|
enable_uppercase ? "uppercase " : "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
// 27 passwords/second (empirical value)
|
// 27 passwords/second (empirical value)
|
||||||
const int speed = 27;
|
const int speed = 27;
|
||||||
|
int no_iter = 0;
|
||||||
|
|
||||||
|
if (etd.bruteforce_mode == BRUTEFORCE_MODE_RANGE) {
|
||||||
|
no_iter = etd.password2 - etd.password1 + 1;
|
||||||
|
PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]"
|
||||||
|
, no_iter
|
||||||
|
, etd.password1
|
||||||
|
, etd.password2
|
||||||
|
);
|
||||||
|
} else if (etd.bruteforce_mode == BRUTEFORCE_MODE_CHARSET) {
|
||||||
|
unsigned int digits = 0;
|
||||||
|
|
||||||
|
if (etd.bruteforce_charset & CHARSET_DIGITS)
|
||||||
|
digits += CHARSET_DIGITS_SIZE;
|
||||||
|
|
||||||
|
if (etd.bruteforce_charset & CHARSET_UPPERCASE)
|
||||||
|
digits += CHARSET_UPPERCASE_SIZE;
|
||||||
|
|
||||||
|
no_iter = pow(digits, 4);
|
||||||
|
}
|
||||||
|
|
||||||
// print some information
|
// print some information
|
||||||
int no_iter = etd.password2 - etd.password1 + 1;
|
|
||||||
int dur_s = no_iter / speed;
|
int dur_s = no_iter / speed;
|
||||||
int dur_h = dur_s / 3600;
|
int dur_h = dur_s / 3600;
|
||||||
int dur_m = (dur_s - dur_h * 3600) / 60;
|
int dur_m = (dur_s - dur_h * 3600) / 60;
|
||||||
|
|
||||||
dur_s -= dur_h * 3600 + dur_m * 60;
|
dur_s -= dur_h * 3600 + dur_m * 60;
|
||||||
PrintAndLogEx(INFO, "Trying " _YELLOW_("%i") " passwords in range [0x%08x, 0x%08x]"
|
|
||||||
, no_iter
|
|
||||||
, etd.password1
|
|
||||||
, etd.password2
|
|
||||||
);
|
|
||||||
PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s);
|
PrintAndLogEx(INFO, "Estimated duration: %ih %im %is", dur_h, dur_m, dur_s);
|
||||||
|
|
||||||
// start
|
// start
|
||||||
|
@ -1190,7 +1255,7 @@ int CmdEM4x50Sim(const char *Cmd) {
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"},
|
||||||
{"brute", CmdEM4x50Brute, IfPm3EM4x50, "Simple bruteforce attack to find password"},
|
{"brute", CmdEM4x50Brute, IfPm3EM4x50, "Bruteforce attack to find password"},
|
||||||
{"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords from dictionary"},
|
{"chk", CmdEM4x50Chk, IfPm3EM4x50, "Check passwords from dictionary"},
|
||||||
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"},
|
{"dump", CmdEM4x50Dump, IfPm3EM4x50, "Dump EM4x50 tag"},
|
||||||
{"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"},
|
{"info", CmdEM4x50Info, IfPm3EM4x50, "Tag information"},
|
||||||
|
|
|
@ -68,15 +68,20 @@ static int usart_txrx(uint8_t *srcdata, size_t srclen, uint8_t *dstdata, size_t
|
||||||
struct payload_header header;
|
struct payload_header header;
|
||||||
uint8_t data[PM3_CMD_DATA_SIZE - sizeof(uint32_t)];
|
uint8_t data[PM3_CMD_DATA_SIZE - sizeof(uint32_t)];
|
||||||
} PACKED payload;
|
} PACKED payload;
|
||||||
|
|
||||||
payload.header.waittime = waittime;
|
payload.header.waittime = waittime;
|
||||||
if (srclen >= sizeof(payload.data))
|
|
||||||
|
if (srclen >= sizeof(payload.data)) {
|
||||||
return PM3_EOVFLOW;
|
return PM3_EOVFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(payload.data, srcdata, srclen);
|
memcpy(payload.data, srcdata, srclen);
|
||||||
SendCommandNG(CMD_USART_TXRX, (uint8_t *)&payload, srclen + sizeof(payload.header));
|
SendCommandNG(CMD_USART_TXRX, (uint8_t *)&payload, srclen + sizeof(payload.header));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_USART_TXRX, &resp, waittime + 500)) {
|
if (WaitForResponseTimeout(CMD_USART_TXRX, &resp, waittime + 500) == false) {
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.status == PM3_SUCCESS) {
|
if (resp.status == PM3_SUCCESS) {
|
||||||
*dstlen = resp.length;
|
*dstlen = resp.length;
|
||||||
memcpy(dstdata, resp.data.asBytes, resp.length);
|
memcpy(dstdata, resp.data.asBytes, resp.length);
|
||||||
|
@ -154,10 +159,11 @@ static int usart_bt_testcomm(uint32_t baudrate, uint8_t parity) {
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "TX (%3zu):%.*s at %u 8%c1", strlen(string), (int)strlen(string), string, baudrate, parity);
|
PrintAndLogEx(SUCCESS, "TX (%3zu):%.*s at %u 8%c1", strlen(string), (int)strlen(string), string, baudrate, parity);
|
||||||
|
|
||||||
ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); // such large timeout needed
|
// 1000, such large timeout needed
|
||||||
|
ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000);
|
||||||
if (ret == PM3_SUCCESS) {
|
if (ret == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "RX (%3zu):%.*s", len, (int)len, data);
|
PrintAndLogEx(SUCCESS, "RX (%3zu):%.*s", len, (int)len, data);
|
||||||
if (strcmp((char *)data, "hc01.comV2.0") == 0) {
|
if (str_startswith((char *)data, "hc01.comV2.0") || str_startswith((char *)data, "BT SPP V3.0")) {
|
||||||
PrintAndLogEx(SUCCESS, "Add-on " _GREEN_("found!"));
|
PrintAndLogEx(SUCCESS, "Add-on " _GREEN_("found!"));
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@
|
||||||
#include "util_posix.h" // msclock
|
#include "util_posix.h" // msclock
|
||||||
#include "util_darwin.h" // en/dis-ableNapp();
|
#include "util_darwin.h" // en/dis-ableNapp();
|
||||||
|
|
||||||
//#define COMMS_DEBUG
|
// #define COMMS_DEBUG
|
||||||
//#define COMMS_DEBUG_RAW
|
// #define COMMS_DEBUG_RAW
|
||||||
|
|
||||||
// Serial port that we are communicating with the PM3 on.
|
// Serial port that we are communicating with the PM3 on.
|
||||||
static serial_port sp = NULL;
|
static serial_port sp = NULL;
|
||||||
|
@ -369,6 +369,7 @@ __attribute__((force_align_arg_pointer))
|
||||||
}
|
}
|
||||||
|
|
||||||
res = uart_receive(sp, (uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), &rxlen);
|
res = uart_receive(sp, (uint8_t *)&rx_raw.pre, sizeof(PacketResponseNGPreamble), &rxlen);
|
||||||
|
|
||||||
if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) {
|
if ((res == PM3_SUCCESS) && (rxlen == sizeof(PacketResponseNGPreamble))) {
|
||||||
rx.magic = rx_raw.pre.magic;
|
rx.magic = rx_raw.pre.magic;
|
||||||
uint16_t length = rx_raw.pre.length;
|
uint16_t length = rx_raw.pre.length;
|
||||||
|
@ -380,6 +381,7 @@ __attribute__((force_align_arg_pointer))
|
||||||
PrintAndLogEx(WARNING, "Received packet frame with incompatible length: 0x%04x", length);
|
PrintAndLogEx(WARNING, "Received packet frame with incompatible length: 0x%04x", length);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!error) && (length > 0)) { // Get the variable length payload
|
if ((!error) && (length > 0)) { // Get the variable length payload
|
||||||
|
|
||||||
res = uart_receive(sp, (uint8_t *)&rx_raw.data, length, &rxlen);
|
res = uart_receive(sp, (uint8_t *)&rx_raw.data, length, &rxlen);
|
||||||
|
@ -418,10 +420,10 @@ __attribute__((force_align_arg_pointer))
|
||||||
rx.length = 0; // set received length to 0
|
rx.length = 0; // set received length to 0
|
||||||
else { // old frames can't be empty
|
else { // old frames can't be empty
|
||||||
PrintAndLogEx(WARNING, "Received empty MIX packet frame (length: 0x00)");
|
PrintAndLogEx(WARNING, "Received empty MIX packet frame (length: 0x00)");
|
||||||
|
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error) { // Get the postamble
|
if (!error) { // Get the postamble
|
||||||
res = uart_receive(sp, (uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), &rxlen);
|
res = uart_receive(sp, (uint8_t *)&rx_raw.foopost, sizeof(PacketResponseNGPostamble), &rxlen);
|
||||||
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseNGPostamble))) {
|
if ((res != PM3_SUCCESS) || (rxlen != sizeof(PacketResponseNGPostamble))) {
|
||||||
|
@ -429,6 +431,7 @@ __attribute__((force_align_arg_pointer))
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error) { // Check CRC, accept MAGIC as placeholder
|
if (!error) { // Check CRC, accept MAGIC as placeholder
|
||||||
rx.crc = rx_raw.foopost.crc;
|
rx.crc = rx_raw.foopost.crc;
|
||||||
if (rx.crc != RESPONSENG_POSTAMBLE_MAGIC) {
|
if (rx.crc != RESPONSENG_POSTAMBLE_MAGIC) {
|
||||||
|
|
|
@ -805,7 +805,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_
|
||||||
fflush(f);
|
fflush(f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName);
|
PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s"), fileName);
|
||||||
PrintAndLogEx(INFO, "FYI! --> " _YELLOW_("0xFFFFFFFFFFFF") " <-- has been inserted for unknown keys where " _YELLOW_("res") " is " _YELLOW_("0"));
|
PrintAndLogEx(INFO, "FYI! --> " _YELLOW_("0xFFFFFFFFFFFF") " <-- has been inserted for unknown keys where " _YELLOW_("res") " is " _RED_("0"));
|
||||||
free(fileName);
|
free(fileName);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -530,7 +530,7 @@ uint8_t mfSectorTrailerOfSector(uint8_t sectorNo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes blockno is 0-255..
|
// assumes blockno is 0-255..
|
||||||
uint8_t mfSectorTrailer(uint8_t blockNo) {
|
uint8_t mfSectorTrailer(uint16_t blockNo) {
|
||||||
if (blockNo < 32 * 4) {
|
if (blockNo < 32 * 4) {
|
||||||
return (blockNo | 0x03);
|
return (blockNo | 0x03);
|
||||||
} else {
|
} else {
|
||||||
|
@ -539,15 +539,15 @@ uint8_t mfSectorTrailer(uint8_t blockNo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes blockno is 0-255..
|
// assumes blockno is 0-255..
|
||||||
bool mfIsSectorTrailer(uint8_t blockNo) {
|
bool mfIsSectorTrailer(uint16_t blockNo) {
|
||||||
return (blockNo == mfSectorTrailer(blockNo));
|
return (blockNo == mfSectorTrailer(blockNo));
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes blockno is 0-255..
|
// assumes blockno is 0-255..
|
||||||
uint8_t mfSectorNum(uint8_t blockNo) {
|
uint8_t mfSectorNum(uint16_t blockNo) {
|
||||||
if (blockNo < 32 * 4)
|
if (blockNo < 32 * 4)
|
||||||
return blockNo / 4;
|
return (blockNo / 4);
|
||||||
else
|
else
|
||||||
return 32 + (blockNo - 32 * 4) / 16;
|
return (32 + (blockNo - 32 * 4) / 16);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,9 @@ const char *mfGetAccessConditionsDesc(uint8_t blockn, const uint8_t *data);
|
||||||
uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
|
uint8_t mfNumBlocksPerSector(uint8_t sectorNo);
|
||||||
uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
|
uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
|
||||||
uint8_t mfSectorTrailerOfSector(uint8_t sectorNo);
|
uint8_t mfSectorTrailerOfSector(uint8_t sectorNo);
|
||||||
uint8_t mfSectorTrailer(uint8_t blockNo);
|
uint8_t mfSectorTrailer(uint16_t blockNo);
|
||||||
bool mfIsSectorTrailer(uint8_t blockNo);
|
bool mfIsSectorTrailer(uint16_t blockNo);
|
||||||
uint8_t mfSectorNum(uint8_t blockNo);
|
uint8_t mfSectorNum(uint16_t blockNo);
|
||||||
|
|
||||||
|
|
||||||
#endif // mifare4.h
|
#endif // mifare4.h
|
||||||
|
|
|
@ -45,7 +45,10 @@ static const uint64_t g_mifare_default_keys[] = {
|
||||||
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||||
0xa0a1a2a3a4a5, // NFCForum MAD key
|
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||||
0xd3f7d3f7d3f7, // NDEF public key
|
0xd3f7d3f7d3f7, // NDEF public key
|
||||||
0x4b791bea7bcc, // MFC EV1 Signature B
|
0x4b791bea7bcc, // MFC EV1 Signature 17 B
|
||||||
|
0x5C8FF9990DA2, // MFC EV1 Signature 16 A
|
||||||
|
0xD01AFEEB890A, // MFC EV1 Signature 16 B
|
||||||
|
0x75CCB59C9BED, // MFC EV1 Signature 17 A
|
||||||
0xfc00018778f7, // Public Transport
|
0xfc00018778f7, // Public Transport
|
||||||
0x6471a5ef2d1a, // SimonsVoss
|
0x6471a5ef2d1a, // SimonsVoss
|
||||||
0x4E3552426B32, // ID06
|
0x4E3552426B32, // ID06
|
||||||
|
@ -72,6 +75,11 @@ static const uint64_t g_mifare_default_keys[] = {
|
||||||
0x199404281998, // NSP B
|
0x199404281998, // NSP B
|
||||||
0x6A1987C40A21, // SALTO
|
0x6A1987C40A21, // SALTO
|
||||||
0x7F33625BC129, // SALTO
|
0x7F33625BC129, // SALTO
|
||||||
|
0x484944204953, // HID
|
||||||
|
0x204752454154, // HID
|
||||||
|
0x3B7E4FD575AD, // HID
|
||||||
|
0x11496F97752A, // HID
|
||||||
|
0x3E65E4FB65B3, // Gym
|
||||||
0x000000000000, // Blank key
|
0x000000000000, // Blank key
|
||||||
0xb0b1b2b3b4b5,
|
0xb0b1b2b3b4b5,
|
||||||
0xaabbccddeeff,
|
0xaabbccddeeff,
|
||||||
|
|
|
@ -285,6 +285,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
|
||||||
|
|
||||||
// Try to retrieve the old (current) terminal info struct
|
// Try to retrieve the old (current) terminal info struct
|
||||||
if (tcgetattr(sp->fd, &sp->tiOld) == -1) {
|
if (tcgetattr(sp->fd, &sp->tiOld) == -1) {
|
||||||
|
PrintAndLogEx(ERR, "error: UART get terminal info attribute");
|
||||||
uart_close(sp);
|
uart_close(sp);
|
||||||
return INVALID_SERIAL_PORT;
|
return INVALID_SERIAL_PORT;
|
||||||
}
|
}
|
||||||
|
@ -305,6 +306,8 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
|
||||||
|
|
||||||
// Try to set the new terminal info struct
|
// Try to set the new terminal info struct
|
||||||
if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) {
|
if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) {
|
||||||
|
PrintAndLogEx(ERR, "error: UART set terminal info attribute");
|
||||||
|
perror("tcsetattr() error");
|
||||||
uart_close(sp);
|
uart_close(sp);
|
||||||
return INVALID_SERIAL_PORT;
|
return INVALID_SERIAL_PORT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
|
||||||
free(prefix);
|
free(prefix);
|
||||||
|
|
||||||
if (strlen(pcPortName) <= 4) {
|
if (strlen(pcPortName) <= 4) {
|
||||||
|
PrintAndLogEx(ERR, "error: tcp port name length too short");
|
||||||
free(sp);
|
free(sp);
|
||||||
return INVALID_SERIAL_PORT;
|
return INVALID_SERIAL_PORT;
|
||||||
}
|
}
|
||||||
|
|
129
common/bruteforce.c
Normal file
129
common/bruteforce.c
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "bruteforce.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
uint8_t charset_digits[] = {
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t charset_uppercase[] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
|
||||||
|
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'W',
|
||||||
|
'X', 'Y', 'Z'
|
||||||
|
};
|
||||||
|
|
||||||
|
void bf_generator_init(generator_context_t *ctx, uint8_t mode) {
|
||||||
|
memset(ctx, 0, sizeof(generator_context_t));
|
||||||
|
ctx->mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets) {
|
||||||
|
if (ctx->mode != BRUTEFORCE_MODE_CHARSET) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charsets & CHARSET_DIGITS) {
|
||||||
|
memcpy(ctx->charset, charset_digits, sizeof(charset_digits));
|
||||||
|
ctx->charset_length += sizeof(charset_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (charsets & CHARSET_UPPERCASE) {
|
||||||
|
memcpy(ctx->charset + ctx->charset_length, charset_uppercase, sizeof(charset_uppercase));
|
||||||
|
ctx->charset_length += sizeof(charset_uppercase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bf_generate32(generator_context_t *ctx) {
|
||||||
|
|
||||||
|
switch (ctx->mode) {
|
||||||
|
case BRUTEFORCE_MODE_RANGE:
|
||||||
|
return _bf_generate_mode_range32(ctx);
|
||||||
|
case BRUTEFORCE_MODE_CHARSET:
|
||||||
|
return _bf_generate_mode_charset32(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GENERATOR_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _bf_generate_mode_range32(generator_context_t *ctx) {
|
||||||
|
|
||||||
|
if (ctx->current_key32 >= ctx->range_high) {
|
||||||
|
return GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we use flag1 as indicator if value of range_low was already emitted
|
||||||
|
// so the range generated is <range_low, range_high>
|
||||||
|
if (ctx->current_key32 <= ctx->range_low && ctx->flag1 == false) {
|
||||||
|
ctx->current_key32 = ctx->range_low;
|
||||||
|
ctx->pos[0] = true;
|
||||||
|
return GENERATOR_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->current_key32++;
|
||||||
|
return GENERATOR_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _bf_generate_mode_charset32(generator_context_t *ctx) {
|
||||||
|
|
||||||
|
if (ctx->flag1)
|
||||||
|
return GENERATOR_END;
|
||||||
|
|
||||||
|
ctx->current_key32 = ctx->charset[ctx->pos[0]] << 24 | ctx->charset[ctx->pos[1]] << 16 |
|
||||||
|
ctx->charset[ctx->pos[2]] << 8 | ctx->charset[ctx->pos[3]];
|
||||||
|
|
||||||
|
|
||||||
|
if (bf_array_increment(ctx->pos, 4, ctx->charset_length) == -1)
|
||||||
|
// set flag1 to emit value last time and end generation
|
||||||
|
ctx->flag1 = true;
|
||||||
|
|
||||||
|
return GENERATOR_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increments values in array with carryover using modulo limit for each byte
|
||||||
|
// this is used to iterate each byte in key over charset table
|
||||||
|
// returns -1 if incrementing reaches its end
|
||||||
|
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) {
|
||||||
|
|
||||||
|
uint8_t prev_value;
|
||||||
|
|
||||||
|
// check if we reached max value already
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < data_len; i++)
|
||||||
|
if (data[i] < modulo - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == data_len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (uint8_t pos = data_len - 1;; pos--) {
|
||||||
|
prev_value = ++data[pos];
|
||||||
|
data[pos] = data[pos] % modulo;
|
||||||
|
if (prev_value == data[pos])
|
||||||
|
return 0;
|
||||||
|
else if (pos == 0) {
|
||||||
|
// we cannot carryover to next byte
|
||||||
|
// with the max value check in place before, we should not reach this place
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
79
common/bruteforce.h
Normal file
79
common/bruteforce.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// functions for bruteforcing card keys - key generators
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef BRUTEFORCE_H__
|
||||||
|
#define BRUTEFORCE_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef uint8_t bruteforce_mode_t;
|
||||||
|
// bruteforcing all keys sequentially between X and Y
|
||||||
|
#define BRUTEFORCE_MODE_RANGE 1
|
||||||
|
|
||||||
|
// try keys based on limited charset/passphrases
|
||||||
|
// some payment systems use user-provided passphrase as system key
|
||||||
|
#define BRUTEFORCE_MODE_CHARSET 2
|
||||||
|
|
||||||
|
// "smart" mode - try some predictable patterns
|
||||||
|
#define BRUTEFORCE_MODE_SMART 3
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint8_t bruteforce_charset_t;
|
||||||
|
// bit flags - can be used together using logical OR
|
||||||
|
#define CHARSET_DIGITS 1
|
||||||
|
#define CHARSET_UPPERCASE 2
|
||||||
|
|
||||||
|
#define GENERATOR_END 0
|
||||||
|
#define GENERATOR_NEXT 1
|
||||||
|
#define GENERATOR_ERROR 2
|
||||||
|
|
||||||
|
#define CHARSET_DIGITS_SIZE 10
|
||||||
|
#define CHARSET_UPPERCASE_SIZE 25
|
||||||
|
|
||||||
|
extern uint8_t charset_digits[];
|
||||||
|
extern uint8_t charset_uppercase[];
|
||||||
|
|
||||||
|
// structure to hold key generator temporary data
|
||||||
|
typedef struct {
|
||||||
|
// position of each of 4 bytes in 32 bit key in charset mode
|
||||||
|
// add more bytes to support larger keys
|
||||||
|
// pos[0] is most significant byte - all maths avoid relying on little/big endian memory layout
|
||||||
|
uint8_t pos[4];
|
||||||
|
uint32_t current_key32;
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t charset[
|
||||||
|
CHARSET_DIGITS_SIZE
|
||||||
|
+ CHARSET_UPPERCASE_SIZE
|
||||||
|
];
|
||||||
|
uint8_t charset_length;
|
||||||
|
|
||||||
|
uint32_t range_low;
|
||||||
|
uint32_t range_high;
|
||||||
|
// flags to use internally by generators as they wish
|
||||||
|
bool flag1, flag2, flag3;
|
||||||
|
|
||||||
|
} generator_context_t;
|
||||||
|
|
||||||
|
void bf_generator_init(generator_context_t *ctx, uint8_t mode);
|
||||||
|
int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets);
|
||||||
|
int bf_generate32(generator_context_t *ctx);
|
||||||
|
int _bf_generate_mode_range32(generator_context_t *ctx);
|
||||||
|
int _bf_generate_mode_charset32(generator_context_t *ctx);
|
||||||
|
int _bf_generate_mode_smart32(generator_context_t *ctx);
|
||||||
|
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo);
|
||||||
|
#endif // BRUTEFORCE_H__
|
|
@ -4370,9 +4370,10 @@
|
||||||
"--1k MIFARE Classic 1k / S50 (def)",
|
"--1k MIFARE Classic 1k / S50 (def)",
|
||||||
"--2k MIFARE Classic/Plus 2k",
|
"--2k MIFARE Classic/Plus 2k",
|
||||||
"--4k MIFARE Classic 4k / S70",
|
"--4k MIFARE Classic 4k / S70",
|
||||||
"-v, --verbose verbose output"
|
"-v, --verbose verbose output",
|
||||||
|
"--sk Save extracted keys to file"
|
||||||
],
|
],
|
||||||
"usage": "hf mf eview [-hv] [--mini] [--1k] [--2k] [--4k]"
|
"usage": "hf mf eview [-hv] [--mini] [--1k] [--2k] [--4k] [--sk]"
|
||||||
},
|
},
|
||||||
"hf mf fchk": {
|
"hf mf fchk": {
|
||||||
"command": "hf mf fchk",
|
"command": "hf mf fchk",
|
||||||
|
@ -4950,9 +4951,10 @@
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
"-f, --file <fn> filename of dump",
|
"-f, --file <fn> filename of dump",
|
||||||
"-v, --verbose verbose output"
|
"-v, --verbose verbose output",
|
||||||
|
"--sk Save extracted keys to file"
|
||||||
],
|
],
|
||||||
"usage": "hf mf view [-hv] -f <fn>"
|
"usage": "hf mf view [-hv] -f <fn> [--sk]"
|
||||||
},
|
},
|
||||||
"hf mf wipe": {
|
"hf mf wipe": {
|
||||||
"command": "hf mf wipe",
|
"command": "hf mf wipe",
|
||||||
|
@ -8061,15 +8063,19 @@
|
||||||
"command": "lf em 4x50 brute",
|
"command": "lf em 4x50 brute",
|
||||||
"description": "Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.",
|
"description": "Tries to bruteforce the password of a EM4x50 card. Function can be stopped by pressing pm3 button.",
|
||||||
"notes": [
|
"notes": [
|
||||||
"lf em 4x50 brute --first 12330000 --last 12340000 -> tries pwds from 0x12330000 to 0x1234000000"
|
"lf em 4x50 brute --mode range --begin 12330000 --end 12340000 -> tries pwds from 0x12330000 to 0x12340000",
|
||||||
|
"lf em 4x50 brute --mode charset --digits --uppercase -> tries all combinations of ASCII codes for digits and uppercase letters"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
"--first <hex> first password (start), 4 bytes, lsb",
|
"--mode <str> Bruteforce mode (range|charset)",
|
||||||
"--last <hex> last password (stop), 4 bytes, lsb"
|
"--begin <hex> Range mode - start of the key range",
|
||||||
|
"--end <hex> Range mode - end of the key range",
|
||||||
|
"--digits Charset mode - include ASCII codes for digits",
|
||||||
|
"--uppercase Charset mode - include ASCII codes for uppercase letters"
|
||||||
],
|
],
|
||||||
"usage": "lf em 4x50 brute [-h] --first <hex> --last <hex>"
|
"usage": "lf em 4x50 brute [-h] --mode <str> [--begin <hex>] [--end <hex>] [--digits] [--uppercase]"
|
||||||
},
|
},
|
||||||
"lf em 4x50 chk": {
|
"lf em 4x50 chk": {
|
||||||
"command": "lf em 4x50 chk",
|
"command": "lf em 4x50 chk",
|
||||||
|
@ -10896,7 +10902,7 @@
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
"-f, --file <fn> SPIFFS file to view",
|
"-f, --file <fn> SPIFFS file to view",
|
||||||
"-c, --cols <dec> column breaks (def 32)"
|
"-c, --cols <dec> column breaks (def 16)"
|
||||||
],
|
],
|
||||||
"usage": "mem spiffs view [-h] -f <fn> [-c <dec>]"
|
"usage": "mem spiffs view [-h] -f <fn> [-c <dec>]"
|
||||||
},
|
},
|
||||||
|
@ -12019,5 +12025,6 @@
|
||||||
"commands_extracted": 755,
|
"commands_extracted": 755,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2023-06-04T15:36:56"
|
"extracted_on": "2023-06-04T15:36:56"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -875,7 +875,7 @@ Check column "offline" for their availability.
|
||||||
|command |offline |description
|
|command |offline |description
|
||||||
|------- |------- |-----------
|
|------- |------- |-----------
|
||||||
|`lf em 4x50 help `|Y |`This help`
|
|`lf em 4x50 help `|Y |`This help`
|
||||||
|`lf em 4x50 brute `|N |`Simple bruteforce attack to find password`
|
|`lf em 4x50 brute `|N |`Bruteforce attack to find password`
|
||||||
|`lf em 4x50 chk `|N |`Check passwords from dictionary`
|
|`lf em 4x50 chk `|N |`Check passwords from dictionary`
|
||||||
|`lf em 4x50 dump `|N |`Dump EM4x50 tag`
|
|`lf em 4x50 dump `|N |`Dump EM4x50 tag`
|
||||||
|`lf em 4x50 info `|N |`Tag information`
|
|`lf em 4x50 info `|N |`Tag information`
|
||||||
|
|
|
@ -199,7 +199,7 @@ The ROLE command takes its parameter after an equal sign:
|
||||||
|
|
||||||
|Command |Description |Reply |
|
|Command |Description |Reply |
|
||||||
|-------------------|------------------------------------------------------|--------------|
|
|-------------------|------------------------------------------------------|--------------|
|
||||||
|`AT+VERSION` |print firmware version |`hc01.comV2.0`|
|
|`AT+VERSION` |print firmware version |`hc01.comV2.0` or `BT SPP V3.0`|
|
||||||
|`AT+BAUD8` |set baudrate to 115200 |`OK115200` |
|
|`AT+BAUD8` |set baudrate to 115200 |`OK115200` |
|
||||||
|`AT+PIN1234` |set PINCODE to 1234. (must be numbers) |`OKsetPIN` |
|
|`AT+PIN1234` |set PINCODE to 1234. (must be numbers) |`OKsetPIN` |
|
||||||
|`AT+NAMEPM3_RDV4.0`|set device name (as shown to BT hosts) to `PM3_RDV4.0`|`OKsetname` |
|
|`AT+NAMEPM3_RDV4.0`|set device name (as shown to BT hosts) to `PM3_RDV4.0`|`OKsetname` |
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -222,7 +222,7 @@ reg signed [10:0] rx_mod_falling_edge_max;
|
||||||
reg signed [10:0] rx_mod_rising_edge_max;
|
reg signed [10:0] rx_mod_rising_edge_max;
|
||||||
reg curbit;
|
reg curbit;
|
||||||
|
|
||||||
`define EDGE_DETECT_THRESHOLD 3
|
`define EDGE_DETECT_THRESHOLD 5
|
||||||
`define EDGE_DETECT_THRESHOLDHIGH 20
|
`define EDGE_DETECT_THRESHOLDHIGH 20
|
||||||
|
|
||||||
always @(negedge adc_clk)
|
always @(negedge adc_clk)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define EM4X50_H__
|
#define EM4X50_H__
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "bruteforce.h"
|
||||||
|
|
||||||
#define EM4X50_NO_WORDS 34
|
#define EM4X50_NO_WORDS 34
|
||||||
|
|
||||||
|
@ -62,6 +63,8 @@ typedef struct {
|
||||||
uint32_t password2;
|
uint32_t password2;
|
||||||
uint32_t word;
|
uint32_t word;
|
||||||
uint32_t addresses;
|
uint32_t addresses;
|
||||||
|
bruteforce_mode_t bruteforce_mode;
|
||||||
|
bruteforce_charset_t bruteforce_charset;
|
||||||
} PACKED em4x50_data_t;
|
} PACKED em4x50_data_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
2
pm3
2
pm3
|
@ -115,7 +115,7 @@ function get_pm3_list_Linux {
|
||||||
if $FINDBTDIRECT; then
|
if $FINDBTDIRECT; then
|
||||||
# check if the MAC of a Proxmark3 was registered in the known devices
|
# check if the MAC of a Proxmark3 was registered in the known devices
|
||||||
for MAC in $(dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/' org.freedesktop.DBus.ObjectManager.GetManagedObjects 2>/dev/null|\
|
for MAC in $(dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/' org.freedesktop.DBus.ObjectManager.GetManagedObjects 2>/dev/null|\
|
||||||
awk '/"Address"/{getline;gsub(/"/,"",$3);a=$3}/Name/{getline;if (/PM3_RDV4/) print a}'); do
|
awk '/"Address"/{getline;gsub(/"/,"",$3);a=$3}/Name/{getline;if (/PM3_RDV4/ || /Proxmark3 SE/) print a}'); do
|
||||||
PM3LIST+=("bt:$MAC")
|
PM3LIST+=("bt:$MAC")
|
||||||
done
|
done
|
||||||
# we don't probe the device so there is no guarantee the device is actually present
|
# we don't probe the device so there is no guarantee the device is actually present
|
||||||
|
|
1
tools/btaddon/requirements.txt
Normal file
1
tools/btaddon/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pyserial==3.5.0
|
Loading…
Add table
Add a link
Reference in a new issue