mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 21:33:47 -07:00
Merge branch 'RfidResearchGroup:master' into master
This commit is contained in:
commit
9a1f0356a6
52 changed files with 1953 additions and 1419 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
|
||||
## [Seven.4.16717][2023-06-25]
|
||||
- Change `hf 14a info` - now identifes QL88 tags (@iceman1001)
|
||||
- Added support for compiling on iOS (@The-SamminAter)
|
||||
- Fixed viewing MFC dump - border char is now white (@iceman1001)
|
||||
- Changed `data diff` - to print filenames in header if it fits (@iceman1001)
|
||||
- Changed viewing MFC dump files - it now colors ACL + GPB bytes (@iceman1001)
|
||||
- Added `hf mf supercard --furui` - now supports key recovery from Furui detection card. Thanks foxushka! (@iceman1001)
|
||||
- Added `hf topaz dump --ns` - now supports nosave param (@iceman1001)
|
||||
- Changed `hf topaz rdbl` - unified output (@iceman1001)
|
||||
- Fixed `hf topaz wrbl` - now supports tear off and write_nonerase command (@iceman1001)
|
||||
- Fixed `hf mf` commands (@iceman1001)
|
||||
- Fixed `hf mfp` commands (@iceman1001)
|
||||
- Added more default keys (@iceman1001) Thanks anon!
|
||||
- Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001)
|
||||
- Fixed `hf 15693/iclass sniff` trace timings (@nvx)
|
||||
- Fix LegicCash segment handling in `hf_legic.lua` script (@jmichelp)
|
||||
|
|
|
@ -75,7 +75,15 @@ else
|
|||
endif
|
||||
|
||||
ifeq ($(platform),Darwin)
|
||||
USE_BREW ?= 1
|
||||
ifeq ($(shell uname -p),arm64)
|
||||
# The platform is iOS
|
||||
USE_BREW ?= 0
|
||||
# iOS refuses to compile unless this is set
|
||||
export IPHONEOS_DEPLOYMENT_TARGET=11.0
|
||||
else
|
||||
# M* macOS devices return arm
|
||||
USE_BREW ?= 1
|
||||
endif
|
||||
USE_MACPORTS ?= 0
|
||||
AR= /usr/bin/ar rcs
|
||||
RANLIB= /usr/bin/ranlib
|
||||
|
@ -132,6 +140,10 @@ ifeq ($(shell expr $(CC_VERSION) \>= 10), 1)
|
|||
endif
|
||||
endif
|
||||
ifeq ($(platform),Darwin)
|
||||
ifeq ($(shell uname -p),arm64)
|
||||
# iOS will refuse to compile without the minimum target of iOS 11.0
|
||||
DEFCFLAGS += -mios-version-min=11.0
|
||||
endif
|
||||
# their readline has strict-prototype issues
|
||||
DEFCFLAGS += -Wno-strict-prototypes
|
||||
# some warnings about braced initializers on structs we want to ignore
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Iceman Fork - Proxmark3 a RFID / NFC project.
|
||||
# Iceman Fork - Proxmark3
|
||||
|
||||
The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the vast majority of RFID tags on a global scale. Originally built by Jonathan Westhues, the device is now the goto tool for RFID Analysis for the enthusiast. Iceman repository is considered to be the pinnacle of features and functionality, enabling a huge range of extremely useful and convenient commands and LUA scripts to automate chip identification, penetration testing, and programming
|
||||
|
||||
|
|
|
@ -3094,13 +3094,33 @@ void ReaderIso14443a(PacketCommandNG *c) {
|
|||
}
|
||||
}
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
FpgaDisableTracing();
|
||||
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
|
||||
if ((param & ISO14A_TOPAZMODE)) {
|
||||
|
||||
if (cmd[0] == TOPAZ_WRITE_E8 || cmd[0] == TOPAZ_WRITE_NE8) {
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
FpgaDisableTracing();
|
||||
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
|
||||
} else {
|
||||
arg0 = ReaderReceive(buf, par);
|
||||
FpgaDisableTracing();
|
||||
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
||||
}
|
||||
} else {
|
||||
arg0 = ReaderReceive(buf, par);
|
||||
FpgaDisableTracing();
|
||||
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
} else {
|
||||
arg0 = ReaderReceive(buf, par);
|
||||
FpgaDisableTracing();
|
||||
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
FpgaDisableTracing();
|
||||
reply_mix(CMD_ACK, 0, 0, 0, NULL, 0);
|
||||
} else {
|
||||
arg0 = ReaderReceive(buf, par);
|
||||
FpgaDisableTracing();
|
||||
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1835,20 +1835,20 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
switch_off();
|
||||
|
||||
DbpString("");
|
||||
DbpString(_CYAN_("Sniff statistics"));
|
||||
DbpString("=================================");
|
||||
Dbprintf(" DecodeTag State........%d", dtag.state);
|
||||
Dbprintf(" DecodeTag byteCnt......%d", dtag.len);
|
||||
Dbprintf(" DecodeTag posCount.....%d", dtag.posCount);
|
||||
Dbprintf(" DecodeTagFSK State.....%d", dtagfsk.state);
|
||||
Dbprintf(" DecodeTagFSK byteCnt...%d", dtagfsk.len);
|
||||
Dbprintf(" DecodeTagFSK count.....%d", dtagfsk.count);
|
||||
Dbprintf(" DecodeReader State.....%d", dreader.state);
|
||||
Dbprintf(" DecodeReader byteCnt...%d", dreader.byteCount);
|
||||
Dbprintf(" DecodeReader posCount..%d", dreader.posCount);
|
||||
Dbprintf(" Trace length..........." _YELLOW_("%d"), BigBuf_get_traceLen());
|
||||
DbpString("");
|
||||
|
||||
if (g_dbglevel > DBG_ERROR) {
|
||||
DbpString(_CYAN_("Sniff statistics"));
|
||||
DbpString("=================================");
|
||||
Dbprintf("DecodeTag State........ %d", dtag.state);
|
||||
Dbprintf("DecodeTag byteCnt...... %d", dtag.len);
|
||||
Dbprintf("DecodeTag posCount..... %d", dtag.posCount);
|
||||
Dbprintf("DecodeTagFSK State..... %d", dtagfsk.state);
|
||||
Dbprintf("DecodeTagFSK byteCnt... %d", dtagfsk.len);
|
||||
Dbprintf("DecodeTagFSK count..... %d", dtagfsk.count);
|
||||
Dbprintf("DecodeReader State..... %d", dreader.state);
|
||||
Dbprintf("DecodeReader byteCnt... %d", dreader.byteCount);
|
||||
Dbprintf("DecodeReader posCount.. %d", dreader.posCount);
|
||||
}
|
||||
Dbprintf("Trace length........... " _YELLOW_("%d"), BigBuf_get_traceLen());
|
||||
}
|
||||
|
||||
// Initialize Proxmark3 as ISO15693 reader
|
||||
|
|
|
@ -484,8 +484,8 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
if (res == PM3_ETEAROFF) {
|
||||
retval = PM3_ETEAROFF;
|
||||
goto OUT;
|
||||
} else if (res) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
} else if (res != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -554,7 +554,7 @@ void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t
|
|||
if (res == PM3_ETEAROFF) {
|
||||
retval = PM3_ETEAROFF;
|
||||
goto OUT;
|
||||
} else if (res) {
|
||||
} else if (res != PM3_SUCCESS) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -688,8 +688,8 @@ void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
|
|||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_classic_value(pcs, cuid, blockNo, blockdata, action) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
break;
|
||||
};
|
||||
|
||||
|
@ -777,8 +777,8 @@ static void MifareUWriteBlockEx(uint8_t arg0, uint8_t arg1, uint8_t *datain, boo
|
|||
}
|
||||
}
|
||||
|
||||
if (mifare_ultra_writeblock(blockNo, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock(blockNo, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -851,8 +851,8 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
}
|
||||
}
|
||||
|
||||
if (mifare_ultra_writeblock_compat(blockNo, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock_compat(blockNo, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -896,8 +896,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[1] = pwd[6];
|
||||
blockdata[2] = pwd[5];
|
||||
blockdata[3] = pwd[4];
|
||||
if (mifare_ultra_writeblock(44, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock(44, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(44);
|
||||
return;
|
||||
};
|
||||
|
@ -906,8 +906,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[1] = pwd[2];
|
||||
blockdata[2] = pwd[1];
|
||||
blockdata[3] = pwd[0];
|
||||
if (mifare_ultra_writeblock(45, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock(45, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(45);
|
||||
return;
|
||||
};
|
||||
|
@ -916,8 +916,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[1] = pwd[14];
|
||||
blockdata[2] = pwd[13];
|
||||
blockdata[3] = pwd[12];
|
||||
if (mifare_ultra_writeblock(46, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock(46, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(46);
|
||||
return;
|
||||
};
|
||||
|
@ -926,8 +926,8 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[1] = pwd[10];
|
||||
blockdata[2] = pwd[9];
|
||||
blockdata[3] = pwd[8];
|
||||
if (mifare_ultra_writeblock(47, blockdata)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Write block error");
|
||||
if (mifare_ultra_writeblock(47, blockdata) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Write block error");
|
||||
OnError(47);
|
||||
return;
|
||||
};
|
||||
|
@ -1522,7 +1522,6 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
target_ks[0] = nt2 ^ target_nt[0];
|
||||
|
||||
// second collection
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2303,64 +2302,98 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype) {
|
|||
|
||||
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
|
||||
|
||||
uint32_t cuid = 0;
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
||||
// variables
|
||||
uint8_t dataoutbuf[16] = {0x00};
|
||||
uint8_t dataoutbuf2[16] = {0x00};
|
||||
uint8_t uid[10] = {0x00};
|
||||
|
||||
LED_A_ON();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
// variables
|
||||
bool have_uid = false;
|
||||
uint8_t cascade_levels = 0;
|
||||
uint32_t cuid = 0;
|
||||
uint8_t uid[10] = {0x00};
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
retval = PM3_ESOFT;
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("Can't select card");
|
||||
goto out;
|
||||
}
|
||||
for (uint8_t s = 0; s < sectorcnt; s++) {
|
||||
uint64_t ui64Key = emlGetKey(s, keytype);
|
||||
|
||||
for (uint8_t sectorNo = 0; sectorNo < sectorcnt; sectorNo++) {
|
||||
uint64_t ui64Key = emlGetKey(sectorNo, keytype);
|
||||
if (sectorNo == 0) {
|
||||
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) {
|
||||
retval = PM3_EPARTIAL;
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo);
|
||||
// MFC 1K EV1 sector 16,17 don't use key A.
|
||||
if ((sectorcnt == 18) && (keytype == 0) && s > 15) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// use fast select
|
||||
if (have_uid == false) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) {
|
||||
retval = PM3_EPARTIAL;
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
|
||||
|
||||
switch (card_info.uidlen) {
|
||||
case 4 :
|
||||
cascade_levels = 1;
|
||||
break;
|
||||
case 7 :
|
||||
cascade_levels = 2;
|
||||
break;
|
||||
case 10:
|
||||
cascade_levels = 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (iso14443a_fast_select_card(uid, cascade_levels) == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
|
||||
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
|
||||
retval = PM3_EPARTIAL;
|
||||
|
||||
if (g_dbglevel > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
|
||||
continue;
|
||||
// Auth
|
||||
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(s), keytype, ui64Key, AUTH_FIRST)) {
|
||||
retval = PM3_EPARTIAL;
|
||||
if (g_dbglevel > DBG_ERROR) {
|
||||
Dbprintf("Sector %2d - Auth error", s);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(dataoutbuf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
|
||||
continue;
|
||||
}
|
||||
#define MAX_RETRIES 2
|
||||
|
||||
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
|
||||
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
} else { // sector trailer, keep the keys, set only the AC
|
||||
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
memcpy(dataoutbuf2 + 6, dataoutbuf + 6, 4);
|
||||
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
uint8_t data[16] = {0x00};
|
||||
for (uint8_t b = 0; b < NumBlocksPerSector(s); b++) {
|
||||
|
||||
memset(data, 0x00, sizeof(data));
|
||||
|
||||
for (uint8_t r = 0; r < MAX_RETRIES; r++) {
|
||||
|
||||
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(s) + b, data)) {
|
||||
retval |= PM3_EPARTIAL;
|
||||
if (g_dbglevel > DBG_ERROR) {
|
||||
Dbprintf("Error reading sector %2d block %2d", s, b);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// No need to copy empty
|
||||
if (memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b < NumBlocksPerSector(s) - 1) {
|
||||
emlSetMem(data, FirstBlockOfSector(s) + b, 1);
|
||||
} else {
|
||||
// sector trailer, keep the keys, set only the AC
|
||||
uint8_t st[16] = {0x00};
|
||||
emlGetMem(st, FirstBlockOfSector(s) + b, 1);
|
||||
memcpy(st + 6, data + 6, 4);
|
||||
emlSetMem(st, FirstBlockOfSector(s) + b, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2368,9 +2401,6 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
|
|||
int res = mifare_classic_halt(pcs, cuid);
|
||||
(void)res;
|
||||
|
||||
if (g_dbglevel >= DBG_INFO) DbpString("Emulator fill sectors finished");
|
||||
|
||||
out:
|
||||
crypto1_deinit(pcs);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
|
@ -2601,6 +2631,7 @@ void MifareCIdent(bool is_mfc) {
|
|||
uint8_t gen4gmd[4] = {MIFARE_MAGIC_GDM_AUTH_KEY, 0x00, 0x6C, 0x92};
|
||||
uint8_t gen4GetConf[8] = {GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
|
||||
uint8_t superGen1[9] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
@ -2757,7 +2788,24 @@ void MifareCIdent(bool is_mfc) {
|
|||
isGen = MAGIC_GEN_4GDM;
|
||||
}
|
||||
}
|
||||
|
||||
if (isGen != MAGIC_GEN_4GDM) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
if (mifare_classic_authex(pcs, cuid, 68, MF_KEY_B, 0x707B11FC1481, AUTH_FIRST, NULL, NULL) == 0) {
|
||||
isGen = MAGIC_QL88;
|
||||
}
|
||||
crypto1_deinit(pcs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2836,6 +2884,10 @@ OUT:
|
|||
crypto1_deinit(pcs);
|
||||
}
|
||||
|
||||
// FUDAN card w static encrypted nonces
|
||||
// 2B F9 1C 1B D5 08 48 48 03 A4 B1 B1 75 FF 2D 90
|
||||
// ^^ ^^
|
||||
|
||||
void OnSuccessMagic(void) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
|
@ -3218,7 +3270,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain) {
|
|||
return;
|
||||
};
|
||||
|
||||
if (mifare_desfire_des_auth1(cuid, dataout)) {
|
||||
if (mifare_desfire_des_auth1(cuid, dataout) != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication part1: Fail.");
|
||||
OnError(4);
|
||||
return;
|
||||
|
@ -3238,7 +3290,7 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
|
|||
|
||||
isOK = mifare_desfire_des_auth2(cuid, key, dataout);
|
||||
|
||||
if (isOK) {
|
||||
if (isOK != PM3_SUCCESS) {
|
||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Authentication part2: Failed");
|
||||
OnError(4);
|
||||
return;
|
||||
|
|
|
@ -46,6 +46,15 @@
|
|||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
|
||||
static bool IsKeyBReadable(uint8_t blockNo) {
|
||||
uint8_t sector_trailer[16];
|
||||
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
|
||||
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
||||
| ((sector_trailer[8] >> 2) & 0x02)
|
||||
| ((sector_trailer[8] >> 7) & 0x01);
|
||||
return (AC == 0x00 || AC == 0x01 || AC == 0x02);
|
||||
}
|
||||
|
||||
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||
uint8_t sector_trailer[16];
|
||||
emlGetMem(sector_trailer, blockNo, 1);
|
||||
|
@ -872,8 +881,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) {
|
||||
blockNo = receivedCmd_dec[1];
|
||||
if (MifareBlockToSector(blockNo) != cardAUTHSC) {
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
|
||||
FpgaDisableTracing();
|
||||
|
||||
|
@ -881,6 +890,18 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC);
|
||||
break;
|
||||
}
|
||||
|
||||
// Compliance of MIFARE Classic EV1 1K Datasheet footnote of Table 8
|
||||
// If access bits show that key B is Readable, any subsequent memory access will be refused.
|
||||
|
||||
if (cardAUTHKEY == AUTHKEYB && IsKeyBReadable(blockNo)) {
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
Dbprintf("[MFEMUL_WORK] Access denied: Reader tried to access memory on authentication with key B while key B is readable in sector (0x%02x)", cardAUTHSC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// case MFEMUL_WORK => CMD READ block
|
||||
|
|
|
@ -433,8 +433,8 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
|
|||
}
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
uint8_t d_block[18], d_block_enc[18];
|
||||
|
@ -465,11 +465,11 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
|
|||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return 2;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) {
|
||||
|
@ -480,7 +480,7 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u
|
|||
|
||||
uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) {
|
||||
return 1;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
uint8_t d_block[18], d_block_enc[18];
|
||||
|
@ -511,14 +511,12 @@ int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, u
|
|||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
return 2;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
|
||||
// variables
|
||||
uint16_t len = 0;
|
||||
|
@ -540,8 +538,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
memcpy(d_block, blockData, 4);
|
||||
|
@ -566,12 +564,12 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return 2;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
||||
|
@ -585,9 +583,10 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
memcpy(d_block, blockData, 16);
|
||||
|
@ -599,11 +598,12 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len);
|
||||
return 2;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
|
||||
|
@ -618,11 +618,12 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
int mifare_classic_halt_ex(struct Crypto1State *pcs) {
|
||||
uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
@ -729,8 +730,8 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) {
|
|||
|
||||
uint64_t emlGetKey(int sectorNum, int keyType) {
|
||||
uint8_t key[6] = {0x00};
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
|
||||
uint8_t *em = BigBuf_get_EM_addr();
|
||||
memcpy(key, em + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
|
||||
return bytes_to_num(key, 6);
|
||||
}
|
||||
|
||||
|
@ -804,9 +805,10 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
|
|||
|
||||
len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len == 1) {
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (len == 12) {
|
||||
|
@ -817,9 +819,9 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
|
|||
receivedAnswer[10], receivedAnswer[11]);
|
||||
}
|
||||
memcpy(blockData, receivedAnswer, 12);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return 1;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
||||
|
@ -834,9 +836,10 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
|||
len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) {
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (len == 12) {
|
||||
|
@ -847,7 +850,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
|||
receivedAnswer[10], receivedAnswer[11]);
|
||||
}
|
||||
memcpy(blockData, receivedAnswer, 12);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return 1;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
|
|
@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
|
|||
if (APPLE)
|
||||
message(STATUS "Apple device detected.")
|
||||
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
|
||||
find_library(UIKIT_LIBRARY UIKit)
|
||||
if (NOT UIKIT_LIBRARY)
|
||||
message(STATUS "UIKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit")
|
||||
endif()
|
||||
|
||||
find_library(APPKIT_LIBRARY AppKit)
|
||||
if (NOT APPKIT_LIBRARY)
|
||||
message(STATUS "AppKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
endif()
|
||||
|
||||
endif (APPLE)
|
||||
|
||||
if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND))
|
||||
|
|
|
@ -434,7 +434,13 @@ LDFLAGS += $(MYLDFLAGS)
|
|||
|
||||
PM3LDFLAGS = $(LDFLAGS)
|
||||
ifeq ($(platform),Darwin)
|
||||
PM3LDFLAGS += -framework Foundation -framework AppKit
|
||||
ifeq ($(shell uname -p),arm64)
|
||||
# The platform is iOS
|
||||
PM3LDFLAGS += -framework Foundation -framework UIKit
|
||||
else
|
||||
# M* macOS devices return arm
|
||||
PM3LDFLAGS += -framework Foundation -framework AppKit
|
||||
endif
|
||||
endif
|
||||
|
||||
###################
|
||||
|
|
|
@ -22,6 +22,9 @@ endif
|
|||
ifneq ($(findstring aarch64, $(cpu_arch)), )
|
||||
IS_SIMD_ARCH=arm64
|
||||
endif
|
||||
ifneq ($(findstring iP, $(cpu_arch)), )
|
||||
IS_SIMD_ARCH=arm64
|
||||
endif
|
||||
|
||||
ifneq ($(IS_SIMD_ARCH), )
|
||||
MULTIARCHSRCS = hardnested_bf_core.c hardnested_bitarray_core.c
|
||||
|
|
|
@ -31,6 +31,11 @@ D01AFEEB890A
|
|||
# 17 B
|
||||
4B791BEA7BCC
|
||||
#
|
||||
# QL88 keys
|
||||
# 17 A/B
|
||||
2612C6DE84CA
|
||||
707B11FC1481
|
||||
#
|
||||
#
|
||||
B0B1B2B3B4B5
|
||||
C0C1C2C3C4C5
|
||||
|
@ -145,6 +150,9 @@ F1D83F964314
|
|||
222222222222
|
||||
27DD91F1FCF1
|
||||
#
|
||||
# Hotel system
|
||||
505209016A1F
|
||||
#
|
||||
# Directory and eventlog KeyB
|
||||
2BA9621E0A36
|
||||
#
|
||||
|
|
|
@ -37,7 +37,7 @@ A5B4C3D2
|
|||
E9920427
|
||||
# paxton bullit?
|
||||
575F4F4B
|
||||
#
|
||||
# Hotel system
|
||||
50520901
|
||||
# iCopy-X
|
||||
20206666
|
||||
|
@ -52,6 +52,8 @@ C0F5009A
|
|||
# prefered pwds of members in the community
|
||||
FEEDBEEF
|
||||
DEADC0DE
|
||||
# derived from BCARD key B
|
||||
A9EF2AFC
|
||||
# Default pwd, simple:
|
||||
00000000
|
||||
11111111
|
||||
|
|
|
@ -380,7 +380,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
|
|||
if (APPLE)
|
||||
message(STATUS "Apple device detected.")
|
||||
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
|
||||
find_library(UIKIT_LIBRARY UIKit)
|
||||
if (NOT UIKIT_LIBRARY)
|
||||
message(STATUS "UIKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit")
|
||||
endif()
|
||||
|
||||
find_library(APPKIT_LIBRARY AppKit)
|
||||
if (NOT APPKIT_LIBRARY)
|
||||
message(STATUS "AppKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
endif()
|
||||
|
||||
endif (APPLE)
|
||||
|
||||
if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND))
|
||||
|
|
|
@ -2520,11 +2520,11 @@ function modifyMode()
|
|||
---
|
||||
-- edit data-portion of single segment
|
||||
["ed"] = function(x)
|
||||
if (type(x)=="string" and string.len(x)>0) then sel=tonumber(x,10)
|
||||
else sel=selectSegment(inTAG) end
|
||||
if (type(x) == "string" and string.len(x)>0) then sel=tonumber(x,10)
|
||||
else sel = selectSegment(inTAG) end
|
||||
if (istable(inTAG.SEG[sel])) then
|
||||
local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
|
||||
inTAG.SEG[sel].data=editSegmentData(inTAG.SEG[sel].data, uid)
|
||||
local uid = inTAG.MCD..inTAG.MSN0..inTAG.MSN1..inTAG.MSN2
|
||||
inTAG.SEG[sel].data = editSegmentData(inTAG.SEG[sel].data, uid)
|
||||
end
|
||||
end,
|
||||
---
|
||||
|
|
|
@ -113,7 +113,7 @@ local function getDefault(block0)
|
|||
|
||||
block0 = block0:upper()
|
||||
|
||||
local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks
|
||||
local T55X7_DEFAULT_CONFIG_BLOCK = '000880E8' --// compat mode, RF/32, manchester, STT, 7 data blocks
|
||||
local T55X7_RAW_CONFIG_BLOCK = '000880E0' --// compat mode, RF/32, manchester, 7 data blocks
|
||||
local T55X7_EM_UNIQUE_CONFIG_BLOCK = '00148040' --// emulate em4x02/unique - compat mode, manchester, RF/64, 2 data blocks
|
||||
-- FDXB requires data inversion and BiPhase 57 is simply BipHase 50 inverted, so we can either do it using the modulation scheme or the inversion flag
|
||||
|
|
|
@ -62,21 +62,19 @@ def build_arg_parser():
|
|||
|
||||
|
||||
def build_help_regex():
|
||||
"""The regex uses to parse the full text output of help data from the pm3 client."""
|
||||
# Reads the divider followed by the command itself
|
||||
re_command = r'-{87}\n(?P<command>.+)\n'
|
||||
# Reads if the command is available offline
|
||||
re_offline = r'available offline: (?P<offline>yes|no)\n+'
|
||||
# Reads the description lines
|
||||
re_description = r'(?P<description>(?:.+\n)+)\n+'
|
||||
re_description = r'(?P<description>\n[\s\S]*?(?=usage:))'
|
||||
# Reads the usage string
|
||||
re_usage = r'(?:usage:\n(?P<usage>(?:.+\n)+)\n+)?'
|
||||
# Reads the options and there individual descriptions
|
||||
re_options = r'(?:options:\n(?P<options>(?:.+\n)+)\n+)?'
|
||||
# Reads the notes and examples
|
||||
re_notes = r'(?:examples\/notes:\n(?P<notes>(?:.+\n)+)\n+)?'
|
||||
re_notes = r'(?:examples\/notes:\n(?P<notes>[\s\S]*?(?=(===|---|\n\n))))'
|
||||
# Combine them into a single regex object
|
||||
re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE);
|
||||
re_full = re.compile(re_command+re_offline+re_description+re_usage+re_options+re_notes, re.MULTILINE)
|
||||
return re_full
|
||||
|
||||
|
||||
|
|
|
@ -2255,13 +2255,21 @@
|
|||
"Description": "Student ID cards",
|
||||
"Type": "identity"
|
||||
},
|
||||
{
|
||||
"AID": "D2760000254D010200",
|
||||
"Vendor": "Zentraler Kreditausschuss (ZKA)",
|
||||
"Country": "Germany",
|
||||
"Name": "Girocard Jugendschutz",
|
||||
"Description": "Age verification",
|
||||
"Type": "identity"
|
||||
},
|
||||
{
|
||||
"AID": "A000000809434343444B467631",
|
||||
"Vendor": "Car Connectivity Consortium (CCC)",
|
||||
"Country": "",
|
||||
"Name": "Digital Car Key Framework",
|
||||
"Description": "Used during key provisioning and configuration",
|
||||
"Type": "access"
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "A000000809434343444B417631",
|
||||
|
@ -2295,13 +2303,69 @@
|
|||
"Description": "AID prefix used by MIFARE 2GO-based cards",
|
||||
"Type": ""
|
||||
},
|
||||
{
|
||||
"AID": "A00000039656434103F1216000000000",
|
||||
"Vendor": "LV Monorail",
|
||||
"Country": "United States",
|
||||
"Name": "Las Vegas Monorail",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A00000039656434103F8852200000000",
|
||||
"Vendor": "Ubian",
|
||||
"Country": "Slovakia",
|
||||
"Name": "Ubian digital transit card",
|
||||
"Description": "DESFire-based virtual transit card",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "DE5C0D1F1CADA5",
|
||||
"Vendor": "CRTM",
|
||||
"Country": "Spain",
|
||||
"Name": "Madrid transit card",
|
||||
"Description": "DESFire-based transit card",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A00000F21100",
|
||||
"Vendor": "PTV",
|
||||
"Country": "Australia",
|
||||
"Name": "Myki transit card",
|
||||
"Description": "DESFire-based transit card",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "637001ff4c41",
|
||||
"Vendor": "Cubic",
|
||||
"Country": "United States",
|
||||
"Name": "LA Tap",
|
||||
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffLA)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "637001ff574d415441",
|
||||
"Vendor": "Cubic",
|
||||
"Country": "United States",
|
||||
"Name": "Smart Trip",
|
||||
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffWMATA)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "637001ff434c4950504552",
|
||||
"Vendor": "Cubic",
|
||||
"Country": "United States",
|
||||
"Name": "Clipper",
|
||||
"Description": "DESFire-based transit card (ASCII cp\\x01\\xffCLIPPER)",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A0000002164954534F2D31",
|
||||
"Vendor": "ITSO",
|
||||
"Country": "United Kingdom",
|
||||
"Name": "ITSO CMD2",
|
||||
"Description": "AID used by ITSO for smartcard/phone-based transit cards",
|
||||
"Type": "transit"
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A000000632010105",
|
||||
|
@ -2309,22 +2373,38 @@
|
|||
"Country": "China",
|
||||
"Name": "China T-Union",
|
||||
"Description": "Universal transit card used by many big public transit operators",
|
||||
"Type": "transit"
|
||||
},
|
||||
{
|
||||
"AID": "D2760000254D010200",
|
||||
"Vendor": "Zentraler Kreditausschuss (ZKA)",
|
||||
"Country": "Germany",
|
||||
"Name": "Girocard Jugendschutz",
|
||||
"Description": "Age verification",
|
||||
"Type": ""
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A00000000491",
|
||||
"Vendor": "MasterCard International",
|
||||
"Country": "",
|
||||
"Name": "Mastercard Private Label Transit",
|
||||
"Description": "AID prefix used by transit cards that use private label mastercards (E.g. Ventra and HOP)",
|
||||
"Type": "transit"
|
||||
"Description": "AID prefix used by transit cards that use private label mastercard",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A0000000049100",
|
||||
"Vendor": "MasterCard International",
|
||||
"Country": "United States",
|
||||
"Name": "HOP Fastpass",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A0000000049101",
|
||||
"Vendor": "MasterCard International",
|
||||
"Country": "United States",
|
||||
"Name": "Ventra",
|
||||
"Description": "",
|
||||
"Type": "transport"
|
||||
},
|
||||
{
|
||||
"AID": "A000000858044F53452E4348",
|
||||
"Vendor": "Apple",
|
||||
"Country": "",
|
||||
"Name": "AirDrop connection negotiation",
|
||||
"Description": "Used by NFC-based AirDrop negotiation added in IOS17",
|
||||
"Type": ""
|
||||
}
|
||||
]
|
||||
|
|
|
@ -4073,6 +4073,20 @@
|
|||
"service_provider": "HID Corporation",
|
||||
"system_integrator": "HID Corporation"
|
||||
},
|
||||
{
|
||||
"application": "City transport, prepaid ticket, cardholder, servicespass",
|
||||
"company": "Ridango AS",
|
||||
"mad": "0x3C56",
|
||||
"service_provider": "Pilet.ee ekaart",
|
||||
"system_integrator": "Pilet.ee ekaart"
|
||||
},
|
||||
{
|
||||
"application": "City transport, prepaid ticket, cardholder, servicespass",
|
||||
"company": "Ridango AS",
|
||||
"mad": "0x3D56",
|
||||
"service_provider": "Pilet.ee ekaart",
|
||||
"system_integrator": "Pilet.ee ekaart"
|
||||
},
|
||||
{
|
||||
"application": "City transport bus, ferry, administration",
|
||||
"company": "VFJ Technology Pty Ltd",
|
||||
|
|
|
@ -2939,7 +2939,7 @@ static int CmdDiff(const char *Cmd) {
|
|||
// "data diff -a fileA --cb\n"
|
||||
"data diff --fa fileA -b fileB\n"
|
||||
"data diff --fa fileA --fb fileB\n"
|
||||
"data diff --ea --cb\n"
|
||||
// "data diff --ea --cb\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -3083,10 +3083,19 @@ static int CmdDiff(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "inB null");
|
||||
|
||||
int hdr_sln = (width * 4) + 2;
|
||||
char hdr0[300] = {0};
|
||||
|
||||
char hdr0[200] = " # | " _CYAN_("a");
|
||||
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2);
|
||||
strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b"));
|
||||
int max_fn_space = (width * 5);
|
||||
|
||||
if (fnlenA && fnlenB && (max_fn_space > fnlenA) && (max_fn_space > fnlenB)) {
|
||||
snprintf(hdr0, sizeof(hdr0) - 1, " # | " _CYAN_("%.*s"), max_fn_space, filenameA);
|
||||
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - strlen(filenameA) - 1);
|
||||
snprintf(hdr0 + strlen(hdr0), sizeof(hdr0) - 1 - strlen(hdr0), "| " _CYAN_("%.*s"), max_fn_space, filenameB);
|
||||
} else {
|
||||
strcat(hdr0, " # | " _CYAN_("a"));
|
||||
memset(hdr0 + strlen(hdr0), ' ', hdr_sln - 2);
|
||||
strcat(hdr0 + strlen(hdr0), "| " _CYAN_("b"));
|
||||
}
|
||||
|
||||
char hdr1[200] = "----+";
|
||||
memset(hdr1 + strlen(hdr1), '-', hdr_sln);
|
||||
|
|
|
@ -2229,33 +2229,35 @@ int infoHF14B(bool verbose, bool do_aid_search) {
|
|||
|
||||
// get and print general info about all known 14b chips
|
||||
int readHF14B(bool loop, bool verbose) {
|
||||
bool found = false;
|
||||
do {
|
||||
found = false;
|
||||
|
||||
// try std 14b (atqb)
|
||||
if (HF14B_std_reader(verbose))
|
||||
if (loop)
|
||||
continue;
|
||||
found |= HF14B_std_reader(verbose);
|
||||
if (found && loop)
|
||||
continue;
|
||||
|
||||
// try ST Microelectronics 14b
|
||||
if (HF14B_st_reader(verbose))
|
||||
if (loop)
|
||||
continue;
|
||||
found |= HF14B_st_reader(verbose);
|
||||
if (found && loop)
|
||||
continue;
|
||||
|
||||
// try ASK CT 14b
|
||||
if (HF14B_ask_ct_reader(verbose))
|
||||
if (loop)
|
||||
continue;
|
||||
found |= HF14B_ask_ct_reader(verbose);
|
||||
if (found && loop)
|
||||
continue;
|
||||
|
||||
// try unknown 14b read commands (to be identified later)
|
||||
// could be read of calypso, CEPAS, moneo, or pico pass.
|
||||
if (HF14B_other_reader(verbose))
|
||||
if (loop)
|
||||
continue;
|
||||
|
||||
found |= HF14B_other_reader(verbose);
|
||||
if (found && loop)
|
||||
continue;
|
||||
|
||||
} while (loop && kbd_enter_pressed() == false);
|
||||
|
||||
if (verbose) {
|
||||
if (verbose && found == false) {
|
||||
PrintAndLogEx(FAILED, "no ISO 14443-B tag found");
|
||||
}
|
||||
return PM3_EOPABORTED;
|
||||
return (found) ? PM3_SUCCESS : PM3_EOPABORTED;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#define Logic1 Iso15693Logic1
|
||||
#define FrameEOF Iso15693FrameEOF
|
||||
#define CARD_MEMORY_SIZE 4096
|
||||
#define HF15_UID_LENGTH 8
|
||||
#define HF15_UID_LENGTH 8
|
||||
|
||||
#ifndef Crc15
|
||||
# define Crc15(data, len) Crc16ex(CRC_15693, (data), (len))
|
||||
|
|
|
@ -355,7 +355,7 @@ static int CmdHFFudanWrBl(const char *Cmd) {
|
|||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf fudan wrbl",
|
||||
"Write fudan block with 4 hex bytes of data\n",
|
||||
"hf mf wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304"
|
||||
"hf fudan wrbl --blk 1 -k FFFFFFFFFFFF -d 01020304"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
|
|
@ -683,8 +683,13 @@ static int CmdHFiClassSniff(const char *Cmd) {
|
|||
|
||||
WaitForResponse(CMD_HF_ICLASS_SNIFF, &resp);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass list") "` to view captured tracelog");
|
||||
PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save -f hf_iclass_mytrace") "` to save tracelog for later analysing");
|
||||
if (jam_epurse_update) {
|
||||
PrintAndLogEx(HINT, "Verify if the jam worked by comparing value in trace and block 2");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -682,7 +682,7 @@ static int CmdLegicCalcCrc(const char *Cmd) {
|
|||
|
||||
switch (type) {
|
||||
case 16:
|
||||
init_table(CRC_LEGIC);
|
||||
init_table(CRC_LEGIC_16);
|
||||
PrintAndLogEx(SUCCESS, "Legic crc16: %X", crc16_legic(data, data_len, mcc[0]));
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -189,7 +189,7 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
|||
if (cmd[1] == 0x01 && cmdsize == 7) {
|
||||
snprintf(exp, size, "ECP1");
|
||||
return PM3_SUCCESS;
|
||||
} else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0f) + 7) {
|
||||
} else if (cmd[1] == 0x02 && cmdsize == (cmd[2] & 0x0F) + 7) {
|
||||
// Byte 3 is the reader type
|
||||
switch (cmd[3]) {
|
||||
case 0x01:
|
||||
|
@ -201,6 +201,9 @@ int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool i
|
|||
case 0x03:
|
||||
snprintf(exp, size, "ECP2 (Identity)");
|
||||
break;
|
||||
case 0x05:
|
||||
snprintf(exp, size, "ECP2 (AirDrop)");
|
||||
break;
|
||||
default:
|
||||
snprintf(exp, size, "ECP2");
|
||||
break;
|
||||
|
@ -496,7 +499,7 @@ void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool
|
|||
|
||||
uint8_t key[8];
|
||||
if (check_known_default(csn, epurse, rmac, tmac, key)) {
|
||||
snprintf(exp, size, "CHECK ( %s )", sprint_hex_inrow(key, 8));
|
||||
snprintf(exp, size, "CHECK ( " _GREEN_("%s") " )", sprint_hex_inrow(key, 8));
|
||||
} else {
|
||||
snprintf(exp, size, "CHECK");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -34,19 +34,12 @@
|
|||
#include "protocols.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include "cmdhfmf.h" // printblock, header
|
||||
#include "cmdtrace.h"
|
||||
|
||||
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
||||
static const uint8_t mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
|
||||
|
||||
typedef enum {
|
||||
MFP_UNKNOWN = 0,
|
||||
DESFIRE_MF3ICD40,
|
||||
DESFIRE_EV1,
|
||||
DESFIRE_EV2,
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
} nxp_cardtype_t;
|
||||
#define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1))
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -233,9 +226,10 @@ static int get_plus_signature(uint8_t *signature, int *signature_len) {
|
|||
*signature_len = 0;
|
||||
retval = PM3_ESOFT;
|
||||
}
|
||||
mfpSetVerboseMode(false);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// GET VERSION
|
||||
static int plus_print_version(uint8_t *version) {
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(version + 14, 7));
|
||||
|
@ -261,12 +255,12 @@ static int plus_print_version(uint8_t *version) {
|
|||
PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[13], false));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int get_plus_version(uint8_t *version, int *version_len) {
|
||||
|
||||
int resplen = 0, retval = PM3_SUCCESS;
|
||||
mfpSetVerboseMode(false);
|
||||
MFPGetVersion(true, false, version, *version_len, &resplen);
|
||||
mfpSetVerboseMode(false);
|
||||
|
||||
*version_len = resplen;
|
||||
if (resplen != 28) {
|
||||
|
@ -484,16 +478,16 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keyLen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keyLen = 16;
|
||||
}
|
||||
|
||||
if (keyNumLen != 2) {
|
||||
PrintAndLogEx(ERR, "Key number length must be 2 bytes instead of: %d", keyNumLen);
|
||||
PrintAndLogEx(ERR, "Key number length must be 2 bytes. Got %d", keyNumLen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (keyLen != 16) {
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen);
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes. Got %d", keyLen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -507,7 +501,7 @@ static int CmdHFMFPWritePerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 3) {
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen);
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -539,17 +533,18 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
bool verbose2 = arg_get_lit(ctx, 1) > 1;
|
||||
|
||||
uint8_t key[256] = {0};
|
||||
int keyLen = 0;
|
||||
CLIGetHexWithReturn(ctx, 2, key, &keyLen);
|
||||
int keylen = 0;
|
||||
CLIGetHexWithReturn(ctx, 2, key, &keylen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (keyLen && keyLen != 16) {
|
||||
PrintAndLogEx(ERR, "Key length must be 16 bytes instead of: %d", keyLen);
|
||||
if (keylen && keylen != 16) {
|
||||
PrintAndLogEx(FAILED, "Key length must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (!keyLen)
|
||||
memmove(key, DefaultKey, 16);
|
||||
if (keylen == 0) {
|
||||
memmove(key, mfp_default_key, sizeof(mfp_default_key));
|
||||
}
|
||||
|
||||
uint8_t keyNum[2] = {0};
|
||||
uint8_t data[250] = {0};
|
||||
|
@ -572,15 +567,15 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
mfpSetVerboseMode(verbose);
|
||||
for (int i = 0; i < ARRAYLEN(CardAddresses); i++) {
|
||||
keyNum[0] = CardAddresses[i] >> 8;
|
||||
keyNum[1] = CardAddresses[i] & 0xff;
|
||||
for (int i = 0; i < ARRAYLEN(mfp_card_adresses); i++) {
|
||||
keyNum[0] = mfp_card_adresses[i] >> 8;
|
||||
keyNum[1] = mfp_card_adresses[i] & 0xff;
|
||||
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
|
||||
if (!res && (datalen == 3) && data[0] == 0x09) {
|
||||
PrintAndLogEx(WARNING, "Skipped[%04x]...", CardAddresses[i]);
|
||||
PrintAndLogEx(WARNING, "Skipped[%04x]...", mfp_card_adresses[i]);
|
||||
} else {
|
||||
if (res || (datalen != 3) || data[0] != 0x90) {
|
||||
PrintAndLogEx(ERR, "Write error on address %04x", CardAddresses[i]);
|
||||
PrintAndLogEx(ERR, "Write error on address %04x", mfp_card_adresses[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -597,7 +592,9 @@ static int CmdHFMFPInitPerso(const char *Cmd) {
|
|||
static int CmdHFMFPCommitPerso(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp commitp",
|
||||
"Executes Commit Perso command. Can be used in SL0 mode only.\nOBS! This command will not be executed if CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
|
||||
"Executes Commit Perso command. Can be used in SL0 mode only.\n"
|
||||
"OBS! This command will not be executed if \n"
|
||||
"CardConfigKey, CardMasterKey and L3SwitchKey AES keys are not written.",
|
||||
"hf mfp commitp\n"
|
||||
// "hf mfp commitp --sl 1"
|
||||
);
|
||||
|
@ -625,7 +622,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 3) {
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes instead of: %d", datalen);
|
||||
PrintAndLogEx(ERR, "Command must return 3 bytes. Got %d", datalen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -633,7 +630,7 @@ static int CmdHFMFPCommitPerso(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Command error: %02x %s", data[0], mfpGetErrorDescription(data[0]));
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Switch level ( " _GREEN_("ok") " )");
|
||||
PrintAndLogEx(INFO, "Switched security level ( " _GREEN_("ok") " )");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -645,7 +642,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp auth",
|
||||
"Executes AES authentication command for Mifare Plus card",
|
||||
"Executes AES authentication command for MIFARE Plus card",
|
||||
"hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
|
||||
"hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data");
|
||||
|
||||
|
@ -664,12 +661,12 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
if (keynlen != 2) {
|
||||
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes long instead of: %d", keynlen);
|
||||
PrintAndLogEx(ERR, "ERROR: <key number> must be 2 bytes. Got %d", keynlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes long instead of: %d", keylen);
|
||||
PrintAndLogEx(ERR, "ERROR: <key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -679,7 +676,7 @@ static int CmdHFMFPAuth(const char *Cmd) {
|
|||
static int CmdHFMFPRdbl(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp rdbl",
|
||||
"Reads several blocks from Mifare Plus card",
|
||||
"Reads blocks from MIFARE Plus card",
|
||||
"hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
|
||||
"hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF");
|
||||
|
||||
|
@ -710,23 +707,23 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (blockn > 255) {
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockn);
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255]. got %d", blockn);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// 3 blocks - wo iso14443-4 chaining
|
||||
if (blocksCount > 3) {
|
||||
PrintAndLogEx(ERR, "blocks count must be less than 3. got: %d", blocksCount);
|
||||
PrintAndLogEx(ERR, "blocks count must be less than 3. Got %d", blocksCount);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -763,7 +760,7 @@ static int CmdHFMFPRdbl(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (datalen != 1 + blocksCount * 16 + 8 + 2) {
|
||||
PrintAndLogEx(ERR, "Error return length:%d", datalen);
|
||||
PrintAndLogEx(ERR, "Error return length: %d", datalen);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -820,17 +817,17 @@ static int CmdHFMFPRdsc(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (sectorNum > 39) {
|
||||
PrintAndLogEx(ERR, "<sector number> must be in range [0..39] got: %d", sectorNum);
|
||||
PrintAndLogEx(ERR, "<sector number> must be in range [0..39]. Got %d", sectorNum);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -894,7 +891,7 @@ static int CmdHFMFPRdsc(const char *Cmd) {
|
|||
static int CmdHFMFPWrbl(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp wrbl",
|
||||
"Writes one block to Mifare Plus card",
|
||||
"Writes one block to MIFARE Plus card",
|
||||
"hf mfp wrbl --blk 1 -d ff0000000000000000000000000000ff --key 000102030405060708090a0b0c0d0e0f -> write block 1 data\n"
|
||||
"hf mfp wrbl --blk 2 -d ff0000000000000000000000000000ff -v -> write block 2 data with default key 0xFF..0xFF"
|
||||
);
|
||||
|
@ -928,22 +925,22 @@ static int CmdHFMFPWrbl(const char *Cmd) {
|
|||
mfpSetVerboseMode(verbose);
|
||||
|
||||
if (!keylen) {
|
||||
memmove(key, DefaultKey, 16);
|
||||
memmove(key, mfp_default_key, 16);
|
||||
keylen = 16;
|
||||
}
|
||||
|
||||
if (blockNum > 255) {
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255] got: %d", blockNum);
|
||||
PrintAndLogEx(ERR, "<block number> must be in range [0..255]. Got %d", blockNum);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (keylen != 16) {
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes long. got: %d", keylen);
|
||||
PrintAndLogEx(ERR, "<key> must be 16 bytes. Got %d", keylen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (datainlen != 16) {
|
||||
PrintAndLogEx(ERR, "<data> must be 16 bytes long. got: %d", datainlen);
|
||||
PrintAndLogEx(ERR, "<data> must be 16 bytes. Got %d", datainlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -997,12 +994,9 @@ static int CmdHFMFPWrbl(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define AES_KEY_LEN 16
|
||||
#define MAX_KEYS_LIST_LEN 1024
|
||||
|
||||
static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB,
|
||||
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
|
||||
bool verbose) {
|
||||
uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1],
|
||||
bool verbose) {
|
||||
int res;
|
||||
bool selectCard = true;
|
||||
uint8_t keyn[2] = {0};
|
||||
|
@ -1088,7 +1082,7 @@ static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startK
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
|
||||
static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) {
|
||||
for (uint32_t pt = *startPattern; pt < 0x10000; pt++) {
|
||||
keyList[*keyListLen][0] = (pt >> 8) & 0xff;
|
||||
keyList[*keyListLen][1] = pt & 0xff;
|
||||
|
@ -1097,7 +1091,7 @@ static void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], uint3
|
|||
memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8);
|
||||
(*keyListLen)++;
|
||||
*startPattern = pt;
|
||||
if (*keyListLen == MAX_KEYS_LIST_LEN)
|
||||
if (*keyListLen == MAX_AES_KEYS_LIST_LEN)
|
||||
break;
|
||||
}
|
||||
(*startPattern)++;
|
||||
|
@ -1111,7 +1105,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
"hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n"
|
||||
"hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n"
|
||||
"hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n"
|
||||
"hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n"
|
||||
"hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n"
|
||||
"hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00");
|
||||
|
||||
void *argtable[] = {
|
||||
|
@ -1125,7 +1119,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"),
|
||||
arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"),
|
||||
arg_str0(NULL, "startp2b", "<pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
|
||||
arg_str0("j", "json", "<fn>", "Json filename to save keys"),
|
||||
arg_lit0(NULL, "dump", "Dump found keys to JSON file"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -1136,7 +1130,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
uint8_t startSector = arg_get_int_def(ctx, 3, 0);
|
||||
uint8_t endSector = arg_get_int_def(ctx, 4, 0);
|
||||
|
||||
uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
|
||||
uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}};
|
||||
uint32_t keyListLen = 0;
|
||||
uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}};
|
||||
|
||||
|
@ -1148,7 +1142,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&keyList[keyListLen], vkey, 16);
|
||||
keyListLen++;
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Specified key must have 16 bytes length.");
|
||||
PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1185,7 +1179,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
if (vpatternlen <= 2) {
|
||||
startPattern = (vpattern[0] << 8) + vpattern[1];
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Pattern must be 2-byte length.");
|
||||
PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -1193,17 +1187,8 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search.");
|
||||
}
|
||||
|
||||
uint8_t jsonname[250] = {0};
|
||||
int jsonnamelen = 0;
|
||||
if (CLIParamStrToBuf(arg_get_str(ctx, 10), jsonname, sizeof(jsonname), &jsonnamelen)) {
|
||||
PrintAndLogEx(ERR, "Invalid json name.");
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
jsonname[jsonnamelen] = 0;
|
||||
|
||||
bool create_dumpfile = arg_get_lit(ctx, 10);
|
||||
bool verbose = arg_get_lit(ctx, 11);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t startKeyAB = 0;
|
||||
|
@ -1227,8 +1212,9 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
}
|
||||
|
||||
// 2-byte pattern search mode
|
||||
if (pattern2b)
|
||||
if (pattern2b) {
|
||||
Fill2bPattern(keyList, &keyListLen, &startPattern);
|
||||
}
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
|
@ -1295,15 +1281,25 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (verbose == false)
|
||||
|
||||
if (verbose == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
// print result
|
||||
char strA[46 + 1] = {0};
|
||||
char strB[46 + 1] = {0};
|
||||
|
||||
uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
|
||||
bool has_ndef_key = false;
|
||||
bool printedHeader = false;
|
||||
for (uint8_t s = startSector; s <= endSector; s++) {
|
||||
|
||||
if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) ||
|
||||
(memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) {
|
||||
has_ndef_key = true;
|
||||
}
|
||||
|
||||
if (printedHeader == false) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------");
|
||||
|
@ -1324,7 +1320,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
snprintf(strB, sizeof(strB), _RED_("%s"), "--------------------------------");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB);
|
||||
}
|
||||
|
||||
if (printedHeader == false)
|
||||
|
@ -1333,7 +1329,13 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n");
|
||||
|
||||
// save keys to json
|
||||
if ((jsonnamelen > 0) && printedHeader) {
|
||||
if (create_dumpfile && printedHeader) {
|
||||
|
||||
size_t keys_len = (2 * 64 * (AES_KEY_LEN + 1));
|
||||
|
||||
uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len];
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
// Mifare Plus info
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
|
||||
|
||||
|
@ -1344,8 +1346,6 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t));
|
||||
|
||||
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
|
||||
uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0};
|
||||
uint8_t atslen = 0;
|
||||
if (select_status == 1 || select_status == 2) {
|
||||
memcpy(data, card.uid, card.uidlen);
|
||||
|
@ -1357,19 +1357,117 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
memcpy(&data[14], card.ats, atslen);
|
||||
}
|
||||
|
||||
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t));
|
||||
strcpy(fptr, "hf-mfp-");
|
||||
|
||||
FillFileNameByUID(fptr, card.uid, "-key", card.uidlen);
|
||||
|
||||
// length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1]
|
||||
memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1));
|
||||
saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64, NULL);
|
||||
memcpy(&data[14 + atslen], foundKeys, keys_len);
|
||||
// 64 here is for how many "rows" there is in the data array. A bit confusing
|
||||
saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
// MAD detection
|
||||
if ((memcmp(&foundKeys[0][0][1], "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", AES_KEY_LEN) == 0)) {
|
||||
PrintAndLogEx(HINT, "MAD key detected. Try " _YELLOW_("`hf mfp mad`") " for more details");
|
||||
}
|
||||
|
||||
// NDEF detection
|
||||
if (has_ndef_key) {
|
||||
PrintAndLogEx(HINT, "NDEF key detected. Try " _YELLOW_("`hf mfp ndefread -h`") " for more details");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPDump(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp dump",
|
||||
"Dump MIFARE Plus tag to binary file\n"
|
||||
"If no <name> given, UID will be used as filename",
|
||||
"hf mfp dump\n"
|
||||
"hf mfp dump --keys hf-mf-066C8B78-key.bin --> MIFARE Plus with keys from specified file\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("f", "file", "<fn>", "filename of dump"),
|
||||
arg_str0("k", "keys", "<fn>", "filename of keys"),
|
||||
arg_lit0(NULL, "ns", "no save to file"),
|
||||
arg_lit0("v", "verbose", "Verbose mode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
int datafnlen = 0;
|
||||
char data_fn[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)data_fn, FILE_PATH_SIZE, &datafnlen);
|
||||
|
||||
int keyfnlen = 0;
|
||||
char key_fn[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)key_fn, FILE_PATH_SIZE, &keyfnlen);
|
||||
|
||||
bool nosave = arg_get_lit(ctx, 3);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
mfpSetVerboseMode(verbose);
|
||||
|
||||
// read card
|
||||
uint8_t *mem = calloc(MIFARE_4K_MAXBLOCK * MFBLOCK_SIZE, sizeof(uint8_t));
|
||||
if (mem == NULL) {
|
||||
PrintAndLogEx(ERR, "failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
iso14a_card_select_t card ;
|
||||
int res = mfp_read_tag(&card, mem, key_fn);
|
||||
if (res != PM3_SUCCESS) {
|
||||
free(mem);
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
|
||||
// Skip saving card data to file
|
||||
if (nosave) {
|
||||
PrintAndLogEx(INFO, "Called with no save option");
|
||||
free(mem);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
// Save to file
|
||||
if (strlen(data_fn) < 1) {
|
||||
|
||||
char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-dump")) + card.uidlen * 2 + 1, sizeof(uint8_t));
|
||||
strcpy(fptr, "hf-mfp-");
|
||||
|
||||
FillFileNameByUID(fptr, card.uid, "-dump", card.uidlen);
|
||||
|
||||
strcpy(data_fn, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
saveFile(data_fn, ".bin", mem, MIFARE_4K_MAX_BYTES);
|
||||
saveFileEML(data_fn, mem, MIFARE_4K_MAX_BYTES, MFBLOCK_SIZE);
|
||||
|
||||
iso14a_mf_extdump_t xdump;
|
||||
xdump.card_info = card;
|
||||
xdump.dump = mem;
|
||||
xdump.dumplen = MIFARE_4K_MAX_BYTES;
|
||||
saveFileJSON(data_fn, jsfCardMemory, (uint8_t *)&xdump, sizeof(xdump), NULL);
|
||||
*/
|
||||
free(mem);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHFMFPMAD(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp mad",
|
||||
"Checks and prints Mifare Application Directory (MAD)",
|
||||
"Checks and prints MIFARE Application Directory (MAD)",
|
||||
"hf mfp mad\n"
|
||||
"hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid");
|
||||
|
||||
|
@ -1411,9 +1509,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Mifare App Directory Information") " ----------------");
|
||||
PrintAndLogEx(INFO, "-----------------------------------------------------");
|
||||
MADPrintHeader();
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "Raw:");
|
||||
|
@ -1427,7 +1523,7 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
if (haveMAD2) {
|
||||
if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(ERR, "error, read sector 0x10. card doesn't have MAD or doesn't have MAD on default keys");
|
||||
PrintAndLogEx(ERR, "error, read sector " _YELLOW_("0x10") ". Card doesn't have MAD or doesn't have MAD on default keys");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -1505,6 +1601,36 @@ static int CmdHFMFPMAD(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPNDEFFormat(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp ndefformat",
|
||||
"format MIFARE Plus Tag as a NFC tag with Data Exchange Format (NDEF)\n"
|
||||
"If no <name> given, UID will be used as filename. \n"
|
||||
"It will try default keys and MAD keys to detect if tag is already formatted in order to write.\n"
|
||||
"\n"
|
||||
"If not, it will try finding a key file based on your UID. ie, if you ran autopwn before",
|
||||
"hf mfp ndefformat\n"
|
||||
"hf mfp ndefformat --keys hf-mf-01020304-key.bin --> with keys from specified file\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "keys", "<fn>", "filename of keys"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
int keyfnlen = 0;
|
||||
char keyFilename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)keyFilename, FILE_PATH_SIZE, &keyfnlen);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFMFPNDEFRead(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -1641,20 +1767,74 @@ int CmdHFMFPNDEFRead(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPNDEFWrite(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf mfp ndefwrite",
|
||||
"Write raw NDEF hex bytes to tag. This commands assumes tag already been NFC/NDEF formatted.\n",
|
||||
"hf mfp ndefwrite -d 0300FE -> write empty record to tag\n"
|
||||
"hf mfp ndefwrite -f myfilename\n"
|
||||
"hf mfp ndefwrite -d 033fd1023a53709101195405656e2d55534963656d616e2054776974746572206c696e6b5101195502747769747465722e636f6d2f686572726d616e6e31303031\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("d", NULL, "<hex>", "raw NDEF hex bytes"),
|
||||
arg_str0("f", "file", "<fn>", "write raw NDEF file to tag"),
|
||||
arg_lit0("p", NULL, "fix NDEF record headers / terminator block if missing"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
uint8_t raw[4096] = {0};
|
||||
int rawlen;
|
||||
CLIGetHexWithReturn(ctx, 1, raw, &rawlen);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
bool fix_msg = arg_get_lit(ctx, 3);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (fix_msg) {
|
||||
PrintAndLogEx(NORMAL, "called with fix NDEF message param");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Not implemented yet. Feel free to contribute!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFMFPList(const char *Cmd) {
|
||||
return CmdTraceListAlias(Cmd, "hf mf", "mf");
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about Mifare Plus tag"},
|
||||
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
|
||||
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
|
||||
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Move card to SL1 or SL3 mode"},
|
||||
{"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"},
|
||||
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
|
||||
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
|
||||
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
|
||||
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
|
||||
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"},
|
||||
{"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFMFPList, AlwaysAvailable, "List MIFARE Plus history"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
|
||||
{"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"},
|
||||
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
|
||||
{"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Plus tag to binary file"},
|
||||
{"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"},
|
||||
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"},
|
||||
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"},
|
||||
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"},
|
||||
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write block to card"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------- " _CYAN_("personalization") " -------------------"},
|
||||
{"commitp", CmdHFMFPCommitPerso, IfPm3Iso14443a, "Configure security layer (SL1/SL3 mode)"},
|
||||
{"initp", CmdHFMFPInitPerso, IfPm3Iso14443a, "Fill all the card's keys in SL0 mode"},
|
||||
{"wrp", CmdHFMFPWritePerso, IfPm3Iso14443a, "Write Perso command"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "---------------------- " _CYAN_("ndef") " ------------------------"},
|
||||
{"ndefformat", CmdHFMFPNDEFFormat, IfPm3Iso14443a, "Format MIFARE Plus Tag as NFC Tag"},
|
||||
{"ndefread", CmdHFMFPNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
||||
{"ndefwrite", CmdHFMFPNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
|
|
|
@ -20,6 +20,30 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define AES_KEY_LEN 16
|
||||
#define MAX_AES_KEYS_LIST_LEN 1024
|
||||
|
||||
typedef enum {
|
||||
MFP_UNKNOWN = 0,
|
||||
DESFIRE_MF3ICD40,
|
||||
DESFIRE_EV1,
|
||||
DESFIRE_EV2,
|
||||
DESFIRE_EV3,
|
||||
DESFIRE_LIGHT,
|
||||
PLUS_EV1,
|
||||
} nxp_cardtype_t;
|
||||
|
||||
typedef struct mfp_key_item {
|
||||
uint8_t a[16];
|
||||
uint8_t b[16];
|
||||
} mfp_key_item_t;
|
||||
|
||||
typedef struct mfp_keys {
|
||||
uint8_t success;
|
||||
mfp_key_item_t *keys;
|
||||
} mfp_keys_t;
|
||||
|
||||
int CmdHFMFP(const char *Cmd);
|
||||
int CmdHFMFPNDEFRead(const char *Cmd);
|
||||
|
||||
|
|
|
@ -1424,7 +1424,7 @@ static mfu_identify_t *mfu_match_fingerprint(uint8_t *version, uint8_t *data) {
|
|||
uint8_t mtmp[40] = {0};
|
||||
param_gethex_to_eol(mfu_ident_table[i].match, 0, mtmp, sizeof(mtmp), &ml);
|
||||
|
||||
bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0);
|
||||
bool m2 = (memcmp(mtmp, data + mfu_ident_table[i].mpos, mfu_ident_table[i].mlen) == 0);
|
||||
if (m2) {
|
||||
PrintAndLogEx(DEBUG, "(fingerprint) found %s", mfu_ident_table[i].desc);
|
||||
return &mfu_ident_table[i];
|
||||
|
@ -3608,7 +3608,7 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
|||
if (ul_select(&card)) {
|
||||
// Philips toothbrush needs page 0x21-0x23
|
||||
uint8_t data[16] = {0x00};
|
||||
int status = ul_read(0x21, data, sizeof(data));
|
||||
int status = ul_read(0x21, data, sizeof(data));
|
||||
if (status == -1) {
|
||||
PrintAndLogEx(DEBUG, "Error: tag didn't answer to READ");
|
||||
} else if (status == 16) {
|
||||
|
|
|
@ -224,6 +224,8 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) {
|
|||
uint16_t resp_len = 11;
|
||||
uint8_t response[11] = {0};
|
||||
|
||||
//
|
||||
|
||||
if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) {
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT; // WriteErase 8bytes failed
|
||||
|
@ -243,6 +245,61 @@ static int topaz_write_erase8_block(uint8_t blockno, uint8_t *block_data) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// write a block (8 Bytes) of a selected Topaz tag.
|
||||
static int topaz_write_nonerase8_block(uint8_t blockno, uint8_t *block_data) {
|
||||
|
||||
uint8_t atqa[2] = {0};
|
||||
uint8_t rid_response[8] = {0};
|
||||
int res = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), true);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t *uid_echo = &rid_response[2];
|
||||
uint8_t rall_response[124] = {0};
|
||||
|
||||
res = topaz_rall(uid_echo, rall_response);
|
||||
if (res == PM3_ESOFT) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// ADD
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// b b b --- Byte 0 - 7
|
||||
// B B B B --------- BLOCK
|
||||
// r ----------------- 0
|
||||
//
|
||||
|
||||
uint8_t wr8_cmd[] = {TOPAZ_WRITE_NE8, blockno, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
memcpy(wr8_cmd + 10, uid_echo, 4);
|
||||
memcpy(wr8_cmd + 2, block_data, 8);
|
||||
|
||||
uint16_t resp_len = 11;
|
||||
uint8_t response[11] = {0};
|
||||
|
||||
//
|
||||
if (topaz_send_cmd(wr8_cmd, sizeof(wr8_cmd), response, &resp_len, true) == PM3_ETIMEOUT) {
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (resp_len != 11) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (blockno != response[0]) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (memcmp(block_data, response + 1, 8) == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// search for the lock area descriptor for the lockable area including byteno
|
||||
static dynamic_lock_area_t *get_dynamic_lock_area(uint16_t byteno) {
|
||||
|
@ -402,6 +459,12 @@ static int topaz_print_CC(uint8_t *data) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void topaz_print_hdr(uint8_t blockno) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, " # | block " _GREEN_("0x%02X") " | ascii", blockno);
|
||||
PrintAndLogEx(INFO, "----+-------------------------+---------");
|
||||
}
|
||||
|
||||
// return type, length and value of a TLV, starting at memory position *TLV_ptr
|
||||
static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) {
|
||||
*TLV_length = 0;
|
||||
|
@ -782,6 +845,7 @@ static int CmdHFTopazDump(const char *Cmd) {
|
|||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("f", "file", "<fn>", "filename of dump"),
|
||||
arg_lit0(NULL, "ns", "no save to file"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -789,6 +853,8 @@ static int CmdHFTopazDump(const char *Cmd) {
|
|||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
bool nosave = arg_get_lit(ctx, 2);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int status = readTopazUid(false, false);
|
||||
|
@ -811,9 +877,18 @@ static int CmdHFTopazDump(const char *Cmd) {
|
|||
);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
topaz_switch_off_field();
|
||||
|
||||
// Skip saving card data to file
|
||||
if (nosave) {
|
||||
PrintAndLogEx(INFO, "Called with no save option");
|
||||
if (set_dynamic) {
|
||||
free(topaz_tag.dynamic_memory);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// user supplied filename?
|
||||
if (fnlen < 1) {
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
|
@ -888,13 +963,13 @@ static int CmdHFTopazRdBl(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf topaz rdbl",
|
||||
"Read a block",
|
||||
"hf topaz rdbl -b 7\n"
|
||||
"Read Topaz block",
|
||||
"hf topaz rdbl --blk 7\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("b", "block", "<dec>", "Block number to write"),
|
||||
arg_int1(NULL, "blk", "<dec>", "Block number"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -910,7 +985,11 @@ static int CmdHFTopazRdBl(const char *Cmd) {
|
|||
uint8_t data[8] = {0};
|
||||
int res = topaz_read_block(blockno, data);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, sizeof(data)));
|
||||
|
||||
topaz_print_hdr(blockno);
|
||||
|
||||
PrintAndLogEx(INFO, " %2d | %s", blockno, sprint_hex_ascii(data, sizeof(data)));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
topaz_switch_off_field();
|
||||
|
@ -922,13 +1001,13 @@ static int CmdHFTopazWrBl(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf topaz wrbl",
|
||||
"Write a block",
|
||||
"hf topaz wrbl -b 7 -d 1122334455667788\n"
|
||||
"Write Topaz block with 8 hex bytes of data",
|
||||
"hf topaz wrbl --blk 7 -d 1122334455667788\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("b", "block", "<dec>", "Block number to write"),
|
||||
arg_int1(NULL, "blk", "<dec>", "Block number"),
|
||||
arg_str1("d", "data", "<hex>", "Block data (8 hex bytes)"),
|
||||
arg_param_end
|
||||
};
|
||||
|
@ -954,14 +1033,23 @@ static int CmdHFTopazWrBl(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(INFO, "Block: %0d (0x%02X) [ %s]", blockno, blockno, sprint_hex(data, dlen));
|
||||
|
||||
// send write Block
|
||||
int res = topaz_write_erase8_block(blockno, data);
|
||||
int res;
|
||||
if (blockno != 13 && blockno != 14) {
|
||||
// send write/erase block
|
||||
res = topaz_write_erase8_block(blockno, data);
|
||||
} else {
|
||||
// send write/non erase block
|
||||
res = topaz_write_nonerase8_block(blockno, data);
|
||||
}
|
||||
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "Write ( " _GREEN_("ok") " )");
|
||||
PrintAndLogEx(HINT, "try `" _YELLOW_("hf topaz rdbl --blk %u") "` to verify", blockno);
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Write ( " _RED_("fail") " )");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
topaz_switch_off_field();
|
||||
return res;
|
||||
|
@ -970,18 +1058,24 @@ static int CmdHFTopazWrBl(const char *Cmd) {
|
|||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"},
|
||||
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
|
||||
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
|
||||
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"},
|
||||
{"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
|
||||
{"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||
{"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"},
|
||||
{"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
{"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("operations") " ---------------------"},
|
||||
{"dump", CmdHFTopazDump, IfPm3Iso14443a, "Dump TOPAZ family tag to file"},
|
||||
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"raw", CmdHFTopazRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||
{"rdbl", CmdHFTopazRdBl, IfPm3Iso14443a, "Read block"},
|
||||
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
|
||||
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "Simulate Topaz tag"},
|
||||
{"sniff", CmdHFTopazSniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
|
||||
{"view", CmdHFTopazView, AlwaysAvailable, "Display content from tag dump file"},
|
||||
{"wrbl", CmdHFTopazWrBl, IfPm3Iso14443a, "Write block"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
|
||||
// {"ndefformat", CmdHFTopazNDEFFormat, IfPm3Iso14443a, "Format Topaz Tag as NFC Tag"},
|
||||
// {"ndefread", CmdHFTopazNDEFRead, IfPm3Iso14443a, "Read and print NDEF records from card"},
|
||||
// {"ndefwrite", CmdHFTopazNDEFWrite, IfPm3Iso14443a, "Write NDEF records to card"},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
|
|
|
@ -120,7 +120,7 @@ static void decodeHeden2L(uint8_t *bits) {
|
|||
if (bits[offset + 7]) cardnumber += 16384;
|
||||
if (bits[offset + 23]) cardnumber += 32768;
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Heden-2L | %u", cardnumber);
|
||||
PrintAndLogEx(SUCCESS, " Heden-2L...... %u", cardnumber);
|
||||
}
|
||||
|
||||
// sending three times. Didn't seem to break the previous sim?
|
||||
|
@ -301,10 +301,11 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
);
|
||||
PrintAndLogEx(DEBUG, "two bit checksum... " _GREEN_("%1d%1d"), checksum >> 1 & 0x01, checksum & 0x01);
|
||||
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
|
||||
// This doesn't seem to line up with the hot-stamp numbers on any HID cards I have seen, but, leaving it alone since I do not know how those work. -MS
|
||||
PrintAndLogEx(SUCCESS, " Printed | __%04d__ [0x%X]", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, " Internal ID | %" PRIu64, foo);
|
||||
PrintAndLogEx(SUCCESS, " Printed....... __%04d__ ( 0x%X )", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, " Internal ID... %" PRIu64, foo);
|
||||
decodeHeden2L(g_DemodBuffer);
|
||||
|
||||
} else {
|
||||
|
@ -336,6 +337,7 @@ int demodIndalaEx(int clk, int invert, int maxErr, bool verbose) {
|
|||
PrintAndLogEx(DEBUG, "DEBUG: Indala - printing DemodBuffer");
|
||||
printDemodBuff(0, false, false, false);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -503,7 +505,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
showbits[bit] = '.' + bits[bit];
|
||||
}
|
||||
showbits[bit + 1] = '\0';
|
||||
PrintAndLogEx(SUCCESS, "Partial UID | %s", showbits);
|
||||
PrintAndLogEx(SUCCESS, "Partial UID... %s", showbits);
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
for (bit = 0; bit < uidlen; bit++) {
|
||||
|
@ -528,7 +530,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
uid2 = (uid2 << 1) | 1;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x)", showbits, uid1, uid2);
|
||||
PrintAndLogEx(SUCCESS, "UID... %s ( %x%08x )", showbits, uid1, uid2);
|
||||
} else {
|
||||
uint32_t uid3 = 0;
|
||||
uint32_t uid4 = 0;
|
||||
|
@ -549,7 +551,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) {
|
|||
else
|
||||
uid7 = (uid7 << 1) | 1;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "UID | %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
PrintAndLogEx(SUCCESS, "UID... %s (%x%08x%08x%08x%08x%08x%08x)", showbits, uid1, uid2, uid3, uid4, uid5, uid6, uid7);
|
||||
}
|
||||
|
||||
// Checking UID against next occurrences
|
||||
|
|
|
@ -571,9 +571,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
//2 Not crc-command
|
||||
|
||||
// Draw the data column
|
||||
#define TRACE_MAX_LINES 36
|
||||
#define TRACE_MAX_LINES 36
|
||||
// number of hex bytes to be printed per row (16 data + 2 crc)
|
||||
#define TRACE_MAX_HEX_BYTES 18
|
||||
#define TRACE_MAX_HEX_BYTES 18
|
||||
|
||||
char line[TRACE_MAX_LINES][160] = {{0}};
|
||||
|
||||
|
@ -700,8 +700,8 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
|
||||
// mark short bytes (less than 8 Bit + Parity)
|
||||
if (protocol == ISO_14443A ||
|
||||
protocol == PROTO_MIFARE ||
|
||||
protocol == THINFILM) {
|
||||
protocol == PROTO_MIFARE ||
|
||||
protocol == THINFILM) {
|
||||
|
||||
// approximated with 128 * (9 * data_len);
|
||||
uint16_t bitime = 1056 + 32;
|
||||
|
@ -874,13 +874,13 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
} else {
|
||||
|
||||
|
||||
if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) {
|
||||
if (last_line && (memcmp(crc, "\x20\x20\x20\x20", 4) != 0) && g_session.supports_colors && markCRCBytes) {
|
||||
str_padder = 85;
|
||||
// odd case of multiline, and last single byte on empty row has been colorised...
|
||||
if (strlen(line[j]) < 14) {
|
||||
str_padder = 81;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr->isResponse) {
|
||||
PrintAndLogEx(NORMAL, " | | |%-*s | %s| %s",
|
||||
|
@ -909,7 +909,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
annotateIso14443a(explanation, sizeof(explanation), mfData, mfDataLen, hdr->isResponse);
|
||||
uint8_t crcc = iso14443A_CRC_check(hdr->isResponse, mfData, mfDataLen);
|
||||
|
||||
//iceman: colorise crc bytes here will need a refactor of code from above.
|
||||
//iceman: colorise crc bytes here will need a refactor of code from above.
|
||||
PrintAndLogEx(NORMAL, " | | * |%-*s | %-4s| %s",
|
||||
str_padder,
|
||||
sprint_hex_inrow_spaces(mfData, mfDataLen, 2),
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "cmdhficlass.h" // pagemap
|
||||
#include "protocols.h" // iclass defines
|
||||
#include "cmdhftopaz.h" // TOPAZ defines
|
||||
#include "mifare/mifaredefault.h" // MFP / AES defines
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "scandir.h"
|
||||
|
@ -543,13 +544,14 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
break;
|
||||
}
|
||||
case jsfMfPlusKeys: {
|
||||
JsonSaveStr(root, "FileType", "mfp");
|
||||
JsonSaveStr(root, "FileType", "mfpkeys");
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2);
|
||||
uint8_t atslen = data[13];
|
||||
if (atslen > 0)
|
||||
if (atslen > 0) {
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen);
|
||||
}
|
||||
|
||||
uint8_t vdata[2][64][17] = {{{0}}};
|
||||
memcpy(vdata, data + (14 + atslen), 2 * 64 * 17);
|
||||
|
@ -559,12 +561,12 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
|
||||
if (vdata[0][i][0]) {
|
||||
snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyA", i);
|
||||
JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16);
|
||||
JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], AES_KEY_LEN);
|
||||
}
|
||||
|
||||
if (vdata[1][i][0]) {
|
||||
snprintf(path, sizeof(path), "$.SectorKeys.%zu.KeyB", i);
|
||||
JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16);
|
||||
JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], AES_KEY_LEN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1296,6 +1298,40 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
|||
|
||||
*datalen += sptr;
|
||||
}
|
||||
|
||||
if (!strcmp(ctype, "mfpkeys")) {
|
||||
|
||||
JsonLoadBufAsHex(root, "$.Card.UID", udata.bytes, 7, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.SAK", udata.bytes + 10, 1, datalen);
|
||||
JsonLoadBufAsHex(root, "$.Card.ATQA", udata.bytes + 11, 2, datalen);
|
||||
uint8_t atslen = udata.bytes[13];
|
||||
if (atslen > 0) {
|
||||
JsonLoadBufAsHex(root, "$.Card.ATS", udata.bytes + 14, atslen, datalen);
|
||||
}
|
||||
|
||||
size_t sptr = (14 + atslen);
|
||||
|
||||
// memcpy(vdata, udata.bytes + (14 + atslen), 2 * 64 * 17);
|
||||
for (size_t i = 0; i < 64; i++) {
|
||||
|
||||
if ((sptr + (AES_KEY_LEN * 2)) > maxdatalen) {
|
||||
break;
|
||||
}
|
||||
|
||||
size_t offset = (14 + atslen) + (i * 2 * AES_KEY_LEN);
|
||||
|
||||
char blocks[40] = {0};
|
||||
snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyA", i);
|
||||
JsonLoadBufAsHex(root, blocks, udata.bytes + offset, AES_KEY_LEN, datalen);
|
||||
|
||||
snprintf(blocks, sizeof(blocks), "$.SectorKeys.%zu.KeyB", i);
|
||||
JsonLoadBufAsHex(root, blocks, udata.bytes + offset + AES_KEY_LEN, AES_KEY_LEN, datalen);
|
||||
|
||||
sptr += (2 * AES_KEY_LEN);
|
||||
}
|
||||
*datalen += sptr;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (callback != NULL) {
|
||||
|
|
|
@ -190,7 +190,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
|
|||
|
||||
uint8_t GPB = sector0[(3 * 16) + 9];
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x"), "GPB", GPB);
|
||||
PrintAndLogEx(SUCCESS, "GPB....... " _GREEN_("0x%02X"), GPB);
|
||||
|
||||
// DA (MAD available)
|
||||
if (!(GPB & 0x80)) {
|
||||
|
@ -200,21 +200,22 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
|
|||
|
||||
uint8_t mad_ver = GPB & 0x03;
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("%d"), "MAD version", mad_ver);
|
||||
PrintAndLogEx(SUCCESS, "Version... " _GREEN_("%d"), mad_ver);
|
||||
|
||||
// MAD version
|
||||
if ((mad_ver != 0x01) && (mad_ver != 0x02)) {
|
||||
PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02x"), mad_ver);
|
||||
PrintAndLogEx(ERR, "Wrong MAD version " _RED_("0x%02X"), mad_ver);
|
||||
return PM3_ESOFT;
|
||||
};
|
||||
|
||||
if (haveMAD2)
|
||||
if (haveMAD2) {
|
||||
*haveMAD2 = (mad_ver == 2);
|
||||
}
|
||||
|
||||
int res = madCRCCheck(sector0, true, 1);
|
||||
|
||||
if (verbose && res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector0[16], _GREEN_("ok"));
|
||||
if (verbose && res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector0[16], _GREEN_("ok"));
|
||||
}
|
||||
|
||||
if (mad_ver == 2 && sector10) {
|
||||
int res2 = madCRCCheck(sector10, true, 2);
|
||||
|
@ -222,7 +223,7 @@ int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2)
|
|||
res = res2;
|
||||
|
||||
if (verbose && !res2)
|
||||
PrintAndLogEx(SUCCESS, "%14s " _GREEN_("0x%02x") " ( %s )", "CRC8", sector10[0], _GREEN_("ok"));
|
||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( %s )", sector10[0], _GREEN_("ok"));
|
||||
}
|
||||
|
||||
// MA (multi-application card)
|
||||
|
@ -284,9 +285,10 @@ static int MADInfoByteDecode(const uint8_t *sector, bool swapmad, int mad_ver, b
|
|||
info = sector[16 + 1] & 0x3f;
|
||||
if (info >= 0xF) {
|
||||
PrintAndLogEx(WARNING, "Invalid Info byte (MAD1) value " _YELLOW_("0x%02x"), info);
|
||||
if (verbose)
|
||||
if (verbose) {
|
||||
// I understand the spec in a way that MAD1 InfoByte should not point into MAD2 sectors, @lukaskuzmiak
|
||||
PrintAndLogEx(WARNING, "MAD1 Info byte points outside of MAD1 sector space (0x%02x), report a bug?", info);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
|
@ -318,7 +320,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
|
|||
int ibs = MADInfoByteDecode(sector, swapmad, 1, verbose);
|
||||
|
||||
if (ibs > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs);
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
|
||||
}
|
||||
|
@ -331,19 +333,19 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
|
|||
for (int i = 1; i < 16; i++) {
|
||||
uint16_t aid = madGetAID(sector, swapmad, 1, i);
|
||||
if (aid < 6) {
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s",
|
||||
i,
|
||||
aid,
|
||||
aid_admin[aid]
|
||||
);
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s",
|
||||
i,
|
||||
aid,
|
||||
aid_admin[aid]
|
||||
);
|
||||
|
||||
} else if (prev_aid == aid) {
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation",
|
||||
i,
|
||||
aid
|
||||
);
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation",
|
||||
i,
|
||||
aid
|
||||
);
|
||||
} else {
|
||||
char fmt[60];
|
||||
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i, aid, "%s");
|
||||
|
@ -356,7 +358,7 @@ int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMA
|
|||
}
|
||||
|
||||
int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
||||
open_mad_file(&mad_known_aids, verbose);
|
||||
open_mad_file(&mad_known_aids, false);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "------------ " _CYAN_("MAD v2 details") " -------------");
|
||||
|
@ -364,14 +366,14 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
|||
int res = madCRCCheck(sector, true, 2);
|
||||
if (verbose) {
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "CRC8 ( %s )", _GREEN_("ok"));
|
||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _GREEN_("%s") " )", sector[0], "ok");
|
||||
else
|
||||
PrintAndLogEx(WARNING, "CRC8 ( %s )", _RED_("fail"));
|
||||
PrintAndLogEx(SUCCESS, "CRC8...... 0x%02X ( " _RED_("%s") " )", sector[0], "fail");
|
||||
}
|
||||
|
||||
int ibs = MADInfoByteDecode(sector, swapmad, 2, verbose);
|
||||
if (ibs > 0) {
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02x"), ibs);
|
||||
PrintAndLogEx(SUCCESS, "Card publisher sector " _MAGENTA_("0x%02X"), ibs);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Card publisher " _RED_("not") " present " _YELLOW_("0x%02x"), ibs);
|
||||
}
|
||||
|
@ -385,12 +387,21 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) {
|
|||
for (int i = 1; i < 8 + 8 + 7 + 1; i++) {
|
||||
uint16_t aid = madGetAID(sector, swapmad, 2, i);
|
||||
if (aid < 6) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (%s)") : " %02d [%04X] (%s)", i + 16, aid, aid_admin[aid]);
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s",
|
||||
i + 16,
|
||||
aid,
|
||||
aid_admin[aid]
|
||||
);
|
||||
} else if (prev_aid == aid) {
|
||||
PrintAndLogEx(INFO, (ibs == i) ? _MAGENTA_(" %02d [%04X] (continuation)") : " %02d [%04X] (continuation)", i + 16, aid);
|
||||
PrintAndLogEx(INFO,
|
||||
(ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation",
|
||||
i + 16,
|
||||
aid
|
||||
);
|
||||
} else {
|
||||
char fmt[30];
|
||||
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [%04X]%s", i + 16, aid, "%s");
|
||||
char fmt[60];
|
||||
snprintf(fmt, sizeof(fmt), (ibs == i) ? _MAGENTA_(" %02d [%04X]%s") : " %02d [" _GREEN_("%04X") "]%s", i + 16, aid, "%s");
|
||||
print_aid_description(mad_known_aids, aid, fmt, verbose);
|
||||
prev_aid = aid;
|
||||
}
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#include "ui.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
static bool VerboseMode = false;
|
||||
static bool g_verbose_mode = false;
|
||||
void mfpSetVerboseMode(bool verbose) {
|
||||
VerboseMode = verbose;
|
||||
g_verbose_mode = verbose;
|
||||
}
|
||||
|
||||
static const PlusErrorsElm_t PlusErrors[] = {
|
||||
|
@ -340,12 +340,12 @@ int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool acti
|
|||
}
|
||||
|
||||
static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
if (VerboseMode)
|
||||
if (g_verbose_mode)
|
||||
PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen));
|
||||
|
||||
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false);
|
||||
|
||||
if (VerboseMode)
|
||||
if (g_verbose_mode)
|
||||
PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen));
|
||||
|
||||
return res;
|
||||
|
@ -367,7 +367,7 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int
|
|||
int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||
uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount};
|
||||
if (!plain && mf4session)
|
||||
CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
|
||||
CalculateMAC(mf4session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], g_verbose_mode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if (res)
|
||||
|
@ -377,7 +377,7 @@ int MFPReadBlock(mf4Session_t *mf4session, bool plain, uint8_t blockNum, uint8_t
|
|||
mf4session->R_Ctr++;
|
||||
|
||||
if (mf4session && mac && *dataoutlen > 11)
|
||||
CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
|
||||
CalculateMAC(mf4session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, g_verbose_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo
|
|||
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
|
||||
memmove(&rcmd[3], data, 16);
|
||||
if (mf4session)
|
||||
CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
|
||||
CalculateMAC(mf4session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], g_verbose_mode);
|
||||
|
||||
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
|
||||
if (res)
|
||||
|
@ -396,7 +396,7 @@ int MFPWriteBlock(mf4Session_t *mf4session, uint8_t blockNum, uint8_t *data, boo
|
|||
mf4session->W_Ctr++;
|
||||
|
||||
if (mf4session && mac && *dataoutlen > 3)
|
||||
CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
|
||||
CalculateMAC(mf4session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, g_verbose_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -534,7 +534,7 @@ uint8_t mfSectorTrailer(uint16_t blockNo) {
|
|||
if (blockNo < 32 * 4) {
|
||||
return (blockNo | 0x03);
|
||||
} else {
|
||||
return (blockNo | 0x0f);
|
||||
return (blockNo | 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,3 +551,11 @@ uint8_t mfSectorNum(uint16_t blockNo) {
|
|||
return (32 + (blockNo - 32 * 4) / 16);
|
||||
|
||||
}
|
||||
|
||||
bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno) {
|
||||
if (sectorno < 32) {
|
||||
return ((blockno | 0x03) == blockno);
|
||||
} else {
|
||||
return ((blockno | 0x0F) == blockno);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ uint8_t mfFirstBlockOfSector(uint8_t sectorNo);
|
|||
uint8_t mfSectorTrailerOfSector(uint8_t sectorNo);
|
||||
uint8_t mfSectorTrailer(uint16_t blockNo);
|
||||
bool mfIsSectorTrailer(uint16_t blockNo);
|
||||
bool mfIsSectorTrailerBasedOnBlocks(uint8_t sectorno, uint16_t blockno);
|
||||
uint8_t mfSectorNum(uint16_t blockNo);
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define AES_KEY_LEN 16
|
||||
#define MAX_AES_KEYS_LIST_LEN 1024
|
||||
|
||||
#define MFKEY_SIZE 6
|
||||
#define MFBLOCK_SIZE 16
|
||||
|
||||
|
@ -41,6 +44,12 @@
|
|||
|
||||
#define MIFARE_KEY_SIZE 6
|
||||
|
||||
#define MIFARE_MINI_MAX_KEY_SIZE (MIFARE_MINI_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
|
||||
#define MIFARE_1K_MAX_KEY_SIZE (MIFARE_1K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
|
||||
#define MIFARE_2K_MAX_KEY_SIZE (MIFARE_2K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
|
||||
#define MIFARE_4K_MAX_KEY_SIZE (MIFARE_4K_MAXSECTOR * 2 * MIFARE_KEY_SIZE)
|
||||
|
||||
|
||||
static const uint64_t g_mifare_default_keys[] = {
|
||||
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||
|
|
|
@ -1431,6 +1431,8 @@ int detect_mf_magic(bool is_mfc) {
|
|||
case MAGIC_NTAG21X:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x"));
|
||||
break;
|
||||
case MAGIC_QL88:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("QL88"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -927,7 +927,7 @@ static int ndefDecodeExternal_record(NDEFHeader_t *ndef) {
|
|||
print_hex_noascii_break(ndef->Payload, ndef->PayloadLen, 32);
|
||||
|
||||
// do a character check?
|
||||
if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:2", ndef->TypeLen)) {
|
||||
if (!strncmp((char *)ndef->Type, "pilet.ee:ekaart:", ndef->TypeLen - 1)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("Ekaart detected") " - Trying ASN1 decode...");
|
||||
asn1_print(ndef->Payload, ndef->PayloadLen, " ");
|
||||
|
|
|
@ -367,17 +367,21 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 0, "hf mf ndefread" },
|
||||
{ 0, "hf mf ndefwrite" },
|
||||
{ 1, "hf mfp help" },
|
||||
{ 0, "hf mfp info" },
|
||||
{ 0, "hf mfp wrp" },
|
||||
{ 0, "hf mfp initp" },
|
||||
{ 0, "hf mfp commitp" },
|
||||
{ 1, "hf mfp list" },
|
||||
{ 0, "hf mfp auth" },
|
||||
{ 0, "hf mfp chk" },
|
||||
{ 0, "hf mfp dump" },
|
||||
{ 0, "hf mfp info" },
|
||||
{ 0, "hf mfp mad" },
|
||||
{ 0, "hf mfp rdbl" },
|
||||
{ 0, "hf mfp rdsc" },
|
||||
{ 0, "hf mfp wrbl" },
|
||||
{ 0, "hf mfp chk" },
|
||||
{ 0, "hf mfp mad" },
|
||||
{ 0, "hf mfp commitp" },
|
||||
{ 0, "hf mfp initp" },
|
||||
{ 0, "hf mfp wrp" },
|
||||
{ 0, "hf mfp ndefformat" },
|
||||
{ 0, "hf mfp ndefread" },
|
||||
{ 0, "hf mfp ndefwrite" },
|
||||
{ 1, "hf mfu help" },
|
||||
{ 1, "hf mfu keygen" },
|
||||
{ 1, "hf mfu pwdgen" },
|
||||
|
@ -461,14 +465,14 @@ const static vocabulory_t vocabulory[] = {
|
|||
{ 1, "hf thinfilm list" },
|
||||
{ 0, "hf thinfilm sim" },
|
||||
{ 1, "hf topaz help" },
|
||||
{ 0, "hf topaz dump" },
|
||||
{ 1, "hf topaz list" },
|
||||
{ 0, "hf topaz dump" },
|
||||
{ 0, "hf topaz info" },
|
||||
{ 0, "hf topaz raw" },
|
||||
{ 0, "hf topaz rdbl" },
|
||||
{ 0, "hf topaz reader" },
|
||||
{ 0, "hf topaz sim" },
|
||||
{ 0, "hf topaz sniff" },
|
||||
{ 0, "hf topaz raw" },
|
||||
{ 0, "hf topaz rdbl" },
|
||||
{ 1, "hf topaz view" },
|
||||
{ 0, "hf topaz wrbl" },
|
||||
{ 1, "hf xerox help" },
|
||||
|
|
|
@ -189,6 +189,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
|
|||
free(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
int sfd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
|
||||
if (sfd == -1) {
|
||||
PrintAndLogEx(ERR, "Error opening Bluetooth socket");
|
||||
|
@ -196,6 +197,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) {
|
|||
free(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
if (connect(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
PrintAndLogEx(ERR, "Error: cannot connect device " _YELLOW_("%s") " over Bluetooth", addrstr);
|
||||
close(sfd);
|
||||
|
|
|
@ -730,7 +730,9 @@ static bool Pack_C15001(wiegand_card_t *card, wiegand_message_t *packed, bool pr
|
|||
static bool Unpack_C15001(wiegand_message_t *packed, wiegand_card_t *card) {
|
||||
memset(card, 0, sizeof(wiegand_card_t));
|
||||
|
||||
if (packed->Length != 36) return false; // Wrong length? Stop here.
|
||||
|
||||
if (packed->Length != 36)
|
||||
return false; // Wrong length? Stop here.
|
||||
|
||||
card->OEM = get_linear_field(packed, 1, 10);
|
||||
card->FacilityCode = get_linear_field(packed, 11, 8);
|
||||
|
@ -976,8 +978,10 @@ static bool Pack_C1k48s(wiegand_card_t *card, wiegand_message_t *packed, bool pr
|
|||
packed->Mid |= (evenparity32((packed->Mid & 0x00001B6D) ^ (packed->Bot & 0xB6DB6DB6))) << 14;
|
||||
packed->Bot |= (oddparity32((packed->Mid & 0x000036DB) ^ (packed->Bot & 0x6DB6DB6C)));
|
||||
packed->Mid |= (oddparity32((packed->Mid & 0x00007FFF) ^ (packed->Bot & 0xFFFFFFFF))) << 15;
|
||||
|
||||
if (preamble)
|
||||
return add_HID_header(packed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,4 +354,4 @@ uint16_t crc16_legic(uint8_t const *d, size_t n, uint8_t uidcrc) {
|
|||
|
||||
uint16_t crc16_philips(uint8_t const *d, size_t n) {
|
||||
return crc16_fast(d, n, 0x49A3, false, false);
|
||||
}
|
||||
}
|
||||
|
|
1165
doc/commands.json
1165
doc/commands.json
File diff suppressed because it is too large
Load diff
|
@ -538,17 +538,21 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf mfp help `|Y |`This help`
|
||||
|`hf mfp info `|N |`Info about Mifare Plus tag`
|
||||
|`hf mfp wrp `|N |`Write Perso command`
|
||||
|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode`
|
||||
|`hf mfp commitp `|N |`Move card to SL1 or SL3 mode`
|
||||
|`hf mfp list `|Y |`List MIFARE Plus history`
|
||||
|`hf mfp auth `|N |`Authentication`
|
||||
|`hf mfp rdbl `|N |`Read blocks`
|
||||
|`hf mfp rdsc `|N |`Read sectors`
|
||||
|`hf mfp wrbl `|N |`Write blocks`
|
||||
|`hf mfp chk `|N |`Check keys`
|
||||
|`hf mfp dump `|N |`Dump MIFARE Plus tag to binary file`
|
||||
|`hf mfp info `|N |`Info about MIFARE Plus tag`
|
||||
|`hf mfp mad `|N |`Check and print MAD`
|
||||
|`hf mfp rdbl `|N |`Read blocks from card`
|
||||
|`hf mfp rdsc `|N |`Read sectors from card`
|
||||
|`hf mfp wrbl `|N |`Write block to card`
|
||||
|`hf mfp commitp `|N |`Configure security layer (SL1/SL3 mode)`
|
||||
|`hf mfp initp `|N |`Fill all the card's keys in SL0 mode`
|
||||
|`hf mfp wrp `|N |`Write Perso command`
|
||||
|`hf mfp ndefformat `|N |`Format MIFARE Plus Tag as NFC Tag`
|
||||
|`hf mfp ndefread `|N |`Read and print NDEF records from card`
|
||||
|`hf mfp ndefwrite `|N |`Write NDEF records to card`
|
||||
|
||||
|
||||
### hf mfu
|
||||
|
@ -704,14 +708,14 @@ Check column "offline" for their availability.
|
|||
|command |offline |description
|
||||
|------- |------- |-----------
|
||||
|`hf topaz help `|Y |`This help`
|
||||
|`hf topaz dump `|N |`Dump TOPAZ family tag to file`
|
||||
|`hf topaz list `|Y |`List Topaz history`
|
||||
|`hf topaz dump `|N |`Dump TOPAZ family tag to file`
|
||||
|`hf topaz info `|N |`Tag information`
|
||||
|`hf topaz raw `|N |`Send raw hex data to tag`
|
||||
|`hf topaz rdbl `|N |`Read block`
|
||||
|`hf topaz reader `|N |`Act like a Topaz reader`
|
||||
|`hf topaz sim `|N |`Simulate Topaz tag`
|
||||
|`hf topaz sniff `|N |`Sniff Topaz reader-tag communication`
|
||||
|`hf topaz raw `|N |`Send raw hex data to tag`
|
||||
|`hf topaz rdbl `|N |`Read block`
|
||||
|`hf topaz view `|Y |`Display content from tag dump file`
|
||||
|`hf topaz wrbl `|N |`Write block`
|
||||
|
||||
|
|
|
@ -621,6 +621,7 @@ typedef struct {
|
|||
#define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613
|
||||
#define CMD_HF_MIFARE_ACQ_NONCES 0x0614
|
||||
#define CMD_HF_MIFARE_STATIC_NESTED 0x0615
|
||||
#define CMD_HF_MIFARE_STATIC_ENC 0x0616
|
||||
|
||||
#define CMD_HF_MIFARE_READBL 0x0620
|
||||
#define CMD_HF_MIFAREU_READBL 0x0720
|
||||
|
|
|
@ -263,6 +263,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define MAGIC_GEN_3 9
|
||||
#define MAGIC_GEN_4GTU 10
|
||||
#define MAGIC_GEN_4GDM 11
|
||||
#define MAGIC_QL88 12
|
||||
|
||||
|
||||
// Commands for configuration of Gen4 GTU cards.
|
||||
// see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md
|
||||
|
|
|
@ -9,6 +9,9 @@ MYLDLIBS = -lcrypto
|
|||
cpu_arch = $(shell uname -m)
|
||||
ifneq ($(findstring arm64, $(cpu_arch)), )
|
||||
MYCFLAGS += -mcpu=native
|
||||
# iOS 'fun'
|
||||
else ifneq ($(findstring iP, $(cpu_arch)), )
|
||||
MYCFLAGS += -mcpu=native
|
||||
else
|
||||
MYCFLAGS += -march=native
|
||||
endif
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include "util_posix.h"
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
//#include <mbedtls/aes.h>
|
||||
#include "util_posix.h"
|
||||
#include "randoms.h"
|
||||
|
|
|
@ -437,8 +437,7 @@ while true; do
|
|||
if ! CheckExecute slow "lf T55 hid_48 test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_hid_48.pm3; lf hid demod'" \
|
||||
"HID Corporate 1000 48-bit"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala_hedem test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf search -1'" "Indala ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" \
|
||||
"Heden-2L \| 888"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala_hedem test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala_hedem.pm3; lf indala demod'" "Heden-2L...... 888"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala test" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf search -1'" "Indala ID found"; then break; fi
|
||||
if ! CheckExecute slow "lf T55 indala test2" "$CLIENTBIN -c 'data load -f traces/lf_ATA5577_indala.pm3; lf indala demod'" \
|
||||
"Fmt 26 FC: 123 Card: 1337 Parity: 11"; then break; fi
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue