mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 13:00:42 -07:00
commit
53927b6a5c
11 changed files with 212 additions and 78 deletions
|
@ -930,12 +930,12 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
|
|
||||||
#ifdef WITH_HITAG
|
#ifdef WITH_HITAG
|
||||||
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
|
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
|
||||||
SniffHitag();
|
SniffHitag2();
|
||||||
// SniffHitag(packet->oldarg[0]);
|
// SniffHitag2(packet->oldarg[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content
|
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content
|
||||||
SimulateHitagTag((bool)packet->oldarg[0], packet->data.asBytes);
|
SimulateHitag2((bool)packet->oldarg[0], packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function
|
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function
|
||||||
|
@ -1176,6 +1176,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_HF_MIFARE_CHKKEYS_FILE: {
|
||||||
|
struct p {
|
||||||
|
uint8_t filename[32];
|
||||||
|
} PACKED;
|
||||||
|
struct p *payload = (struct p *) packet->data.asBytes;
|
||||||
|
MifareChkKeys_file(payload->filename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case CMD_HF_MIFARE_SIMULATE: {
|
case CMD_HF_MIFARE_SIMULATE: {
|
||||||
struct p {
|
struct p {
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
|
@ -35,6 +35,12 @@
|
||||||
#include "lfdemod.h"
|
#include "lfdemod.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define test_bit(data, i) (*(data + (i/8)) >> (7-(i % 8))) & 1
|
||||||
|
#define set_bit(data, i) *(data + (i/8)) |= (1 << (7-(i % 8)))
|
||||||
|
#define clear_bit(data, i) *(data + (i/8)) &= ~(1 << (7-(i % 8)))
|
||||||
|
#define flip_bit(data, i) *(data + (i/8)) ^= (1 << (7-(i % 8)))
|
||||||
|
|
||||||
// Successful crypto auth
|
// Successful crypto auth
|
||||||
static bool bCrypto;
|
static bool bCrypto;
|
||||||
// Is in auth stage
|
// Is in auth stage
|
||||||
|
@ -70,7 +76,6 @@ static enum {
|
||||||
WRITE_STATE_PROG
|
WRITE_STATE_PROG
|
||||||
} writestate;
|
} writestate;
|
||||||
|
|
||||||
|
|
||||||
// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces.
|
// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces.
|
||||||
// Historically it used to be FREE_BUFFER_SIZE, which was 2744.
|
// Historically it used to be FREE_BUFFER_SIZE, which was 2744.
|
||||||
#define AUTH_TABLE_LENGTH 2744
|
#define AUTH_TABLE_LENGTH 2744
|
||||||
|
@ -87,6 +92,11 @@ uint8_t nonce[4];
|
||||||
bool key_no;
|
bool key_no;
|
||||||
static uint64_t cipher_state;
|
static uint64_t cipher_state;
|
||||||
|
|
||||||
|
size_t blocknr;
|
||||||
|
size_t flipped_bit = 0;
|
||||||
|
uint32_t byte_value = 0;
|
||||||
|
|
||||||
|
|
||||||
static int hitag2_reset(void) {
|
static int hitag2_reset(void) {
|
||||||
tag.state = TAG_STATE_RESET;
|
tag.state = TAG_STATE_RESET;
|
||||||
tag.crypto_active = 0;
|
tag.crypto_active = 0;
|
||||||
|
@ -135,10 +145,12 @@ static int hitag2_init(void) {
|
||||||
|
|
||||||
static void hitag_send_bit(int bit) {
|
static void hitag_send_bit(int bit) {
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
|
||||||
// Reset clock for the next bit
|
// Reset clock for the next bit
|
||||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||||
|
|
||||||
// Fixed modulation, earlier proxmark version used inverted signal
|
// Fixed modulation, earlier proxmark version used inverted signal
|
||||||
|
// check datasheet if reader uses BiPhase?
|
||||||
if (bit == 0) {
|
if (bit == 0) {
|
||||||
// Manchester: Unloaded, then loaded |__--|
|
// Manchester: Unloaded, then loaded |__--|
|
||||||
LOW(GPIO_SSC_DOUT);
|
LOW(GPIO_SSC_DOUT);
|
||||||
|
@ -351,8 +363,6 @@ static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len)
|
||||||
return wait;
|
return wait;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t blocknr;
|
|
||||||
|
|
||||||
uint8_t hitag_crc(uint8_t *data, size_t length) {
|
uint8_t hitag_crc(uint8_t *data, size_t length) {
|
||||||
uint8_t crc = 0xff;
|
uint8_t crc = 0xff;
|
||||||
unsigned int byte, bit;
|
unsigned int byte, bit;
|
||||||
|
@ -371,10 +381,7 @@ uint8_t hitag_crc(uint8_t *data, size_t length) {
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define test_bit(data, i) (*(data+(i/8)) >> (7-(i%8))) & 1
|
/*
|
||||||
#define set_bit(data, i) *(data+(i/8)) |= (1 << (7-(i%8)))
|
|
||||||
#define clear_bit(data, i) *(data+(i/8)) &= ~(1 << (7-(i%8)))
|
|
||||||
#define flip_bit(data, i) *(data+(i/8)) ^= (1 << (7-(i%8)))
|
|
||||||
void fix_ac_decoding(uint8_t *input, size_t len) {
|
void fix_ac_decoding(uint8_t *input, size_t len) {
|
||||||
// Reader routine tries to decode AC data after Manchester decoding
|
// Reader routine tries to decode AC data after Manchester decoding
|
||||||
// AC has double the bitrate, extract data from bit-pairs
|
// AC has double the bitrate, extract data from bit-pairs
|
||||||
|
@ -388,7 +395,12 @@ void fix_ac_decoding(uint8_t *input, size_t len) {
|
||||||
}
|
}
|
||||||
memcpy(input, temp, sizeof(temp));
|
memcpy(input, temp, sizeof(temp));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// looks at number of received bits.
|
||||||
|
// 0 = collision?
|
||||||
|
// 32 = good response
|
||||||
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
|
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
|
||||||
uint8_t crc;
|
uint8_t crc;
|
||||||
*txlen = 0;
|
*txlen = 0;
|
||||||
|
@ -457,9 +469,7 @@ bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bo
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t flipped_bit = 0;
|
|
||||||
|
|
||||||
uint32_t byte_value = 0;
|
|
||||||
bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) {
|
||||||
uint8_t crc;
|
uint8_t crc;
|
||||||
*txlen = 0;
|
*txlen = 0;
|
||||||
|
@ -958,7 +968,7 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitag2 Sniffing
|
// Hitag2 Sniffing
|
||||||
void SniffHitag(void) {
|
void SniffHitag2(void) {
|
||||||
|
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
StopTicks();
|
StopTicks();
|
||||||
|
@ -1037,7 +1047,7 @@ void SniffHitag(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hitag2 simulation
|
// Hitag2 simulation
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) {
|
void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
||||||
|
|
||||||
StopTicks();
|
StopTicks();
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "hitag.h"
|
#include "hitag.h"
|
||||||
|
|
||||||
void SniffHitag(void);
|
void SniffHitag2(void);
|
||||||
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data);
|
void SimulateHitag2(bool tag_mem_supplied, uint8_t *data);
|
||||||
void ReaderHitag(hitag_function htf, hitag_data *htd);
|
void ReaderHitag(hitag_function htf, hitag_data *htd);
|
||||||
void WriterHitag(hitag_function htf, hitag_data *htd, int page);
|
void WriterHitag(hitag_function htf, hitag_data *htd, int page);
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,9 @@ void lf_init(bool reader) {
|
||||||
|
|
||||||
if (logging) initSampleBuffer(&bufsize);
|
if (logging) initSampleBuffer(&bufsize);
|
||||||
|
|
||||||
|
sample_config *sc = getSamplingConfig();
|
||||||
|
sc->decimation = 2;
|
||||||
|
sc->averaging = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lf_finalize() {
|
void lf_finalize() {
|
||||||
|
@ -202,6 +205,10 @@ void lf_finalize() {
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
|
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
|
||||||
|
sample_config *sc = getSamplingConfig();
|
||||||
|
sc->decimation = 1;
|
||||||
|
sc->averaging = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t lf_detect_field_drop(size_t max) {
|
size_t lf_detect_field_drop(size_t max) {
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "dbprint.h"
|
#include "dbprint.h"
|
||||||
#include "ticks.h"
|
#include "ticks.h"
|
||||||
#include "usb_cdc.h" // usb_poll_validate_length
|
#include "usb_cdc.h" // usb_poll_validate_length
|
||||||
|
#include "spiffs.h" // spiffs
|
||||||
|
|
||||||
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
||||||
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||||
|
@ -1701,14 +1702,15 @@ void MifareChkKeys(uint8_t *datain) {
|
||||||
bool found;
|
bool found;
|
||||||
} PACKED keyresult;
|
} PACKED keyresult;
|
||||||
keyresult.found = false;
|
keyresult.found = false;
|
||||||
uint8_t blockNo, keyType, keyCount;
|
uint8_t blockNo, keyType;
|
||||||
|
uint16_t keyCount;
|
||||||
bool clearTrace, have_uid = false;
|
bool clearTrace, have_uid = false;
|
||||||
|
|
||||||
keyType = datain[0];
|
keyType = datain[0];
|
||||||
blockNo = datain[1];
|
blockNo = datain[1];
|
||||||
clearTrace = datain[2];
|
clearTrace = datain[2];
|
||||||
keyCount = datain[3];
|
keyCount = (datain[3] << 8) | datain[4];
|
||||||
datain += 4;
|
datain += 5;
|
||||||
|
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
LED_A_ON();
|
LED_A_ON();
|
||||||
|
@ -1780,6 +1782,27 @@ void MifareChkKeys(uint8_t *datain) {
|
||||||
DBGLEVEL = oldbg;
|
DBGLEVEL = oldbg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MifareChkKeys_file(uint8_t *fn) {
|
||||||
|
|
||||||
|
SpinOff(0);
|
||||||
|
|
||||||
|
int changed = rdv40_spiffs_lazy_mount();
|
||||||
|
uint32_t size = size_in_spiffs((char *)fn);
|
||||||
|
uint8_t *mem = BigBuf_malloc(size);
|
||||||
|
|
||||||
|
rdv40_spiffs_read_as_filetype((char *)fn, mem, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
rdv40_spiffs_lazy_unmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinOff(0);
|
||||||
|
|
||||||
|
MifareChkKeys(mem);
|
||||||
|
|
||||||
|
BigBuf_free();
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Work with emulator memory
|
// Work with emulator memory
|
||||||
//
|
//
|
||||||
|
|
|
@ -31,6 +31,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
||||||
void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
|
void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
|
||||||
void MifareChkKeys(uint8_t *datain);
|
void MifareChkKeys(uint8_t *datain);
|
||||||
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
void MifareChkKeys_file(uint8_t *fn);
|
||||||
|
|
||||||
void MifareEMemClr(void);
|
void MifareEMemClr(void);
|
||||||
void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain);
|
void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain);
|
||||||
|
|
|
@ -349,10 +349,15 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
||||||
bytes_sent += bytes_in_packet;
|
bytes_sent += bytes_in_packet;
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
|
||||||
|
uint8_t retry = 3;
|
||||||
|
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||||
ret_val = PM3_ETIMEOUT;
|
retry--;
|
||||||
break;
|
if (retry == 0) {
|
||||||
|
ret_val = PM3_ETIMEOUT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||||
|
@ -363,6 +368,9 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
clearCommandBuffer();
|
||||||
|
|
||||||
// turn off fast push mode
|
// turn off fast push mode
|
||||||
conn.block_after_ACK = false;
|
conn.block_after_ACK = false;
|
||||||
|
|
||||||
|
|
|
@ -563,25 +563,11 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
|
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
|
||||||
|
uint8_t *data = NULL;
|
||||||
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
|
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
|
||||||
|
|
||||||
if (htf != RHT2F_UID_ONLY) {
|
if (htf != RHT2F_UID_ONLY) {
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
|
|
||||||
uint8_t *data = resp.data.asBytes;
|
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE];
|
|
||||||
char *fnameptr = filename;
|
|
||||||
fnameptr += sprintf(fnameptr, "lf-hitag-");
|
|
||||||
FillFileNameByUID(fnameptr, data, "-dump", 4);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
saveFile(filename, ".bin", data, 48);
|
|
||||||
saveFileEML(filename, data, 48, 4);
|
|
||||||
saveFileJSON(filename, jsfHitag, data, 48);
|
|
||||||
|
|
||||||
// block3, 1 byte
|
// block3, 1 byte
|
||||||
printHitagConfiguration(data[4 * 3]);
|
printHitagConfiguration(data[4 * 3]);
|
||||||
}
|
}
|
||||||
|
@ -688,16 +674,29 @@ static int CmdLFHitagWriter(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int CmdLFHitag2Dump(const char *Cmd) {
|
||||||
static int CmdLFHitagDump(const char *Cmd) {
|
|
||||||
PrintAndLogEx(INFO, "Dumping of tag memory");
|
PrintAndLogEx(INFO, "Dumping of tag memory");
|
||||||
PrintAndLogEx(INFO, "To be done!");
|
|
||||||
|
|
||||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||||
if (ctmp == 'h') return usage_hitag_dump();
|
if (ctmp == 'h') return 0; // usage_hitag_dump();
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
|
||||||
|
uint8_t *data = resp.data.asBytes;
|
||||||
|
|
||||||
|
char filename[FILE_PATH_SIZE];
|
||||||
|
char *fnameptr = filename;
|
||||||
|
fnameptr += sprintf(fnameptr, "lf-hitag-");
|
||||||
|
FillFileNameByUID(fnameptr, data, "-dump", 4);
|
||||||
|
|
||||||
|
saveFile(filename, ".bin", data, 48);
|
||||||
|
saveFileEML(filename, data, 48, 4);
|
||||||
|
saveFileJSON(filename, jsfHitag, data, 48);
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Annotate HITAG protocol
|
// Annotate HITAG protocol
|
||||||
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
|
@ -740,14 +739,15 @@ void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help" },
|
{"help", CmdHelp, AlwaysAvailable, "This help" },
|
||||||
{"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" },
|
{"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" },
|
||||||
{"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" },
|
{"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" },
|
||||||
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" },
|
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" },
|
||||||
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" },
|
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" },
|
||||||
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" },
|
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" },
|
||||||
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" },
|
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" },
|
||||||
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" },
|
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag" },
|
||||||
|
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" },
|
||||||
{ NULL, NULL, 0, NULL }
|
{ NULL, NULL, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,14 @@
|
||||||
#include "comms.h"
|
#include "comms.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
#include "mifare4.h"
|
#include "mifare4.h"
|
||||||
#include "ui.h" // PrintAndLog...
|
#include "ui.h" // PrintAndLog...
|
||||||
#include "crapto1/crapto1.h"
|
#include "crapto1/crapto1.h"
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "mfkey.h"
|
#include "mfkey.h"
|
||||||
#include "util_posix.h" // msclock
|
#include "util_posix.h" // msclock
|
||||||
|
#include "cmdparser.h" // detection of flash capabilities
|
||||||
|
#include "cmdflashmemspiffs.h" // upload to flash mem
|
||||||
|
|
||||||
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||||
uint32_t uid = 0;
|
uint32_t uid = 0;
|
||||||
|
@ -168,9 +170,10 @@ int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keyc
|
||||||
data[0] = keyType;
|
data[0] = keyType;
|
||||||
data[1] = blockNo;
|
data[1] = blockNo;
|
||||||
data[2] = clear_trace;
|
data[2] = clear_trace;
|
||||||
data[3] = keycnt;
|
data[3] = 0;
|
||||||
memcpy(data + 4, keyBlock, 6 * keycnt);
|
data[4] = keycnt;
|
||||||
SendCommandNG(CMD_HF_MIFARE_CHKKEYS, data, (4 + 6 * keycnt));
|
memcpy(data + 5, keyBlock, 6 * keycnt);
|
||||||
|
SendCommandNG(CMD_HF_MIFARE_CHKKEYS, data, (5 + 6 * keycnt));
|
||||||
|
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_CHKKEYS, &resp, 2500)) return PM3_ETIMEOUT;
|
if (!WaitForResponseTimeout(CMD_HF_MIFARE_CHKKEYS, &resp, 2500)) return PM3_ETIMEOUT;
|
||||||
|
@ -265,6 +268,45 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger device to use a binary file on flash mem as keylist for mfCheckKeys.
|
||||||
|
// As of now, 255 keys possible in the file
|
||||||
|
// 6 * 255 = 1500 bytes
|
||||||
|
int mfCheckKeys_file(uint8_t *destfn, uint64_t *key) {
|
||||||
|
*key = -1;
|
||||||
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t filename[32];
|
||||||
|
} PACKED payload_file;
|
||||||
|
|
||||||
|
strncpy((char*)payload_file.filename, (char*)destfn, sizeof(payload_file.filename));
|
||||||
|
|
||||||
|
PacketResponseNG resp;
|
||||||
|
clearCommandBuffer();
|
||||||
|
SendCommandNG(CMD_HF_MIFARE_CHKKEYS_FILE, (uint8_t *)&payload_file, sizeof(payload_file));
|
||||||
|
|
||||||
|
uint8_t retry = 10;
|
||||||
|
|
||||||
|
while (!WaitForResponseTimeout(CMD_HF_MIFARE_CHKKEYS, &resp, 2000)) {
|
||||||
|
retry--;
|
||||||
|
if (retry ==0) {
|
||||||
|
PrintAndLogEx(WARNING, "Chk keys file, timeouted");
|
||||||
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.status != PM3_SUCCESS) return resp.status;
|
||||||
|
|
||||||
|
struct kr {
|
||||||
|
uint8_t key[6];
|
||||||
|
bool found;
|
||||||
|
} PACKED;
|
||||||
|
struct kr *keyresult = (struct kr *)&resp.data.asBytes;
|
||||||
|
if (!keyresult->found) return PM3_ESOFT;
|
||||||
|
*key = bytes_to_num(keyresult->key, sizeof(keyresult->key));
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// PM3 imp of J-Run mf_key_brute (part 2)
|
// PM3 imp of J-Run mf_key_brute (part 2)
|
||||||
// ref: https://github.com/J-Run/mf_key_brute
|
// ref: https://github.com/J-Run/mf_key_brute
|
||||||
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey) {
|
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey) {
|
||||||
|
@ -461,7 +503,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||||
if (keycnt == 0) goto out;
|
if (keycnt == 0) goto out;
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt);
|
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt);
|
||||||
|
|
||||||
memset(resultKey, 0, 6);
|
memset(resultKey, 0, 6);
|
||||||
uint64_t key64 = -1;
|
uint64_t key64 = -1;
|
||||||
|
|
||||||
|
@ -469,10 +511,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||||
uint32_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
|
uint32_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
|
||||||
uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00};
|
uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00};
|
||||||
|
|
||||||
uint64_t start_time = msclock();
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < keycnt; i += max_keys) {
|
for (uint32_t i = 0; i < keycnt; i += max_keys) {
|
||||||
|
|
||||||
|
uint64_t start_time = msclock();
|
||||||
|
|
||||||
uint8_t size = keycnt - i > max_keys ? max_keys : keycnt - i;
|
uint8_t size = keycnt - i > max_keys ? max_keys : keycnt - i;
|
||||||
|
|
||||||
register uint8_t j;
|
register uint8_t j;
|
||||||
|
@ -498,7 +540,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||||
start_time = msclock();
|
start_time = msclock();
|
||||||
|
|
||||||
if ( i + 1 % 10 == 0)
|
if ( i + 1 % 10 == 0)
|
||||||
PrintAndLogEx(INFO, " %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", keycnt - i, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
PrintAndLogEx(INFO, " %8d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt , bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,47 +643,79 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
uint64_t key64 = -1;
|
uint64_t key64 = -1;
|
||||||
|
|
||||||
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
// The list may still contain several key candidates. Test each of them with mfCheckKeys
|
||||||
uint32_t max_keys_slice = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
|
uint32_t maxkeysinblock = IfPm3Flash() ? 1600 : KEYS_IN_BLOCK;
|
||||||
uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00};
|
uint32_t max_keys_slice = keycnt > maxkeysinblock ? maxkeysinblock : keycnt;
|
||||||
|
|
||||||
|
uint8_t *mem = calloc( (maxkeysinblock * 6) + 5, sizeof(uint8_t));
|
||||||
|
if (mem == NULL) {
|
||||||
|
free(statelists[0].head.slhead);
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *p_keyblock = mem + 5;
|
||||||
|
mem[0] = statelists[0].keyType;
|
||||||
|
mem[1] = statelists[0].blockNo;
|
||||||
|
mem[2] = 1;
|
||||||
|
mem[3] = ((maxkeysinblock >> 8) & 0xFF);
|
||||||
|
mem[4] = (maxkeysinblock & 0xFF);
|
||||||
|
|
||||||
|
uint8_t destfn[32];
|
||||||
|
strncpy((char*)destfn, "static_nested_000.bin", sizeof(destfn) - 1);
|
||||||
|
|
||||||
uint64_t start_time = msclock();
|
|
||||||
for (uint32_t i = 0; i < keycnt; i += max_keys_slice) {
|
for (uint32_t i = 0; i < keycnt; i += max_keys_slice) {
|
||||||
|
|
||||||
// PrintAndLogEx(INFO, "Testing %u / %u ", i, keycnt);
|
int res = 0;
|
||||||
|
uint64_t start_time = msclock();
|
||||||
|
|
||||||
key64 = 0;
|
key64 = 0;
|
||||||
|
uint32_t size = keycnt - i > max_keys_slice ? max_keys_slice : keycnt - i;
|
||||||
uint8_t size = keycnt - i > max_keys_slice ? max_keys_slice : keycnt - i;
|
|
||||||
|
|
||||||
// copy x keys to device.
|
// copy x keys to device.
|
||||||
register uint8_t j;
|
for (uint32_t j = 0; j < size; j++) {
|
||||||
for (j = 0; j < size; j++) {
|
|
||||||
crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64);
|
crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64);
|
||||||
num_to_bytes(key64, 6, keyBlock + j * 6);
|
num_to_bytes(key64, 6, p_keyblock + j * 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check a block of generated candidate keys.
|
// check a block of generated candidate keys.
|
||||||
if (mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, size, keyBlock, &key64) == PM3_SUCCESS) {
|
if (IfPm3Flash()) {
|
||||||
|
// upload to flash.
|
||||||
|
res = flashmem_spiffs_load(destfn, mem, 5 + (size * 6) );
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(WARNING, "SPIFFS upload failed");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
free(statelists[0].head.slhead);
|
res = mfCheckKeys_file(destfn, &key64);
|
||||||
|
} else {
|
||||||
|
res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, size, mem, &key64);
|
||||||
|
}
|
||||||
|
|
||||||
num_to_bytes(key64, 6, resultKey);
|
if (res == PM3_SUCCESS) {
|
||||||
|
p_keyblock = NULL;
|
||||||
|
free(statelists[0].head.slhead);
|
||||||
|
free(mem);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
num_to_bytes(key64, 6, resultKey);
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||||
package->block,
|
package->block,
|
||||||
package->keytype ? 'B' : 'A',
|
package->keytype ? 'B' : 'A',
|
||||||
sprint_hex_inrow(resultKey, 6)
|
sprint_hex_inrow(resultKey, 6)
|
||||||
);
|
);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
} else if (res == PM3_ETIMEOUT) {
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
float bruteforce_per_second = (float)KEYS_IN_BLOCK / (float)(msclock() - start_time) * 1000.0;
|
|
||||||
|
float bruteforce_per_second = (float)maxkeysinblock / (float)(msclock() - start_time) * 1000.0;
|
||||||
start_time = msclock();
|
start_time = msclock();
|
||||||
|
|
||||||
if ( i+1 % 10 == 0)
|
PrintAndLogEx(INFO, "Chunk %8u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||||
PrintAndLogEx(INFO, " %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", keycnt - i, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p_keyblock = NULL;
|
||||||
|
free(mem);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c",
|
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c",
|
||||||
package->block,
|
package->block,
|
||||||
|
@ -649,7 +723,6 @@ out:
|
||||||
);
|
);
|
||||||
|
|
||||||
free(statelists[0].head.slhead);
|
free(statelists[0].head.slhead);
|
||||||
|
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||||
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
|
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
|
||||||
int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
|
int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk,
|
||||||
uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory);
|
uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory);
|
||||||
|
|
||||||
|
int mfCheckKeys_file(uint8_t *destfn, uint64_t *key);
|
||||||
|
|
||||||
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
|
int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey);
|
||||||
|
|
||||||
int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data);
|
int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data);
|
||||||
|
|
|
@ -500,6 +500,7 @@ typedef struct {
|
||||||
#define CMD_HF_MIFARE_CHKKEYS 0x0623
|
#define CMD_HF_MIFARE_CHKKEYS 0x0623
|
||||||
#define CMD_HF_MIFARE_SETMOD 0x0624
|
#define CMD_HF_MIFARE_SETMOD 0x0624
|
||||||
#define CMD_HF_MIFARE_CHKKEYS_FAST 0x0625
|
#define CMD_HF_MIFARE_CHKKEYS_FAST 0x0625
|
||||||
|
#define CMD_HF_MIFARE_CHKKEYS_FILE 0x0626
|
||||||
|
|
||||||
#define CMD_HF_MIFARE_SNIFF 0x0630
|
#define CMD_HF_MIFARE_SNIFF 0x0630
|
||||||
#define CMD_HF_MIFARE_MFKEY 0x0631
|
#define CMD_HF_MIFARE_MFKEY 0x0631
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue