mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-01 18:45:10 +08:00
Merge pull request #1821 from DidierA/gen4_ident
Add Magic Gen4 GTU detection
This commit is contained in:
commit
f9aa183382
6 changed files with 149 additions and 76 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added detection of magic Gen4 GTU (@DidierA)
|
||||
- Added luascript `hf_i2c_plus_2k_utils` - Script for dumping/modifying user memory of sectors 0 and 1 (@flamebarke)
|
||||
- Added `hf mfu esave` - saves emulator memory to mfu dump file (@DidierA)
|
||||
- Added luascript `hf_mfu_ntag` - Script for configuring NTAG216 configuration pages (@flamebarke)
|
||||
|
|
|
@ -2356,6 +2356,7 @@ void MifareCIdent(bool is_mfc) {
|
|||
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
|
||||
uint8_t rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||
uint8_t rdbl00[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
||||
uint8_t gen4GetConf[8] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_GETCNF, 0, 0};
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
@ -2388,6 +2389,26 @@ void MifareCIdent(bool is_mfc) {
|
|||
|
||||
int res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
|
||||
// Check for Magic Gen4 GTU with default password :
|
||||
// Get config should return 30 bytes.
|
||||
AddCrc14A(gen4GetConf, sizeof(gen4GetConf) - 2);
|
||||
ReaderTransmit(gen4GetConf, sizeof(gen4GetConf), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 32) {
|
||||
isGen = MAGIC_GEN_4GTU;
|
||||
goto OUT;
|
||||
}
|
||||
}
|
||||
|
||||
// reset card
|
||||
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) {
|
||||
|
||||
if (cuid == 0xAA55C396) {
|
||||
isGen = MAGIC_GEN_UNFUSED;
|
||||
goto OUT;
|
||||
|
@ -2746,7 +2767,7 @@ void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags) {
|
|||
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
|
||||
}
|
||||
|
||||
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCE, blockno,
|
||||
uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_READ, blockno,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
|
@ -2822,7 +2843,7 @@ void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t work
|
|||
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 1000); // 2 seconds timeout
|
||||
}
|
||||
|
||||
uint8_t cmd[] = { 0xCF, 0x00, 0x00, 0x00, 0x00, 0xCD, blockno,
|
||||
uint8_t cmd[] = { GEN_4GTU_CMD, 0x00, 0x00, 0x00, 0x00, GEN_4GTU_WRITE, blockno,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
|
|
|
@ -228,7 +228,6 @@ local function read_config()
|
|||
if ulmode == '03' then versionstr = 'Ultralight'
|
||||
elseif ulmode == '02' then versionstr = 'Ultralight-C'
|
||||
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
|
||||
elseif cversion == '0004030101000B03' then versionstr = 'UL EV1 48b'
|
||||
elseif cversion == '0004030101000E03' then versionstr = 'UL EV1 128b'
|
||||
elseif cversion == '0004040101000B03' then versionstr = 'NTAG 210'
|
||||
elseif cversion == '0004040101000E03' then versionstr = 'NTAG 212'
|
||||
|
@ -845,86 +844,101 @@ local function set_type(tagtype)
|
|||
end
|
||||
end
|
||||
---
|
||||
-- returns true if b is the index of a sector trailer
|
||||
local function mfIsSectorTrailer(b)
|
||||
n=b+1
|
||||
if (n < 32*4 ) then
|
||||
if (n % 4 == 0) then return true
|
||||
else return false
|
||||
end
|
||||
end
|
||||
|
||||
if (n % 16 == 0) then return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
---
|
||||
-- wipe tag
|
||||
local function wipe(wtype)
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
if wtype == '0' then
|
||||
print('Starting Mifare Wipe')
|
||||
print('Starting Mifare Wipe')
|
||||
send("CF".._key.."F000000000000002000978009102DABC19101011121314151604000800")
|
||||
send("CF".._key.."CD000102030404080400000000000000BEAF")
|
||||
local err, msg, resp
|
||||
local cmd_empty = 'CF'.._key..'CD%02X00000000000000000000000000000000'
|
||||
local cmd_cfg1 = 'CF'.._key..'CD%02XFFFFFFFFFFFFFF078069FFFFFFFFFFFF'
|
||||
for b = 1, 0xFB do
|
||||
if b == 0x03 or b == 0x07 or b == 0x0B or b == 0x0F or b == 0x13 or b == 0x17 or b == 0x1B or b == 0x1F or b == 0x23 or b == 0x27 or b == 0x2B or b == 0x2F or b == 0x33 or b == 0x37 or b == 0x3B or b == 0x3F then
|
||||
local cmd = (cmd_cfg1):format(b)
|
||||
resp = send(cmd)
|
||||
else
|
||||
local cmd = (cmd_empty):format(b)
|
||||
resp = send(cmd)
|
||||
end
|
||||
if resp == nil then
|
||||
io.write('\nwrote block '..b, ' failed\n')
|
||||
err = true
|
||||
else
|
||||
io.write('.')
|
||||
end
|
||||
io.flush()
|
||||
end
|
||||
print('\n')
|
||||
err, msg = set_type(3)
|
||||
if err == nil then return err, msg end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
local err, msg, resp
|
||||
local cmd_empty = 'CF'.._key..'CD%02X00000000000000000000000000000000'
|
||||
local cmd_trail = 'CF'.._key..'CD%02XFFFFFFFFFFFFFF078069FFFFFFFFFFFF'
|
||||
for b = 1, 0xFF do
|
||||
if mfIsSectorTrailer(b) then
|
||||
local cmd = (cmd_trail):format(b)
|
||||
resp = send(cmd)
|
||||
else
|
||||
local cmd = (cmd_empty):format(b)
|
||||
resp = send(cmd)
|
||||
end
|
||||
if resp == nil then
|
||||
io.write('\nwrote block '..b, ' failed\n')
|
||||
err = true
|
||||
else
|
||||
io.write('.')
|
||||
end
|
||||
io.flush()
|
||||
end
|
||||
print('\n')
|
||||
err, msg = set_type(3)
|
||||
if err == nil then return err, msg end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
elseif wtype == '1' then
|
||||
print('Starting Ultralight Wipe')
|
||||
local err, msg, resp
|
||||
local cmd_empty = 'A2%02X00000000'
|
||||
local cmd_cfg1 = 'A2%02X000000FF'
|
||||
local cmd_cfg2 = 'A2%02X00050000'
|
||||
print('Wiping tag')
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
print('Starting Ultralight Wipe')
|
||||
local err, msg, resp
|
||||
local cmd_empty = 'A2%02X00000000'
|
||||
local cmd_cfg1 = 'A2%02X000000FF'
|
||||
local cmd_cfg2 = 'A2%02X00050000'
|
||||
print('Wiping tag')
|
||||
local info = connect()
|
||||
if not info then return false, "Can't select card" end
|
||||
send("CF".._key.."F001010000000003000978009102DABC19101011121314151644000001")
|
||||
for b = 3, 0xFB do
|
||||
--configuration block 0
|
||||
if b == 0x29 or b == 0x83 or b == 0xe3 then
|
||||
local cmd = (cmd_cfg1):format(b)
|
||||
resp = send(cmd)
|
||||
--configuration block 1
|
||||
elseif b == 0x2a or b == 0x84 or b == 0xe4 then
|
||||
local cmd = (cmd_cfg2):format(b)
|
||||
resp = send(cmd)
|
||||
else
|
||||
resp = send(cmd_empty:format(b))
|
||||
end
|
||||
if resp == '04' or #resp == 0 then
|
||||
io.write('\nwrote block '..b, ' failed\n')
|
||||
err = true
|
||||
else
|
||||
io.write('.')
|
||||
end
|
||||
io.flush()
|
||||
end
|
||||
io.write('\r\n')
|
||||
lib14a.disconnect()
|
||||
print('\n')
|
||||
if err then return nil, "Tag locked down, "..err_lock end
|
||||
-- set NTAG213 default values
|
||||
err, msg = set_type(14)
|
||||
if err == nil then return err, msg end
|
||||
--set UID
|
||||
err, msg = write_uid('04112233445566')
|
||||
if err == nil then return err, msg end
|
||||
--set NTAG pwd
|
||||
err, msg = write_ntagpwd('FFFFFFFF')
|
||||
if err == nil then return err, msg end
|
||||
--set pack
|
||||
err, msg = write_pack('0000')
|
||||
if err == nil then return err, msg end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
for b = 3, 0xFB do
|
||||
--configuration block 0
|
||||
if b == 0x29 or b == 0x83 or b == 0xe3 then
|
||||
local cmd = (cmd_cfg1):format(b)
|
||||
resp = send(cmd)
|
||||
--configuration block 1
|
||||
elseif b == 0x2a or b == 0x84 or b == 0xe4 then
|
||||
local cmd = (cmd_cfg2):format(b)
|
||||
resp = send(cmd)
|
||||
else
|
||||
resp = send(cmd_empty:format(b))
|
||||
end
|
||||
if resp == '04' or #resp == 0 then
|
||||
io.write('\nwrote block '..b, ' failed\n')
|
||||
err = true
|
||||
else
|
||||
io.write('.')
|
||||
end
|
||||
io.flush()
|
||||
end
|
||||
io.write('\r\n')
|
||||
lib14a.disconnect()
|
||||
print('\n')
|
||||
if err then return nil, "Tag locked down, "..err_lock end
|
||||
-- set NTAG213 default values
|
||||
err, msg = set_type(14)
|
||||
if err == nil then return err, msg end
|
||||
--set UID
|
||||
err, msg = write_uid('04112233445566')
|
||||
if err == nil then return err, msg end
|
||||
--set NTAG pwd
|
||||
err, msg = write_ntagpwd('FFFFFFFF')
|
||||
if err == nil then return err, msg end
|
||||
--set pack
|
||||
err, msg = write_pack('0000')
|
||||
if err == nil then return err, msg end
|
||||
lib14a.disconnect()
|
||||
return true, 'Ok'
|
||||
else oops('Use 0 for Mifare wipe or 1 for Ultralight wipe')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1408,6 +1408,9 @@ int detect_mf_magic(bool is_mfc) {
|
|||
case MAGIC_GEN_3:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : possibly " _GREEN_("Gen 3 / APDU"));
|
||||
break;
|
||||
case MAGIC_GEN_4GTU:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 4 GTU"));
|
||||
break;
|
||||
case MAGIC_GEN_UNFUSED:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID"));
|
||||
break;
|
||||
|
|
|
@ -998,9 +998,14 @@ Can emulate MIFARE Classic, Ultralight/NTAG families, 14b UID & App Data
|
|||
### Identify
|
||||
^[Top](#top) ^^[Gen4](#g4top)
|
||||
|
||||
👉 **TODO** Tag doesn't get identified correctly by latest Proxmark3 client (it might get mislabeled as MFC Gen2/CUID, Gen3/APDU or NTAG21x Modifiable, depending on configured UID/ATQA/SAK/ATS)
|
||||
👉 **TODO** If the password is not default, Tag doesn't get identified correctly by latest Proxmark3 client (it might get mislabeled as MFC Gen2/CUID, Gen3/APDU or NTAG21x Modifiable, depending on configured UID/ATQA/SAK/ATS)
|
||||
|
||||
One can identify manually such card if the password is still the default one, with the command to get the current configuration:
|
||||
```
|
||||
hf 14a info
|
||||
[+] Magic capabilities : Gen 4 GTU
|
||||
```
|
||||
|
||||
The card will be identified only if the password is the default one. One can identify manually such card if the password is still the default one, with the command to get the current configuration:
|
||||
```
|
||||
hf 14a raw -s -c -t 1000 CF00000000C6
|
||||
```
|
||||
|
@ -1108,6 +1113,14 @@ Default `<passwd>`: `00000000`
|
|||
```
|
||||
# view contents of tag memory:
|
||||
hf mf gview
|
||||
# Read a specific block via backdoor command:
|
||||
hf mf ggetblk
|
||||
# Write a specific block via backdoor command:
|
||||
hf mf gsetblk
|
||||
# Load dump to tag:
|
||||
hf mf gload
|
||||
# Save dump from tag:
|
||||
hf mf gsave
|
||||
```
|
||||
👉 **TODO** `hf mf gview` is currently missing Ultralight memory maps
|
||||
|
||||
|
@ -1120,6 +1133,8 @@ hf 14a raw -s -c -t 1000 CF00000000CE02
|
|||
...
|
||||
```
|
||||
|
||||
👉 **TODO** In Mifare Ultralight / NTAG mode, the special writes (option -s, -e, -r) do not apply. Use `script run hf_mf_ultimatecard` for UID and signature, and `hf mfu wrbl` for PWD and PACK.
|
||||
|
||||
### Change ATQA / SAK
|
||||
^[Top](#top) ^^[Gen4](#g4top)
|
||||
|
||||
|
|
|
@ -252,6 +252,25 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define MAGIC_SUPER 6
|
||||
#define MAGIC_NTAG21X 7
|
||||
#define MAGIC_GEN_3 8
|
||||
#define MAGIC_GEN_4GTU 9
|
||||
|
||||
// Commands for configuration of Gen4 GTU cards.
|
||||
// see https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/magic_cards_notes.md
|
||||
#define GEN_4GTU_CMD 0xCF // Prefix for all commands, followed by pasword (4b)
|
||||
#define GEN_4GTU_SHADOW 0x32 // Configure GTU shadow mode
|
||||
#define GEN_4GTU_ATS 0x34 // Configure ATS
|
||||
#define GEN_4GTU_ATQA 0x35 // Configure ATQA/SAK (swap ATQA bytes)
|
||||
#define GEN_4GTU_UIDLEN 0x68 // Configure UID length
|
||||
#define GEN_4GTU_ULEN 0x69 // (De)Activate Ultralight mode
|
||||
#define GEN_4GTU_ULMODE 0x6A // Select Ultralight mode
|
||||
#define GEN_4GTU_GETCNF 0xC6 // Dump configuration
|
||||
#define GEN_4GTU_TEST 0xCC // Factory test, returns 6666
|
||||
#define GEN_4GTU_WRITE 0xCD // Backdoor write 16b block
|
||||
#define GEN_4GTU_READ 0xCE // Backdoor read 16b block
|
||||
#define GEN_4GTU_SETCNF 0xF0 // Configure all params in one cmd
|
||||
#define GEN_4GTU_FUSCNF 0xF1 // Configure all params in one cmd and fuse the configuration permanently
|
||||
#define GEN_4GTU_CHPWD 0xFE // change password
|
||||
|
||||
/**
|
||||
06 00 = INITIATE
|
||||
0E xx = SELECT ID (xx = Chip-ID)
|
||||
|
|
Loading…
Reference in a new issue