Update changelog

This commit is contained in:
AloneLiberty 2023-03-25 18:07:52 +03:00
commit fc56a51c56
9 changed files with 257 additions and 28 deletions

View file

@ -4,6 +4,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased]
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
- Added `hf mf gdmgetblk` - Support Gen4 GDM read configuration block (@iceman1001)
- Changed magic note to include a section about GDM tags (@iceman1001)
- Added `hf mf gdmsetblk` - Support Gen4 GDM write block (@iceman1001)
- Changed `hf 14a info` - detect Gen GDM magic tags (@iceman1001)
- Changed CLI max string argument length limit from 512 to 4096 (@iceman1001)
@ -20,7 +22,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Fixed `pm3` script for passing arguments (@doegox)
- Fixed python paths to include current directory (@jmichelp)
- Fixed infinite loops in spindelayus (@lnv42)
- Add ICECLASS standalone read/sim mode (@natesales)
- Changed ICECLASS standalone to support a read/sim mode (@natesales)
- Changed `hf iclass encode` - added verbose flag (@natesales)
- Changed `hf waveshare` - now identify 1.54 nfc epaper correct (@ah01)
- Fixed `Makefile` regression that broke `make install` (@henrygab)
@ -32,12 +34,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added `--back` option to `clear` command to clear the scrollback buffer (@wh201906)
- Changed `hf iclass decrypt` - mark credentials as decrypted in the dump (@natesales)
- Changed `hf iclass view` - show credentials on a decrypted dump (@natesales)
- Show NTAG213TT tamper info in `hf mfu info` and add commands for configuring it's tamper feature (@mjaksn)
- Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
- Changed `hf mfu info` - NTAG213TT tamper info (mjaksn)
- Added commands for configuring NTAG213TT tamper featue (@mjaksn)
- Added Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
- Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb)
-
## [Nitride.4.16191][2023-01-29]
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)

View file

@ -1735,7 +1735,16 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareG4WriteBlk(payload->blockno, payload->pwd, payload->data, payload->workFlags);
break;
}
case CMD_HF_MIFARE_G4_GDM_RDBL: {
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
} PACKED;
struct p *payload = (struct p *) packet->data.asBytes;
MifareReadBlockGDM(payload->blockno, payload->keytype, payload->key);
break;
}
case CMD_HF_MIFARE_G4_GDM_WRBL: {
struct p {
uint8_t blockno;

View file

@ -214,6 +214,65 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
LEDsoff();
}
void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key) {
int retval = PM3_SUCCESS;
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
if (par == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
uint8_t *uid = BigBuf_malloc(10);
if (uid == NULL) {
retval = PM3_EMALLOC;
goto OUT;
}
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
// variables
uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint64_t ui64key = bytes_to_num(key, 6);
uint8_t outbuf[16] = {0x00};
if (iso14443a_select_card(uid, NULL, &cuid, true, 0, true) == false) {
retval = PM3_ESOFT;
goto OUT;
}
if (mifare_classic_authex_2(pcs, cuid, blockno, keytype, ui64key, AUTH_FIRST, NULL, NULL, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_readblock_ex(pcs, cuid, blockno, outbuf, true)) {
retval = PM3_ESOFT;
goto OUT;
};
if (mifare_classic_halt(pcs, cuid)) {
retval = PM3_ESOFT;
goto OUT;
};
OUT:
crypto1_deinit(pcs);
reply_ng(CMD_HF_MIFARE_G4_GDM_RDBL, retval, outbuf, sizeof(outbuf));
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
set_tracing(false);
BigBuf_free();
}
//-----------------------------------------------------------------------------
// Select, Authenticate, Read a MIFARE tag.
// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)

View file

@ -59,6 +59,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overw
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
// MFC GEN4 GDM
void MifareReadBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key);
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
// MFC GEN4 GTU

View file

@ -230,13 +230,20 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
}
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
return mifare_classic_readblock_ex(pcs, uid, blockNo, blockData, false);
}
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
int len;
uint8_t bt[2] = {0x00, 0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
uint16_t len;
if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else {
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
}
if (len == 1) {
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]);
return 1;
@ -246,6 +253,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
return 2;
}
uint8_t bt[2] = {0x00, 0x00};
memcpy(bt, receivedAnswer + 16, 2);
AddCrc14A(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
@ -416,19 +424,14 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) {
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
return mifare_classic_writeblock_ex(pcs, uid, blockNo, blockData, false);
}
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
// variables
uint16_t len = 0;
uint32_t pos = 0;
uint8_t par[3] = {0x00, 0x00, 0x00}; // enough for 18 Bytes to send
uint8_t res = 0;
uint8_t d_block[18], d_block_enc[18];
// variables
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// command MIFARE_MAGIC_GDM_WRITEBLOCK
uint16_t len;
if (is_gdm) {
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
} else {
@ -440,11 +443,14 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
return 1;
}
uint8_t d_block[18], d_block_enc[18];
memcpy(d_block, blockData, 16);
AddCrc14A(d_block, 16);
// enough for 18 Bytes to send
uint8_t par[3] = {0x00, 0x00, 0x00};
// crypto
for (pos = 0; pos < 18; pos++) {
for (uint32_t pos = 0; pos < 18; pos++) {
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
}
@ -452,9 +458,10 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
// Receive the response
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
res = 0;
uint8_t res = 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;

View file

@ -73,7 +73,10 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);

View file

@ -7674,6 +7674,78 @@ static int CmdHF14AGen4Save(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdHF14AGen4_GDM_GetBlk(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mf gdmgetblk",
"Get block data from magic gen4 GDM card.",
"hf mf gdmgetblk --blk 0 --> get block 0 (manufacturer)\n"
"hf mf gdmgetblk --blk 3 -v --> get block 3, decode sector trailer\n"
);
void *argtable[] = {
arg_param_begin,
arg_int1("b", "blk", "<dec>", "block number"),
arg_lit0("v", "verbose", "verbose output"),
arg_str0("k", "key", "<hex>", "key 6 bytes"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int b = arg_get_int_def(ctx, 1, 0);
bool verbose = arg_get_lit(ctx, 2);
int keylen = 0;
uint8_t key[6] = {0};
CLIGetHexWithReturn(ctx, 3, key, &keylen);
CLIParserFree(ctx);
// validate args
if (b < 0 || b >= MIFARE_4K_MAXBLOCK) {
PrintAndLogEx(FAILED, "target block number out-of-range, got %i", b);
return PM3_EINVARG;
}
if (keylen != 6 && keylen != 0) {
PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen);
return PM3_EINVARG;
}
uint8_t blockno = (uint8_t)b;
PrintAndLogEx(NORMAL, "Block: %x", blockno) ;
struct p {
uint8_t blockno;
uint8_t keytype;
uint8_t key[6];
} PACKED payload;
payload.blockno = blockno;
payload.keytype = 0;
memcpy(payload.key, key, sizeof(payload.key));
clearCommandBuffer();
SendCommandNG(CMD_HF_MIFARE_G4_GDM_RDBL, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_RDBL, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "command execute timeout");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
uint8_t sector = mfSectorNum(blockno);
mf_print_sector_hdr(sector);
uint8_t *d = resp.data.asBytes;
mf_print_block_one(blockno, d, verbose);
if (verbose) {
decode_print_st(blockno, d);
} else {
PrintAndLogEx(NORMAL, "");
}
}
return resp.status;
}
static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserContext *ctx;
@ -7713,7 +7785,7 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
CLIParserFree(ctx);
if (blen != MFBLOCK_SIZE) {
PrintAndLogEx(WARNING, "expected 16 HEX bytes. got %i", blen);
PrintAndLogEx(WARNING, "expected %u HEX bytes. got %i", MFBLOCK_SIZE, blen);
return PM3_EINVARG;
}
@ -7722,6 +7794,11 @@ static int CmdHF14AGen4_GDM_SetBlk(const char *Cmd) {
return PM3_EINVARG;
}
if (keylen != 6 && keylen != 0) {
PrintAndLogEx(FAILED, "Must specify 6 bytes, got " _YELLOW_("%u"), keylen);
return PM3_EINVARG;
}
uint8_t blockno = (uint8_t)b;
PrintAndLogEx(INFO, "Writing block no %d, key %c - %s", blockno, (keytype == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(key, sizeof(key)));
@ -8022,6 +8099,7 @@ static command_t CommandTable[] = {
{"gsetblk", CmdHF14AGen4SetBlk, IfPm3Iso14443a, "Write block to card"},
{"gview", CmdHF14AGen4View, IfPm3Iso14443a, "View card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "-------------------- " _CYAN_("magic gen4 GDM") " --------------------------"},
{"gdmgetblk", CmdHF14AGen4_GDM_GetBlk, IfPm3Iso14443a, "Read block from card"},
{"gdmsetblk", CmdHF14AGen4_GDM_SetBlk, IfPm3Iso14443a, "Write block to card"},
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("ndef") " -----------------------"},
// {"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},

View file

@ -20,6 +20,7 @@ Useful docs:
* [MIFARE Classic DirectWrite, UFUID version](#mifare-classic-directwrite-ufuid-version)
* [MIFARE Classic, other versions](#mifare-classic-other-versions)
* [MIFARE Classic Gen3 aka APDU](#mifare-classic-gen3-aka-apdu)
* [MIFARE Classic Gen4 aka GDM](#mifare-classic-gen4-aka-gdm)
* [MIFARE Classic Super](#mifare-classic-super)
- [MIFARE Ultralight](#mifare-ultralight)
* [MIFARE Ultralight blocks 0..2](#mifare-ultralight-blocks-02)
@ -68,6 +69,7 @@ To restore anticollision config of the Proxmark3:
```
hf 14a config --std
```
# MIFARE Classic
^[Top](#top)
@ -89,7 +91,7 @@ UID 4b: (actually NUID as there are no more "unique" IDs on 4b)
```
Computing BCC on UID 11223344: `hf analyse lcr -d 11223344` = `44`
Computing BCC on UID 11223344: `analyse lcr -d 11223344` = `44`
UID 7b:
@ -262,6 +264,8 @@ hf 14a info
* Read: `40(7)`, `30xx`
* Write: `40(7)`, `A0xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
## MIFARE Classic DirectWrite aka Gen2 aka CUID
^[Top](#top)
@ -396,6 +400,7 @@ hf mf wrbl --blk 0 -k FFFFFFFFFFFF -d 04112233445566184200626364656667 # for 4k
hf 14a config --std
hf 14a reader
```
## MIFARE Classic DirectWrite, FUID version aka 1-write
^[Top](#top)
@ -436,14 +441,6 @@ hf 14a raw -k -c e100
hf 14a raw -c 85000000000000000000000000000008
```
## MIFARE Classic, other versions
^[Top](#top)
**TODO**
* ZXUID, EUID, ICUID ?
* Some cards exhibit a specific SAK=28 ??
## MIFARE Classic Gen3 aka APDU
^[Top](#top)
@ -517,6 +514,72 @@ hf 14a raw -s -c -t 2000 90F0CCCC10 041219c3219316984200e32000000000
hf 14a raw -s -c 90FD111100
```
## MIFARE Classic Gen4 aka GDM
^[Top](#top)
Tag has shadow mode enabled from start.
Meaning every write or changes to normal MFC memory is restored back to a copy from persistent memory after about 3 seconds
off rfid field.
Tag also seems to support Gen2 style, direct write, to block 0 to the normal MFC memory.
The persistent memory is also writable. For that tag uses its own backdoor commands.
for example to write, you must use a customer authentication byte, 0x80, to authenticate with an all zeros key, 0x0000000000.
Then send the data to be written.
** OBS **
When writing to persistent memory it is possible to write _bad_ ACL and perm-brick the tag.
### Identify
^[Top](#top)
```
hf 14a info
...
[+] Magic capabilities : Gen 4 GDM
```
### Magic commands
^[Top](#top)
* Auth: `80xx`+crc
* Write: `A8xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
* Read : `E000`+crc (unidentified)
### Characteristics
^[Top](#top)
* Have no knowledge in ATQA/SAK/BCC quirks or if there is a wipe, softbrick recover
* Its magic part seem to be three identified custom command.
* Auth command 0x80, with the key 0x0000000000, Write 0xA8 allows writing to persistent memory, Read 0xE0 which seems to return a configuration. This is unknown today what these bytes are.
It is unknown what kind of block 0 changes the tag supports
* UID: 4b
* ATQA/SAK: unknown
* BCC: unknown
* ATS: none
### Proxmark3 commands
^[Top](#top)
```
# Write to persistent memory
hf mf gdmsetblk
# Read 0xE0 configuration:
hf mf gdmgetblk
```
### libnfc commands
^[Top](#top)
No implemented commands today
## MIFARE Classic, other versions
^[Top](#top)
**TODO**
* ZXUID, EUID, ICUID ?
* Some cards exhibit a specific SAK=28 ??
## MIFARE Classic Super
^[Top](#top)
@ -1019,7 +1082,6 @@ script run hf_15_magic -u E004013344556677
A.k.a ultimate magic card, most promenent feature is shadow mode (GTU) and optional password protected backdoor commands.
Can emulate MIFARE Classic, Ultralight/NTAG families, 14b UID & App Data
- [Identify](#identify)
@ -1057,6 +1119,7 @@ The card will be identified only if the password is the default one. One can ide
hf 14a raw -s -c -t 1000 CF00000000C6
```
If the card is an Ultimate Magic Card, it returns 30 or 32 bytes.
### Magic commands
^[Top](#top) ^^[Gen4](#g4top)
@ -1203,6 +1266,7 @@ OR (Note the script will correct the ATQA correctly)
```
script run hf_mf_ultimatecard -q 004428
```
### Change ATS
^[Top](#top) ^^[Gen4](#g4top)
@ -1240,6 +1304,7 @@ Example: set UID length to 7 bytes, default pwd
```
hf 14a raw -s -c -t 1000 CF000000006801
```
### Set 14443A UID
^[Top](#top) ^^[Gen4](#g4top)
@ -1353,6 +1418,7 @@ script run hf_mf_ultimatecard -m 02
```
Now the card supports the 3DES UL-C authentication.
### Set Ultralight and M1 maximum read/write sectors
^[Top](#top) ^^[Gen4](#g4top)
@ -1366,6 +1432,7 @@ Example: set maximum 63 blocks read/write for Mifare Classic 1K
```
hf 14a raw -s -c -t 1000 CF000000006B3F
```
### Set shadow mode (GTU)
^[Top](#top) ^^[Gen4](#g4top)
@ -1479,6 +1546,7 @@ Default configuration:
^^ cf cmd 68: UID length
^^ cf cmd 69: Ultralight protocol
```
### Fast configuration
^[Top](#top) ^^[Gen4](#g4top)

View file

@ -193,6 +193,7 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
#define MIFARE_MAGIC_GDM_AUTH_KEYA 0x80
#define MIFARE_MAGIC_GDM_AUTH_KEYB 0x81
#define MIFARE_MAGIC_GDM_WRITEBLOCK 0xA8
#define MIFARE_MAGIC_GDM_READBLOCK 0xE0
#define MIFARE_EV1_PERSONAL_UID 0x40
#define MIFARE_EV1_SETMODE 0x43