2019-03-09 15:49:41 +08:00
//-----------------------------------------------------------------------------
// Copyright (C) 2011,2012 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE commands
//-----------------------------------------------------------------------------
# include "cmdhfmf.h"
2019-08-08 22:57:33 +08:00
# include <ctype.h>
# include "cmdparser.h" // command_t
# include "commonutil.h" // ARRAYLEN
# include "comms.h" // clearCommandBuffer
2019-08-21 20:41:33 +08:00
# include "fileutils.h"
2019-08-08 22:57:33 +08:00
# include "cmdtrace.h"
# include "emv/dump.h"
# include "mifare/mifaredefault.h" // mifare default key array
# include "cliparser/cliparser.h" // argtable
# include "hardnested/hardnested_bf_core.h" // SetSIMDInstr
2019-03-09 15:49:41 +08:00
# include "mifare/mad.h"
# include "mifare/ndef.h"
2019-08-08 22:57:33 +08:00
# include "protocols.h"
# include "util_posix.h" // msclock
2019-03-09 15:49:41 +08:00
# define MFBLOCK_SIZE 16
# define MIFARE_4K_MAXBLOCK 256
2019-03-09 15:59:13 +08:00
# define MIFARE_2K_MAXBLOCK 128
2019-03-09 15:49:41 +08:00
# define MIFARE_1K_MAXBLOCK 64
# define MIFARE_MINI_MAXBLOCK 20
# define MIFARE_MINI_MAXSECTOR 5
# define MIFARE_1K_MAXSECTOR 16
# define MIFARE_2K_MAXSECTOR 32
# define MIFARE_4K_MAXSECTOR 40
static int CmdHelp ( const char * Cmd ) ;
2019-04-10 19:06:05 +08:00
static int usage_hf14_ice ( void ) {
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf ice [l <limit>] [f <name>] " ) ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " l <limit> nonces to be collected " ) ;
PrintAndLogEx ( NORMAL , " f <name> save nonces to <name> instead of hf-mf-<UID>-nonces.bin " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf ice " ) ;
PrintAndLogEx ( NORMAL , " hf mf ice f nonces.bin " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_dump ( void ) {
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf dump [card memory] [k <name>] [f <name>] " ) ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " k <name> : key filename, if no <name> given, UID will be used as filename " ) ;
PrintAndLogEx ( NORMAL , " f <name> : data filename, if no <name> given, UID will be used as filename " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf dump " ) ;
PrintAndLogEx ( NORMAL , " hf mf dump 4 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_mifare ( void ) {
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf darkside <block number> <A|B> " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <block number> (Optional) target other block " ) ;
PrintAndLogEx ( NORMAL , " <A|B> (optional) target key type " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf darkside " ) ;
PrintAndLogEx ( NORMAL , " hf mf darkside 16 " ) ;
PrintAndLogEx ( NORMAL , " hf mf darkside 16 B " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-18 02:36:10 +08:00
static int usage_hf14_mfsim ( void ) {
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf sim [u <uid>] [n <numreads>] [t] [a <ATQA>] [s <SAK>] [i] [x] [e] [v] " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
2019-08-07 06:47:32 +08:00
PrintAndLogEx ( NORMAL , " u (Optional) UID 4,7 or 10bytes. If not specified, the UID 4b/7b from emulator memory will be used " ) ;
PrintAndLogEx ( NORMAL , " t (Optional) Enforce ATQA/SAK: " ) ;
PrintAndLogEx ( NORMAL , " 0 = MIFARE Mini " ) ;
2019-03-16 04:04:25 +08:00
PrintAndLogEx ( NORMAL , " 1 = MIFARE Classic 1k (Default) " ) ;
2019-04-19 02:02:48 +08:00
PrintAndLogEx ( NORMAL , " 2 = MIFARE Classic 2k plus in SL0 mode " ) ;
2019-03-16 04:04:25 +08:00
PrintAndLogEx ( NORMAL , " 4 = MIFARE Classic 4k " ) ;
2019-08-07 07:32:37 +08:00
PrintAndLogEx ( NORMAL , " a (Optional) Provide explicitly ATQA (2 bytes, override option t) " ) ;
PrintAndLogEx ( NORMAL , " s (Optional) Provide explicitly SAK (1 byte, override option t) " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " n (Optional) Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite " ) ;
PrintAndLogEx ( NORMAL , " i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted " ) ;
PrintAndLogEx ( NORMAL , " x (Optional) Crack, performs the 'reader attack', nr/ar attack against a reader " ) ;
PrintAndLogEx ( NORMAL , " e (Optional) Fill simulator keys from found keys " ) ;
PrintAndLogEx ( NORMAL , " v (Optional) Verbose " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf sim u 0a0a0a0a " ) ;
PrintAndLogEx ( NORMAL , " hf mf sim u 11223344556677 " ) ;
PrintAndLogEx ( NORMAL , " hf mf sim u 112233445566778899AA " ) ;
PrintAndLogEx ( NORMAL , " hf mf sim u 11223344 i x " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
/*
* static int usage_hf14_sniff ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It continuously gets data from the field and saves it to: log, emulator, emulator file. " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf sniff [h] [l] [d] [f] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " l save encrypted sequence to logfile `uid.log` " ) ;
PrintAndLogEx ( NORMAL , " d decrypt sequence and put it to log file `uid.log` " ) ;
// PrintAndLogEx(NORMAL, " n/a e decrypt sequence, collect read and write commands and save the result of the sequence to emulator memory");
PrintAndLogEx ( NORMAL , " f decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml` " ) ;
PrintAndLogEx ( NORMAL , " Example: " ) ;
PrintAndLogEx ( NORMAL , " hf mf sniff l d f " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
*/
2019-04-10 19:06:05 +08:00
static int usage_hf14_nested ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: " ) ;
PrintAndLogEx ( NORMAL , " all sectors: hf mf nested <card memory> <block number> <key A/B> <key (12 hex symbols)> [t,d] " ) ;
PrintAndLogEx ( NORMAL , " one sector: hf mf nested o <block number> <key A/B> <key (12 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " <target block number> <target key A/B> [t] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K " ) ;
PrintAndLogEx ( NORMAL , " t transfer keys into emulator memory " ) ;
PrintAndLogEx ( NORMAL , " d write keys to binary file `hf-mf-<UID>-key.bin` " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2019-05-24 03:04:48 +08:00
PrintAndLogEx ( NORMAL , " hf mf nested 1 0 A FFFFFFFFFFFF -- nested attack against 1k,block 0, Key A using key FFFFFFFFFFFF " ) ;
PrintAndLogEx ( NORMAL , " hf mf nested 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory " ) ;
PrintAndLogEx ( NORMAL , " hf mf nested 1 0 A FFFFFFFFFFFF d -- or write keys to binary file " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " hf mf nested o 0 A FFFFFFFFFFFF 4 A " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_hardnested ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested <block number> <key A|B> <key (12 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " <target block number> <target key A|B> [known target key (12 hex symbols)] [w] [s] " ) ;
PrintAndLogEx ( NORMAL , " or hf mf hardnested r [known target key] " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " w acquire nonces and UID, and write them to binary file with default name hf-mf-<UID>-nonces.bin " ) ;
PrintAndLogEx ( NORMAL , " s slower acquisition (required by some non standard cards) " ) ;
PrintAndLogEx ( NORMAL , " r read hf-mf-<UID>-nonces.bin if tag present, otherwise read nonces.bin, then start attack " ) ;
PrintAndLogEx ( NORMAL , " u <UID> read/write hf-mf-<UID>-nonces.bin instead of default name " ) ;
PrintAndLogEx ( NORMAL , " f <name> read/write <name> instead of default name " ) ;
PrintAndLogEx ( NORMAL , " t tests? " ) ;
PrintAndLogEx ( NORMAL , " i <X> set type of SIMD instructions. Without this flag programs autodetect it. " ) ;
PrintAndLogEx ( NORMAL , " i 5 = AVX512 " ) ;
PrintAndLogEx ( NORMAL , " i 2 = AVX2 " ) ;
PrintAndLogEx ( NORMAL , " i a = AVX " ) ;
PrintAndLogEx ( NORMAL , " i s = SSE2 " ) ;
PrintAndLogEx ( NORMAL , " i m = MMX " ) ;
PrintAndLogEx ( NORMAL , " i n = none (use CPU regular instruction set) " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested 0 A FFFFFFFFFFFF 4 A " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested 0 A FFFFFFFFFFFF 4 A w " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested 0 A FFFFFFFFFFFF 4 A f nonces.bin w s " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested r " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested r a0a1a2a3a4a5 " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Add the known target key to check if it is present in the remaining key space: " ) ;
PrintAndLogEx ( NORMAL , " hf mf hardnested 0 A A0A1A2A3A4A5 4 A FFFFFFFFFFFF " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-08-25 00:11:03 +08:00
static int usage_hf14_autopwn ( void ) {
2019-08-22 18:49:26 +08:00
PrintAndLogEx ( NORMAL , " Usage: " ) ;
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( NORMAL , " hf mf autopwn [k] <sector number> <key A|B> <key (12 hex symbols)> " ) ;
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " [* <card memory>] [f <dictionary>[.dic]] [s] [i <simd type>] [l] [v] " ) ;
2019-08-22 18:49:26 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( NORMAL , " Description: " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( NORMAL , " This command automates the key recovery process on Mifare classic cards. " ) ;
2019-08-27 03:24:29 +08:00
PrintAndLogEx ( NORMAL , " It uses the darkside, nested and hardnested attack to extract the keys and card content. " ) ;
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-08-22 18:49:26 +08:00
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( NORMAL , " k <sector> <key A|B> <key> known key is supplied " ) ;
PrintAndLogEx ( NORMAL , " f <dictionary>[.dic] key dictionary file " ) ;
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " s slower acquisition for hardnested (required by some non standard cards) " ) ;
PrintAndLogEx ( NORMAL , " v verbose output (statistics) " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( NORMAL , " l legacy mode (use the slow 'mf chk' for the key enumeration) " ) ;
PrintAndLogEx ( NORMAL , " * <card memory> all sectors based on card memory " ) ;
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( NORMAL , " * 0 = MINI(320 bytes) " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( NORMAL , " * 1 = 1k (default) " ) ;
PrintAndLogEx ( NORMAL , " * 2 = 2k " ) ;
PrintAndLogEx ( NORMAL , " * 4 = 4k " ) ;
2019-08-27 02:57:23 +08:00
PrintAndLogEx ( NORMAL , " i <simd type> set type of SIMD instructions for hardnested. Default: autodetection. " ) ;
2019-08-22 18:49:26 +08:00
PrintAndLogEx ( NORMAL , " i 5 = AVX512 " ) ;
PrintAndLogEx ( NORMAL , " i 2 = AVX2 " ) ;
PrintAndLogEx ( NORMAL , " i a = AVX " ) ;
PrintAndLogEx ( NORMAL , " i s = SSE2 " ) ;
PrintAndLogEx ( NORMAL , " i m = MMX " ) ;
PrintAndLogEx ( NORMAL , " i n = none (use CPU regular instruction set) " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( NORMAL , " hf mf autopwn -- target Mifare classic card with default keys " ) ;
PrintAndLogEx ( NORMAL , " hf mf autopwn * 1 f mfc_default_keys -- target Mifare classic card (size 1k) with default dictionary " ) ;
PrintAndLogEx ( NORMAL , " hf mf autopwn k 0 A FFFFFFFFFFFF -- target Mifare classic card with Sector0 typeA with known key 'FFFFFFFFFFFF' " ) ;
2019-08-27 03:24:29 +08:00
PrintAndLogEx ( NORMAL , " hf mf autopwn k 0 A FFFFFFFFFFFF * 1 f mfc_default_keys -- this command combines the two above (reduce the need for nested / hardnested attacks, by using a dictionary) " ) ;
2019-08-22 18:49:26 +08:00
return 0 ;
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_chk ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf chk [h] <block number>|<*card memory> <key type (A/B/?)> [t|d] [<key (12 hex symbols)>] [<dic (*.dic)>] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " * all sectors based on card memory, other values then below defaults to 1k " ) ;
PrintAndLogEx ( NORMAL , " 0 - MINI(320 bytes) " ) ;
PrintAndLogEx ( NORMAL , " 1 - 1K " ) ;
PrintAndLogEx ( NORMAL , " 2 - 2K " ) ;
PrintAndLogEx ( NORMAL , " 4 - 4K " ) ;
PrintAndLogEx ( NORMAL , " d write keys to binary file " ) ;
PrintAndLogEx ( NORMAL , " t write keys to emulator memory \n " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2019-08-26 19:03:11 +08:00
PrintAndLogEx ( NORMAL , " hf mf chk 0 A 1234567890ab -- target block 0, Key A using key 1234567890ab " ) ;
PrintAndLogEx ( NORMAL , " hf mf chk 0 A mfc_default_keys.dic -- target block 0, Key A using default dictionary file " ) ;
PrintAndLogEx ( NORMAL , " hf mf chk *1 ? t -- target all blocks, all keys, 1K, write to emulator memory " ) ;
PrintAndLogEx ( NORMAL , " hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file " ) ;
2019-03-10 06:35:06 +08:00
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_chk_fast ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " This is a improved checkkeys method speedwise. It checks Mifare Classic tags sector keys against a dictionary file with keys " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf fchk [h] <card memory> [t|d|f] [<key (12 hex symbols)>] [<dic (*.dic)>] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <cardmem> all sectors based on card memory, other values than below defaults to 1k " ) ;
PrintAndLogEx ( NORMAL , " 0 - MINI(320 bytes) " ) ;
PrintAndLogEx ( NORMAL , " 1 - 1K <default> " ) ;
PrintAndLogEx ( NORMAL , " 2 - 2K " ) ;
PrintAndLogEx ( NORMAL , " 4 - 4K " ) ;
PrintAndLogEx ( NORMAL , " d write keys to binary file " ) ;
PrintAndLogEx ( NORMAL , " t write keys to emulator memory " ) ;
PrintAndLogEx ( NORMAL , " m use dictionary from flashmemory \n " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
2019-08-26 19:03:11 +08:00
PrintAndLogEx ( NORMAL , " hf mf fchk 1 1234567890ab -- target 1K using key 1234567890ab " ) ;
PrintAndLogEx ( NORMAL , " hf mf fchk 1 mfc_default_keys.dic -- target 1K using default dictionary file " ) ;
PrintAndLogEx ( NORMAL , " hf mf fchk 1 t -- target 1K, write to emulator memory " ) ;
PrintAndLogEx ( NORMAL , " hf mf fchk 1 d -- target 1K, write to file " ) ;
2019-05-02 03:46:29 +08:00
if ( IfPm3Flash ( ) )
2019-08-26 19:03:11 +08:00
PrintAndLogEx ( NORMAL , " hf mf fchk 1 m -- target 1K, use dictionary from flashmemory " ) ;
2019-03-10 06:35:06 +08:00
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-09-08 18:57:25 +08:00
/*
2019-04-10 19:06:05 +08:00
static int usage_hf14_keybrute ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " J_Run's 2nd phase of multiple sector nested authentication key recovery " ) ;
PrintAndLogEx ( NORMAL , " You have a known 4 last bytes of a key recovered with mf_nonce_brute tool. " ) ;
PrintAndLogEx ( NORMAL , " First 2 bytes of key will be bruteforced " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " ---[ This attack is obsolete, try hardnested instead ]--- " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf keybrute [h] <block number> <A|B> <key> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <block number> target block number " ) ;
PrintAndLogEx ( NORMAL , " <A|B> target key type " ) ;
PrintAndLogEx ( NORMAL , " <key> candidate key from mf_nonce_brute tool " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf keybrute 1 A 000011223344 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-09-08 18:57:25 +08:00
*/
2019-04-10 19:06:05 +08:00
static int usage_hf14_restore ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf restore [card memory] u <UID> k <name> f <name> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " u <UID> : uid, try to restore from hf-mf-<UID>-key.bin and hf-mf-<UID>-data.bin " ) ;
PrintAndLogEx ( NORMAL , " k <name> : key filename, specific the full filename of key file " ) ;
PrintAndLogEx ( NORMAL , " f <name> : data filename, specific the full filename of data file " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf restore -- read the UID from tag first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin " ) ;
PrintAndLogEx ( NORMAL , " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-data.bin " ) ;
PrintAndLogEx ( NORMAL , " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-data.bin " ) ;
PrintAndLogEx ( NORMAL , " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_decryptbytes ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Decrypt Crypto-1 encrypted bytes given some known state of crypto. See tracelog to gather needed values \n " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf decrypt [h] <nt> <ar_enc> <at_enc> <data> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <nt> reader nonce " ) ;
PrintAndLogEx ( NORMAL , " <ar_enc> encrypted reader response " ) ;
PrintAndLogEx ( NORMAL , " <at_enc> encrypted tag response " ) ;
PrintAndLogEx ( NORMAL , " <data> encrypted data, taken directly after at_enc and forward " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf decrypt b830049b 9248314a 9280e203 41e586f9 \n " ) ;
PrintAndLogEx ( NORMAL , " this sample decrypts 41e586f9 -> 3003999a Annotated: 30 03 [99 9a] auth block 3 [crc] " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_eget ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf eget <block number> " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf eget 0 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_eclr ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF \n " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf eclr " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_eset ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf eset <block number> <block data (32 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf eset 1 000102030405060708090a0b0c0d0e0f " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_eload ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It loads emul dump from the file `filename.eml` " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf eload [card memory] <file name w/o `.eml`> [numblocks] " ) ;
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K, u = UL " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf eload filename " ) ;
PrintAndLogEx ( NORMAL , " hf mf eload 4 filename " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_esave ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It saves emul dump into the file `filename.eml` or `cardID.eml` " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf esave [card memory] [file name w/o `.eml`] " ) ;
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf esave " ) ;
PrintAndLogEx ( NORMAL , " hf mf esave 4 " ) ;
PrintAndLogEx ( NORMAL , " hf mf esave 4 filename " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_ecfill ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Read card and transfer its data to emulator memory. " ) ;
PrintAndLogEx ( NORMAL , " Keys must be laid in the emulator memory. \n " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf ecfill <key A/B> [card memory] " ) ;
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf ecfill A " ) ;
PrintAndLogEx ( NORMAL , " hf mf ecfill A 4 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_ekeyprn ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It prints the keys loaded in the emulator memory " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf ekeyprn [card memory] " ) ;
PrintAndLogEx ( NORMAL , " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf ekeyprn 1 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_csetuid ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Set UID, ATQA, and SAK for magic Chinese card. Only works with magic cards " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf csetuid [h] <UID 8 hex symbols> [ATQA 4 hex symbols] [SAK 2 hex symbols] [w] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " w wipe card before writing " ) ;
PrintAndLogEx ( NORMAL , " <uid> UID 8 hex symbols " ) ;
PrintAndLogEx ( NORMAL , " <atqa> ATQA 4 hex symbols " ) ;
PrintAndLogEx ( NORMAL , " <sak> SAK 2 hex symbols " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf csetuid 01020304 " ) ;
PrintAndLogEx ( NORMAL , " hf mf csetuid 01020304 0004 08 w " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_csetblk ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Set block data for magic Chinese card. Only works with magic cards " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf csetblk [h] <block number> <block data (32 hex symbols)> [w] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " w wipe card before writing " ) ;
PrintAndLogEx ( NORMAL , " <block> block number " ) ;
PrintAndLogEx ( NORMAL , " <data> block data to write (32 hex symbols) " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf csetblk 1 01020304050607080910111213141516 " ) ;
PrintAndLogEx ( NORMAL , " hf mf csetblk 1 01020304050607080910111213141516 w " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_cload ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It loads magic Chinese card from the file `filename.eml` " ) ;
PrintAndLogEx ( NORMAL , " or from emulator memory " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf cload [h] [e] <file name w/o `.eml`> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " e load card with data from emulator memory " ) ;
PrintAndLogEx ( NORMAL , " j <filename> load card with data from json file " ) ;
PrintAndLogEx ( NORMAL , " b <filename> load card with data from binary file " ) ;
PrintAndLogEx ( NORMAL , " <filename> load card with data from eml file " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf cload mydump " ) ;
PrintAndLogEx ( NORMAL , " hf mf cload e " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_cgetblk ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Get block data from magic Chinese card. Only works with magic cards \n " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf cgetblk [h] <block number> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <block> block number " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf cgetblk 1 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_cgetsc ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Get sector data from magic Chinese card. Only works with magic cards \n " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf cgetsc [h] <sector number> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " <sector> sector number " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf cgetsc 0 " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_csave ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml` " ) ;
PrintAndLogEx ( NORMAL , " or into emulator memory " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf csave [h] [e] [u] [card memory] i <file name w/o `.eml`> " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " e save data to emulator memory " ) ;
PrintAndLogEx ( NORMAL , " u save data to file, use carduid as filename " ) ;
PrintAndLogEx ( NORMAL , " card memory 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K " ) ;
PrintAndLogEx ( NORMAL , " o <filename> save data to file " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf csave u 1 " ) ;
PrintAndLogEx ( NORMAL , " hf mf csave e 1 " ) ;
PrintAndLogEx ( NORMAL , " hf mf csave 4 o filename " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-10 19:06:05 +08:00
static int usage_hf14_nack ( void ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Test a mifare classic based card for the NACK bug. " ) ;
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf nack [h] [v] " ) ;
PrintAndLogEx ( NORMAL , " Options: " ) ;
PrintAndLogEx ( NORMAL , " h this help " ) ;
PrintAndLogEx ( NORMAL , " v verbose " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf nack " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
static int GetHFMF14AUID ( uint8_t * uid , int * uidlen ) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandMIX ( CMD_HF_ISO14443A_READER , ISO14A_CONNECT , 0 , 0 , NULL , 0 ) ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & resp , 2500 ) ) {
PrintAndLogEx ( WARNING , " iso14443a card select failed " ) ;
DropField ( ) ;
return 0 ;
}
iso14a_card_select_t card ;
2019-04-18 05:44:48 +08:00
memcpy ( & card , ( iso14a_card_select_t * ) resp . data . asBytes , sizeof ( iso14a_card_select_t ) ) ;
2019-03-10 06:35:06 +08:00
memcpy ( uid , card . uid , card . uidlen * sizeof ( uint8_t ) ) ;
* uidlen = card . uidlen ;
return 1 ;
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
static char * GenerateFilename ( const char * prefix , const char * suffix ) {
2019-03-10 07:00:59 +08:00
uint8_t uid [ 10 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
int uidlen = 0 ;
char * fptr = calloc ( sizeof ( char ) * ( strlen ( prefix ) + strlen ( suffix ) ) + sizeof ( uid ) * 2 + 1 , sizeof ( uint8_t ) ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
GetHFMF14AUID ( uid , & uidlen ) ;
if ( ! uidlen ) {
PrintAndLogEx ( WARNING , " No tag found. " ) ;
free ( fptr ) ;
return NULL ;
}
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
strcpy ( fptr , prefix ) ;
FillFileNameByUID ( fptr , uid , suffix , uidlen ) ;
return fptr ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfDarkside ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t blockno = 0 , key_type = MIFARE_AUTH_KEYA ;
uint64_t key = 0 ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( cmdp = = ' h ' ) return usage_hf14_mifare ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
blockno = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
cmdp = tolower ( param_getchar ( Cmd , 1 ) ) ;
if ( cmdp = = ' b ' )
key_type = MIFARE_AUTH_KEYB ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
int isOK = mfDarkside ( blockno , key_type , & key ) ;
PrintAndLogEx ( NORMAL , " " ) ;
switch ( isOK ) {
2019-03-10 07:00:59 +08:00
case - 1 :
PrintAndLogEx ( WARNING , " button pressed. Aborted. " ) ;
return 1 ;
case - 2 :
PrintAndLogEx ( FAILED , " card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). " ) ;
return 1 ;
case - 3 :
PrintAndLogEx ( FAILED , " card is not vulnerable to Darkside attack (its random number generator is not predictable). " ) ;
return 1 ;
case - 4 :
PrintAndLogEx ( FAILED , " card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown " ) ;
PrintAndLogEx ( FAILED , " generating polynomial with 16 effective bits only, but shows unexpected behaviour. " ) ;
return 1 ;
case - 5 :
PrintAndLogEx ( WARNING , " aborted via keyboard. " ) ;
return 1 ;
default :
PrintAndLogEx ( SUCCESS , " found valid key: %012 " PRIx64 " \n " , key ) ;
break ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " " ) ;
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfWrBl ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t blockNo = 0 ;
uint8_t keyType = 0 ;
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
uint8_t bldata [ 16 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
char cmdp = 0x00 ;
if ( strlen ( Cmd ) < 3 ) {
PrintAndLogEx ( NORMAL , " Usage: hf mf wrbl <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf wrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F " ) ;
return 0 ;
}
blockNo = param_get8 ( Cmd , 0 ) ;
cmdp = tolower ( param_getchar ( Cmd , 1 ) ) ;
if ( cmdp = = 0x00 ) {
PrintAndLogEx ( NORMAL , " Key type must be A or B " ) ;
return 1 ;
}
if ( cmdp ! = ' a ' )
keyType = 1 ;
if ( param_gethex ( Cmd , 2 , key , 12 ) ) {
PrintAndLogEx ( NORMAL , " Key must include 12 HEX symbols " ) ;
return 1 ;
}
if ( param_gethex ( Cmd , 3 , bldata , 32 ) ) {
PrintAndLogEx ( NORMAL , " Block data must include 32 HEX symbols " ) ;
return 1 ;
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " --block no:%d, key type:%c, key:%s " , blockNo , keyType ? ' B ' : ' A ' , sprint_hex ( key , 6 ) ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " --data: %s " , sprint_hex ( bldata , 16 ) ) ;
2019-04-19 23:03:39 +08:00
uint8_t data [ 26 ] ;
memcpy ( data , key , 6 ) ;
memcpy ( data + 10 , bldata , 16 ) ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandOLD ( CMD_HF_MIFARE_WRITEBL , blockNo , keyType , 0 , data , sizeof ( data ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
if ( WaitForResponseTimeout ( CMD_ACK , & resp , 1500 ) ) {
2019-04-18 05:44:48 +08:00
uint8_t isOK = resp . oldarg [ 0 ] & 0xff ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " isOk:%02x " , isOK ) ;
} else {
PrintAndLogEx ( NORMAL , " Command execute timeout " ) ;
}
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfRdBl ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t blockNo = 0 ;
uint8_t keyType = 0 ;
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
char cmdp = 0x00 ;
2019-03-10 07:00:59 +08:00
if ( strlen ( Cmd ) < 3 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Usage: hf mf rdbl <block number> <key A/B> <key (12 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf rdbl 0 A FFFFFFFFFFFF " ) ;
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
blockNo = param_get8 ( Cmd , 0 ) ;
cmdp = tolower ( param_getchar ( Cmd , 1 ) ) ;
if ( cmdp = = 0x00 ) {
PrintAndLogEx ( NORMAL , " Key type must be A or B " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( cmdp ! = ' a ' )
keyType = 1 ;
if ( param_gethex ( Cmd , 2 , key , 12 ) ) {
PrintAndLogEx ( NORMAL , " Key must include 12 HEX symbols " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " --block no:%d, key type:%c, key:%s " , blockNo , keyType ? ' B ' : ' A ' , sprint_hex ( key , 6 ) ) ;
2019-03-10 06:35:06 +08:00
2019-05-29 01:20:56 +08:00
mf_readblock_t payload ;
payload . blockno = blockNo ;
payload . keytype = keyType ;
memcpy ( payload . key , key , sizeof ( payload . key ) ) ;
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
if ( WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ) {
2019-04-18 05:44:48 +08:00
uint8_t * data = resp . data . asBytes ;
2019-03-10 06:35:06 +08:00
2019-05-29 01:20:56 +08:00
if ( resp . status = = PM3_SUCCESS ) {
PrintAndLogEx ( NORMAL , " data: %s " , sprint_hex ( data , 16 ) ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-05-29 01:20:56 +08:00
PrintAndLogEx ( FAILED , " failed reading block " ) ;
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( mfIsSectorTrailer ( blockNo ) & & ( data [ 6 ] | | data [ 7 ] | | data [ 8 ] ) ) {
PrintAndLogEx ( NORMAL , " Trailer decoded: " ) ;
int bln = mfFirstBlockOfSector ( mfSectorNum ( blockNo ) ) ;
int blinc = ( mfNumBlocksPerSector ( mfSectorNum ( blockNo ) ) > 4 ) ? 5 : 1 ;
for ( int i = 0 ; i < 4 ; i + + ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " Access block %d%s: %s " , bln , ( ( blinc > 1 ) & & ( i < 3 ) ? " + " : " " ) , mfGetAccessConditionsDesc ( i , & data [ 6 ] ) ) ;
2019-03-10 06:35:06 +08:00
bln + = blinc ;
}
PrintAndLogEx ( NORMAL , " UserData: %s " , sprint_hex_inrow ( & data [ 9 ] , 1 ) ) ;
}
} else {
PrintAndLogEx ( WARNING , " Command execute timeout " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ETIMEOUT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfRdSc ( const char * Cmd ) {
2019-06-08 00:41:39 +08:00
uint8_t sectorNo = 0 , keyType = 0 ;
2019-03-10 06:35:06 +08:00
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
char cmdp = 0x00 ;
if ( strlen ( Cmd ) < 3 ) {
PrintAndLogEx ( NORMAL , " Usage: hf mf rdsc <sector number> <key A/B> <key (12 hex symbols)> " ) ;
PrintAndLogEx ( NORMAL , " Examples: " ) ;
PrintAndLogEx ( NORMAL , " hf mf rdsc 0 A FFFFFFFFFFFF " ) ;
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
sectorNo = param_get8 ( Cmd , 0 ) ;
2019-03-10 07:00:59 +08:00
if ( sectorNo > MIFARE_4K_MAXSECTOR ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Sector number must be less than 40 " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
cmdp = tolower ( param_getchar ( Cmd , 1 ) ) ;
if ( cmdp ! = ' a ' & & cmdp ! = ' b ' ) {
PrintAndLogEx ( NORMAL , " Key type must be A or B " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( cmdp ! = ' a ' )
keyType = 1 ;
if ( param_gethex ( Cmd , 2 , key , 12 ) ) {
PrintAndLogEx ( NORMAL , " Key must include 12 HEX symbols " ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " --sector no:%d key type:%c key:%s " , sectorNo , keyType ? ' B ' : ' A ' , sprint_hex ( key , 6 ) ) ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandOLD ( CMD_HF_MIFARE_READSC , sectorNo , keyType , 0 , key , 6 ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
if ( WaitForResponseTimeout ( CMD_ACK , & resp , 1500 ) ) {
2019-06-08 00:41:39 +08:00
uint8_t isOK = resp . oldarg [ 0 ] & 0xff ;
uint8_t * data = resp . data . asBytes ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " isOk:%02x " , isOK ) ;
if ( isOK ) {
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < ( sectorNo < 32 ? 3 : 15 ) ; i + + ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " data : %s " , sprint_hex ( data + i * 16 , 16 ) ) ;
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " trailer: %s " , sprint_hex ( data + ( sectorNo < 32 ? 3 : 15 ) * 16 , 16 ) ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " Trailer decoded: " ) ;
2019-03-09 15:49:41 +08:00
int bln = mfFirstBlockOfSector ( sectorNo ) ;
2019-03-10 06:35:06 +08:00
int blinc = ( mfNumBlocksPerSector ( sectorNo ) > 4 ) ? 5 : 1 ;
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " Access block %d%s: %s " , bln , ( ( blinc > 1 ) & & ( i < 3 ) ? " + " : " " ) , mfGetAccessConditionsDesc ( i , & ( data + ( sectorNo < 32 ? 3 : 15 ) * 16 ) [ 6 ] ) ) ;
2019-03-09 15:49:41 +08:00
bln + = blinc ;
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " UserData: %s " , sprint_hex_inrow ( & ( data + ( sectorNo < 32 ? 3 : 15 ) * 16 ) [ 9 ] , 1 ) ) ;
2019-03-10 06:35:06 +08:00
}
} else {
PrintAndLogEx ( WARNING , " Command execute timeout " ) ;
}
2019-03-09 15:49:41 +08:00
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
static uint16_t NumOfBlocks ( char card ) {
2019-03-10 07:00:59 +08:00
switch ( card ) {
case ' 0 ' :
return MIFARE_MINI_MAXBLOCK ;
case ' 1 ' :
return MIFARE_1K_MAXBLOCK ;
case ' 2 ' :
return MIFARE_2K_MAXBLOCK ;
case ' 4 ' :
return MIFARE_4K_MAXBLOCK ;
default :
2019-04-29 03:34:05 +08:00
return 0 ;
2019-03-10 07:00:59 +08:00
}
}
2019-04-14 03:54:04 +08:00
static uint8_t NumOfSectors ( char card ) {
2019-03-10 07:00:59 +08:00
switch ( card ) {
case ' 0 ' :
return MIFARE_MINI_MAXSECTOR ;
case ' 1 ' :
return MIFARE_1K_MAXSECTOR ;
case ' 2 ' :
return MIFARE_2K_MAXSECTOR ;
case ' 4 ' :
return MIFARE_4K_MAXSECTOR ;
default :
2019-04-29 03:34:05 +08:00
return 0 ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
static uint8_t FirstBlockOfSector ( uint8_t sectorNo ) {
2019-03-10 06:35:06 +08:00
if ( sectorNo < 32 ) {
return sectorNo * 4 ;
} else {
return 32 * 4 + ( sectorNo - 32 ) * 16 ;
}
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
static uint8_t NumBlocksPerSector ( uint8_t sectorNo ) {
2019-03-10 06:35:06 +08:00
if ( sectorNo < 32 ) {
return 4 ;
} else {
return 16 ;
}
2019-03-09 15:49:41 +08:00
}
2019-08-29 03:21:27 +08:00
2019-08-27 17:08:03 +08:00
static uint8_t GetSectorFromBlockNo ( uint8_t blockNo ) {
2019-08-27 23:28:08 +08:00
if ( blockNo < 128 )
return blockNo / 4 ;
else
return 32 + ( ( 128 - blockNo ) / 16 ) ;
2019-08-27 17:08:03 +08:00
}
2019-08-29 03:21:27 +08:00
static char GetFormatFromSector ( uint8_t sectorNo ) {
switch ( sectorNo ) {
case MIFARE_MINI_MAXSECTOR :
return ' 0 ' ;
case MIFARE_1K_MAXSECTOR :
return ' 1 ' ;
case MIFARE_2K_MAXSECTOR :
return ' 2 ' ;
case MIFARE_4K_MAXSECTOR :
return ' 4 ' ;
default :
return ' ' ;
}
}
2019-08-30 16:45:52 +08:00
static int FastDumpWithEcFill ( uint8_t numsectors ) {
PacketResponseNG resp ;
mfc_eload_t payload ;
payload . sectorcnt = numsectors ;
payload . keytype = 0 ;
// ecfill key A
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_HF_MIFARE_EML_LOAD , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
int res = WaitForResponseTimeout ( CMD_HF_MIFARE_EML_LOAD , & resp , 2000 ) ;
if ( res ! = PM3_SUCCESS ) {
}
// ecfill key B
payload . keytype = 1 ;
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_HF_MIFARE_EML_LOAD , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
res = WaitForResponseTimeout ( CMD_HF_MIFARE_EML_LOAD , & resp , 2000 ) ;
if ( res ! = PM3_SUCCESS ) {
}
return PM3_SUCCESS ;
2019-08-29 03:21:27 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfDump ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-06-01 02:07:07 +08:00
uint64_t t1 = msclock ( ) ;
2019-03-10 06:35:06 +08:00
uint8_t sectorNo , blockNo ;
uint8_t keyA [ 40 ] [ 6 ] ;
uint8_t keyB [ 40 ] [ 6 ] ;
uint8_t rights [ 40 ] [ 4 ] ;
uint8_t carddata [ 256 ] [ 16 ] ;
uint8_t numSectors = 16 ;
uint8_t cmdp = 0 ;
char keyFilename [ FILE_PATH_SIZE ] = { 0 } ;
char dataFilename [ FILE_PATH_SIZE ] ;
2019-03-10 07:00:59 +08:00
char * fptr ;
2019-03-10 06:35:06 +08:00
memset ( keyFilename , 0 , sizeof ( keyFilename ) ) ;
memset ( dataFilename , 0 , sizeof ( dataFilename ) ) ;
FILE * f ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 ) {
2019-03-10 06:35:06 +08:00
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
2019-03-10 07:00:59 +08:00
case ' h ' :
2019-03-10 06:35:06 +08:00
return usage_hf14_dump ( ) ;
2019-03-10 07:00:59 +08:00
case ' k ' :
param_getstr ( Cmd , cmdp + 1 , keyFilename , FILE_PATH_SIZE ) ;
cmdp + = 2 ;
break ;
case ' f ' :
param_getstr ( Cmd , cmdp + 1 , dataFilename , FILE_PATH_SIZE ) ;
cmdp + = 2 ;
break ;
default :
if ( cmdp = = 0 ) {
numSectors = NumOfSectors ( param_getchar ( Cmd , cmdp ) ) ;
2019-04-29 03:34:05 +08:00
if ( numSectors = = 0 ) return usage_hf14_dump ( ) ;
2019-03-10 07:00:59 +08:00
cmdp + + ;
} else {
PrintAndLogEx ( WARNING , " Unknown parameter '%c' \n " , param_getchar ( Cmd , cmdp ) ) ;
return usage_hf14_dump ( ) ;
}
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:00:59 +08:00
if ( keyFilename [ 0 ] = = 0x00 ) {
2019-03-10 06:35:06 +08:00
fptr = GenerateFilename ( " hf-mf- " , " -key.bin " ) ;
if ( fptr = = NULL )
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
strcpy ( keyFilename , fptr ) ;
}
if ( ( f = fopen ( keyFilename , " rb " ) ) = = NULL ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( WARNING , " Could not find file " _YELLOW_ ( " %s " ) , keyFilename ) ;
2019-05-29 01:20:56 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
// Read keys A from file
size_t bytes_read ;
2019-03-10 07:00:59 +08:00
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
bytes_read = fread ( keyA [ sectorNo ] , 1 , 6 , f ) ;
if ( bytes_read ! = 6 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File reading error. " ) ;
2019-03-10 06:35:06 +08:00
fclose ( f ) ;
2019-05-29 01:20:56 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
}
// Read keys B from file
2019-03-10 07:00:59 +08:00
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
bytes_read = fread ( keyB [ sectorNo ] , 1 , 6 , f ) ;
if ( bytes_read ! = 6 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File reading error. " ) ;
2019-03-10 06:35:06 +08:00
fclose ( f ) ;
2019-05-29 01:20:56 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
}
fclose ( f ) ;
PrintAndLogEx ( INFO , " Reading sector access bits... " ) ;
2019-04-16 21:29:18 +08:00
uint8_t tries ;
2019-06-01 02:07:07 +08:00
mf_readblock_t payload ;
2019-03-10 06:35:06 +08:00
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
for ( tries = 0 ; tries < MIFARE_SECTOR_RETRY ; tries + + ) {
2019-06-08 03:40:33 +08:00
printf ( " . " ) ;
2019-05-29 01:20:56 +08:00
fflush ( NULL ) ;
2019-06-08 03:40:33 +08:00
2019-05-29 01:20:56 +08:00
payload . blockno = FirstBlockOfSector ( sectorNo ) + NumBlocksPerSector ( sectorNo ) - 1 ;
payload . keytype = 0 ;
memcpy ( payload . key , keyA [ sectorNo ] , sizeof ( payload . key ) ) ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
2019-05-29 01:20:56 +08:00
2019-08-04 01:17:00 +08:00
if ( WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ) {
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
uint8_t * data = resp . data . asBytes ;
2019-05-29 01:20:56 +08:00
if ( resp . status = = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
rights [ sectorNo ] [ 0 ] = ( ( data [ 7 ] & 0x10 ) > > 2 ) | ( ( data [ 8 ] & 0x1 ) < < 1 ) | ( ( data [ 8 ] & 0x10 ) > > 4 ) ; // C1C2C3 for data area 0
rights [ sectorNo ] [ 1 ] = ( ( data [ 7 ] & 0x20 ) > > 3 ) | ( ( data [ 8 ] & 0x2 ) < < 0 ) | ( ( data [ 8 ] & 0x20 ) > > 5 ) ; // C1C2C3 for data area 1
rights [ sectorNo ] [ 2 ] = ( ( data [ 7 ] & 0x40 ) > > 4 ) | ( ( data [ 8 ] & 0x4 ) > > 1 ) | ( ( data [ 8 ] & 0x40 ) > > 6 ) ; // C1C2C3 for data area 2
rights [ sectorNo ] [ 3 ] = ( ( data [ 7 ] & 0x80 ) > > 5 ) | ( ( data [ 8 ] & 0x8 ) > > 2 ) | ( ( data [ 8 ] & 0x80 ) > > 7 ) ; // C1C2C3 for sector trailer
break ;
} else if ( tries = = 2 ) { // on last try set defaults
PrintAndLogEx ( FAILED , " could not get access rights for sector %2d. Trying with defaults... " , sectorNo ) ;
rights [ sectorNo ] [ 0 ] = rights [ sectorNo ] [ 1 ] = rights [ sectorNo ] [ 2 ] = 0x00 ;
rights [ sectorNo ] [ 3 ] = 0x01 ;
}
} else {
PrintAndLogEx ( FAILED , " command execute timeout when trying to read access rights for sector %2d. Trying with defaults... " , sectorNo ) ;
rights [ sectorNo ] [ 0 ] = rights [ sectorNo ] [ 1 ] = rights [ sectorNo ] [ 2 ] = 0x00 ;
rights [ sectorNo ] [ 3 ] = 0x01 ;
}
}
}
2019-05-29 01:20:56 +08:00
printf ( " \n " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " Finished reading sector access bits " ) ;
PrintAndLogEx ( INFO , " Dumping all blocks from card... " ) ;
2019-05-29 01:20:56 +08:00
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
for ( blockNo = 0 ; blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
2019-03-10 06:35:06 +08:00
bool received = false ;
for ( tries = 0 ; tries < MIFARE_SECTOR_RETRY ; tries + + ) {
if ( blockNo = = NumBlocksPerSector ( sectorNo ) - 1 ) { // sector trailer. At least the Access Conditions can always be read with key A.
2019-06-08 03:40:33 +08:00
2019-05-29 01:20:56 +08:00
payload . blockno = FirstBlockOfSector ( sectorNo ) + blockNo ;
payload . keytype = 0 ;
memcpy ( payload . key , keyA [ sectorNo ] , sizeof ( payload . key ) ) ;
2019-06-08 03:40:33 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
received = WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ;
2019-03-10 06:35:06 +08:00
} else { // data block. Check if it can be read with key A or key B
2019-03-10 07:00:59 +08:00
uint8_t data_area = ( sectorNo < 32 ) ? blockNo : blockNo / 5 ;
2019-03-10 06:35:06 +08:00
if ( ( rights [ sectorNo ] [ data_area ] = = 0x03 ) | | ( rights [ sectorNo ] [ data_area ] = = 0x05 ) ) { // only key B would work
2019-05-29 01:20:56 +08:00
payload . blockno = FirstBlockOfSector ( sectorNo ) + blockNo ;
payload . keytype = 1 ;
memcpy ( payload . key , keyB [ sectorNo ] , sizeof ( payload . key ) ) ;
2019-06-08 03:40:33 +08:00
2019-05-29 01:20:56 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
received = WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ;
2019-03-10 06:35:06 +08:00
} else if ( rights [ sectorNo ] [ data_area ] = = 0x07 ) { // no key would work
PrintAndLogEx ( WARNING , " access rights do not allow reading of sector %2d block %3d " , sectorNo , blockNo ) ;
2019-05-29 01:20:56 +08:00
// where do you want to go?? Next sector or block?
break ;
2019-03-10 06:35:06 +08:00
} else { // key A would work
2019-05-29 01:20:56 +08:00
payload . blockno = FirstBlockOfSector ( sectorNo ) + blockNo ;
payload . keytype = 0 ;
memcpy ( payload . key , keyA [ sectorNo ] , sizeof ( payload . key ) ) ;
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
received = WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ;
2019-03-10 06:35:06 +08:00
}
}
if ( received ) {
2019-05-29 01:20:56 +08:00
if ( resp . status = = PM3_SUCCESS ) {
// break the re-try loop
break ;
}
2019-03-10 06:35:06 +08:00
}
}
if ( received ) {
2019-04-18 05:44:48 +08:00
uint8_t * data = resp . data . asBytes ;
2019-03-10 06:35:06 +08:00
if ( blockNo = = NumBlocksPerSector ( sectorNo ) - 1 ) { // sector trailer. Fill in the keys.
data [ 0 ] = ( keyA [ sectorNo ] [ 0 ] ) ;
data [ 1 ] = ( keyA [ sectorNo ] [ 1 ] ) ;
data [ 2 ] = ( keyA [ sectorNo ] [ 2 ] ) ;
data [ 3 ] = ( keyA [ sectorNo ] [ 3 ] ) ;
data [ 4 ] = ( keyA [ sectorNo ] [ 4 ] ) ;
data [ 5 ] = ( keyA [ sectorNo ] [ 5 ] ) ;
data [ 10 ] = ( keyB [ sectorNo ] [ 0 ] ) ;
data [ 11 ] = ( keyB [ sectorNo ] [ 1 ] ) ;
data [ 12 ] = ( keyB [ sectorNo ] [ 2 ] ) ;
data [ 13 ] = ( keyB [ sectorNo ] [ 3 ] ) ;
data [ 14 ] = ( keyB [ sectorNo ] [ 4 ] ) ;
data [ 15 ] = ( keyB [ sectorNo ] [ 5 ] ) ;
}
2019-05-29 01:20:56 +08:00
if ( resp . status = = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
memcpy ( carddata [ FirstBlockOfSector ( sectorNo ) + blockNo ] , data , 16 ) ;
2019-03-09 15:49:41 +08:00
PrintAndLogEx ( SUCCESS , " successfully read block %2d of sector %2d. " , blockNo , sectorNo ) ;
2019-03-10 06:35:06 +08:00
} else {
PrintAndLogEx ( FAILED , " could not read block %2d of sector %2d " , blockNo , sectorNo ) ;
break ;
}
2019-03-10 07:00:59 +08:00
} else {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " command execute timeout when trying to read block %2d of sector %2d. " , blockNo , sectorNo ) ;
break ;
}
}
}
2019-06-08 03:40:33 +08:00
2019-06-01 02:07:07 +08:00
PrintAndLogEx ( SUCCESS , " time: % " PRIu64 " seconds \n " , ( msclock ( ) - t1 ) / 1000 ) ;
2019-06-08 03:40:33 +08:00
2019-09-14 23:44:58 +08:00
PrintAndLogEx ( SUCCESS , " \n Succeeded in dumping all blocks " ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( strlen ( dataFilename ) < 1 ) {
2019-08-27 23:28:08 +08:00
fptr = GenerateFilename ( " hf-mf- " , " -data " ) ;
if ( fptr = = NULL )
return PM3_ESOFT ;
2019-08-27 23:15:42 +08:00
2019-08-27 23:28:08 +08:00
strcpy ( dataFilename , fptr ) ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
uint16_t bytes = 16 * ( FirstBlockOfSector ( numSectors - 1 ) + NumBlocksPerSector ( numSectors - 1 ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-29 02:42:57 +08:00
saveFile ( dataFilename , " .bin " , ( uint8_t * ) carddata , bytes ) ;
saveFileEML ( dataFilename , ( uint8_t * ) carddata , bytes , MFBLOCK_SIZE ) ;
saveFileJSON ( dataFilename , jsfCardMemory , ( uint8_t * ) carddata , bytes ) ;
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfRestore ( const char * Cmd ) {
2019-03-10 07:00:59 +08:00
uint8_t sectorNo , blockNo ;
2019-03-10 06:35:06 +08:00
uint8_t keyType = 0 ;
2019-03-10 07:00:59 +08:00
uint8_t key [ 6 ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
2019-03-10 06:35:06 +08:00
uint8_t bldata [ 16 ] = { 0x00 } ;
uint8_t keyA [ 40 ] [ 6 ] ;
uint8_t keyB [ 40 ] [ 6 ] ;
uint8_t numSectors = 16 ;
uint8_t cmdp = 0 ;
char keyFilename [ FILE_PATH_SIZE ] = " " ;
char dataFilename [ FILE_PATH_SIZE ] = " " ;
2019-03-10 07:00:59 +08:00
char szTemp [ FILE_PATH_SIZE - 20 ] = " " ;
2019-03-10 06:35:06 +08:00
char * fptr ;
FILE * fdump , * fkeys ;
2019-03-10 07:00:59 +08:00
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 ) {
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' h ' :
2019-03-10 06:35:06 +08:00
return usage_hf14_restore ( ) ;
2019-03-10 07:00:59 +08:00
case ' u ' :
param_getstr ( Cmd , cmdp + 1 , szTemp , FILE_PATH_SIZE - 20 ) ;
if ( keyFilename [ 0 ] = = 0x00 )
snprintf ( keyFilename , FILE_PATH_SIZE , " hf-mf-%s-key.bin " , szTemp ) ;
if ( dataFilename [ 0 ] = = 0x00 )
snprintf ( dataFilename , FILE_PATH_SIZE , " hf-mf-%s-data.bin " , szTemp ) ;
cmdp + = 2 ;
break ;
case ' k ' :
param_getstr ( Cmd , cmdp + 1 , keyFilename , FILE_PATH_SIZE ) ;
cmdp + = 2 ;
break ;
case ' f ' :
param_getstr ( Cmd , cmdp + 1 , dataFilename , FILE_PATH_SIZE ) ;
cmdp + = 2 ;
break ;
default :
if ( cmdp = = 0 ) {
numSectors = NumOfSectors ( param_getchar ( Cmd , cmdp ) ) ;
2019-04-29 03:34:05 +08:00
if ( numSectors = = 0 ) return usage_hf14_restore ( ) ;
2019-03-10 07:00:59 +08:00
cmdp + + ;
} else {
PrintAndLogEx ( WARNING , " Unknown parameter '%c' \n " , param_getchar ( Cmd , cmdp ) ) ;
return usage_hf14_restore ( ) ;
}
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:00:59 +08:00
if ( keyFilename [ 0 ] = = 0x00 ) {
2019-03-10 06:35:06 +08:00
fptr = GenerateFilename ( " hf-mf- " , " -key.bin " ) ;
if ( fptr = = NULL )
return 1 ;
strcpy ( keyFilename , fptr ) ;
}
if ( ( fkeys = fopen ( keyFilename , " rb " ) ) = = NULL ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( WARNING , " Could not find file " _YELLOW_ ( " %s " ) , keyFilename ) ;
2019-03-10 06:35:06 +08:00
return 1 ;
}
size_t bytes_read ;
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
2019-03-10 07:00:59 +08:00
bytes_read = fread ( keyA [ sectorNo ] , 1 , 6 , fkeys ) ;
if ( bytes_read ! = 6 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File reading error " _YELLOW_ ( " %s " ) , keyFilename ) ;
2019-03-10 06:35:06 +08:00
fclose ( fkeys ) ;
return 2 ;
}
}
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
2019-03-10 07:00:59 +08:00
bytes_read = fread ( keyB [ sectorNo ] , 1 , 6 , fkeys ) ;
if ( bytes_read ! = 6 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File reading error " _YELLOW_ ( " %s " ) , keyFilename ) ;
2019-03-10 06:35:06 +08:00
fclose ( fkeys ) ;
return 2 ;
}
}
fclose ( fkeys ) ;
2019-03-10 07:00:59 +08:00
if ( dataFilename [ 0 ] = = 0x00 ) {
2019-03-10 06:35:06 +08:00
fptr = GenerateFilename ( " hf-mf- " , " -data.bin " ) ;
if ( fptr = = NULL )
return 1 ;
2019-03-10 07:00:59 +08:00
strcpy ( dataFilename , fptr ) ;
2019-03-10 06:35:06 +08:00
}
if ( ( fdump = fopen ( dataFilename , " rb " ) ) = = NULL ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( WARNING , " Could not find file " _YELLOW_ ( " %s " ) , dataFilename ) ;
2019-03-10 06:35:06 +08:00
return 1 ;
}
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( INFO , " Restoring " _YELLOW_ ( " %s " ) " to card " , dataFilename ) ;
2019-03-10 06:35:06 +08:00
for ( sectorNo = 0 ; sectorNo < numSectors ; sectorNo + + ) {
for ( blockNo = 0 ; blockNo < NumBlocksPerSector ( sectorNo ) ; blockNo + + ) {
2019-04-19 23:03:39 +08:00
uint8_t data [ 26 ] ;
memcpy ( data , key , 6 ) ;
2019-03-10 06:35:06 +08:00
bytes_read = fread ( bldata , 1 , 16 , fdump ) ;
2019-03-10 07:00:59 +08:00
if ( bytes_read ! = 16 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File reading error " _YELLOW_ ( " %s " ) , dataFilename ) ;
2019-03-10 06:35:06 +08:00
fclose ( fdump ) ;
fdump = NULL ;
return 2 ;
}
if ( blockNo = = NumBlocksPerSector ( sectorNo ) - 1 ) { // sector trailer
bldata [ 0 ] = ( keyA [ sectorNo ] [ 0 ] ) ;
bldata [ 1 ] = ( keyA [ sectorNo ] [ 1 ] ) ;
bldata [ 2 ] = ( keyA [ sectorNo ] [ 2 ] ) ;
bldata [ 3 ] = ( keyA [ sectorNo ] [ 3 ] ) ;
bldata [ 4 ] = ( keyA [ sectorNo ] [ 4 ] ) ;
bldata [ 5 ] = ( keyA [ sectorNo ] [ 5 ] ) ;
bldata [ 10 ] = ( keyB [ sectorNo ] [ 0 ] ) ;
bldata [ 11 ] = ( keyB [ sectorNo ] [ 1 ] ) ;
bldata [ 12 ] = ( keyB [ sectorNo ] [ 2 ] ) ;
bldata [ 13 ] = ( keyB [ sectorNo ] [ 3 ] ) ;
bldata [ 14 ] = ( keyB [ sectorNo ] [ 4 ] ) ;
bldata [ 15 ] = ( keyB [ sectorNo ] [ 5 ] ) ;
}
PrintAndLogEx ( NORMAL , " Writing to block %3d: %s " , FirstBlockOfSector ( sectorNo ) + blockNo , sprint_hex ( bldata , 16 ) ) ;
2019-04-19 23:03:39 +08:00
memcpy ( data + 10 , bldata , 16 ) ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandOLD ( CMD_HF_MIFARE_WRITEBL , FirstBlockOfSector ( sectorNo ) + blockNo , keyType , 0 , data , sizeof ( data ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 07:00:59 +08:00
if ( WaitForResponseTimeout ( CMD_ACK , & resp , 1500 ) ) {
2019-04-18 05:44:48 +08:00
uint8_t isOK = resp . oldarg [ 0 ] & 0xff ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " isOk:%02x " , isOK ) ;
} else {
PrintAndLogEx ( WARNING , " Command execute timeout " ) ;
}
}
}
fclose ( fdump ) ;
2019-04-07 01:09:01 +08:00
PrintAndLogEx ( INFO , " Finish restore " ) ;
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfNested ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
sector_t * e_sector = NULL ;
uint8_t keyType = 0 ;
uint8_t trgBlockNo = 0 ;
uint8_t trgKeyType = 0 ;
uint8_t SectorsCnt = 0 ;
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
2019-08-01 05:44:53 +08:00
uint8_t keyBlock [ ( ARRAYLEN ( g_mifare_default_keys ) + 1 ) * 6 ] ;
2019-03-10 06:35:06 +08:00
uint64_t key64 = 0 ;
bool transferToEml = false ;
bool createDumpFile = false ;
if ( strlen ( Cmd ) < 3 ) return usage_hf14_nested ( ) ;
char cmdp , ctmp ;
cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-06-08 00:41:39 +08:00
uint8_t blockNo = param_get8 ( Cmd , 1 ) ;
2019-03-10 06:35:06 +08:00
ctmp = tolower ( param_getchar ( Cmd , 2 ) ) ;
if ( ctmp ! = ' a ' & & ctmp ! = ' b ' ) {
PrintAndLogEx ( WARNING , " key type must be A or B " ) ;
2019-05-29 01:20:56 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
if ( ctmp ! = ' a ' )
keyType = 1 ;
if ( param_gethex ( Cmd , 3 , key , 12 ) ) {
PrintAndLogEx ( WARNING , " key must include 12 HEX symbols " ) ;
2019-05-29 01:20:56 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
if ( cmdp = = ' o ' ) {
trgBlockNo = param_get8 ( Cmd , 4 ) ;
ctmp = tolower ( param_getchar ( Cmd , 5 ) ) ;
if ( ctmp ! = ' a ' & & ctmp ! = ' b ' ) {
PrintAndLogEx ( WARNING , " target key type must be A or B " ) ;
2019-05-29 01:20:56 +08:00
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
if ( ctmp ! = ' a ' ) {
trgKeyType = 1 ;
}
} else {
SectorsCnt = NumOfSectors ( cmdp ) ;
2019-04-29 03:34:05 +08:00
if ( SectorsCnt = = 0 ) return usage_hf14_nested ( ) ;
2019-03-10 06:35:06 +08:00
}
uint8_t j = 4 ;
2019-03-10 07:00:59 +08:00
while ( ctmp ! = 0x00 ) {
2019-03-10 06:35:06 +08:00
ctmp = tolower ( param_getchar ( Cmd , j ) ) ;
transferToEml | = ( ctmp = = ' t ' ) ;
createDumpFile | = ( ctmp = = ' d ' ) ;
j + + ;
}
// check if we can authenticate to sector
2019-05-01 18:19:51 +08:00
if ( mfCheckKeys ( blockNo , keyType , true , 1 , key , & key64 ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Wrong key. Can't authenticate to block:%3d key type:%c " , blockNo , keyType ? ' B ' : ' A ' ) ;
return 3 ;
}
if ( cmdp = = ' o ' ) {
int16_t isOK = mfnested ( blockNo , keyType , key , trgBlockNo , trgKeyType , keyBlock , true ) ;
switch ( isOK ) {
2019-03-10 07:00:59 +08:00
case - 1 :
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Error: No response from Proxmark3. \n " ) ;
2019-03-10 07:00:59 +08:00
break ;
case - 2 :
PrintAndLogEx ( WARNING , " Button pressed. Aborted. \n " ) ;
break ;
case - 3 :
PrintAndLogEx ( FAILED , " Tag isn't vulnerable to Nested Attack (PRNG is not predictable). \n " ) ;
break ;
case - 4 :
PrintAndLogEx ( FAILED , " No valid key found " ) ;
break ;
2019-03-10 06:35:06 +08:00
case - 5 :
key64 = bytes_to_num ( keyBlock , 6 ) ;
// transfer key to the emulator
if ( transferToEml ) {
uint8_t sectortrailer ;
2019-03-10 07:00:59 +08:00
if ( trgBlockNo < 32 * 4 ) { // 4 block sector
sectortrailer = trgBlockNo | 0x03 ;
2019-03-10 06:35:06 +08:00
} else { // 16 block sector
2019-03-10 07:00:59 +08:00
sectortrailer = trgBlockNo | 0x0f ;
2019-03-10 06:35:06 +08:00
}
mfEmlGetMem ( keyBlock , sectortrailer , 1 ) ;
if ( ! trgKeyType )
num_to_bytes ( key64 , 6 , keyBlock ) ;
else
num_to_bytes ( key64 , 6 , & keyBlock [ 10 ] ) ;
mfEmlSetMem ( keyBlock , sectortrailer , 1 ) ;
PrintAndLogEx ( SUCCESS , " Key transferred to emulator memory. " ) ;
}
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-10 07:00:59 +08:00
default :
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Unknown Error. \n " ) ;
2019-03-10 06:35:06 +08:00
}
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-10 07:00:59 +08:00
} else { // ------------------------------------ multiple sectors working
2019-03-10 06:35:06 +08:00
uint64_t t1 = msclock ( ) ;
e_sector = calloc ( SectorsCnt , sizeof ( sector_t ) ) ;
2019-05-29 01:20:56 +08:00
if ( e_sector = = NULL ) return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
2019-08-27 23:28:08 +08:00
// add our known key
e_sector [ GetSectorFromBlockNo ( blockNo ) ] . foundKey [ keyType ] = 1 ;
e_sector [ GetSectorFromBlockNo ( blockNo ) ] . Key [ keyType ] = key64 ;
2019-08-27 17:08:03 +08:00
2019-03-10 06:35:06 +08:00
//test current key and additional standard keys first
// add parameter key
2019-08-01 05:44:53 +08:00
memcpy ( keyBlock + ( ARRAYLEN ( g_mifare_default_keys ) * 6 ) , key , 6 ) ;
2019-03-10 06:35:06 +08:00
2019-08-01 05:44:53 +08:00
for ( int cnt = 0 ; cnt < ARRAYLEN ( g_mifare_default_keys ) ; cnt + + ) {
2019-03-10 07:00:59 +08:00
num_to_bytes ( g_mifare_default_keys [ cnt ] , 6 , ( uint8_t * ) ( keyBlock + cnt * 6 ) ) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " Testing known keys. Sector count=%d " , SectorsCnt ) ;
2019-08-29 03:21:27 +08:00
int res = mfCheckKeys_fast ( SectorsCnt , true , true , 1 , ARRAYLEN ( g_mifare_default_keys ) + 1 , keyBlock , e_sector , false ) ;
2019-08-30 16:45:52 +08:00
if ( res = = PM3_SUCCESS ) {
// all keys found
PrintAndLogEx ( SUCCESS , " Fast check found all keys " ) ;
goto jumptoend ;
}
2019-03-10 06:35:06 +08:00
uint64_t t2 = msclock ( ) - t1 ;
2019-10-06 05:56:19 +08:00
PrintAndLogEx ( SUCCESS , " Time to check %zu known keys: %.0f seconds \n " , ARRAYLEN ( g_mifare_default_keys ) , ( float ) t2 / 1000.0 ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " enter nested attack " ) ;
// nested sectors
2019-06-08 00:41:39 +08:00
// int iterations = 0;
2019-03-10 06:35:06 +08:00
bool calibrate = true ;
2019-08-27 02:37:33 +08:00
for ( trgKeyType = 0 ; trgKeyType < 2 ; + + trgKeyType ) {
2019-03-10 06:35:06 +08:00
for ( uint8_t sectorNo = 0 ; sectorNo < SectorsCnt ; + + sectorNo ) {
2019-08-27 02:37:33 +08:00
for ( int i = 0 ; i < MIFARE_SECTOR_RETRY ; i + + ) {
2019-03-10 06:35:06 +08:00
if ( e_sector [ sectorNo ] . foundKey [ trgKeyType ] ) continue ;
int16_t isOK = mfnested ( blockNo , keyType , key , FirstBlockOfSector ( sectorNo ) , trgKeyType , keyBlock , calibrate ) ;
switch ( isOK ) {
2019-03-10 07:00:59 +08:00
case - 1 :
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " error: No response from Proxmark3. \n " ) ;
2019-03-10 07:00:59 +08:00
break ;
case - 2 :
PrintAndLogEx ( WARNING , " button pressed. Aborted. \n " ) ;
break ;
case - 3 :
PrintAndLogEx ( FAILED , " Tag isn't vulnerable to Nested Attack (PRNG is not predictable). \n " ) ;
break ;
2019-03-10 06:35:06 +08:00
case - 4 : //key not found
calibrate = false ;
2019-06-08 00:41:39 +08:00
// iterations++;
2019-03-10 06:35:06 +08:00
continue ;
case - 5 :
calibrate = false ;
2019-06-08 00:41:39 +08:00
// iterations++;
2019-03-10 06:35:06 +08:00
e_sector [ sectorNo ] . foundKey [ trgKeyType ] = 1 ;
e_sector [ sectorNo ] . Key [ trgKeyType ] = bytes_to_num ( keyBlock , 6 ) ;
2019-05-09 04:02:14 +08:00
mfCheckKeys_fast ( SectorsCnt , true , true , 2 , 1 , keyBlock , e_sector , false ) ;
2019-03-10 06:35:06 +08:00
continue ;
2019-03-10 07:00:59 +08:00
default :
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " unknown Error. \n " ) ;
2019-03-10 06:35:06 +08:00
}
free ( e_sector ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
}
}
t1 = msclock ( ) - t1 ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " time in nested: %.0f seconds \n " , ( float ) t1 / 1000.0 ) ;
2019-03-10 06:35:06 +08:00
// 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
PrintAndLogEx ( INFO , " trying to read key B... " ) ;
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < SectorsCnt ; i + + ) {
2019-03-10 06:35:06 +08:00
// KEY A but not KEY B
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] & & ! e_sector [ i ] . foundKey [ 1 ] ) {
2019-03-10 06:35:06 +08:00
uint8_t sectrail = ( FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 ) ;
PrintAndLogEx ( SUCCESS , " reading block %d " , sectrail ) ;
2019-05-29 01:20:56 +08:00
mf_readblock_t payload ;
payload . blockno = sectrail ;
payload . keytype = 0 ;
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , payload . key ) ; // KEY A
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ) continue ;
2019-03-10 06:35:06 +08:00
2019-05-29 01:20:56 +08:00
if ( resp . status ! = PM3_SUCCESS ) continue ;
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
uint8_t * data = resp . data . asBytes ;
2019-03-10 07:00:59 +08:00
key64 = bytes_to_num ( data + 10 , 6 ) ;
2019-03-10 06:35:06 +08:00
if ( key64 ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " data: %s " , sprint_hex ( data + 10 , 6 ) ) ;
2019-03-10 06:35:06 +08:00
e_sector [ i ] . foundKey [ 1 ] = true ;
e_sector [ i ] . Key [ 1 ] = key64 ;
}
}
}
2019-08-29 03:21:27 +08:00
jumptoend :
2019-03-10 06:35:06 +08:00
//print them
2019-03-10 07:00:59 +08:00
printKeyTable ( SectorsCnt , e_sector ) ;
2019-03-10 06:35:06 +08:00
// transfer them to the emulator
if ( transferToEml ) {
2019-05-09 03:54:15 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < SectorsCnt ; i + + ) {
2019-03-10 06:35:06 +08:00
mfEmlGetMem ( keyBlock , FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 , 1 ) ;
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] )
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , keyBlock ) ;
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
if ( e_sector [ i ] . foundKey [ 1 ] )
num_to_bytes ( e_sector [ i ] . Key [ 1 ] , 6 , & keyBlock [ 10 ] ) ;
2019-06-08 03:40:33 +08:00
2019-05-09 03:54:15 +08:00
if ( i = = SectorsCnt - 1 ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
2019-03-10 06:35:06 +08:00
mfEmlSetMem ( keyBlock , FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 , 1 ) ;
}
PrintAndLogEx ( SUCCESS , " keys transferred to emulator memory. " ) ;
}
// Create dump file
if ( createDumpFile ) {
2019-06-08 00:41:39 +08:00
char * fptr = GenerateFilename ( " hf-mf- " , " -key.bin " ) ;
2019-03-10 06:35:06 +08:00
if ( fptr = = NULL ) {
free ( e_sector ) ;
2019-05-29 01:20:56 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-06-08 00:41:39 +08:00
FILE * fkeys ;
2019-03-10 06:35:06 +08:00
if ( ( fkeys = fopen ( fptr , " wb " ) ) = = NULL ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( WARNING , " could not create file " _YELLOW_ ( " %s " ) , fptr ) ;
2019-03-10 06:35:06 +08:00
free ( e_sector ) ;
2019-05-29 01:20:56 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( SUCCESS , " saving keys to binary file " _YELLOW_ ( " %s " ) , fptr ) ;
2019-09-14 23:44:58 +08:00
uint8_t standard [ 6 ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
2019-06-08 00:41:39 +08:00
uint8_t tempkey [ 6 ] = { 0xFF , 0xFF , 0xFF , 0xFF , 0xFF , 0xFF } ;
for ( int i = 0 ; i < SectorsCnt ; i + + ) {
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] ) {
2019-03-10 06:35:06 +08:00
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , tempkey ) ;
2019-03-10 07:00:59 +08:00
fwrite ( tempkey , 1 , 6 , fkeys ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-09-14 23:44:58 +08:00
fwrite ( & standard , 1 , 6 , fkeys ) ;
2019-03-10 06:35:06 +08:00
}
}
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < SectorsCnt ; i + + ) {
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 1 ] ) {
2019-03-10 06:35:06 +08:00
num_to_bytes ( e_sector [ i ] . Key [ 1 ] , 6 , tempkey ) ;
2019-03-10 07:00:59 +08:00
fwrite ( tempkey , 1 , 6 , fkeys ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-09-14 23:44:58 +08:00
fwrite ( & standard , 1 , 6 , fkeys ) ;
2019-03-10 06:35:06 +08:00
}
}
fflush ( fkeys ) ;
fclose ( fkeys ) ;
}
free ( e_sector ) ;
}
2019-05-29 01:20:56 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfNestedHard ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t blockNo = 0 ;
uint8_t keyType = 0 ;
uint8_t trgBlockNo = 0 ;
uint8_t trgKeyType = 0 ;
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
uint8_t trgkey [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
2019-03-10 07:00:59 +08:00
uint8_t cmdp = 0 ;
2019-04-10 02:15:08 +08:00
char filename [ FILE_PATH_SIZE ] = { 0 } , * fptr ;
2019-03-10 07:00:59 +08:00
char szTemp [ FILE_PATH_SIZE - 20 ] ;
2019-03-10 06:35:06 +08:00
char ctmp ;
bool know_target_key = false ;
bool nonce_file_read = false ;
bool nonce_file_write = false ;
bool slow = false ;
int tests = 0 ;
2019-03-10 07:00:59 +08:00
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' h ' :
return usage_hf14_hardnested ( ) ;
2019-03-10 06:35:06 +08:00
case ' r ' :
2019-03-10 07:00:59 +08:00
fptr = GenerateFilename ( " hf-mf- " , " -nonces.bin " ) ;
2019-03-10 06:35:06 +08:00
if ( fptr = = NULL )
2019-03-19 06:59:35 +08:00
strncpy ( filename , " nonces.bin " , FILE_PATH_SIZE - 1 ) ;
2019-03-10 06:35:06 +08:00
else
2019-03-10 07:00:59 +08:00
strncpy ( filename , fptr , FILE_PATH_SIZE - 1 ) ;
2019-03-10 06:35:06 +08:00
nonce_file_read = true ;
2019-03-10 07:00:59 +08:00
if ( ! param_gethex ( Cmd , cmdp + 1 , trgkey , 12 ) ) {
2019-03-10 06:35:06 +08:00
know_target_key = true ;
}
cmdp + + ;
break ;
case ' t ' :
2019-03-10 07:00:59 +08:00
tests = param_get32ex ( Cmd , cmdp + 1 , 100 , 10 ) ;
if ( ! param_gethex ( Cmd , cmdp + 2 , trgkey , 12 ) ) {
2019-03-10 06:35:06 +08:00
know_target_key = true ;
}
cmdp + = 2 ;
break ;
default :
2019-03-10 07:00:59 +08:00
if ( param_getchar ( Cmd , cmdp ) = = 0x00 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Block number is missing " ) ;
return 1 ;
}
blockNo = param_get8 ( Cmd , cmdp ) ;
2019-03-10 07:00:59 +08:00
ctmp = tolower ( param_getchar ( Cmd , cmdp + 1 ) ) ;
2019-03-10 06:35:06 +08:00
if ( ctmp ! = ' a ' & & ctmp ! = ' b ' ) {
PrintAndLogEx ( WARNING , " Key type must be A or B " ) ;
return 1 ;
}
if ( ctmp ! = ' a ' ) {
keyType = 1 ;
}
2019-03-10 07:00:59 +08:00
if ( param_gethex ( Cmd , cmdp + 2 , key , 12 ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Key must include 12 HEX symbols " ) ;
return 1 ;
}
2019-03-10 07:00:59 +08:00
if ( param_getchar ( Cmd , cmdp + 3 ) = = 0x00 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Target block number is missing " ) ;
return 1 ;
}
2019-03-10 07:00:59 +08:00
trgBlockNo = param_get8 ( Cmd , cmdp + 3 ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
ctmp = tolower ( param_getchar ( Cmd , cmdp + 4 ) ) ;
2019-03-10 06:35:06 +08:00
if ( ctmp ! = ' a ' & & ctmp ! = ' b ' ) {
PrintAndLogEx ( WARNING , " Target key type must be A or B " ) ;
return 1 ;
}
if ( ctmp ! = ' a ' ) {
trgKeyType = 1 ;
}
cmdp + = 5 ;
}
if ( ! param_gethex ( Cmd , cmdp , trgkey , 12 ) ) {
know_target_key = true ;
cmdp + + ;
}
while ( ( ctmp = param_getchar ( Cmd , cmdp ) ) ) {
2019-03-10 07:00:59 +08:00
switch ( tolower ( ctmp ) ) {
case ' s ' :
slow = true ;
break ;
case ' w ' :
nonce_file_write = true ;
fptr = GenerateFilename ( " hf-mf- " , " -nonces.bin " ) ;
if ( fptr = = NULL )
2019-03-10 06:35:06 +08:00
return 1 ;
2019-03-10 07:00:59 +08:00
strncpy ( filename , fptr , FILE_PATH_SIZE - 1 ) ;
break ;
case ' u ' :
param_getstr ( Cmd , cmdp + 1 , szTemp , FILE_PATH_SIZE - 20 ) ;
snprintf ( filename , FILE_PATH_SIZE , " hf-mf-%s-nonces.bin " , szTemp ) ;
cmdp + + ;
break ;
case ' f ' :
param_getstr ( Cmd , cmdp + 1 , szTemp , FILE_PATH_SIZE - 20 ) ;
strncpy ( filename , szTemp , FILE_PATH_SIZE - 20 ) ;
cmdp + + ;
break ;
case ' i ' :
SetSIMDInstr ( SIMD_AUTO ) ;
ctmp = tolower ( param_getchar ( Cmd , cmdp + 1 ) ) ;
switch ( ctmp ) {
case ' 5 ' :
SetSIMDInstr ( SIMD_AVX512 ) ;
break ;
case ' 2 ' :
SetSIMDInstr ( SIMD_AVX2 ) ;
break ;
case ' a ' :
SetSIMDInstr ( SIMD_AVX ) ;
break ;
case ' s ' :
SetSIMDInstr ( SIMD_SSE2 ) ;
break ;
case ' m ' :
SetSIMDInstr ( SIMD_MMX ) ;
break ;
case ' n ' :
SetSIMDInstr ( SIMD_NONE ) ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown SIMD type. %c " , ctmp ) ;
return 1 ;
}
cmdp + = 2 ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' \n " , ctmp ) ;
usage_hf14_hardnested ( ) ;
return 1 ;
2019-03-10 06:35:06 +08:00
}
cmdp + + ;
}
2019-04-09 23:14:47 +08:00
if ( ! know_target_key & & nonce_file_read = = false ) {
2019-03-10 06:35:06 +08:00
uint64_t key64 = 0 ;
// check if we can authenticate to sector
2019-05-01 18:19:51 +08:00
if ( mfCheckKeys ( blockNo , keyType , true , 1 , key , & key64 ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Key is wrong. Can't authenticate to block:%3d key type:%c " , blockNo , keyType ? ' B ' : ' A ' ) ;
return 3 ;
}
}
PrintAndLogEx ( NORMAL , " --target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d " ,
2019-03-10 07:00:59 +08:00
trgBlockNo ,
trgKeyType ? ' B ' : ' A ' ,
trgkey [ 0 ] , trgkey [ 1 ] , trgkey [ 2 ] , trgkey [ 3 ] , trgkey [ 4 ] , trgkey [ 5 ] ,
know_target_key ? " " : " (not set) " ,
nonce_file_write ? " write " : nonce_file_read ? " read " : " none " ,
slow ? " Yes " : " No " ,
tests ) ;
2019-03-10 06:35:06 +08:00
uint64_t foundkey = 0 ;
int16_t isOK = mfnestedhard ( blockNo , keyType , key , trgBlockNo , trgKeyType , know_target_key ? trgkey : NULL , nonce_file_read , nonce_file_write , slow , tests , & foundkey , filename ) ;
DropField ( ) ;
if ( isOK ) {
switch ( isOK ) {
2019-03-10 07:00:59 +08:00
case 1 :
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Error: No response from Proxmark3. \n " ) ;
2019-03-10 07:00:59 +08:00
break ;
case 2 :
PrintAndLogEx ( NORMAL , " Button pressed. Aborted. \n " ) ;
break ;
default :
break ;
2019-03-10 06:35:06 +08:00
}
return 2 ;
}
return 0 ;
2019-03-09 15:49:41 +08:00
}
2019-08-25 00:11:03 +08:00
static int CmdHF14AMfAutoPWN ( const char * Cmd ) {
// Nested and Hardnested parameter
2019-08-22 18:49:26 +08:00
uint8_t blockNo = 0 ;
uint8_t keyType = 0 ;
2019-08-23 23:17:17 +08:00
uint8_t key [ 6 ] = { 0 } ;
2019-08-22 18:49:26 +08:00
uint64_t key64 = 0 ;
2019-08-26 04:24:52 +08:00
bool calibrate = true ;
2019-08-25 00:11:03 +08:00
// Attack key storage variables
2019-08-28 15:45:11 +08:00
uint8_t * keyBlock = NULL ;
2019-08-26 18:27:40 +08:00
uint16_t key_cnt = 0 ;
sector_t * e_sector ;
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR ;
int block_cnt = MIFARE_1K_MAXBLOCK ;
uint8_t tmp_key [ 6 ] = { 0 } ;
bool know_target_key = false ;
2019-10-09 01:49:34 +08:00
// For the timer
2019-08-25 00:11:03 +08:00
uint64_t t1 ;
// Parameters and dictionary file
2019-08-23 23:17:17 +08:00
char filename [ FILE_PATH_SIZE ] = { 0 } ;
2019-08-22 20:55:06 +08:00
uint8_t cmdp = 0 ;
char ctmp ;
2019-08-25 00:11:03 +08:00
// Nested and Hardnested returned status
2019-08-22 20:55:06 +08:00
uint64_t foundkey = 0 ;
int16_t isOK = 0 ;
2019-08-23 23:17:17 +08:00
int current_sector_i = 0 , current_key_type_i = 0 ;
2019-08-25 17:13:53 +08:00
// Dumping and transfere to simulater memory
uint8_t block [ 16 ] = { 0x00 } ;
uint8_t * dump ;
int bytes ;
2019-08-27 04:28:39 +08:00
char * fnameptr = filename ;
2019-08-25 00:11:03 +08:00
// Settings
2019-08-22 18:49:26 +08:00
bool slow = false ;
2019-08-23 23:17:17 +08:00
bool legacy_mfchk = false ;
2019-09-08 01:41:48 +08:00
int prng_type = PM3_EUNDEF ;
2019-08-26 04:24:52 +08:00
bool verbose = false ;
2019-08-29 03:21:27 +08:00
bool has_filename = false ;
2019-08-30 16:45:52 +08:00
bool errors = false ;
2019-10-09 01:49:34 +08:00
uint8_t num_found_keys = 0 ;
2019-08-22 18:49:26 +08:00
2019-08-25 00:11:03 +08:00
// Parse the options given by the user
2019-08-30 16:45:52 +08:00
while ( ( ctmp = param_getchar ( Cmd , cmdp ) ) & & ! errors ) {
2019-08-22 18:49:26 +08:00
switch ( tolower ( ctmp ) ) {
case ' h ' :
2019-08-25 00:11:03 +08:00
return usage_hf14_autopwn ( ) ;
2019-08-22 18:49:26 +08:00
case ' f ' :
2019-08-27 04:28:39 +08:00
if ( param_getstr ( Cmd , cmdp + 1 , filename , FILE_PATH_SIZE ) > = FILE_PATH_SIZE ) {
2019-08-22 18:49:26 +08:00
PrintAndLogEx ( FAILED , " Filename too long " ) ;
2019-08-30 16:45:52 +08:00
errors = true ;
2019-08-29 03:21:27 +08:00
} else {
2019-08-30 16:45:52 +08:00
has_filename = true ;
2019-08-22 18:49:26 +08:00
}
2019-08-29 03:21:27 +08:00
cmdp + = 2 ;
2019-08-22 18:49:26 +08:00
break ;
2019-08-23 23:17:17 +08:00
case ' l ' :
legacy_mfchk = true ;
2019-08-30 16:45:52 +08:00
cmdp + + ;
2019-08-23 23:17:17 +08:00
break ;
2019-08-26 04:24:52 +08:00
case ' v ' :
verbose = true ;
2019-08-30 16:45:52 +08:00
cmdp + + ;
2019-08-26 04:24:52 +08:00
break ;
2019-08-22 18:49:26 +08:00
case ' * ' :
2019-08-23 23:17:17 +08:00
// Get the number of sectors
2019-08-26 18:27:40 +08:00
sectors_cnt = NumOfSectors ( param_getchar ( Cmd , cmdp + 1 ) ) ;
block_cnt = NumOfBlocks ( param_getchar ( Cmd , cmdp + 1 ) ) ;
2019-08-29 03:21:27 +08:00
cmdp + = 2 ;
2019-08-22 18:49:26 +08:00
break ;
case ' k ' :
// Get the known block number
if ( param_getchar ( Cmd , cmdp + 1 ) = = 0x00 ) {
2019-08-30 16:45:52 +08:00
errors = true ;
2019-08-29 03:21:27 +08:00
break ;
2019-08-22 18:49:26 +08:00
}
2019-08-30 16:45:52 +08:00
2019-08-22 18:49:26 +08:00
blockNo = param_get8 ( Cmd , cmdp + 1 ) ;
2019-08-30 16:45:52 +08:00
2019-08-22 18:49:26 +08:00
// Get the knonwn block type
ctmp = tolower ( param_getchar ( Cmd , cmdp + 2 ) ) ;
if ( ctmp ! = ' a ' & & ctmp ! = ' b ' ) {
PrintAndLogEx ( WARNING , " Key type must be A or B " ) ;
2019-08-29 03:21:27 +08:00
errors = true ;
2019-08-30 16:45:52 +08:00
break ;
2019-08-22 18:49:26 +08:00
}
2019-08-30 16:45:52 +08:00
2019-08-22 18:49:26 +08:00
if ( ctmp ! = ' a ' ) {
keyType = 1 ;
}
2019-08-30 16:45:52 +08:00
2019-08-22 18:49:26 +08:00
// Get the known block key
if ( param_gethex ( Cmd , cmdp + 3 , key , 12 ) ) {
PrintAndLogEx ( WARNING , " Key must include 12 HEX symbols " ) ;
2019-08-30 16:45:52 +08:00
errors = true ;
2019-08-27 23:15:42 +08:00
return PM3_EINVARG ;
2019-08-22 18:49:26 +08:00
}
2019-08-26 18:27:40 +08:00
know_target_key = true ;
2019-08-22 18:49:26 +08:00
cmdp + = 3 ;
case ' s ' :
slow = true ;
2019-08-30 16:45:52 +08:00
cmdp + + ;
2019-08-22 18:49:26 +08:00
break ;
case ' i ' :
SetSIMDInstr ( SIMD_AUTO ) ;
ctmp = tolower ( param_getchar ( Cmd , cmdp + 1 ) ) ;
switch ( ctmp ) {
case ' 5 ' :
SetSIMDInstr ( SIMD_AVX512 ) ;
break ;
case ' 2 ' :
SetSIMDInstr ( SIMD_AVX2 ) ;
break ;
case ' a ' :
SetSIMDInstr ( SIMD_AVX ) ;
break ;
case ' s ' :
SetSIMDInstr ( SIMD_SSE2 ) ;
break ;
case ' m ' :
SetSIMDInstr ( SIMD_MMX ) ;
break ;
case ' n ' :
SetSIMDInstr ( SIMD_NONE ) ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown SIMD type. %c " , ctmp ) ;
2019-08-27 23:15:42 +08:00
return PM3_EINVARG ;
2019-08-22 18:49:26 +08:00
}
cmdp + = 2 ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' \n " , ctmp ) ;
2019-08-27 23:15:42 +08:00
return usage_hf14_autopwn ( ) ;
2019-08-22 18:49:26 +08:00
}
2019-08-29 03:21:27 +08:00
}
2019-08-30 16:45:52 +08:00
if ( errors ) {
return usage_hf14_autopwn ( ) ;
2019-08-22 18:49:26 +08:00
}
2019-08-23 23:17:17 +08:00
// Create the key storage stucture
2019-08-26 18:27:40 +08:00
e_sector = calloc ( sectors_cnt , sizeof ( sector_t ) ) ;
if ( e_sector = = NULL ) return PM3_EMALLOC ;
2019-08-27 23:28:08 +08:00
2019-08-27 23:15:42 +08:00
// clear the key storage
for ( int i = 0 ; i < sectors_cnt ; i + + ) {
for ( int j = 0 ; j < 2 ; j + + ) {
e_sector [ i ] . Key [ j ] = 0 ;
e_sector [ i ] . foundKey [ j ] = 0 ;
2019-08-22 18:49:26 +08:00
}
}
2019-09-08 01:41:48 +08:00
// card prng type (weak=1 / hard=0 / select/card comm error = negative value)
2019-08-25 00:11:03 +08:00
prng_type = detect_classic_prng ( ) ;
2019-09-13 22:31:17 +08:00
if ( prng_type < 0 ) {
2019-09-07 17:36:41 +08:00
PrintAndLogEx ( FAILED , " \n No tag detected or other tag communication error " ) ;
2019-09-08 01:41:48 +08:00
free ( e_sector ) ;
return prng_type ;
2019-09-07 17:36:41 +08:00
}
2019-08-25 00:11:03 +08:00
2019-08-27 23:15:42 +08:00
// print parameters
2019-08-26 04:24:52 +08:00
if ( verbose ) {
2019-08-29 00:39:01 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= SETTINGS ======================= " ) ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( INFO , " card sectors .. " _YELLOW_ ( " %d " ) , sectors_cnt ) ;
PrintAndLogEx ( INFO , " key supplied .. " _YELLOW_ ( " %s " ) , know_target_key ? " True " : " False " ) ;
PrintAndLogEx ( INFO , " known sector .. " _YELLOW_ ( " %d " ) , blockNo ) ;
PrintAndLogEx ( INFO , " keytype ....... " _YELLOW_ ( " %c " ) , keyType ? ' B ' : ' A ' ) ;
PrintAndLogEx ( INFO , " known key ..... " _YELLOW_ ( " %s " ) , sprint_hex ( key , sizeof ( key ) ) ) ;
PrintAndLogEx ( INFO , " card PRNG ..... " _YELLOW_ ( " %s " ) , prng_type ? " WEAK " : " HARD " ) ;
PrintAndLogEx ( INFO , " dictionary .... " _YELLOW_ ( " %s " ) , strlen ( filename ) ? filename : " NONE " ) ;
PrintAndLogEx ( INFO , " legacy mode ... " _YELLOW_ ( " %s " ) , legacy_mfchk ? " True " : " False " ) ;
2019-08-29 00:39:01 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= SETTINGS ======================= " ) ) ;
2019-08-26 04:24:52 +08:00
}
2019-08-27 04:28:39 +08:00
2019-08-27 23:15:42 +08:00
// Start the timer
t1 = msclock ( ) ;
// check the user supplied key
2019-08-26 18:27:40 +08:00
if ( know_target_key = = false )
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( WARNING , " no known key was supplied, key recovery might fail " ) ;
2019-08-25 00:11:03 +08:00
else {
2019-08-29 12:17:27 +08:00
if ( verbose ) {
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START KNOWN KEY ATTACK ======================= " ) ) ;
}
2019-08-25 00:11:03 +08:00
if ( mfCheckKeys ( FirstBlockOfSector ( blockNo ) , keyType , true , 1 , key , & key64 ) = = PM3_SUCCESS ) {
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " target sector:%3u key type: %c -- using valid key [ " _YELLOW_ ( " %s " ) " ] (used for nested / hardnested attack) " ,
2019-08-27 04:28:39 +08:00
blockNo ,
keyType ? ' B ' : ' A ' ,
2019-08-27 23:15:42 +08:00
sprint_hex ( key , sizeof ( key ) )
2019-08-27 23:28:08 +08:00
) ;
2019-08-27 04:28:39 +08:00
2019-08-25 00:11:03 +08:00
// Store the key for the nested / hardnested attack (if supplied by the user)
2019-08-29 03:21:27 +08:00
e_sector [ blockNo ] . Key [ keyType ] = key64 ;
2019-10-09 01:49:34 +08:00
e_sector [ blockNo ] . foundKey [ keyType ] = ' U ' ;
+ + num_found_keys ;
2019-08-25 00:11:03 +08:00
} else {
2019-08-26 18:27:40 +08:00
know_target_key = false ;
2019-08-28 20:20:52 +08:00
PrintAndLogEx ( FAILED , " Key is wrong. Can't authenticate to sector: " _RED_ ( " %3d " ) " key type: " _RED_ ( " %c " ) " key: " _RED_ ( " %s " ) ,
2019-08-27 04:28:39 +08:00
blockNo ,
keyType ? ' B ' : ' A ' ,
2019-08-27 23:15:42 +08:00
sprint_hex ( key , sizeof ( key ) )
2019-08-27 23:28:08 +08:00
) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( WARNING , " falling back to dictionary " ) ;
2019-08-25 00:11:03 +08:00
}
2019-08-30 16:45:52 +08:00
2019-08-27 04:28:39 +08:00
// Check if the user supplied key is used by other sectors
2019-08-27 23:15:42 +08:00
for ( int i = 0 ; i < sectors_cnt ; i + + ) {
for ( int j = 0 ; j < 2 ; j + + ) {
if ( e_sector [ i ] . foundKey [ j ] = = 0 ) {
if ( mfCheckKeys ( FirstBlockOfSector ( i ) , j , true , 1 , key , & key64 ) = = PM3_SUCCESS ) {
e_sector [ i ] . Key [ j ] = bytes_to_num ( key , 6 ) ;
2019-08-28 21:57:21 +08:00
e_sector [ i ] . foundKey [ j ] = ' U ' ;
2019-08-27 04:28:39 +08:00
2019-08-25 00:11:03 +08:00
// If the user supplied secctor / keytype was wrong --> just be nice and correct it ;)
2019-08-26 18:27:40 +08:00
if ( know_target_key = = false ) {
2019-08-27 23:15:42 +08:00
num_to_bytes ( e_sector [ i ] . Key [ j ] , 6 , key ) ;
2019-08-26 18:27:40 +08:00
know_target_key = true ;
2019-08-27 04:28:39 +08:00
blockNo = i ;
2019-08-27 23:15:42 +08:00
keyType = j ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] (used for nested / hardnested attack) " ,
2019-08-28 20:20:52 +08:00
i ,
j ? ' B ' : ' A ' ,
sprint_hex ( key , sizeof ( key ) )
) ;
} else {
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] " ,
2019-08-28 20:20:52 +08:00
i ,
j ? ' B ' : ' A ' ,
2019-08-27 23:15:42 +08:00
sprint_hex ( key , sizeof ( key ) )
2019-08-27 23:28:08 +08:00
) ;
2019-08-25 00:11:03 +08:00
}
2019-10-09 01:49:34 +08:00
+ + num_found_keys ;
2019-08-27 04:28:39 +08:00
}
2019-08-25 00:11:03 +08:00
}
}
}
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP KNOWN KEY ATTACK ======================= " ) ) ;
2019-10-09 01:49:34 +08:00
if ( num_found_keys = = sectors_cnt * 2 )
2019-10-13 06:48:26 +08:00
goto all_found ;
2019-08-25 00:11:03 +08:00
}
2019-08-29 03:21:27 +08:00
bool load_success = true ;
2019-08-23 23:17:17 +08:00
// Load the dictionary
2019-08-29 03:21:27 +08:00
if ( has_filename ) {
2019-08-30 16:45:52 +08:00
int res = loadFileDICTIONARY_safe ( filename , ( void * * ) & keyBlock , 6 , & key_cnt ) ;
2019-08-29 03:21:27 +08:00
if ( res ! = PM3_SUCCESS | | key_cnt = = 0 | | keyBlock = = NULL ) {
2019-08-28 15:34:46 +08:00
PrintAndLogEx ( FAILED , " An error occurred while loading the dictionary! (we will use the default keys now) " ) ;
2019-08-29 03:21:27 +08:00
if ( keyBlock ! = NULL )
free ( keyBlock ) ;
2019-08-30 16:45:52 +08:00
load_success = false ;
2019-08-26 18:27:40 +08:00
}
2019-08-29 03:21:27 +08:00
}
2019-08-30 16:45:52 +08:00
if ( has_filename = = false | | load_success = = false ) {
2019-08-23 23:17:17 +08:00
keyBlock = calloc ( ARRAYLEN ( g_mifare_default_keys ) , 6 ) ;
2019-08-26 04:24:52 +08:00
if ( keyBlock = = NULL ) {
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_EMALLOC ;
2019-08-26 04:24:52 +08:00
}
2019-08-22 18:49:26 +08:00
2019-08-23 23:17:17 +08:00
for ( int cnt = 0 ; cnt < ARRAYLEN ( g_mifare_default_keys ) ; cnt + + ) {
num_to_bytes ( g_mifare_default_keys [ cnt ] , 6 , keyBlock + cnt * 6 ) ;
2019-08-22 18:49:26 +08:00
}
2019-08-27 04:28:39 +08:00
key_cnt = ARRAYLEN ( g_mifare_default_keys ) ;
2019-08-30 16:45:52 +08:00
PrintAndLogEx ( SUCCESS , " loaded " _GREEN_ ( " %2d " ) " keys from hardcoded default array " , key_cnt ) ;
2019-08-27 04:28:39 +08:00
}
2019-08-25 00:11:03 +08:00
// Use the dictionary to find sector keys on the card
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START DICTIONARY ATTACK ======================= " ) ) ;
2019-08-27 23:28:08 +08:00
2019-08-23 23:17:17 +08:00
if ( legacy_mfchk ) {
2019-08-27 04:28:39 +08:00
// Check all the sectors
2019-08-27 23:15:42 +08:00
for ( int i = 0 ; i < sectors_cnt ; i + + ) {
for ( int j = 0 ; j < 2 ; j + + ) {
2019-08-23 23:17:17 +08:00
// Check if the key is known
2019-08-27 23:15:42 +08:00
if ( e_sector [ i ] . foundKey [ j ] = = 0 ) {
for ( int k = 0 ; k < key_cnt ; k + + ) {
2019-08-27 04:28:39 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-08-27 23:15:42 +08:00
if ( mfCheckKeys ( FirstBlockOfSector ( i ) , j , true , 1 , ( keyBlock + ( 6 * k ) ) , & key64 ) = = PM3_SUCCESS ) {
e_sector [ i ] . Key [ j ] = bytes_to_num ( ( keyBlock + ( 6 * k ) ) , 6 ) ;
2019-08-28 21:57:21 +08:00
e_sector [ i ] . foundKey [ j ] = ' D ' ;
2019-10-09 01:49:34 +08:00
+ + num_found_keys ;
2019-08-23 23:17:17 +08:00
break ;
2019-08-22 18:49:26 +08:00
}
}
}
}
}
2019-08-27 04:28:39 +08:00
printf ( " \n " ) ;
fflush ( stdout ) ;
2019-08-23 23:17:17 +08:00
} else {
2019-08-29 03:21:27 +08:00
2019-08-26 18:27:40 +08:00
int chunksize = key_cnt > ( PM3_CMD_DATA_SIZE / 6 ) ? ( PM3_CMD_DATA_SIZE / 6 ) : key_cnt ;
2019-08-25 00:11:03 +08:00
bool firstChunk = true , lastChunk = false ;
2019-08-29 03:21:27 +08:00
2019-08-23 23:17:17 +08:00
for ( uint8_t strategy = 1 ; strategy < 3 ; strategy + + ) {
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " running strategy %u " , strategy ) ;
2019-08-23 23:17:17 +08:00
// main keychunk loop
2019-08-27 23:15:42 +08:00
for ( int i = 0 ; i < key_cnt ; i + = chunksize ) {
2019-08-23 23:17:17 +08:00
if ( kbd_enter_pressed ( ) ) {
PrintAndLogEx ( WARNING , " \n aborted via keyboard! \n " ) ;
2019-08-27 04:28:39 +08:00
i = key_cnt ;
strategy = 3 ;
break ; // Exit the loop
2019-08-23 23:17:17 +08:00
}
2019-08-26 18:27:40 +08:00
uint32_t size = ( ( key_cnt - i ) > chunksize ) ? chunksize : key_cnt - i ;
2019-08-23 23:17:17 +08:00
// last chunk?
2019-08-26 18:27:40 +08:00
if ( size = = key_cnt - i )
2019-08-23 23:17:17 +08:00
lastChunk = true ;
2019-08-27 23:15:42 +08:00
2019-08-26 18:27:40 +08:00
int res = mfCheckKeys_fast ( sectors_cnt , firstChunk , lastChunk , strategy , size , keyBlock + ( i * 6 ) , e_sector , false ) ;
2019-08-23 23:17:17 +08:00
if ( firstChunk )
firstChunk = false ;
// all keys, aborted
2019-08-29 03:21:27 +08:00
if ( res = = PM3_SUCCESS ) {
2019-08-27 04:28:39 +08:00
i = key_cnt ;
strategy = 3 ;
break ; // Exit the loop
2019-08-23 23:17:17 +08:00
}
} // end chunks of keys
firstChunk = true ;
lastChunk = false ;
} // end strategy
2019-08-22 18:49:26 +08:00
}
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP DICTIONARY ATTACK ======================= " ) ) ;
2019-08-28 20:20:52 +08:00
2019-08-22 18:49:26 +08:00
2019-08-25 00:11:03 +08:00
// Analyse the dictionary attack
2019-08-27 23:15:42 +08:00
for ( int i = 0 ; i < sectors_cnt ; i + + ) {
for ( int j = 0 ; j < 2 ; j + + ) {
if ( e_sector [ i ] . foundKey [ j ] = = 1 ) {
2019-08-28 21:57:21 +08:00
e_sector [ i ] . foundKey [ j ] = ' D ' ;
2019-08-27 23:15:42 +08:00
num_to_bytes ( e_sector [ i ] . Key [ j ] , 6 , tmp_key ) ;
2019-08-30 16:45:52 +08:00
2019-08-27 04:21:23 +08:00
// Store valid credentials for the nested / hardnested attack if none exist
2019-08-26 18:27:40 +08:00
if ( know_target_key = = false ) {
2019-10-09 16:41:59 +08:00
num_to_bytes ( e_sector [ i ] . Key [ j ] , 6 , tmp_key ) ;
2019-08-26 18:27:40 +08:00
know_target_key = true ;
2019-08-27 04:28:39 +08:00
blockNo = i ;
2019-08-27 23:15:42 +08:00
keyType = j ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] (used for nested / hardnested attack) " ,
2019-08-28 20:20:52 +08:00
i ,
j ? ' B ' : ' A ' ,
sprint_hex ( tmp_key , sizeof ( tmp_key ) )
) ;
} else {
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] " ,
2019-08-28 20:20:52 +08:00
i ,
j ? ' B ' : ' A ' ,
sprint_hex ( tmp_key , sizeof ( tmp_key ) )
2019-08-27 23:28:08 +08:00
) ;
2019-08-25 00:11:03 +08:00
}
2019-08-23 23:17:17 +08:00
}
}
}
2019-08-25 00:11:03 +08:00
2019-08-23 23:17:17 +08:00
// Check if at least one sector key was found
2019-08-26 18:27:40 +08:00
if ( know_target_key = = false ) {
2019-08-25 00:11:03 +08:00
// Check if the darkside attack can be used
if ( prng_type ) {
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START DARKSIDE ATTACK ======================= " ) ) ;
2019-08-25 00:11:03 +08:00
int isOK = mfDarkside ( FirstBlockOfSector ( blockNo ) , keyType , & key64 ) ;
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP DARKSIDE ATTACK ======================= " ) ) ;
2019-08-25 00:11:03 +08:00
switch ( isOK ) {
case - 1 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( WARNING , " \n Button pressed. Aborted. " ) ;
2019-08-25 00:11:03 +08:00
goto noValidKeyFound ;
case - 2 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( FAILED , " \n Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). " ) ;
2019-08-25 00:11:03 +08:00
goto noValidKeyFound ;
case - 3 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( FAILED , " \n Card is not vulnerable to Darkside attack (its random number generator is not predictable). " ) ;
2019-08-25 00:11:03 +08:00
goto noValidKeyFound ;
case - 4 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( FAILED , " \n Card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown " ) ;
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( FAILED , " generating polynomial with 16 effective bits only, but shows unexpected behaviour. " ) ;
goto noValidKeyFound ;
case - 5 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( WARNING , " \n Aborted via keyboard. " ) ;
2019-08-25 00:11:03 +08:00
goto noValidKeyFound ;
default :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( SUCCESS , " \n Found valid key: %012 " PRIx64 " \n " , key64 ) ;
2019-08-25 00:11:03 +08:00
break ;
}
2019-08-29 03:21:27 +08:00
2019-08-25 00:11:03 +08:00
// Store the keys
2019-08-29 03:21:27 +08:00
e_sector [ blockNo ] . Key [ keyType ] = key64 ;
2019-08-28 21:57:21 +08:00
e_sector [ blockNo ] . foundKey [ keyType ] = ' S ' ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] (used for nested / hardnested attack) " ,
2019-08-28 20:20:52 +08:00
blockNo ,
keyType ? ' B ' : ' A ' ,
sprint_hex ( key , sizeof ( key ) )
) ;
2019-08-25 00:11:03 +08:00
} else {
2019-08-27 04:28:39 +08:00
noValidKeyFound :
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( FAILED , " No usable key was found! " ) ;
2019-08-23 23:17:17 +08:00
free ( keyBlock ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_ESOFT ;
2019-08-23 23:17:17 +08:00
}
2019-08-22 18:49:26 +08:00
}
2019-08-30 16:45:52 +08:00
2019-08-25 00:11:03 +08:00
free ( keyBlock ) ;
// Clear the needed variables
2019-08-27 04:28:39 +08:00
num_to_bytes ( 0 , 6 , tmp_key ) ;
2019-08-27 04:21:23 +08:00
bool nested_failed = false ;
2019-08-22 18:49:26 +08:00
2019-08-22 20:55:06 +08:00
// Iterate over each sector and key(A/B)
2019-08-27 04:28:39 +08:00
for ( current_sector_i = 0 ; current_sector_i < sectors_cnt ; current_sector_i + + ) {
for ( current_key_type_i = 0 ; current_key_type_i < 2 ; current_key_type_i + + ) {
2019-08-22 18:49:26 +08:00
2019-08-23 23:17:17 +08:00
// If the key is already known, just skip it
2019-08-26 18:27:40 +08:00
if ( e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] = = 0 ) {
2019-08-23 23:17:17 +08:00
2019-08-25 00:11:03 +08:00
// Try the found keys are reused
2019-08-27 04:28:39 +08:00
if ( bytes_to_num ( tmp_key , 6 ) ! = 0 ) {
2019-08-26 18:27:40 +08:00
// <!> The fast check --> mfCheckKeys_fast(sectors_cnt, true, true, 2, 1, tmp_key, e_sector, false);
2019-08-25 00:11:03 +08:00
// <!> Returns false keys, so we just stick to the slower mfchk.
2019-08-27 23:15:42 +08:00
for ( int i = 0 ; i < sectors_cnt ; i + + ) {
for ( int j = 0 ; j < 2 ; j + + ) {
2019-08-25 00:11:03 +08:00
// Check if the sector key is already broken
2019-08-27 23:15:42 +08:00
if ( e_sector [ i ] . foundKey [ j ] )
2019-08-27 23:28:08 +08:00
continue ;
// Check if the key works
if ( mfCheckKeys ( FirstBlockOfSector ( i ) , j , true , 1 , tmp_key , & key64 ) = = PM3_SUCCESS ) {
e_sector [ i ] . Key [ j ] = bytes_to_num ( tmp_key , 6 ) ;
2019-08-28 21:57:21 +08:00
e_sector [ i ] . foundKey [ j ] = ' R ' ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] " ,
2019-08-27 23:28:08 +08:00
i ,
j ? ' B ' : ' A ' ,
sprint_hex ( tmp_key , sizeof ( tmp_key ) )
) ;
2019-08-23 23:17:17 +08:00
}
2019-08-22 18:49:26 +08:00
}
}
}
2019-08-23 23:17:17 +08:00
// Clear the last found key
2019-08-26 18:27:40 +08:00
num_to_bytes ( 0 , 6 , tmp_key ) ;
2019-08-23 23:17:17 +08:00
2019-08-28 01:45:37 +08:00
if ( current_key_type_i = = 1 ) {
if ( e_sector [ current_sector_i ] . foundKey [ 0 ] & & ! e_sector [ current_sector_i ] . foundKey [ 1 ] ) {
2019-08-29 00:39:01 +08:00
if ( verbose ) {
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START READ B KEY ATTACK ======================= " ) ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " reading B key: sector: %3d key type: %c " ,
2019-08-30 16:45:52 +08:00
current_sector_i ,
2019-08-29 00:39:01 +08:00
current_key_type_i ? ' B ' : ' A ' ) ;
}
2019-08-28 01:45:37 +08:00
uint8_t sectrail = ( FirstBlockOfSector ( current_sector_i ) + NumBlocksPerSector ( current_sector_i ) - 1 ) ;
mf_readblock_t payload ;
payload . blockno = sectrail ;
payload . keytype = 0 ;
num_to_bytes ( e_sector [ current_sector_i ] . Key [ 0 ] , 6 , payload . key ) ; // KEY A
clearCommandBuffer ( ) ;
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
PacketResponseNG resp ;
2019-08-28 01:55:45 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ) goto skipReadBKey ;
2019-08-28 01:45:37 +08:00
2019-08-28 01:55:45 +08:00
if ( resp . status ! = PM3_SUCCESS ) goto skipReadBKey ;
2019-08-28 01:45:37 +08:00
uint8_t * data = resp . data . asBytes ;
key64 = bytes_to_num ( data + 10 , 6 ) ;
if ( key64 ) {
2019-08-28 21:57:21 +08:00
e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] = ' A ' ;
2019-08-28 01:45:37 +08:00
e_sector [ current_sector_i ] . Key [ current_key_type_i ] = key64 ;
num_to_bytes ( key64 , 6 , tmp_key ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] " ,
2019-08-28 02:28:28 +08:00
current_sector_i ,
current_key_type_i ? ' B ' : ' A ' ,
sprint_hex ( tmp_key , sizeof ( tmp_key ) )
) ;
2019-08-28 21:57:21 +08:00
} else {
2019-08-29 12:17:27 +08:00
if ( verbose ) PrintAndLogEx ( WARNING , " unknown B key: sector: %3d key type: %c (reading the B key was not possible, maybe due to insufficient access rights) " ,
2019-08-30 16:45:52 +08:00
current_sector_i ,
current_key_type_i ? ' B ' : ' A '
) ;
2019-08-28 01:45:37 +08:00
}
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP READ B KEY ATTACK ======================= " ) ) ;
2019-08-28 01:45:37 +08:00
}
}
2019-08-25 00:11:03 +08:00
// Use the nested / hardnested attack
2019-08-28 01:55:45 +08:00
skipReadBKey :
2019-08-26 18:27:40 +08:00
if ( e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] = = 0 ) {
2019-08-27 04:21:23 +08:00
if ( prng_type & & ( ! nested_failed ) ) {
uint8_t retries = 0 ;
2019-08-29 00:39:01 +08:00
if ( verbose ) {
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START NESTED ATTACK ======================= " ) ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " sector no: %3d, target key type: %c " ,
2019-08-29 00:39:01 +08:00
current_sector_i ,
current_key_type_i ? ' B ' : ' A ' ) ;
}
2019-08-28 21:57:21 +08:00
tryNested :
2019-08-26 18:27:40 +08:00
isOK = mfnested ( FirstBlockOfSector ( blockNo ) , keyType , key , FirstBlockOfSector ( current_sector_i ) , current_key_type_i , tmp_key , calibrate ) ;
2019-08-23 23:17:17 +08:00
switch ( isOK ) {
2019-08-25 00:11:03 +08:00
case - 1 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( ERR , " \n Error: No response from Proxmark3. " ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_ESOFT ;
2019-08-25 00:11:03 +08:00
case - 2 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( WARNING , " \n Button pressed. Aborted. " ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_ESOFT ;
2019-08-25 00:11:03 +08:00
case - 3 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( FAILED , " Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable). " ) ;
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( FAILED , " Nested attack failed --> try hardnested " ) ;
2019-08-25 00:11:03 +08:00
goto tryHardnested ;
case - 4 : //key not found
calibrate = false ;
2019-08-27 04:21:23 +08:00
// this can happen on some old cards, it's worth trying some more before switching to slower hardnested
if ( retries + + < MIFARE_SECTOR_RETRY ) {
PrintAndLogEx ( FAILED , " Nested attack failed, trying again (%i/%i) " , retries , MIFARE_SECTOR_RETRY ) ;
goto tryNested ;
} else {
PrintAndLogEx ( FAILED , " Nested attack failed, moving to hardnested " ) ;
nested_failed = true ;
goto tryHardnested ;
}
2019-08-25 00:11:03 +08:00
break ;
case - 5 :
calibrate = false ;
2019-08-26 18:27:40 +08:00
e_sector [ current_sector_i ] . Key [ current_key_type_i ] = bytes_to_num ( tmp_key , 6 ) ;
2019-08-28 21:57:21 +08:00
e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] = ' N ' ;
2019-08-23 23:17:17 +08:00
break ;
default :
2019-08-25 00:11:03 +08:00
PrintAndLogEx ( ERR , " unknown Error. \n " ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_ESOFT ;
2019-08-23 23:17:17 +08:00
}
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP NESTED ATTACK ======================= " ) ) ;
2019-08-25 00:11:03 +08:00
} else {
2019-08-27 04:21:23 +08:00
tryHardnested : // If the nested attack fails then we try the hardnested attack
2019-08-29 00:39:01 +08:00
if ( verbose ) {
PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= START HARDNESTED ATTACK ======================= " ) ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " sector no: %3d, target key type: %c, Slow: %s " ,
2019-08-29 00:39:01 +08:00
current_sector_i ,
current_key_type_i ? ' B ' : ' A ' ,
slow ? " Yes " : " No " ) ;
}
2019-08-25 00:11:03 +08:00
2019-08-26 04:24:52 +08:00
isOK = mfnestedhard ( FirstBlockOfSector ( blockNo ) , keyType , key , FirstBlockOfSector ( current_sector_i ) , current_key_type_i , NULL , false , false , slow , 0 , & foundkey , NULL ) ;
2019-08-25 00:11:03 +08:00
DropField ( ) ;
if ( isOK ) {
switch ( isOK ) {
case 1 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( ERR , " \n Error: No response from Proxmark3. " ) ;
2019-08-25 00:11:03 +08:00
break ;
case 2 :
2019-08-26 04:24:52 +08:00
PrintAndLogEx ( NORMAL , " \n Button pressed. Aborted. " ) ;
2019-08-25 00:11:03 +08:00
break ;
default :
break ;
}
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_ESOFT ;
2019-08-25 00:11:03 +08:00
}
2019-08-22 18:49:26 +08:00
2019-08-26 18:27:40 +08:00
// Copy the found key to the tmp_key variale (for the following print statement, and the mfCheckKeys above)
num_to_bytes ( foundkey , 6 , tmp_key ) ;
e_sector [ current_sector_i ] . Key [ current_key_type_i ] = foundkey ;
2019-08-28 21:57:21 +08:00
e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] = ' H ' ;
2019-08-28 20:20:52 +08:00
2019-08-29 00:39:01 +08:00
if ( verbose ) PrintAndLogEx ( INFO , _YELLOW_ ( " ======================= STOP HARDNESTED ATTACK ======================= " ) ) ;
2019-08-25 00:11:03 +08:00
}
// Check if the key was found
2019-08-27 23:15:42 +08:00
if ( e_sector [ current_sector_i ] . foundKey [ current_key_type_i ] ) {
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " target sector:%3u key type: %c -- found valid key [ " _YELLOW_ ( " %s " ) " ] " ,
2019-08-27 04:28:39 +08:00
current_sector_i ,
current_key_type_i ? ' B ' : ' A ' ,
2019-08-27 23:15:42 +08:00
sprint_hex ( tmp_key , sizeof ( tmp_key ) )
2019-08-27 23:28:08 +08:00
) ;
2019-08-25 00:11:03 +08:00
}
2019-08-22 18:49:26 +08:00
}
}
}
}
2019-10-09 01:49:34 +08:00
all_found :
2019-08-25 00:11:03 +08:00
// Show the results to the user
PrintAndLogEx ( NORMAL , " " ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " found Keys: " ) ;
2019-08-27 04:28:39 +08:00
2019-08-29 00:39:01 +08:00
char strA [ 12 + 1 ] = { 0 } ;
char strB [ 12 + 1 ] = { 0 } ;
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
PrintAndLogEx ( NORMAL , " |sec|key A |res|key B |res| " ) ;
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
for ( uint8_t i = 0 ; i < sectors_cnt ; + + i ) {
snprintf ( strA , sizeof ( strA ) , " ------------ " ) ;
snprintf ( strB , sizeof ( strB ) , " ------------ " ) ;
if ( e_sector [ i ] . foundKey [ 0 ] )
snprintf ( strA , sizeof ( strA ) , " %012 " PRIx64 , e_sector [ i ] . Key [ 0 ] ) ;
if ( e_sector [ i ] . foundKey [ 1 ] )
snprintf ( strB , sizeof ( strB ) , " %012 " PRIx64 , e_sector [ i ] . Key [ 1 ] ) ;
PrintAndLogEx ( NORMAL , " |%03d| %s | " _YELLOW_ ( " %c " ) " | %s | " _YELLOW_ ( " %c " ) " | "
, i
, strA , e_sector [ i ] . foundKey [ 0 ]
, strB , e_sector [ i ] . foundKey [ 1 ]
) ;
}
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
2019-08-30 16:45:52 +08:00
PrintAndLogEx ( NORMAL , " ( "
2019-08-29 00:39:01 +08:00
_YELLOW_ ( " D " ) " :Dictionary / "
_YELLOW_ ( " S " ) " :darkSide / "
_YELLOW_ ( " U " ) " :User / "
_YELLOW_ ( " R " ) " :Reused / "
_YELLOW_ ( " N " ) " :Nested / "
2019-08-30 16:45:52 +08:00
_YELLOW_ ( " H " ) " :Hardnested / "
2019-08-29 00:39:01 +08:00
_YELLOW_ ( " A " ) " :keyA "
" ) "
) ;
// Dump the keys
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( INFO , " saving keys " ) ;
2019-08-26 20:29:21 +08:00
createMfcKeyDump ( sectors_cnt , e_sector , GenerateFilename ( " hf-mf- " , " -key.bin " ) ) ;
2019-08-27 04:28:39 +08:00
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( SUCCESS , " transferring keys to simulator memory (Cmd Error: 04 can occur) " ) ;
2019-08-27 23:28:08 +08:00
2019-08-27 04:28:39 +08:00
for ( current_sector_i = 0 ; current_sector_i < sectors_cnt ; current_sector_i + + ) {
2019-08-25 17:13:53 +08:00
mfEmlGetMem ( block , current_sector_i , 1 ) ;
2019-08-26 18:27:40 +08:00
if ( e_sector [ current_sector_i ] . foundKey [ 0 ] )
num_to_bytes ( e_sector [ current_sector_i ] . Key [ 0 ] , 6 , block ) ;
if ( e_sector [ current_sector_i ] . foundKey [ 1 ] )
num_to_bytes ( e_sector [ current_sector_i ] . Key [ 1 ] , 6 , block + 10 ) ;
2019-08-27 23:15:42 +08:00
2019-08-27 04:28:39 +08:00
mfEmlSetMem ( block , FirstBlockOfSector ( current_sector_i ) + NumBlocksPerSector ( current_sector_i ) - 1 , 1 ) ;
2019-08-25 17:13:53 +08:00
}
2019-08-30 16:45:52 +08:00
// use ecfill trick
FastDumpWithEcFill ( sectors_cnt ) ;
2019-08-25 17:13:53 +08:00
2019-08-26 18:27:40 +08:00
bytes = block_cnt * MFBLOCK_SIZE ;
2019-08-25 17:13:53 +08:00
dump = calloc ( bytes , sizeof ( uint8_t ) ) ;
if ( ! dump ) {
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( ERR , " Fail, cannot allocate memory " ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-25 17:13:53 +08:00
return PM3_EMALLOC ;
}
memset ( dump , 0 , bytes ) ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " downloading the card content from emulator memory " ) ;
2019-08-25 17:13:53 +08:00
if ( ! GetFromDevice ( BIG_BUF_EML , dump , bytes , 0 , NULL , 0 , NULL , 2500 , false ) ) {
2019-08-27 23:15:42 +08:00
PrintAndLogEx ( ERR , " Fail, transfer from device time-out " ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-25 17:13:53 +08:00
free ( dump ) ;
return PM3_ETIMEOUT ;
}
2019-08-27 23:15:42 +08:00
fnameptr = GenerateFilename ( " hf-mf- " , " -data " ) ;
2019-08-27 23:28:08 +08:00
if ( fnameptr = = NULL ) {
free ( dump ) ;
free ( e_sector ) ;
return PM3_ESOFT ;
2019-08-27 23:15:42 +08:00
}
2019-08-27 23:28:08 +08:00
strcpy ( filename , fnameptr ) ;
2019-08-25 17:13:53 +08:00
saveFile ( filename , " .bin " , dump , bytes ) ;
saveFileEML ( filename , dump , bytes , MFBLOCK_SIZE ) ;
saveFileJSON ( filename , jsfCardMemory , dump , bytes ) ;
2019-08-26 18:27:40 +08:00
2019-08-26 04:24:52 +08:00
// Generate and show statistics
t1 = msclock ( ) - t1 ;
2019-08-29 12:17:27 +08:00
PrintAndLogEx ( INFO , " autopwn execution time: " _YELLOW_ ( " %.0f " ) " seconds " , ( float ) t1 / 1000.0 ) ;
2019-08-26 04:24:52 +08:00
free ( dump ) ;
2019-08-26 18:27:40 +08:00
free ( e_sector ) ;
2019-08-27 23:15:42 +08:00
return PM3_SUCCESS ;
2019-08-22 18:49:26 +08:00
}
2019-04-14 03:54:04 +08:00
/*
static int randInRange ( int min , int max ) {
2019-03-10 07:00:59 +08:00
return min + ( int ) ( rand ( ) / ( double ) ( RAND_MAX ) * ( max - min + 1 ) ) ;
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
*/
2019-03-09 15:49:41 +08:00
//Fisher– Yates shuffle
2019-04-14 03:54:04 +08:00
/*
static void shuffle ( uint8_t * array , uint16_t len ) {
2019-03-10 06:35:06 +08:00
uint8_t tmp [ 6 ] ;
uint16_t x ;
time_t t ;
srand ( ( unsigned ) time ( & t ) ) ;
while ( len ) {
2019-03-10 07:00:59 +08:00
x = randInRange ( 0 , ( len - = 6 ) ) | 0 ; // 0 = i < n
2019-03-10 06:35:06 +08:00
x % = 6 ;
memcpy ( tmp , array + x , 6 ) ;
memcpy ( array + x , array + len , 6 ) ;
memcpy ( array + len , tmp , 6 ) ;
}
2019-03-09 15:49:41 +08:00
}
2019-04-14 03:54:04 +08:00
*/
2019-03-09 15:49:41 +08:00
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfChk_fast ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char ctmp = 0x00 ;
ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 1 | | ctmp = = ' h ' ) return usage_hf14_chk_fast ( ) ;
2019-03-10 07:00:59 +08:00
FILE * f ;
char filename [ FILE_PATH_SIZE ] = { 0 } ;
2019-03-10 06:35:06 +08:00
char buf [ 13 ] ;
char * fptr ;
2019-03-19 06:59:35 +08:00
uint8_t * keyBlock , * p ;
2019-03-10 06:35:06 +08:00
uint8_t sectorsCnt = 1 ;
int i , keycnt = 0 ;
int clen = 0 ;
int transferToEml = 0 , createDumpFile = 0 ;
2019-08-01 05:44:53 +08:00
uint32_t keyitems = ARRAYLEN ( g_mifare_default_keys ) ;
2019-03-10 06:35:06 +08:00
bool use_flashmemory = false ;
sector_t * e_sector = NULL ;
2019-08-01 05:44:53 +08:00
keyBlock = calloc ( ARRAYLEN ( g_mifare_default_keys ) , 6 ) ;
2019-08-26 19:03:11 +08:00
if ( keyBlock = = NULL ) return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
2019-08-01 05:44:53 +08:00
for ( int cnt = 0 ; cnt < ARRAYLEN ( g_mifare_default_keys ) ; cnt + + )
2019-03-10 06:35:06 +08:00
num_to_bytes ( g_mifare_default_keys [ cnt ] , 6 , keyBlock + cnt * 6 ) ;
// sectors
2019-03-10 07:00:59 +08:00
switch ( ctmp ) {
case ' 0 ' :
sectorsCnt = MIFARE_MINI_MAXSECTOR ;
break ;
case ' 1 ' :
sectorsCnt = MIFARE_1K_MAXSECTOR ;
break ;
case ' 2 ' :
sectorsCnt = MIFARE_2K_MAXSECTOR ;
break ;
case ' 4 ' :
sectorsCnt = MIFARE_4K_MAXSECTOR ;
break ;
default :
sectorsCnt = MIFARE_1K_MAXSECTOR ;
2019-03-10 06:35:06 +08:00
}
for ( i = 1 ; param_getchar ( Cmd , i ) ; i + + ) {
ctmp = tolower ( param_getchar ( Cmd , i ) ) ;
clen = param_getlength ( Cmd , i ) ;
if ( clen = = 12 ) {
2019-03-10 07:00:59 +08:00
if ( param_gethex ( Cmd , i , keyBlock + 6 * keycnt , 12 ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " not hex, skipping " ) ;
continue ;
}
2019-03-10 07:00:59 +08:00
if ( keyitems - keycnt < 2 ) {
2019-03-10 06:35:06 +08:00
p = realloc ( keyBlock , 6 * ( keyitems + = 64 ) ) ;
if ( ! p ) {
PrintAndLogEx ( FAILED , " Cannot allocate memory for Keys " ) ;
free ( keyBlock ) ;
2019-08-26 19:03:11 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
keyBlock = p ;
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " [%2d] key %s " , keycnt , sprint_hex ( ( keyBlock + 6 * keycnt ) , 6 ) ) ;
2019-03-10 06:35:06 +08:00
keycnt + + ;
2019-03-10 07:00:59 +08:00
} else if ( clen = = 1 ) {
if ( ctmp = = ' t ' ) { transferToEml = 1 ; continue ; }
if ( ctmp = = ' d ' ) { createDumpFile = 1 ; continue ; }
2019-05-02 06:18:20 +08:00
if ( ( ctmp = = ' m ' ) & & ( IfPm3Flash ( ) ) ) { use_flashmemory = true ; continue ; }
2019-03-10 06:35:06 +08:00
} else {
// May be a dic file
2019-03-10 07:00:59 +08:00
if ( param_getstr ( Cmd , i , filename , FILE_PATH_SIZE ) > = FILE_PATH_SIZE ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " Filename too long " ) ;
2019-08-26 19:03:11 +08:00
free ( keyBlock ) ;
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
2019-08-26 19:03:11 +08:00
char * dict_path ;
2019-08-30 15:02:01 +08:00
int res = searchFile ( & dict_path , DICTIONARIES_SUBDIR , filename , " .dic " , false ) ;
2019-08-26 19:03:11 +08:00
if ( res ! = PM3_SUCCESS ) {
free ( keyBlock ) ;
return res ;
}
f = fopen ( dict_path , " r " ) ;
2019-03-10 07:00:59 +08:00
if ( ! f ) {
2019-08-26 19:03:11 +08:00
PrintAndLogEx ( FAILED , " File: " _YELLOW_ ( " %s " ) " : not found or locked. " , dict_path ) ;
free ( dict_path ) ;
free ( keyBlock ) ;
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
2019-08-26 19:03:11 +08:00
free ( dict_path ) ;
2019-03-10 06:35:06 +08:00
// read file
2019-03-10 07:00:59 +08:00
while ( fgets ( buf , sizeof ( buf ) , f ) ) {
2019-03-10 06:35:06 +08:00
if ( strlen ( buf ) < 12 | | buf [ 11 ] = = ' \n ' )
continue ;
while ( fgetc ( f ) ! = ' \n ' & & ! feof ( f ) ) ; //goto next line
2019-03-10 07:00:59 +08:00
if ( buf [ 0 ] = = ' # ' ) continue ; //The line start with # is comment, skip
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( ! isxdigit ( buf [ 0 ] ) ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( FAILED , " File content error. ' " _YELLOW_ ( " %s " ) " ' must include 12 HEX symbols " , buf ) ;
2019-08-26 19:53:23 +08:00
continue ;
2019-03-10 06:35:06 +08:00
}
buf [ 12 ] = 0 ;
2019-03-10 07:00:59 +08:00
if ( keyitems - keycnt < 2 ) {
2019-03-10 06:35:06 +08:00
p = realloc ( keyBlock , 6 * ( keyitems + = 64 ) ) ;
if ( ! p ) {
PrintAndLogEx ( FAILED , " Cannot allocate memory for default keys " ) ;
free ( keyBlock ) ;
fclose ( f ) ;
2019-08-26 19:03:11 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
keyBlock = p ;
}
int pos = 6 * keycnt ;
memset ( keyBlock + pos , 0 , 6 ) ;
num_to_bytes ( strtoll ( buf , NULL , 16 ) , 6 , keyBlock + pos ) ;
keycnt + + ;
memset ( buf , 0 , sizeof ( buf ) ) ;
}
fclose ( f ) ;
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( SUCCESS , " Loaded %2d keys from " _YELLOW_ ( " %s " ) , keycnt , filename ) ;
2019-03-10 06:35:06 +08:00
}
}
if ( keycnt = = 0 & & ! use_flashmemory ) {
PrintAndLogEx ( SUCCESS , " No key specified, trying default keys " ) ;
2019-08-01 05:44:53 +08:00
for ( ; keycnt < ARRAYLEN ( g_mifare_default_keys ) ; keycnt + + )
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " [%2d] %02x%02x%02x%02x%02x%02x " , keycnt ,
2019-03-10 07:00:59 +08:00
( keyBlock + 6 * keycnt ) [ 0 ] , ( keyBlock + 6 * keycnt ) [ 1 ] , ( keyBlock + 6 * keycnt ) [ 2 ] ,
( keyBlock + 6 * keycnt ) [ 3 ] , ( keyBlock + 6 * keycnt ) [ 4 ] , ( keyBlock + 6 * keycnt ) [ 5 ] ) ;
2019-03-10 06:35:06 +08:00
}
// // initialize storage for found keys
e_sector = calloc ( sectorsCnt , sizeof ( sector_t ) ) ;
if ( e_sector = = NULL ) {
free ( keyBlock ) ;
2019-08-26 19:03:11 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
2019-05-01 03:10:11 +08:00
uint32_t chunksize = keycnt > ( PM3_CMD_DATA_SIZE / 6 ) ? ( PM3_CMD_DATA_SIZE / 6 ) : keycnt ;
2019-03-10 06:35:06 +08:00
bool firstChunk = true , lastChunk = false ;
// time
uint64_t t1 = msclock ( ) ;
2019-03-10 07:00:59 +08:00
if ( use_flashmemory ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " Using dictionary in flash memory " ) ;
2019-03-10 07:00:59 +08:00
mfCheckKeys_fast ( sectorsCnt , true , true , 1 , 0 , keyBlock , e_sector , use_flashmemory ) ;
2019-03-10 06:35:06 +08:00
} else {
// strategys. 1= deep first on sector 0 AB, 2= width first on all sectors
for ( uint8_t strategy = 1 ; strategy < 3 ; strategy + + ) {
PrintAndLogEx ( SUCCESS , " Running strategy %u " , strategy ) ;
2019-03-10 07:00:59 +08:00
// main keychunk loop
2019-04-08 02:08:53 +08:00
for ( i = 0 ; i < keycnt ; i + = chunksize ) {
2019-03-10 06:35:06 +08:00
2019-07-11 19:01:34 +08:00
if ( kbd_enter_pressed ( ) ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( WARNING , " \n aborted via keyboard! \n " ) ;
goto out ;
}
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
uint32_t size = ( ( keycnt - i ) > chunksize ) ? chunksize : keycnt - i ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
// last chunk?
if ( size = = keycnt - i )
lastChunk = true ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
int res = mfCheckKeys_fast ( sectorsCnt , firstChunk , lastChunk , strategy , size , keyBlock + ( i * 6 ) , e_sector , false ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( firstChunk )
firstChunk = false ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
// all keys, aborted
2019-08-29 03:21:27 +08:00
if ( res = = PM3_SUCCESS | | res = = 2 )
2019-03-10 07:00:59 +08:00
goto out ;
} // end chunks of keys
2019-03-10 06:35:06 +08:00
firstChunk = true ;
lastChunk = false ;
} // end strategy
}
2019-03-09 15:59:13 +08:00
out :
2019-03-10 06:35:06 +08:00
t1 = msclock ( ) - t1 ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " Time in checkkeys (fast): %.1fs \n " , ( float ) ( t1 / 1000.0 ) ) ;
2019-03-10 06:35:06 +08:00
// check..
uint8_t found_keys = 0 ;
2019-04-08 02:08:53 +08:00
for ( i = 0 ; i < sectorsCnt ; + + i ) {
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] )
2019-03-10 06:35:06 +08:00
found_keys + + ;
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 1 ] )
2019-03-10 06:35:06 +08:00
found_keys + + ;
}
2019-03-10 07:00:59 +08:00
if ( found_keys = = 0 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " No keys found " ) ;
} else {
2019-03-10 07:00:59 +08:00
printKeyTable ( sectorsCnt , e_sector ) ;
2019-03-10 06:35:06 +08:00
2019-08-30 16:45:52 +08:00
if ( use_flashmemory & & found_keys = = ( sectorsCnt < < 1 ) ) {
PrintAndLogEx ( SUCCESS , " Card dumped aswell. run " _YELLOW_ ( " `%s %c` " ) ,
" hf mf esave " ,
GetFormatFromSector ( sectorsCnt )
) ;
}
2019-08-29 03:21:27 +08:00
2019-03-10 06:35:06 +08:00
if ( transferToEml ) {
2019-05-09 03:54:15 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-03-10 06:35:06 +08:00
uint8_t block [ 16 ] = { 0x00 } ;
2019-04-10 15:36:23 +08:00
for ( i = 0 ; i < sectorsCnt ; + + i ) {
2019-05-01 21:15:48 +08:00
uint8_t blockno = FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 ;
mfEmlGetMem ( block , blockno , 1 ) ;
2019-03-10 06:35:06 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] )
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , block ) ;
if ( e_sector [ i ] . foundKey [ 1 ] )
2019-03-10 07:00:59 +08:00
num_to_bytes ( e_sector [ i ] . Key [ 1 ] , 6 , block + 10 ) ;
2019-05-09 03:54:15 +08:00
if ( i = = sectorsCnt - 1 ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
2019-05-01 21:15:48 +08:00
mfEmlSetMem ( block , blockno , 1 ) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " Found keys have been transferred to the emulator memory " ) ;
2019-08-30 16:45:52 +08:00
if ( found_keys = = ( sectorsCnt < < 1 ) ) {
FastDumpWithEcFill ( sectorsCnt ) ;
}
2019-03-10 06:35:06 +08:00
}
if ( createDumpFile ) {
fptr = GenerateFilename ( " hf-mf- " , " -key.bin " ) ;
2019-08-26 20:29:21 +08:00
createMfcKeyDump ( sectorsCnt , e_sector , fptr ) ;
2019-03-10 06:35:06 +08:00
}
}
free ( keyBlock ) ;
free ( e_sector ) ;
PrintAndLogEx ( NORMAL , " " ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfChk ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 3 | | ctmp = = ' h ' ) return usage_hf14_chk ( ) ;
2019-03-10 07:00:59 +08:00
FILE * f ;
2019-03-10 06:35:06 +08:00
char filename [ FILE_PATH_SIZE ] = { 0 } ;
char buf [ 13 ] ;
2019-03-19 06:59:35 +08:00
uint8_t * keyBlock , * p ;
2019-03-10 06:35:06 +08:00
sector_t * e_sector = NULL ;
uint8_t blockNo = 0 ;
uint8_t SectorsCnt = 1 ;
uint8_t keyType = 0 ;
2019-08-01 05:44:53 +08:00
uint32_t keyitems = ARRAYLEN ( g_mifare_default_keys ) ;
2019-03-10 06:35:06 +08:00
uint64_t key64 = 0 ;
char * fptr ;
int clen = 0 ;
int transferToEml = 0 ;
int createDumpFile = 0 ;
2019-05-01 18:19:51 +08:00
int i , keycnt = 0 ;
2019-03-10 06:35:06 +08:00
2019-08-01 05:44:53 +08:00
keyBlock = calloc ( ARRAYLEN ( g_mifare_default_keys ) , 6 ) ;
2019-05-27 21:15:53 +08:00
if ( keyBlock = = NULL ) return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
2019-08-01 05:44:53 +08:00
for ( int cnt = 0 ; cnt < ARRAYLEN ( g_mifare_default_keys ) ; cnt + + )
2019-03-10 07:00:59 +08:00
num_to_bytes ( g_mifare_default_keys [ cnt ] , 6 , ( uint8_t * ) ( keyBlock + cnt * 6 ) ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( param_getchar ( Cmd , 0 ) = = ' * ' ) {
2019-03-10 06:35:06 +08:00
blockNo = 3 ;
2019-03-10 07:00:59 +08:00
SectorsCnt = NumOfSectors ( param_getchar ( Cmd + 1 , 0 ) ) ;
2019-10-06 07:18:04 +08:00
if ( SectorsCnt = = 0 ) {
free ( keyBlock ) ;
return usage_hf14_chk ( ) ;
}
2019-03-10 06:35:06 +08:00
} else {
blockNo = param_get8 ( Cmd , 0 ) ;
}
ctmp = tolower ( param_getchar ( Cmd , 1 ) ) ;
clen = param_getlength ( Cmd , 1 ) ;
if ( clen = = 1 ) {
switch ( ctmp ) {
2019-03-10 07:00:59 +08:00
case ' a ' :
keyType = 0 ;
break ;
case ' b ' :
keyType = 1 ;
break ;
case ' ? ' :
keyType = 2 ;
break ;
default :
PrintAndLogEx ( FAILED , " Key type must be A , B or ? " ) ;
free ( keyBlock ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
} ;
}
for ( i = 2 ; param_getchar ( Cmd , i ) ; i + + ) {
ctmp = tolower ( param_getchar ( Cmd , i ) ) ;
clen = param_getlength ( Cmd , i ) ;
if ( clen = = 12 ) {
2019-03-10 07:00:59 +08:00
if ( param_gethex ( Cmd , i , keyBlock + 6 * keycnt , 12 ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " not hex, skipping " ) ;
continue ;
}
2019-03-10 07:00:59 +08:00
if ( keyitems - keycnt < 2 ) {
2019-03-10 06:35:06 +08:00
p = realloc ( keyBlock , 6 * ( keyitems + = 64 ) ) ;
if ( ! p ) {
PrintAndLogEx ( FAILED , " cannot allocate memory for Keys " ) ;
free ( keyBlock ) ;
2019-05-27 21:15:53 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
keyBlock = p ;
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " [%2d] key %s " , keycnt , sprint_hex ( ( keyBlock + 6 * keycnt ) , 6 ) ) ; ;
2019-03-10 06:35:06 +08:00
keycnt + + ;
2019-03-10 07:00:59 +08:00
} else if ( clen = = 1 ) {
if ( ctmp = = ' t ' ) { transferToEml = 1 ; continue ; }
if ( ctmp = = ' d ' ) { createDumpFile = 1 ; continue ; }
2019-03-10 06:35:06 +08:00
} else {
// May be a dic file
2019-03-10 07:00:59 +08:00
if ( param_getstr ( Cmd , i , filename , sizeof ( filename ) ) > = FILE_PATH_SIZE ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " File name too long " ) ;
2019-08-26 19:03:11 +08:00
free ( keyBlock ) ;
return PM3_EINVARG ;
2019-03-10 06:35:06 +08:00
}
2019-08-26 19:03:11 +08:00
char * dict_path ;
2019-08-30 15:02:01 +08:00
int res = searchFile ( & dict_path , DICTIONARIES_SUBDIR , filename , " .dic " , false ) ;
2019-08-26 19:03:11 +08:00
if ( res ! = PM3_SUCCESS ) {
free ( keyBlock ) ;
return PM3_EFILE ;
}
f = fopen ( dict_path , " r " ) ;
2019-03-10 07:00:59 +08:00
if ( ! f ) {
2019-08-26 19:03:11 +08:00
PrintAndLogEx ( FAILED , " File: " _YELLOW_ ( " %s " ) " : not found or locked. " , dict_path ) ;
free ( dict_path ) ;
free ( keyBlock ) ;
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
2019-08-26 19:03:11 +08:00
free ( dict_path ) ;
2019-03-10 06:35:06 +08:00
// load keys from dictionary file
2019-03-10 07:00:59 +08:00
while ( fgets ( buf , sizeof ( buf ) , f ) ) {
2019-03-10 06:35:06 +08:00
if ( strlen ( buf ) < 12 | | buf [ 11 ] = = ' \n ' )
continue ;
while ( fgetc ( f ) ! = ' \n ' & & ! feof ( f ) ) ; //goto next line
2019-03-10 07:00:59 +08:00
if ( buf [ 0 ] = = ' # ' ) continue ; //The line start with # is comment, skip
2019-03-10 06:35:06 +08:00
// codesmell, only checks first char?
2019-03-10 07:00:59 +08:00
if ( ! isxdigit ( buf [ 0 ] ) ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( FAILED , " File content error. ' " _YELLOW_ ( " %s " ) " ' must include 12 HEX symbols " , buf ) ;
2019-08-26 19:53:23 +08:00
continue ;
2019-03-10 06:35:06 +08:00
}
buf [ 12 ] = 0 ;
2019-03-10 07:00:59 +08:00
if ( keyitems - keycnt < 2 ) {
2019-03-10 06:35:06 +08:00
p = realloc ( keyBlock , 6 * ( keyitems + = 64 ) ) ;
if ( ! p ) {
PrintAndLogEx ( FAILED , " Cannot allocate memory for defKeys " ) ;
free ( keyBlock ) ;
fclose ( f ) ;
2019-05-27 21:15:53 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
keyBlock = p ;
}
memset ( keyBlock + 6 * keycnt , 0 , 6 ) ;
2019-03-10 07:00:59 +08:00
num_to_bytes ( strtoll ( buf , NULL , 16 ) , 6 , keyBlock + 6 * keycnt ) ;
2019-03-10 06:35:06 +08:00
//PrintAndLogEx(NORMAL, "check key[%2d] %012" PRIx64, keycnt, bytes_to_num(keyBlock + 6*keycnt, 6));
keycnt + + ;
memset ( buf , 0 , sizeof ( buf ) ) ;
}
fclose ( f ) ;
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( SUCCESS , " Loaded %2d keys from " _YELLOW_ ( " %s " ) , keycnt , filename ) ;
2019-03-10 06:35:06 +08:00
}
}
if ( keycnt = = 0 ) {
PrintAndLogEx ( INFO , " No key specified, trying default keys " ) ;
2019-08-01 05:44:53 +08:00
for ( ; keycnt < ARRAYLEN ( g_mifare_default_keys ) ; keycnt + + )
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " [%2d] %02x%02x%02x%02x%02x%02x " , keycnt ,
2019-10-09 20:22:35 +08:00
( keyBlock + 6 * keycnt ) [ 0 ] ,
( keyBlock + 6 * keycnt ) [ 1 ] ,
( keyBlock + 6 * keycnt ) [ 2 ] ,
( keyBlock + 6 * keycnt ) [ 3 ] ,
( keyBlock + 6 * keycnt ) [ 4 ] ,
( keyBlock + 6 * keycnt ) [ 5 ]
2019-10-13 06:48:26 +08:00
) ;
2019-03-10 06:35:06 +08:00
}
// initialize storage for found keys
e_sector = calloc ( SectorsCnt , sizeof ( sector_t ) ) ;
if ( e_sector = = NULL ) {
free ( keyBlock ) ;
2019-05-27 21:15:53 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
// empty e_sector
2019-04-08 02:08:53 +08:00
for ( i = 0 ; i < SectorsCnt ; + + i ) {
2019-03-10 06:35:06 +08:00
e_sector [ i ] . Key [ 0 ] = 0xffffffffffff ;
e_sector [ i ] . Key [ 1 ] = 0xffffffffffff ;
e_sector [ i ] . foundKey [ 0 ] = false ;
e_sector [ i ] . foundKey [ 1 ] = false ;
}
uint8_t trgKeyType = 0 ;
2019-05-01 20:55:14 +08:00
uint16_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt ;
2019-03-10 06:35:06 +08:00
// time
uint64_t t1 = msclock ( ) ;
2019-04-30 04:39:42 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-03-10 06:35:06 +08:00
2019-07-13 23:26:52 +08:00
// clear trace log by first check keys call only
bool clearLog = true ;
2019-03-10 06:35:06 +08:00
// check keys.
2019-03-10 07:00:59 +08:00
for ( trgKeyType = ( keyType = = 2 ) ? 0 : keyType ; trgKeyType < 2 ; ( keyType = = 2 ) ? ( + + trgKeyType ) : ( trgKeyType = 2 ) ) {
2019-03-10 06:35:06 +08:00
int b = blockNo ;
2019-04-08 02:08:53 +08:00
for ( i = 0 ; i < SectorsCnt ; + + i ) {
2019-03-10 06:35:06 +08:00
// skip already found keys.
if ( e_sector [ i ] . foundKey [ trgKeyType ] ) continue ;
2019-05-01 19:15:51 +08:00
for ( uint16_t c = 0 ; c < keycnt ; c + = max_keys ) {
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-07-11 19:01:34 +08:00
if ( kbd_enter_pressed ( ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " \n aborted via keyboard! \n " ) ;
goto out ;
}
2019-05-01 19:15:51 +08:00
uint16_t size = keycnt - c > max_keys ? max_keys : keycnt - c ;
2019-03-10 06:35:06 +08:00
2019-07-13 23:26:52 +08:00
if ( mfCheckKeys ( b , trgKeyType , clearLog , size , & keyBlock [ 6 * c ] , & key64 ) = = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
e_sector [ i ] . Key [ trgKeyType ] = key64 ;
e_sector [ i ] . foundKey [ trgKeyType ] = true ;
2019-07-13 23:26:52 +08:00
clearLog = false ;
2019-03-10 06:35:06 +08:00
break ;
}
2019-07-13 23:26:52 +08:00
clearLog = false ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
b < 127 ? ( b + = 4 ) : ( b + = 16 ) ;
2019-03-10 06:35:06 +08:00
}
}
t1 = msclock ( ) - t1 ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " \n Time in checkkeys: %.0f seconds \n " , ( float ) t1 / 1000.0 ) ;
2019-03-10 06:35:06 +08:00
// 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
2019-03-10 07:00:59 +08:00
if ( keyType ! = 1 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " testing to read key B... " ) ;
for ( i = 0 ; i < SectorsCnt ; i + + ) {
// KEY A but not KEY B
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] & & ! e_sector [ i ] . foundKey [ 1 ] ) {
2019-03-10 06:35:06 +08:00
uint8_t sectrail = ( FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 ) ;
PrintAndLogEx ( NORMAL , " Reading block %d " , sectrail ) ;
2019-05-29 01:20:56 +08:00
mf_readblock_t payload ;
payload . blockno = sectrail ;
payload . keytype = 0 ;
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , payload . key ) ; // KEY A
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_READBL , ( uint8_t * ) & payload , sizeof ( mf_readblock_t ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
if ( ! WaitForResponseTimeout ( CMD_HF_MIFARE_READBL , & resp , 1500 ) ) continue ;
2019-03-10 06:35:06 +08:00
2019-05-29 01:20:56 +08:00
if ( resp . status ! = PM3_SUCCESS ) continue ;
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
uint8_t * data = resp . data . asBytes ;
2019-03-10 07:00:59 +08:00
key64 = bytes_to_num ( data + 10 , 6 ) ;
2019-03-10 06:35:06 +08:00
if ( key64 ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " Data:%s " , sprint_hex ( data + 10 , 6 ) ) ;
2019-03-10 06:35:06 +08:00
e_sector [ i ] . foundKey [ 1 ] = 1 ;
e_sector [ i ] . Key [ 1 ] = key64 ;
}
}
}
}
2019-03-09 15:49:41 +08:00
out :
2019-03-10 06:35:06 +08:00
//print keys
2019-03-10 07:00:59 +08:00
printKeyTable ( SectorsCnt , e_sector ) ;
2019-03-10 06:35:06 +08:00
if ( transferToEml ) {
2019-05-09 03:54:15 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-03-10 06:35:06 +08:00
uint8_t block [ 16 ] = { 0x00 } ;
2019-04-08 02:08:53 +08:00
for ( i = 0 ; i < SectorsCnt ; + + i ) {
2019-05-01 21:15:48 +08:00
uint8_t blockno = FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 ;
mfEmlGetMem ( block , blockno , 1 ) ;
2019-03-10 06:35:06 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] )
num_to_bytes ( e_sector [ i ] . Key [ 0 ] , 6 , block ) ;
if ( e_sector [ i ] . foundKey [ 1 ] )
2019-03-10 07:00:59 +08:00
num_to_bytes ( e_sector [ i ] . Key [ 1 ] , 6 , block + 10 ) ;
2019-05-09 03:54:15 +08:00
if ( i = = SectorsCnt - 1 ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
2019-05-01 21:15:48 +08:00
mfEmlSetMem ( block , blockno , 1 ) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " Found keys have been transferred to the emulator memory " ) ;
}
if ( createDumpFile ) {
fptr = GenerateFilename ( " hf-mf- " , " -key.bin " ) ;
2019-08-26 20:29:21 +08:00
createMfcKeyDump ( SectorsCnt , e_sector , fptr ) ;
2019-03-10 06:35:06 +08:00
}
free ( keyBlock ) ;
free ( e_sector ) ;
2019-10-10 04:29:42 +08:00
// Disable fast mode and send a dummy command to make it effective
conn . block_after_ACK = false ;
SendCommandNG ( CMD_PING , NULL , 0 ) ;
if ( ! WaitForResponseTimeout ( CMD_PING , NULL , 1000 ) ) {
PrintAndLogEx ( WARNING , " command execution time out " ) ;
return PM3_ETIMEOUT ;
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
sector_t * k_sector = NULL ;
uint8_t k_sectorsCount = 16 ;
2019-03-10 18:20:22 +08:00
static void emptySectorTable ( ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
// initialize storage for found keys
if ( k_sector = = NULL )
k_sector = calloc ( k_sectorsCount , sizeof ( sector_t ) ) ;
if ( k_sector = = NULL )
return ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// empty e_sector
2019-03-10 07:00:59 +08:00
for ( int i = 0 ; i < k_sectorsCount ; + + i ) {
2019-03-10 06:35:06 +08:00
k_sector [ i ] . Key [ 0 ] = 0xffffffffffff ;
k_sector [ i ] . Key [ 1 ] = 0xffffffffffff ;
k_sector [ i ] . foundKey [ 0 ] = false ;
k_sector [ i ] . foundKey [ 1 ] = false ;
}
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void showSectorTable ( ) {
2019-03-10 06:35:06 +08:00
if ( k_sector ! = NULL ) {
printKeyTable ( k_sectorsCount , k_sector ) ;
free ( k_sector ) ;
k_sector = NULL ;
}
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
void readerAttack ( nonces_t data , bool setEmulatorMem , bool verbose ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
uint64_t key = 0 ;
bool success = false ;
if ( k_sector = = NULL )
emptySectorTable ( ) ;
2019-10-17 15:27:55 +08:00
success = mfkey32_moebius ( & data , & key ) ;
2019-03-10 06:35:06 +08:00
if ( success ) {
uint8_t sector = data . sector ;
uint8_t keytype = data . keytype ;
PrintAndLogEx ( INFO , " Reader is trying authenticate with: Key %s, sector %02d: [%012 " PRIx64 " ] "
2019-03-10 07:00:59 +08:00
, keytype ? " B " : " A "
, sector
, key
) ;
2019-03-10 06:35:06 +08:00
k_sector [ sector ] . Key [ keytype ] = key ;
k_sector [ sector ] . foundKey [ keytype ] = true ;
//set emulator memory for keys
if ( setEmulatorMem ) {
2019-03-10 07:00:59 +08:00
uint8_t memBlock [ 16 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0xff , 0x0F , 0x80 , 0x69 , 0 , 0 , 0 , 0 , 0 , 0 } ;
num_to_bytes ( k_sector [ sector ] . Key [ 0 ] , 6 , memBlock ) ;
num_to_bytes ( k_sector [ sector ] . Key [ 1 ] , 6 , memBlock + 10 ) ;
2019-03-10 06:35:06 +08:00
//iceman, guessing this will not work so well for 4K tags.
PrintAndLogEx ( INFO , " Setting Emulator Memory Block %02d: [%s] "
2019-03-10 07:00:59 +08:00
, ( sector * 4 ) + 3
, sprint_hex ( memBlock , sizeof ( memBlock ) )
) ;
mfEmlSetMem ( memBlock , ( sector * 4 ) + 3 , 1 ) ;
2019-03-10 06:35:06 +08:00
}
}
2019-03-09 15:49:41 +08:00
}
2019-04-18 02:36:10 +08:00
static int CmdHF14AMfSim ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
uint8_t uid [ 10 ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2019-08-07 07:32:37 +08:00
uint8_t atqa [ 2 ] = { 0 , 0 } ;
int atqalen = 0 ;
uint8_t sak [ 1 ] = { 0 } ;
int saklen = 0 ;
2019-03-10 06:35:06 +08:00
uint8_t exitAfterNReads = 0 ;
2019-04-17 04:52:05 +08:00
uint16_t flags = 0 ;
2019-03-10 06:35:06 +08:00
int uidlen = 0 ;
uint8_t cmdp = 0 ;
bool errors = false , verbose = false , setEmulatorMem = false ;
nonces_t data [ 1 ] ;
2019-04-25 22:57:18 +08:00
char csize [ 13 ] = { 0 } ;
char uidsize [ 8 ] = { 0 } ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 & & ! errors ) {
switch ( tolower ( param_getchar ( Cmd , cmdp ) ) ) {
case ' e ' :
setEmulatorMem = true ;
cmdp + + ;
break ;
case ' h ' :
2019-04-18 02:36:10 +08:00
return usage_hf14_mfsim ( ) ;
2019-03-10 07:00:59 +08:00
case ' i ' :
flags | = FLAG_INTERACTIVE ;
cmdp + + ;
break ;
case ' n ' :
exitAfterNReads = param_get8 ( Cmd , cmdp + 1 ) ;
cmdp + = 2 ;
break ;
2019-03-16 04:04:25 +08:00
case ' t ' :
switch ( param_get8 ( Cmd , cmdp + 1 ) ) {
case 0 :
flags | = FLAG_MF_MINI ;
2019-04-25 22:57:18 +08:00
sprintf ( csize , " MINI " ) ;
2019-03-16 04:04:25 +08:00
break ;
2019-08-07 07:32:37 +08:00
case 1 :
flags | = FLAG_MF_1K ;
sprintf ( csize , " 1K " ) ;
break ;
2019-03-16 04:04:25 +08:00
case 2 :
flags | = FLAG_MF_2K ;
2019-04-25 22:57:18 +08:00
sprintf ( csize , " 2K with RATS " ) ;
2019-03-16 04:04:25 +08:00
break ;
case 4 :
flags | = FLAG_MF_4K ;
2019-04-25 22:57:18 +08:00
sprintf ( csize , " 4K " ) ;
2019-03-16 04:04:25 +08:00
break ;
default :
2019-08-07 07:32:37 +08:00
PrintAndLogEx ( WARNING , " Unknown parameter for option t " ) ;
errors = true ;
2019-03-16 04:04:25 +08:00
break ;
}
cmdp + = 2 ;
break ;
2019-08-07 07:32:37 +08:00
case ' a ' :
param_gethex_ex ( Cmd , cmdp + 1 , atqa , & atqalen ) ;
if ( atqalen > > 1 ! = 2 ) {
PrintAndLogEx ( WARNING , " Wrong ATQA length " ) ;
errors = true ;
break ;
}
flags | = FLAG_FORCED_ATQA ;
cmdp + = 2 ;
break ;
case ' s ' :
param_gethex_ex ( Cmd , cmdp + 1 , sak , & saklen ) ;
if ( saklen > > 1 ! = 1 ) {
PrintAndLogEx ( WARNING , " Wrong SAK length " ) ;
errors = true ;
break ;
}
flags | = FLAG_FORCED_SAK ;
cmdp + = 2 ;
break ;
2019-03-10 07:00:59 +08:00
case ' u ' :
param_gethex_ex ( Cmd , cmdp + 1 , uid , & uidlen ) ;
2019-05-27 01:42:27 +08:00
uidlen > > = 1 ;
2019-03-10 07:00:59 +08:00
switch ( uidlen ) {
2019-05-27 01:42:27 +08:00
case 10 :
2019-04-17 04:52:05 +08:00
flags | = FLAG_10B_UID_IN_DATA ;
2019-04-25 22:57:18 +08:00
sprintf ( uidsize , " 10 byte " ) ;
2019-03-10 07:00:59 +08:00
break ;
2019-05-27 01:42:27 +08:00
case 7 :
2019-04-17 04:52:05 +08:00
flags | = FLAG_7B_UID_IN_DATA ;
2019-04-25 22:57:18 +08:00
sprintf ( uidsize , " 7 byte " ) ;
2019-03-10 07:00:59 +08:00
break ;
2019-05-27 01:42:27 +08:00
case 4 :
2019-04-17 04:52:05 +08:00
flags | = FLAG_4B_UID_IN_DATA ;
2019-04-25 22:57:18 +08:00
sprintf ( uidsize , " 4 byte " ) ;
2019-03-10 07:00:59 +08:00
break ;
default :
2019-04-18 02:36:10 +08:00
return usage_hf14_mfsim ( ) ;
2019-03-10 07:00:59 +08:00
}
cmdp + = 2 ;
break ;
case ' v ' :
verbose = true ;
cmdp + + ;
break ;
case ' x ' :
flags | = FLAG_NR_AR_ATTACK ;
cmdp + + ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' " , param_getchar ( Cmd , cmdp ) ) ;
errors = true ;
break ;
2019-03-10 06:35:06 +08:00
}
}
//Validations
2019-04-18 02:36:10 +08:00
if ( errors ) return usage_hf14_mfsim ( ) ;
2019-03-10 06:35:06 +08:00
2019-04-17 04:52:05 +08:00
// Use UID, SAK, ATQA from EMUL, if uid not defined
2019-04-25 22:57:18 +08:00
if ( ( flags & ( FLAG_4B_UID_IN_DATA | FLAG_7B_UID_IN_DATA | FLAG_10B_UID_IN_DATA ) ) = = 0 ) {
2019-04-17 04:52:05 +08:00
flags | = FLAG_UID_IN_EMUL ;
2019-04-25 22:57:18 +08:00
}
2019-03-10 06:35:06 +08:00
2019-04-25 22:57:18 +08:00
PrintAndLogEx ( INFO , _YELLOW_ ( " Mifare %s " ) " | %s UID " _YELLOW_ ( " %s " ) " "
, csize
, uidsize
2019-05-27 01:42:27 +08:00
, ( uidlen = = 0 ) ? " N/A " : sprint_hex ( uid , uidlen )
2019-04-28 17:09:46 +08:00
) ;
2019-04-25 22:57:18 +08:00
PrintAndLogEx ( INFO , " Options [ numreads: %d, flags: %d (0x%02x) ] "
2019-03-10 07:00:59 +08:00
, exitAfterNReads
, flags
, flags ) ;
2019-03-10 06:35:06 +08:00
2019-05-27 01:42:27 +08:00
struct {
2019-06-08 03:40:33 +08:00
uint16_t flags ;
uint8_t exitAfter ;
uint8_t uid [ 10 ] ;
2019-08-07 07:32:37 +08:00
uint16_t atqa ;
uint8_t sak ;
2019-05-27 01:42:27 +08:00
} PACKED payload ;
2019-06-08 03:40:33 +08:00
2019-05-27 01:42:27 +08:00
payload . flags = flags ;
payload . exitAfter = exitAfterNReads ;
memcpy ( payload . uid , uid , uidlen ) ;
2019-08-07 07:32:37 +08:00
payload . atqa = ( atqa [ 1 ] < < 8 ) | atqa [ 0 ] ;
payload . sak = sak [ 0 ] ;
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_SIMULATE , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( flags & FLAG_INTERACTIVE ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " Press pm3-button or send another cmd to abort simulation " ) ;
2019-07-11 19:01:34 +08:00
while ( ! kbd_enter_pressed ( ) ) {
2019-03-10 07:00:59 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & resp , 1500 ) ) continue ;
if ( ! ( flags & FLAG_NR_AR_ATTACK ) ) break ;
2019-08-04 01:17:00 +08:00
if ( ( resp . oldarg [ 0 ] & 0xffff ) ! = CMD_HF_MIFARE_SIMULATE ) break ;
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
memcpy ( data , resp . data . asBytes , sizeof ( data ) ) ;
2019-03-10 06:35:06 +08:00
readerAttack ( data [ 0 ] , setEmulatorMem , verbose ) ;
}
showSectorTable ( ) ;
}
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
/*
static int CmdHF14AMfSniff ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
bool wantLogToFile = false ;
bool wantDecrypt = false ;
//bool wantSaveToEml = false; TODO
bool wantSaveToEmlFile = false ;
//var
int res = 0 , len = 0 , blockLen = 0 ;
int pckNum = 0 , num = 0 ;
uint8_t sak = 0 ;
uint8_t uid [ 10 ] ;
uint8_t uid_len = 0 ;
uint8_t atqa [ 2 ] = { 0x00 , 0x00 } ;
bool isTag = false ;
uint8_t * buf = NULL ;
uint16_t bufsize = 0 ;
uint8_t * bufPtr = NULL ;
uint16_t traceLen = 0 ;
memset ( uid , 0x00 , sizeof ( uid ) ) ;
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( ctmp = = ' h ' ) return usage_hf14_sniff ( ) ;
2019-03-10 06:35:06 +08:00
for ( int i = 0 ; i < 4 ; i + + ) {
ctmp = tolower ( param_getchar ( Cmd , i ) ) ;
if ( ctmp = = ' l ' ) wantLogToFile = true ;
if ( ctmp = = ' d ' ) wantDecrypt = true ;
//if (ctmp == 'e') wantSaveToEml = true; TODO
if ( ctmp = = ' f ' ) wantSaveToEmlFile = true ;
}
PrintAndLogEx ( NORMAL , " ------------------------------------------------------------------------- \n " ) ;
PrintAndLogEx ( NORMAL , " Executing mifare sniffing command. \n " ) ;
2019-07-11 19:01:34 +08:00
PrintAndLogEx ( NORMAL , " Press the button on the Proxmark3 device to abort both Proxmark3 and client. \n " ) ;
PrintAndLogEx ( NORMAL , " Press Enter to abort the client. \n " ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " ------------------------------------------------------------------------- \n " ) ;
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_SNIFF , NULL , 0 ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
// wait cycle
while ( true ) {
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-07-11 19:01:34 +08:00
if ( kbd_enter_pressed ( ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " \n aborted via keyboard! \n " ) ;
break ;
}
2019-03-10 07:00:59 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & resp , 2000 ) ) {
2019-03-10 06:35:06 +08:00
continue ;
}
2019-04-18 05:44:48 +08:00
res = resp . oldarg [ 0 ] & 0xff ;
traceLen = resp . oldarg [ 1 ] ;
len = resp . oldarg [ 2 ] ;
2019-03-10 06:35:06 +08:00
if ( res = = 0 ) {
PrintAndLogEx ( SUCCESS , " hf mifare sniff finished " ) ;
free ( buf ) ;
return 0 ;
}
if ( res = = 1 ) { // there is (more) data to be transferred
if ( pckNum = = 0 ) { // first packet, (re)allocate necessary buffer
if ( traceLen > bufsize | | buf = = NULL ) {
uint8_t * p ;
if ( buf = = NULL ) // not yet allocated
p = calloc ( traceLen , sizeof ( uint8_t ) ) ;
else // need more memory
p = realloc ( buf , traceLen ) ;
if ( p = = NULL ) {
PrintAndLogEx ( FAILED , " Cannot allocate memory for trace " ) ;
free ( buf ) ;
return 2 ;
}
buf = p ;
}
bufPtr = buf ;
bufsize = traceLen ;
memset ( buf , 0x00 , traceLen ) ;
}
// what happens if LEN is bigger then TRACELEN --iceman
2019-04-18 05:44:48 +08:00
memcpy ( bufPtr , resp . data . asBytes , len ) ;
2019-03-10 06:35:06 +08:00
bufPtr + = len ;
pckNum + + ;
}
if ( res = = 2 ) { // received all data, start displaying
blockLen = bufPtr - buf ;
bufPtr = buf ;
PrintAndLogEx ( NORMAL , " > \n " ) ;
PrintAndLogEx ( SUCCESS , " received trace len: %d packages: %d " , blockLen , pckNum ) ;
while ( bufPtr - buf < blockLen ) {
bufPtr + = 6 ; // skip (void) timing information
len = * ( ( uint16_t * ) bufPtr ) ;
2019-03-10 07:00:59 +08:00
if ( len & 0x8000 ) {
2019-03-10 06:35:06 +08:00
isTag = true ;
len & = 0x7fff ;
} else {
isTag = false ;
}
bufPtr + = 2 ;
// the uid identification package
// 0xFF 0xFF xx xx xx xx xx xx xx xx xx xx aa aa cc 0xFF 0xFF
// x = uid, a = atqa, c = sak
if ( ( len = = 17 ) & & ( bufPtr [ 0 ] = = 0xff ) & & ( bufPtr [ 1 ] = = 0xff ) & & ( bufPtr [ 15 ] = = 0xff ) & & ( bufPtr [ 16 ] = = 0xff ) ) {
memcpy ( uid , bufPtr + 2 , 10 ) ;
memcpy ( atqa , bufPtr + 2 + 10 , 2 ) ;
switch ( atqa [ 0 ] & 0xC0 ) {
2019-03-10 07:00:59 +08:00
case 0x80 :
uid_len = 10 ;
break ;
case 0x40 :
uid_len = 7 ;
break ;
default :
uid_len = 4 ;
break ;
2019-03-10 06:35:06 +08:00
}
sak = bufPtr [ 14 ] ;
PrintAndLogEx ( SUCCESS , " UID %s | ATQA %02x %02x | SAK 0x%02x " ,
2019-03-10 07:00:59 +08:00
sprint_hex ( uid , uid_len ) ,
atqa [ 1 ] ,
atqa [ 0 ] ,
sak ) ;
2019-03-10 06:35:06 +08:00
if ( wantLogToFile | | wantDecrypt ) {
FillFileNameByUID ( logHexFileName , uid , " .log " , uid_len ) ;
AddLogCurrentDT ( logHexFileName ) ;
PrintAndLogEx ( SUCCESS , " Trace saved to %s " , logHexFileName ) ;
}
if ( wantDecrypt )
mfTraceInit ( uid , uid_len , atqa , sak , wantSaveToEmlFile ) ;
} else {
PrintAndLogEx ( NORMAL , " %03d| %s |%s " , num , isTag ? " TAG " : " RDR " , sprint_hex ( bufPtr , len ) ) ;
if ( wantLogToFile )
2019-03-10 07:00:59 +08:00
AddLogHex ( logHexFileName , isTag ? " TAG| " : " RDR| " , bufPtr , len ) ;
2019-03-10 06:35:06 +08:00
if ( wantDecrypt )
mfTraceDecode ( bufPtr , len , wantSaveToEmlFile ) ;
num + + ;
}
bufPtr + = len ;
2019-03-10 07:00:59 +08:00
bufPtr + = ( ( len - 1 ) / 8 + 1 ) ; // ignore parity
2019-03-10 06:35:06 +08:00
}
pckNum = 0 ;
}
} // while (true)
free ( buf ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
*/
2019-09-08 18:57:25 +08:00
/*
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfKeyBrute ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
uint8_t blockNo = 0 , keytype = 0 ;
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
uint64_t foundkey = 0 ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
char cmdp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( cmdp = = ' h ' ) return usage_hf14_keybrute ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// block number
blockNo = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// keytype
cmdp = tolower ( param_getchar ( Cmd , 1 ) ) ;
2019-03-10 07:00:59 +08:00
if ( cmdp = = ' b ' ) keytype = 1 ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// key
if ( param_gethex ( Cmd , 2 , key , 12 ) ) return usage_hf14_keybrute ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
uint64_t t1 = msclock ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( mfKeyBrute ( blockNo , keytype , key , & foundkey ) )
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( SUCCESS , " found valid key: %012 " PRIx64 " \n " , foundkey ) ;
else
PrintAndLogEx ( FAILED , " key not found " ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
t1 = msclock ( ) - t1 ;
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " \n time in keybrute: %.0f seconds \n " , ( float ) t1 / 1000.0 ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-09-08 18:57:25 +08:00
*/
2019-03-09 15:49:41 +08:00
2019-03-10 18:20:22 +08:00
void printKeyTable ( uint8_t sectorscnt , sector_t * e_sector ) {
2019-03-10 07:00:59 +08:00
char strA [ 12 + 1 ] = { 0 } ;
char strB [ 12 + 1 ] = { 0 } ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
PrintAndLogEx ( NORMAL , " |sec|key A |res|key B |res| " ) ;
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
for ( uint8_t i = 0 ; i < sectorscnt ; + + i ) {
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
snprintf ( strA , sizeof ( strA ) , " ------------ " ) ;
snprintf ( strB , sizeof ( strB ) , " ------------ " ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 0 ] )
2019-03-10 06:35:06 +08:00
snprintf ( strA , sizeof ( strA ) , " %012 " PRIx64 , e_sector [ i ] . Key [ 0 ] ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( e_sector [ i ] . foundKey [ 1 ] )
2019-03-10 06:35:06 +08:00
snprintf ( strB , sizeof ( strB ) , " %012 " PRIx64 , e_sector [ i ] . Key [ 1 ] ) ;
2019-03-09 15:49:41 +08:00
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " |%03d| %s | %d | %s | %d | "
2019-03-10 07:00:59 +08:00
, i
, strA , e_sector [ i ] . foundKey [ 0 ]
, strB , e_sector [ i ] . foundKey [ 1 ]
) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " |---|----------------|---|----------------|---| " ) ;
2019-03-09 15:49:41 +08:00
}
2019-09-08 18:57:25 +08:00
2019-03-09 15:49:41 +08:00
// EMULATOR COMMANDS
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfEGet ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 1 | | c = = ' h ' ) return usage_hf14_eget ( ) ;
2019-03-09 15:59:13 +08:00
2019-05-27 19:46:27 +08:00
uint8_t data [ 16 ] = { 0x00 } ;
uint8_t blockNo = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " " ) ;
2019-05-27 19:46:27 +08:00
if ( mfEmlGetMem ( data , blockNo , 1 ) = = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " data[%3d]:%s " , blockNo , sprint_hex ( data , sizeof ( data ) ) ) ;
}
2019-05-27 19:46:27 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfEClear ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( c = = ' h ' ) return usage_hf14_eclr ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_EML_MEMCLR , NULL , 0 ) ;
2019-05-27 19:46:27 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfESet ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 3 | | c = = ' h ' )
return usage_hf14_eset ( ) ;
2019-06-08 03:40:33 +08:00
2019-05-27 19:46:27 +08:00
uint8_t memBlock [ 16 ] ;
memset ( memBlock , 0x00 , sizeof ( memBlock ) ) ;
2019-03-09 15:59:13 +08:00
2019-05-27 19:46:27 +08:00
uint8_t blockNo = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( param_gethex ( Cmd , 1 , memBlock , 32 ) ) {
PrintAndLogEx ( WARNING , " block data must include 32 HEX symbols " ) ;
2019-05-27 19:46:27 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// 1 - blocks count
return mfEmlSetMem ( memBlock , blockNo , 1 ) ;
2019-03-09 15:49:41 +08:00
}
2019-03-10 18:20:22 +08:00
int CmdHF14AMfELoad ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
size_t counter = 0 ;
char filename [ FILE_PATH_SIZE ] ;
int blockNum , numBlocks , nameParamNo = 1 ;
uint8_t blockWidth = 16 ;
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( strlen ( Cmd ) < 2 & & c = = ' h ' )
2019-03-10 06:35:06 +08:00
return usage_hf14_eload ( ) ;
switch ( c ) {
2019-03-10 07:00:59 +08:00
case ' 0 ' :
numBlocks = MIFARE_MINI_MAXBLOCK ;
break ;
2019-03-10 06:35:06 +08:00
case ' 1 ' :
2019-03-10 07:00:59 +08:00
case ' \0 ' :
numBlocks = MIFARE_1K_MAXBLOCK ;
break ;
case ' 2 ' :
numBlocks = MIFARE_2K_MAXBLOCK ;
break ;
case ' 4 ' :
numBlocks = MIFARE_4K_MAXBLOCK ;
break ;
case ' u ' :
numBlocks = 255 ;
blockWidth = 4 ;
break ;
2019-03-10 06:35:06 +08:00
default : {
numBlocks = MIFARE_1K_MAXBLOCK ;
nameParamNo = 0 ;
}
}
uint32_t numblk2 = param_get32ex ( Cmd , 2 , 0 , 10 ) ;
if ( numblk2 > 0 )
numBlocks = numblk2 ;
2019-04-29 04:16:50 +08:00
if ( 0 = = param_getstr ( Cmd , nameParamNo , filename , sizeof ( filename ) ) )
return usage_hf14_eload ( ) ;
2019-03-10 06:35:06 +08:00
uint8_t * data = calloc ( 4096 , sizeof ( uint8_t ) ) ;
size_t datalen = 0 ;
2019-04-29 01:21:04 +08:00
//int res = loadFile(filename, ".bin", data, maxdatalen, &datalen);
int res = loadFileEML ( filename , data , & datalen ) ;
2019-03-10 07:00:59 +08:00
if ( res ) {
2019-03-10 06:35:06 +08:00
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
// 64 or 256 blocks.
2019-03-10 07:00:59 +08:00
if ( ( datalen % blockWidth ) ! = 0 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " File content error. Size doesn't match blockwidth " ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-04-23 22:07:20 +08:00
// convert old mfu format to new
if ( blockWidth = = 4 ) {
res = convertOldMfuDump ( & data , & datalen ) ;
if ( res ) {
PrintAndLogEx ( FAILED , " Failed convert on load to new Ultralight/NTAG format " ) ;
free ( data ) ;
return res ;
}
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " Copying to emulator memory " ) ;
2019-05-09 03:54:15 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-03-10 06:35:06 +08:00
blockNum = 0 ;
2019-03-10 07:00:59 +08:00
while ( datalen ) {
2019-05-09 03:54:15 +08:00
if ( datalen = = blockWidth ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
2019-03-10 06:35:06 +08:00
2019-06-01 02:07:07 +08:00
if ( mfEmlSetMem_xt ( data + counter , blockNum , 1 , blockWidth ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( FAILED , " Cant set emul block: %3d " , blockNum ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-10 06:35:06 +08:00
blockNum + + ;
counter + = blockWidth ;
datalen - = blockWidth ;
}
PrintAndLogEx ( NORMAL , " \n " ) ;
// Ultralight /Ntag
2019-03-10 07:00:59 +08:00
if ( blockWidth = = 4 ) {
2019-03-10 06:35:06 +08:00
if ( ( blockNum ! = numBlocks ) ) {
PrintAndLogEx ( FAILED , " Warning, Ultralight/Ntag file content, Loaded %d blocks into emulator memory " , blockNum ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
} else {
if ( ( blockNum ! = numBlocks ) ) {
PrintAndLogEx ( FAILED , " Error, file content, Only loaded %d blocks, must be %d blocks into emulator memory " , blockNum , numBlocks ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( SUCCESS , " Loaded %d blocks from file: " _YELLOW_ ( " %s " ) , blockNum , filename ) ;
2019-03-10 06:35:06 +08:00
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfESave ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char filename [ FILE_PATH_SIZE ] ;
2019-03-10 07:00:59 +08:00
char * fnameptr = filename ;
2019-03-10 06:35:06 +08:00
uint8_t * dump ;
int len , bytes , nameParamNo = 1 ;
uint16_t blocks ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
memset ( filename , 0 , sizeof ( filename ) ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( c = = ' h ' ) return usage_hf14_esave ( ) ;
2019-03-09 15:49:41 +08:00
2019-04-29 03:34:05 +08:00
if ( c ! = 0 ) {
blocks = NumOfBlocks ( c ) ;
if ( blocks = = 0 ) return usage_hf14_esave ( ) ;
} else {
blocks = MIFARE_1K_MAXBLOCK ;
}
2019-03-10 06:35:06 +08:00
bytes = blocks * MFBLOCK_SIZE ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
dump = calloc ( bytes , sizeof ( uint8_t ) ) ;
if ( ! dump ) {
PrintAndLogEx ( WARNING , " Fail, cannot allocate memory " ) ;
2019-05-27 21:15:53 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
memset ( dump , 0 , bytes ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " downloading from emulator memory " ) ;
2019-07-24 03:33:52 +08:00
if ( ! GetFromDevice ( BIG_BUF_EML , dump , bytes , 0 , NULL , 0 , NULL , 2500 , false ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Fail, transfer from device time-out " ) ;
free ( dump ) ;
2019-05-27 21:15:53 +08:00
return PM3_ETIMEOUT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
len = param_getstr ( Cmd , nameParamNo , filename , sizeof ( filename ) ) ;
if ( len > FILE_PATH_SIZE - 5 ) len = FILE_PATH_SIZE - 5 ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
// user supplied filename?
if ( len < 1 ) {
fnameptr + = sprintf ( fnameptr , " hf-mf- " ) ;
FillFileNameByUID ( fnameptr , dump , " -dump " , 4 ) ;
}
2019-03-09 15:59:13 +08:00
2019-04-29 02:42:57 +08:00
saveFile ( filename , " .bin " , dump , bytes ) ;
saveFileEML ( filename , dump , bytes , MFBLOCK_SIZE ) ;
saveFileJSON ( filename , jsfCardMemory , dump , bytes ) ;
2019-03-10 06:35:06 +08:00
free ( dump ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfECFill ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t keyType = 0 ;
uint8_t numSectors = 16 ;
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( strlen ( Cmd ) < 1 | | c = = ' h ' )
return usage_hf14_ecfill ( ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
if ( c ! = ' a ' & & c ! = ' b ' ) {
PrintAndLogEx ( WARNING , " Key type must be A or B " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( c ! = ' a ' )
keyType = 1 ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
c = tolower ( param_getchar ( Cmd , 1 ) ) ;
2019-04-29 03:34:05 +08:00
if ( c ! = 0 ) {
numSectors = NumOfSectors ( c ) ;
if ( numSectors = = 0 ) return usage_hf14_ecfill ( ) ;
} else {
numSectors = MIFARE_1K_MAXSECTOR ;
}
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " --params: numSectors: %d, keyType: %c \n " , numSectors , ( keyType = = 0 ) ? ' A ' : ' B ' ) ;
2019-08-29 03:21:27 +08:00
mfc_eload_t payload ;
2019-08-30 16:45:52 +08:00
payload . sectorcnt = numSectors ;
payload . keytype = keyType ;
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-30 16:45:52 +08:00
SendCommandNG ( CMD_HF_MIFARE_EML_LOAD , ( uint8_t * ) & payload , sizeof ( payload ) ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfEKeyPrn ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
int i ;
uint8_t numSectors ;
uint8_t data [ 16 ] ;
char c = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( c = = ' h ' )
2019-03-10 06:35:06 +08:00
return usage_hf14_ekeyprn ( ) ;
2019-04-29 03:34:05 +08:00
if ( c ! = 0 ) {
numSectors = NumOfSectors ( c ) ;
if ( numSectors = = 0 ) return usage_hf14_ekeyprn ( ) ;
} else {
numSectors = MIFARE_1K_MAXSECTOR ;
}
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " |---|----------------|----------------| " ) ;
PrintAndLogEx ( NORMAL , " |sec|key A |key B | " ) ;
PrintAndLogEx ( NORMAL , " |---|----------------|----------------| " ) ;
for ( i = 0 ; i < numSectors ; i + + ) {
2019-05-27 21:15:53 +08:00
if ( mfEmlGetMem ( data , FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 , 1 ) ! = PM3_SUCCESS ) {
2019-07-14 18:17:34 +08:00
PrintAndLogEx ( WARNING , " error get block %d " , FirstBlockOfSector ( i ) + NumBlocksPerSector ( i ) - 1 ) ;
2019-03-10 06:35:06 +08:00
break ;
}
2019-06-08 00:41:39 +08:00
uint64_t keyA = bytes_to_num ( data , 6 ) ;
uint64_t keyB = bytes_to_num ( data + 10 , 6 ) ;
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " |%03d| %012 " PRIx64 " | %012 " PRIx64 " | " , i , keyA , keyB ) ;
}
PrintAndLogEx ( NORMAL , " |---|----------------|----------------| " ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-03-09 15:59:13 +08:00
// CHINESE MAGIC COMMANDS
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCSetUID ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t wipeCard = 0 ;
uint8_t uid [ 8 ] = { 0x00 } ;
uint8_t oldUid [ 8 ] = { 0x00 } ;
uint8_t atqa [ 2 ] = { 0x00 } ;
uint8_t sak [ 1 ] = { 0x00 } ;
uint8_t atqaPresent = 1 ;
int res , argi = 0 ;
char ctmp ;
if ( strlen ( Cmd ) < 1 | | param_getchar ( Cmd , argi ) = = ' h ' )
return usage_hf14_csetuid ( ) ;
if ( param_getchar ( Cmd , argi ) & & param_gethex ( Cmd , argi , uid , 8 ) )
return usage_hf14_csetuid ( ) ;
argi + + ;
ctmp = tolower ( param_getchar ( Cmd , argi ) ) ;
if ( ctmp = = ' w ' ) {
wipeCard = 1 ;
atqaPresent = 0 ;
}
if ( atqaPresent ) {
if ( param_getchar ( Cmd , argi ) ) {
if ( param_gethex ( Cmd , argi , atqa , 4 ) ) {
PrintAndLogEx ( WARNING , " ATQA must include 4 HEX symbols " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
argi + + ;
if ( ! param_getchar ( Cmd , argi ) | | param_gethex ( Cmd , argi , sak , 2 ) ) {
PrintAndLogEx ( WARNING , " SAK must include 2 HEX symbols " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
argi + + ;
} else
atqaPresent = 0 ;
}
if ( ! wipeCard ) {
ctmp = tolower ( param_getchar ( Cmd , argi ) ) ;
if ( ctmp = = ' w ' ) {
wipeCard = 1 ;
}
}
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " --wipe card:%s uid:%s " , ( wipeCard ) ? " YES " : " NO " , sprint_hex ( uid , 4 ) ) ;
2019-03-10 06:35:06 +08:00
res = mfCSetUID ( uid , ( atqaPresent ) ? atqa : NULL , ( atqaPresent ) ? sak : NULL , oldUid , wipeCard ) ;
if ( res ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Can't set UID. error=%d " , res ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " old UID:%s " , sprint_hex ( oldUid , 4 ) ) ;
PrintAndLogEx ( SUCCESS , " new UID:%s " , sprint_hex ( uid , 4 ) ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCSetBlk ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t block [ 16 ] = { 0x00 } ;
uint8_t blockNo = 0 ;
uint8_t params = MAGIC_SINGLE ;
int res ;
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
if ( strlen ( Cmd ) < 1 | | ctmp = = ' h ' ) return usage_hf14_csetblk ( ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
blockNo = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
if ( param_gethex ( Cmd , 1 , block , 32 ) ) return usage_hf14_csetblk ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
ctmp = tolower ( param_getchar ( Cmd , 2 ) ) ;
if ( ctmp = = ' w ' )
params | = MAGIC_WIPE ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " --block number:%2d data:%s " , blockNo , sprint_hex ( block , 16 ) ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
res = mfCSetBlock ( blockNo , block , NULL , params ) ;
if ( res ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Can't write block. error=%d " , res ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCLoad ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
uint8_t fillFromEmulator = 0 ;
bool fillFromJson = false ;
bool fillFromBin = false ;
char fileName [ 50 ] = { 0 } ;
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( param_getlength ( Cmd , 0 ) = = 1 ) {
2019-03-10 06:35:06 +08:00
if ( ctmp = = ' h ' | | ctmp = = 0x00 ) return usage_hf14_cload ( ) ;
2019-03-10 07:00:59 +08:00
if ( ctmp = = ' e ' ) fillFromEmulator = 1 ;
if ( ctmp = = ' j ' ) fillFromJson = true ;
if ( ctmp = = ' b ' ) fillFromBin = true ;
2019-03-10 06:35:06 +08:00
}
if ( fillFromJson | | fillFromBin )
param_getstr ( Cmd , 1 , fileName , sizeof ( fileName ) ) ;
if ( fillFromEmulator ) {
2019-06-08 00:41:39 +08:00
for ( int blockNum = 0 ; blockNum < 16 * 4 ; blockNum + = 1 ) {
int flags = 0 ;
uint8_t buf8 [ 16 ] = { 0x00 } ;
2019-03-10 06:35:06 +08:00
if ( mfEmlGetMem ( buf8 , blockNum , 1 ) ) {
PrintAndLogEx ( WARNING , " Cant get block: %d " , blockNum ) ;
return 2 ;
}
if ( blockNum = = 0 ) flags = MAGIC_INIT + MAGIC_WUPC ; // switch on field and send magic sequence
if ( blockNum = = 1 ) flags = 0 ; // just write
if ( blockNum = = 16 * 4 - 1 ) flags = MAGIC_HALT + MAGIC_OFF ; // Done. Magic Halt and switch off field.
if ( mfCSetBlock ( blockNum , buf8 , NULL , flags ) ) {
PrintAndLogEx ( WARNING , " Cant set magic card block: %d " , blockNum ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " \n " ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
size_t maxdatalen = 4096 ;
uint8_t * data = calloc ( maxdatalen , sizeof ( uint8_t ) ) ;
2019-05-27 21:15:53 +08:00
if ( ! data ) {
PrintAndLogEx ( WARNING , " Fail, cannot allocate memory " ) ;
return PM3_EMALLOC ;
}
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
size_t datalen = 0 ;
int res = 0 ;
if ( fillFromBin ) {
2019-04-29 01:21:04 +08:00
res = loadFile ( fileName , " .bin " , data , maxdatalen , & datalen ) ;
2019-03-10 06:35:06 +08:00
} else {
if ( fillFromJson ) {
2019-04-29 01:21:04 +08:00
res = loadFileJSON ( fileName , data , maxdatalen , & datalen ) ;
2019-03-10 06:35:06 +08:00
} else {
2019-04-29 01:21:04 +08:00
res = loadFileEML ( Cmd , data , & datalen ) ;
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:00:59 +08:00
if ( res ) {
if ( data )
2019-03-10 06:35:06 +08:00
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
// 64 or 256blocks.
if ( datalen ! = 1024 & & datalen ! = 4096 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File content error. " ) ;
2019-03-10 06:35:06 +08:00
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( INFO , " Copying to magic card " ) ;
2019-06-08 00:41:39 +08:00
int blockNum = 0 ;
int flags = 0 ;
2019-03-10 07:00:59 +08:00
while ( datalen ) {
2019-03-10 06:35:06 +08:00
// switch on field and send magic sequence
if ( blockNum = = 0 ) flags = MAGIC_INIT + MAGIC_WUPC ;
// write
if ( blockNum = = 1 ) flags = 0 ;
// Switch off field.
if ( blockNum = = 16 * 4 - 1 ) flags = MAGIC_HALT + MAGIC_OFF ;
if ( mfCSetBlock ( blockNum , data + ( 16 * blockNum ) , NULL , flags ) ) {
PrintAndLogEx ( WARNING , " Can't set magic card block: %d " , blockNum ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
datalen - = 16 ;
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-10 06:35:06 +08:00
blockNum + + ;
// magic card type - mifare 1K
2019-03-10 07:00:59 +08:00
if ( blockNum > = MIFARE_1K_MAXBLOCK ) break ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " \n " ) ;
// 64 or 256blocks.
2019-03-10 07:00:59 +08:00
if ( blockNum ! = 16 * 4 & & blockNum ! = 32 * 4 + 8 * 16 ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " File content error. There must be 64 blocks " ) ;
2019-03-10 06:35:06 +08:00
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( SUCCESS , " Card loaded %d blocks from file " , blockNum ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCGetBlk ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t data [ 16 ] = { 0 } ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 1 | | ctmp = = ' h ' ) return usage_hf14_cgetblk ( ) ;
2019-03-09 15:49:41 +08:00
2019-06-08 00:41:39 +08:00
uint8_t blockNo = param_get8 ( Cmd , 0 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " --block number:%2d " , blockNo ) ;
2019-03-09 15:49:41 +08:00
2019-06-08 00:41:39 +08:00
int res = mfCGetBlock ( blockNo , data , MAGIC_SINGLE ) ;
2019-03-10 06:35:06 +08:00
if ( res ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Can't read block. error=%d " , res ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " data: %s " , sprint_hex ( data , sizeof ( data ) ) ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( mfIsSectorTrailer ( blockNo ) ) {
PrintAndLogEx ( NORMAL , " Trailer decoded: " ) ;
PrintAndLogEx ( NORMAL , " Key A: %s " , sprint_hex_inrow ( data , 6 ) ) ;
PrintAndLogEx ( NORMAL , " Key B: %s " , sprint_hex_inrow ( & data [ 10 ] , 6 ) ) ;
int bln = mfFirstBlockOfSector ( mfSectorNum ( blockNo ) ) ;
int blinc = ( mfNumBlocksPerSector ( mfSectorNum ( blockNo ) ) > 4 ) ? 5 : 1 ;
for ( int i = 0 ; i < 4 ; i + + ) {
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( NORMAL , " Access block %d%s: %s " , bln , ( ( blinc > 1 ) & & ( i < 3 ) ? " + " : " " ) , mfGetAccessConditionsDesc ( i , & data [ 6 ] ) ) ;
2019-03-10 06:35:06 +08:00
bln + = blinc ;
}
PrintAndLogEx ( NORMAL , " UserData: %s " , sprint_hex_inrow ( & data [ 9 ] , 1 ) ) ;
}
2019-03-09 15:59:13 +08:00
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCGetSc ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t data [ 16 ] = { 0 } ;
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 1 | | ctmp = = ' h ' ) return usage_hf14_cgetsc ( ) ;
2019-06-08 00:41:39 +08:00
uint8_t sector = param_get8 ( Cmd , 0 ) ;
2019-03-10 06:35:06 +08:00
if ( sector > 39 ) {
PrintAndLogEx ( WARNING , " Sector number must be less then 40 " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " \n # | data | Sector | %02d/ 0x%02X " , sector , sector ) ;
PrintAndLogEx ( NORMAL , " ----+------------------------------------------------ " ) ;
uint8_t blocks = 4 ;
uint8_t start = sector * 4 ;
2019-03-10 07:00:59 +08:00
if ( sector > 32 ) {
2019-03-10 06:35:06 +08:00
blocks = 16 ;
2019-03-10 07:00:59 +08:00
start = 128 + ( sector - 32 ) * 16 ;
2019-03-10 06:35:06 +08:00
}
2019-06-08 00:41:39 +08:00
int flags = MAGIC_INIT + MAGIC_WUPC ;
2019-03-10 06:35:06 +08:00
2019-06-08 00:41:39 +08:00
for ( int i = 0 ; i < blocks ; i + + ) {
2019-03-10 06:35:06 +08:00
if ( i = = 1 ) flags = 0 ;
2019-03-10 07:00:59 +08:00
if ( i = = blocks - 1 ) flags = MAGIC_HALT + MAGIC_OFF ;
2019-03-10 06:35:06 +08:00
2019-06-08 00:41:39 +08:00
int res = mfCGetBlock ( start + i , data , flags ) ;
2019-03-10 06:35:06 +08:00
if ( res ) {
2019-07-14 06:35:18 +08:00
PrintAndLogEx ( ERR , " Can't read block. %d error=%d " , start + i , res ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " %3d | %s " , start + i , sprint_hex ( data , 16 ) ) ;
}
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfCSave ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char filename [ FILE_PATH_SIZE ] ;
2019-03-10 07:00:59 +08:00
char * fnameptr = filename ;
2019-03-10 06:35:06 +08:00
uint8_t * dump ;
bool fillEmulator = false ;
bool errors = false , hasname = false , useuid = false ;
int i , len , flags ;
uint8_t numblocks = 0 , cmdp = 0 ;
uint16_t bytes = 0 ;
while ( param_getchar ( Cmd , cmdp ) ! = 0x00 & & ! errors ) {
2019-06-08 00:41:39 +08:00
char ctmp = tolower ( param_getchar ( Cmd , cmdp ) ) ;
2019-03-10 06:35:06 +08:00
switch ( ctmp ) {
2019-03-10 07:00:59 +08:00
case ' e ' :
useuid = true ;
fillEmulator = true ;
cmdp + + ;
2019-03-10 06:35:06 +08:00
break ;
2019-03-10 07:00:59 +08:00
case ' h ' :
return usage_hf14_csave ( ) ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 4 ' :
numblocks = NumOfBlocks ( ctmp ) ;
bytes = numblocks * MFBLOCK_SIZE ;
PrintAndLogEx ( SUCCESS , " Saving magic mifare %cK " , ctmp ) ;
cmdp + + ;
break ;
case ' u ' :
useuid = true ;
hasname = true ;
cmdp + + ;
break ;
case ' o ' :
len = param_getstr ( Cmd , cmdp + 1 , filename , FILE_PATH_SIZE ) ;
if ( len < 1 ) {
errors = true ;
break ;
}
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
useuid = false ;
hasname = true ;
cmdp + = 2 ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' " , param_getchar ( Cmd , cmdp ) ) ;
errors = true ;
break ;
2019-03-10 06:35:06 +08:00
}
}
if ( ! hasname & & ! fillEmulator ) errors = true ;
if ( errors | | cmdp = = 0 ) return usage_hf14_csave ( ) ;
dump = calloc ( bytes , sizeof ( uint8_t ) ) ;
if ( ! dump ) {
PrintAndLogEx ( WARNING , " Fail, cannot allocate memory " ) ;
2019-05-27 21:15:53 +08:00
return PM3_EMALLOC ;
2019-03-10 06:35:06 +08:00
}
flags = MAGIC_INIT + MAGIC_WUPC ;
for ( i = 0 ; i < numblocks ; i + + ) {
if ( i = = 1 ) flags = 0 ;
if ( i = = numblocks - 1 ) flags = MAGIC_HALT + MAGIC_OFF ;
2019-03-10 07:00:59 +08:00
if ( mfCGetBlock ( i , dump + ( i * MFBLOCK_SIZE ) , flags ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Cant get block: %d " , i ) ;
free ( dump ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
}
2019-03-10 07:00:59 +08:00
if ( useuid ) {
2019-03-10 06:35:06 +08:00
fnameptr + = sprintf ( fnameptr , " hf-mf- " ) ;
FillFileNameByUID ( fnameptr , dump , " -dump " , 4 ) ;
}
if ( fillEmulator ) {
PrintAndLogEx ( INFO , " uploading to emulator memory " ) ;
2019-05-09 03:54:15 +08:00
// fast push mode
conn . block_after_ACK = true ;
2019-03-10 06:35:06 +08:00
for ( i = 0 ; i < numblocks ; i + = 5 ) {
2019-05-09 03:54:15 +08:00
if ( i = = numblocks - 1 ) {
// Disable fast mode on last packet
conn . block_after_ACK = false ;
}
2019-06-01 02:07:07 +08:00
if ( mfEmlSetMem ( dump + ( i * MFBLOCK_SIZE ) , i , 5 ) ! = PM3_SUCCESS ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Cant set emul block: %d " , i ) ;
}
2019-03-10 07:00:59 +08:00
printf ( " . " ) ;
fflush ( stdout ) ;
2019-03-10 06:35:06 +08:00
}
PrintAndLogEx ( NORMAL , " \n " ) ;
PrintAndLogEx ( SUCCESS , " uploaded %d bytes to emulator memory " , bytes ) ;
}
2019-04-29 02:42:57 +08:00
saveFile ( filename , " .bin " , dump , bytes ) ;
saveFileEML ( filename , dump , bytes , MFBLOCK_SIZE ) ;
saveFileJSON ( filename , jsfCardMemory , dump , bytes ) ;
2019-03-10 06:35:06 +08:00
free ( dump ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
//needs nt, ar, at, Data to decrypt
2019-04-13 00:41:14 +08:00
static int CmdHf14AMfDecryptBytes ( const char * Cmd ) {
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
if ( strlen ( Cmd ) < 1 | | ctmp = = ' h ' ) return usage_hf14_decryptbytes ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
uint32_t nt = param_get32ex ( Cmd , 0 , 0 , 16 ) ;
uint32_t ar_enc = param_get32ex ( Cmd , 1 , 0 , 16 ) ;
uint32_t at_enc = param_get32ex ( Cmd , 2 , 0 , 16 ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
int len = param_getlength ( Cmd , 3 ) ;
2019-03-10 07:00:59 +08:00
if ( len & 1 ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( WARNING , " Uneven hex string length. LEN=%d " , len ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " nt \t %08X " , nt ) ;
PrintAndLogEx ( NORMAL , " ar enc \t %08X " , ar_enc ) ;
PrintAndLogEx ( NORMAL , " at enc \t %08X " , at_enc ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
uint8_t * data = calloc ( len , sizeof ( uint8_t ) ) ;
2019-05-27 21:15:53 +08:00
if ( ! data ) {
PrintAndLogEx ( WARNING , " Fail, cannot allocate memory " ) ;
return PM3_EMALLOC ;
}
2019-06-08 03:40:33 +08:00
2019-03-10 06:35:06 +08:00
param_gethex_ex ( Cmd , 3 , data , & len ) ;
len > > = 1 ;
2019-03-10 07:00:59 +08:00
tryDecryptWord ( nt , ar_enc , at_enc , data , len ) ;
free ( data ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHf14AMfSetMod ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t key [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
uint8_t mod = 2 ;
char ctmp = param_getchar ( Cmd , 0 ) ;
if ( ctmp = = ' 0 ' ) {
mod = 0 ;
} else if ( ctmp = = ' 1 ' ) {
mod = 1 ;
}
int gethexfail = param_gethex ( Cmd , 1 , key , 12 ) ;
if ( mod = = 2 | | gethexfail ) {
PrintAndLogEx ( NORMAL , " Sets the load modulation strength of a MIFARE Classic EV1 card. " ) ;
PrintAndLogEx ( NORMAL , " Usage: hf mf setmod <0|1> <block 0 key A> " ) ;
PrintAndLogEx ( NORMAL , " 0 = normal modulation " ) ;
PrintAndLogEx ( NORMAL , " 1 = strong modulation (default) " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-05-15 18:52:22 +08:00
uint8_t data [ 7 ] ;
data [ 0 ] = mod ;
2019-06-08 03:40:33 +08:00
memcpy ( data + 1 , key , 6 ) ;
2019-05-15 18:52:22 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandNG ( CMD_HF_MIFARE_SETMOD , data , sizeof ( data ) ) ;
2019-03-10 06:35:06 +08:00
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-08-04 01:17:00 +08:00
if ( WaitForResponseTimeout ( CMD_HF_MIFARE_SETMOD , & resp , 1500 ) ) {
2019-06-08 03:40:33 +08:00
if ( resp . status = = PM3_SUCCESS )
2019-05-15 18:52:22 +08:00
PrintAndLogEx ( SUCCESS , " Success " ) ;
else
PrintAndLogEx ( FAILED , " Failed " ) ;
2019-03-10 06:35:06 +08:00
} else {
PrintAndLogEx ( WARNING , " Command execute timeout " ) ;
}
2019-05-15 18:52:22 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
// Mifare NACK bug detection
2019-04-13 00:41:14 +08:00
static int CmdHf14AMfNack ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
char ctmp = tolower ( param_getchar ( Cmd , 0 ) ) ;
2019-03-10 07:00:59 +08:00
if ( ctmp = = ' h ' ) return usage_hf14_nack ( ) ;
2019-05-27 21:15:53 +08:00
bool verbose = ( ctmp = = ' v ' ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
if ( verbose )
2019-07-11 19:01:34 +08:00
PrintAndLogEx ( INFO , " Started testing card for NACK bug. Press Enter to abort " ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
detect_classic_nackbug ( verbose ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfice ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
uint8_t blockNo = 0 ;
uint8_t keyType = 0 ;
uint8_t trgBlockNo = 0 ;
uint8_t trgKeyType = 1 ;
bool slow = false ;
bool initialize = true ;
bool acquisition_completed = false ;
2019-03-10 07:00:59 +08:00
uint8_t cmdp = 0 ;
2019-03-10 06:35:06 +08:00
uint32_t flags = 0 ;
uint32_t total_num_nonces = 0 ;
char ctmp ;
char filename [ FILE_PATH_SIZE ] , * fptr ;
FILE * fnonces = NULL ;
2019-04-18 18:43:35 +08:00
PacketResponseNG resp ;
2019-03-10 06:35:06 +08:00
uint32_t part_limit = 3000 ;
uint32_t limit = 50000 ;
while ( ( ctmp = param_getchar ( Cmd , cmdp ) ) ) {
2019-03-10 07:00:59 +08:00
switch ( tolower ( ctmp ) ) {
case ' h ' :
return usage_hf14_ice ( ) ;
case ' f ' :
param_getstr ( Cmd , cmdp + 1 , filename , FILE_PATH_SIZE ) ;
cmdp + + ;
break ;
case ' l ' :
limit = param_get32ex ( Cmd , cmdp + 1 , 50000 , 10 ) ;
cmdp + + ;
break ;
default :
PrintAndLogEx ( WARNING , " Unknown parameter '%c' \n " , ctmp ) ;
usage_hf14_ice ( ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
cmdp + + ;
}
2019-03-10 07:00:59 +08:00
if ( filename [ 0 ] = = ' \0 ' ) {
fptr = GenerateFilename ( " hf-mf- " , " -nonces.bin " ) ;
2019-03-10 06:35:06 +08:00
if ( fptr = = NULL )
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
strcpy ( filename , fptr ) ;
}
2019-05-27 21:15:53 +08:00
PrintAndLogEx ( NORMAL , " Collecting " _YELLOW_ ( " %u " ) " nonces \n " , limit ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
if ( ( fnonces = fopen ( filename , " wb " ) ) = = NULL ) {
2019-03-10 07:56:00 +08:00
PrintAndLogEx ( WARNING , " Could not create file " _YELLOW_ ( " %s " ) , filename ) ;
2019-05-27 21:15:53 +08:00
return PM3_EFILE ;
2019-03-10 06:35:06 +08:00
}
clearCommandBuffer ( ) ;
uint64_t t1 = msclock ( ) ;
do {
2019-07-11 19:01:34 +08:00
if ( kbd_enter_pressed ( ) ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " \n aborted via keyboard! \n " ) ;
break ;
}
flags = 0 ;
flags | = initialize ? 0x0001 : 0 ;
flags | = slow ? 0x0002 : 0 ;
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandMIX ( CMD_HF_MIFARE_ACQ_NONCES , blockNo + keyType * 0x100 , trgBlockNo + trgKeyType * 0x100 , flags , NULL , 0 ) ;
2019-03-10 06:35:06 +08:00
if ( ! WaitForResponseTimeout ( CMD_ACK , & resp , 3000 ) ) goto out ;
2019-04-18 05:44:48 +08:00
if ( resp . oldarg [ 0 ] ) goto out ;
2019-03-10 06:35:06 +08:00
2019-04-18 05:44:48 +08:00
uint32_t items = resp . oldarg [ 2 ] ;
2019-03-10 06:35:06 +08:00
if ( fnonces ) {
2019-04-18 05:44:48 +08:00
fwrite ( resp . data . asBytes , 1 , items * 4 , fnonces ) ;
2019-03-10 06:35:06 +08:00
fflush ( fnonces ) ;
}
total_num_nonces + = items ;
2019-03-10 07:00:59 +08:00
if ( total_num_nonces > part_limit ) {
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( INFO , " Total nonces %u \n " , total_num_nonces ) ;
part_limit + = 3000 ;
}
2019-03-10 07:00:59 +08:00
acquisition_completed = ( total_num_nonces > limit ) ;
2019-03-10 06:35:06 +08:00
initialize = false ;
} while ( ! acquisition_completed ) ;
2019-03-09 15:49:41 +08:00
out :
2019-03-10 07:00:59 +08:00
PrintAndLogEx ( SUCCESS , " time: % " PRIu64 " seconds \n " , ( msclock ( ) - t1 ) / 1000 ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
if ( fnonces ) {
2019-03-10 06:35:06 +08:00
fflush ( fnonces ) ;
fclose ( fnonces ) ;
}
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-08-04 01:17:00 +08:00
SendCommandMIX ( CMD_HF_MIFARE_ACQ_NONCES , blockNo + keyType * 0x100 , trgBlockNo + trgKeyType * 0x100 , 4 , NULL , 0 ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfAuth4 ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
uint8_t keyn [ 20 ] = { 0 } ;
int keynlen = 0 ;
uint8_t key [ 16 ] = { 0 } ;
int keylen = 0 ;
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
CLIParserInit ( " hf mf auth4 " ,
2019-03-10 07:00:59 +08:00
" Executes AES authentication command in ISO14443-4 " ,
" Usage: \n \t hf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication \n "
" \t hf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication \n " ) ;
2019-03-09 15:49:41 +08:00
2019-03-10 07:00:59 +08:00
void * argtable [ ] = {
2019-03-10 06:35:06 +08:00
arg_param_begin ,
arg_str1 ( NULL , NULL , " <Key Num (HEX 2 bytes)> " , NULL ) ,
arg_str1 ( NULL , NULL , " <Key Value (HEX 16 bytes)> " , NULL ) ,
arg_param_end
} ;
CLIExecWithReturn ( Cmd , argtable , true ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
CLIGetHexWithReturn ( 1 , keyn , & keynlen ) ;
CLIGetHexWithReturn ( 2 , key , & keylen ) ;
CLIParserFree ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( keynlen ! = 2 ) {
PrintAndLogEx ( ERR , " <Key Num> must be 2 bytes long instead of: %d " , keynlen ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 06:35:06 +08:00
if ( keylen ! = 16 ) {
PrintAndLogEx ( ERR , " <Key Value> must be 16 bytes long instead of: %d " , keylen ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
return MifareAuth4 ( NULL , keyn , key , true , false , true ) ;
2019-03-09 15:49:41 +08:00
}
// https://www.nxp.com/docs/en/application-note/AN10787.pdf
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfMAD ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
CLIParserInit ( " hf mf mad " ,
2019-03-10 07:00:59 +08:00
" Checks and prints Mifare Application Directory (MAD) " ,
" Usage: \n \t hf mf mad -> shows MAD if exists \n "
" \t hf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B \n " ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
void * argtable [ ] = {
2019-03-10 06:35:06 +08:00
arg_param_begin ,
arg_lit0 ( " vV " , " verbose " , " show technical data " ) ,
arg_str0 ( " aA " , " aid " , " print all sectors with aid " , NULL ) ,
arg_str0 ( " kK " , " key " , " key for printing sectors " , NULL ) ,
arg_lit0 ( " bB " , " keyb " , " use key B for access printing sectors (by default: key A) " ) ,
arg_param_end
} ;
2019-03-19 03:24:09 +08:00
CLIExecWithReturn ( Cmd , argtable , true ) ;
2019-03-10 06:35:06 +08:00
bool verbose = arg_get_lit ( 1 ) ;
uint8_t aid [ 2 ] = { 0 } ;
int aidlen ;
CLIGetHexWithReturn ( 2 , aid , & aidlen ) ;
uint8_t key [ 6 ] = { 0 } ;
int keylen ;
CLIGetHexWithReturn ( 3 , key , & keylen ) ;
bool keyB = arg_get_lit ( 4 ) ;
CLIParserFree ( ) ;
if ( aidlen ! = 2 & & keylen > 0 ) {
PrintAndLogEx ( WARNING , " do not need a key without aid. " ) ;
}
uint8_t sector0 [ 16 * 4 ] = { 0 } ;
uint8_t sector10 [ 16 * 4 ] = { 0 } ;
if ( mfReadSector ( MF_MAD1_SECTOR , MF_KEY_A , ( uint8_t * ) g_mifare_mad_key , sector0 ) ) {
PrintAndLogEx ( ERR , " read sector 0 error. card don't have MAD or don't have MAD on default keys. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
if ( verbose ) {
2019-03-10 07:00:59 +08:00
for ( int i = 0 ; i < 4 ; i + + )
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " [%d] %s " , i , sprint_hex ( & sector0 [ i * 16 ] , 16 ) ) ;
}
bool haveMAD2 = false ;
MAD1DecodeAndPrint ( sector0 , verbose , & haveMAD2 ) ;
if ( haveMAD2 ) {
if ( mfReadSector ( MF_MAD2_SECTOR , MF_KEY_A , ( uint8_t * ) g_mifare_mad_key , sector10 ) ) {
PrintAndLogEx ( ERR , " read sector 0x10 error. card don't have MAD or don't have MAD on default keys. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
MAD2DecodeAndPrint ( sector10 , verbose ) ;
}
if ( aidlen = = 2 ) {
uint16_t aaid = ( aid [ 0 ] < < 8 ) + aid [ 1 ] ;
PrintAndLogEx ( NORMAL , " \n -------------- AID 0x%04x --------------- " , aaid ) ;
uint16_t mad [ 7 + 8 + 8 + 8 + 8 ] = { 0 } ;
size_t madlen = 0 ;
if ( MADDecode ( sector0 , sector10 , mad , & madlen ) ) {
PrintAndLogEx ( ERR , " can't decode mad. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
uint8_t akey [ 6 ] = { 0 } ;
memcpy ( akey , g_mifare_ndef_key , 6 ) ;
if ( keylen = = 6 ) {
memcpy ( akey , key , 6 ) ;
}
for ( int i = 0 ; i < madlen ; i + + ) {
if ( aaid = = mad [ i ] ) {
uint8_t vsector [ 16 * 4 ] = { 0 } ;
if ( mfReadSector ( i + 1 , keyB ? MF_KEY_B : MF_KEY_A , akey , vsector ) ) {
PrintAndLogEx ( NORMAL , " " ) ;
PrintAndLogEx ( ERR , " read sector %d error. " , i + 1 ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
2019-03-10 07:00:59 +08:00
for ( int j = 0 ; j < ( verbose ? 4 : 3 ) ; j + + )
2019-03-10 06:35:06 +08:00
PrintAndLogEx ( NORMAL , " [%03d] %s " , ( i + 1 ) * 4 + j , sprint_hex ( & vsector [ j * 16 ] , 16 ) ) ;
}
}
}
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHFMFNDEF ( const char * Cmd ) {
2019-03-09 15:49:41 +08:00
2019-03-10 06:35:06 +08:00
CLIParserInit ( " hf mf ndef " ,
2019-03-10 07:00:59 +08:00
" Prints NFC Data Exchange Format (NDEF) " ,
" Usage: \n \t hf mf ndef -> shows NDEF data \n "
" \t hf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B \n " ) ;
2019-03-10 06:35:06 +08:00
2019-03-10 07:00:59 +08:00
void * argtable [ ] = {
2019-03-10 06:35:06 +08:00
arg_param_begin ,
arg_litn ( " vV " , " verbose " , 0 , 2 , " show technical data " ) ,
arg_str0 ( " aA " , " aid " , " replace default aid for NDEF " , NULL ) ,
arg_str0 ( " kK " , " key " , " replace default key for NDEF " , NULL ) ,
arg_lit0 ( " bB " , " keyb " , " use key B for access sectors (by default: key A) " ) ,
arg_param_end
} ;
2019-03-19 03:24:09 +08:00
CLIExecWithReturn ( Cmd , argtable , true ) ;
2019-03-10 06:35:06 +08:00
bool verbose = arg_get_lit ( 1 ) ;
bool verbose2 = arg_get_lit ( 1 ) > 1 ;
uint8_t aid [ 2 ] = { 0 } ;
int aidlen ;
CLIGetHexWithReturn ( 2 , aid , & aidlen ) ;
uint8_t key [ 6 ] = { 0 } ;
int keylen ;
CLIGetHexWithReturn ( 3 , key , & keylen ) ;
bool keyB = arg_get_lit ( 4 ) ;
CLIParserFree ( ) ;
uint16_t ndefAID = 0x03e1 ;
if ( aidlen = = 2 )
ndefAID = ( aid [ 0 ] < < 8 ) + aid [ 1 ] ;
uint8_t ndefkey [ 6 ] = { 0 } ;
memcpy ( ndefkey , g_mifare_ndef_key , 6 ) ;
if ( keylen = = 6 ) {
memcpy ( ndefkey , key , 6 ) ;
}
uint8_t sector0 [ 16 * 4 ] = { 0 } ;
uint8_t sector10 [ 16 * 4 ] = { 0 } ;
uint8_t data [ 4096 ] = { 0 } ;
int datalen = 0 ;
PrintAndLogEx ( NORMAL , " " ) ;
if ( mfReadSector ( MF_MAD1_SECTOR , MF_KEY_A , ( uint8_t * ) g_mifare_mad_key , sector0 ) ) {
PrintAndLogEx ( ERR , " read sector 0 error. card don't have MAD or don't have MAD on default keys. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
bool haveMAD2 = false ;
int res = MADCheck ( sector0 , NULL , verbose , & haveMAD2 ) ;
if ( res ) {
PrintAndLogEx ( ERR , " MAD error %d. " , res ) ;
return res ;
}
if ( haveMAD2 ) {
if ( mfReadSector ( MF_MAD2_SECTOR , MF_KEY_A , ( uint8_t * ) g_mifare_mad_key , sector10 ) ) {
PrintAndLogEx ( ERR , " read sector 0x10 error. card don't have MAD or don't have MAD on default keys. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
}
uint16_t mad [ 7 + 8 + 8 + 8 + 8 ] = { 0 } ;
size_t madlen = 0 ;
if ( MADDecode ( sector0 , ( haveMAD2 ? sector10 : NULL ) , mad , & madlen ) ) {
PrintAndLogEx ( ERR , " can't decode mad. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
printf ( " data reading: " ) ;
for ( int i = 0 ; i < madlen ; i + + ) {
if ( ndefAID = = mad [ i ] ) {
uint8_t vsector [ 16 * 4 ] = { 0 } ;
if ( mfReadSector ( i + 1 , keyB ? MF_KEY_B : MF_KEY_A , ndefkey , vsector ) ) {
PrintAndLogEx ( ERR , " read sector %d error. " , i + 1 ) ;
2019-05-27 21:15:53 +08:00
return PM3_ESOFT ;
2019-03-10 06:35:06 +08:00
}
memcpy ( & data [ datalen ] , vsector , 16 * 3 ) ;
datalen + = 16 * 3 ;
printf ( " . " ) ;
}
}
printf ( " OK \n " ) ;
if ( ! datalen ) {
PrintAndLogEx ( ERR , " no NDEF data. " ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-10 06:35:06 +08:00
}
if ( verbose2 ) {
PrintAndLogEx ( NORMAL , " NDEF data: " ) ;
dump_buffer ( data , datalen , stdout , 1 ) ;
}
NDEFDecodeAndPrint ( data , datalen , verbose ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-03-09 15:49:41 +08:00
}
2019-04-13 00:41:14 +08:00
static int CmdHF14AMfList ( const char * Cmd ) {
2019-04-10 18:23:40 +08:00
( void ) Cmd ; // Cmd is not used so far
2019-05-27 21:15:53 +08:00
return CmdTraceList ( " mf " ) ;
2019-03-09 15:49:41 +08:00
}
static command_t CommandTable [ ] = {
2019-05-02 02:48:15 +08:00
{ " help " , CmdHelp , AlwaysAvailable , " This help " } ,
2019-09-08 18:29:10 +08:00
{ " list " , CmdHF14AMfList , AlwaysAvailable , " List MIFARE history " } ,
{ " darkside " , CmdHF14AMfDarkside , IfPm3Iso14443a , " Darkside attack " } ,
{ " nested " , CmdHF14AMfNested , IfPm3Iso14443a , " Nested attack " } ,
{ " hardnested " , CmdHF14AMfNestedHard , AlwaysAvailable , " Nested attack for hardened MIFARE Classic cards " } ,
{ " autopwn " , CmdHF14AMfAutoPWN , IfPm3Iso14443a , " Automatic key recovery tool for MIFARE Classic " } ,
// {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"},
{ " nack " , CmdHf14AMfNack , IfPm3Iso14443a , " Test for MIFARE NACK bug " } ,
2019-05-02 05:38:57 +08:00
{ " chk " , CmdHF14AMfChk , IfPm3Iso14443a , " Check keys " } ,
{ " fchk " , CmdHF14AMfChk_fast , IfPm3Iso14443a , " Check keys fast, targets all keys on card " } ,
2019-05-02 02:48:15 +08:00
{ " decrypt " , CmdHf14AMfDecryptBytes , AlwaysAvailable , " [nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace " } ,
2019-05-02 05:38:57 +08:00
{ " ----------- " , CmdHelp , IfPm3Iso14443a , " " } ,
{ " rdbl " , CmdHF14AMfRdBl , IfPm3Iso14443a , " Read MIFARE classic block " } ,
{ " rdsc " , CmdHF14AMfRdSc , IfPm3Iso14443a , " Read MIFARE classic sector " } ,
{ " dump " , CmdHF14AMfDump , IfPm3Iso14443a , " Dump MIFARE classic tag to binary file " } ,
{ " restore " , CmdHF14AMfRestore , IfPm3Iso14443a , " Restore MIFARE classic binary file to BLANK tag " } ,
{ " wrbl " , CmdHF14AMfWrBl , IfPm3Iso14443a , " Write MIFARE classic block " } ,
{ " setmod " , CmdHf14AMfSetMod , IfPm3Iso14443a , " Set MIFARE Classic EV1 load modulation strength " } ,
{ " auth4 " , CmdHF14AMfAuth4 , IfPm3Iso14443a , " ISO14443-4 AES authentication " } ,
2019-03-10 06:35:06 +08:00
// {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
2019-05-02 05:38:57 +08:00
{ " ----------- " , CmdHelp , IfPm3Iso14443a , " " } ,
2019-09-08 02:45:12 +08:00
{ " sim " , CmdHF14AMfSim , IfPm3Iso14443a , " Simulate MIFARE card " } ,
2019-05-02 05:38:57 +08:00
{ " eclr " , CmdHF14AMfEClear , IfPm3Iso14443a , " Clear simulator memory " } ,
{ " eget " , CmdHF14AMfEGet , IfPm3Iso14443a , " Get simulator memory block " } ,
{ " eset " , CmdHF14AMfESet , IfPm3Iso14443a , " Set simulator memory block " } ,
{ " eload " , CmdHF14AMfELoad , IfPm3Iso14443a , " Load from file emul dump " } ,
{ " esave " , CmdHF14AMfESave , IfPm3Iso14443a , " Save to file emul dump " } ,
{ " ecfill " , CmdHF14AMfECFill , IfPm3Iso14443a , " Fill simulator memory with help of keys from simulator " } ,
{ " ekeyprn " , CmdHF14AMfEKeyPrn , IfPm3Iso14443a , " Print keys from simulator memory " } ,
{ " ----------- " , CmdHelp , IfPm3Iso14443a , " " } ,
2019-10-03 22:15:47 +08:00
{ " csetuid " , CmdHF14AMfCSetUID , IfPm3Iso14443a , " Set UID (magic chinese card) " } ,
{ " csetblk " , CmdHF14AMfCSetBlk , IfPm3Iso14443a , " Write block (magic chinese card) " } ,
{ " cgetblk " , CmdHF14AMfCGetBlk , IfPm3Iso14443a , " Read block (magic chinese card) " } ,
{ " cgetsc " , CmdHF14AMfCGetSc , IfPm3Iso14443a , " Read sector (magic chinese card) " } ,
{ " cload " , CmdHF14AMfCLoad , IfPm3Iso14443a , " Load dump (magic chinese card) " } ,
{ " csave " , CmdHF14AMfCSave , IfPm3Iso14443a , " Save dump from magic chinese card into file or emulator " } ,
2019-05-02 05:38:57 +08:00
{ " ----------- " , CmdHelp , IfPm3Iso14443a , " " } ,
{ " mad " , CmdHF14AMfMAD , IfPm3Iso14443a , " Checks and prints MAD " } ,
{ " ndef " , CmdHFMFNDEF , IfPm3Iso14443a , " Prints NDEF records from card " } ,
2019-09-08 18:29:10 +08:00
{ " ice " , CmdHF14AMfice , IfPm3Iso14443a , " collect MIFARE Classic nonces to file " } ,
2019-05-02 02:48:15 +08:00
{ NULL , NULL , NULL , NULL }
2019-03-09 15:49:41 +08:00
} ;
2019-04-13 00:41:14 +08:00
static int CmdHelp ( const char * Cmd ) {
( void ) Cmd ; // Cmd is not used so far
CmdsHelp ( CommandTable ) ;
2019-05-27 21:15:53 +08:00
return PM3_SUCCESS ;
2019-04-13 00:41:14 +08:00
}
2019-03-10 18:20:22 +08:00
int CmdHFMF ( const char * Cmd ) {
2019-03-10 06:35:06 +08:00
clearCommandBuffer ( ) ;
2019-04-19 06:47:51 +08:00
return CmdsParse ( CommandTable , Cmd ) ;
2019-03-09 15:49:41 +08:00
}