Rewrote completely cmds & options lf hitag read/dump/wrbl/ta

for more coherence with other pm3 cmds.
Still there remain strange things but it should be a step in the right direction...
This commit is contained in:
Philippe Teuwen 2023-07-20 22:35:42 +02:00
commit 173379b999
2 changed files with 387 additions and 174 deletions

View file

@ -281,7 +281,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
} }
break; break;
// Received RWD authentication challenge and respnse // Received RWD authentication challenge and response
case 64: { case 64: {
// Store the authentication attempt // Store the authentication attempt
if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) { if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) {
@ -891,7 +891,7 @@ static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *
if (bCrypto) { if (bCrypto) {
Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]);
// Removing failed entry from authentiations table // Removing failed entry from authentications table
memcpy(auth_table + auth_table_pos, auth_table + auth_table_pos + 8, 8); memcpy(auth_table + auth_table_pos, auth_table + auth_table_pos + 8, 8);
auth_table_len -= 8; auth_table_len -= 8;

View file

@ -224,7 +224,7 @@ static int CmdLFHitagEload(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str1("f", "file", "<fn>", "Specfiy dump filename"), arg_str1("f", "file", "<fn>", "Specify dump filename"),
arg_lit0("1", NULL, "Card type Hitag 1"), arg_lit0("1", NULL, "Card type Hitag 1"),
arg_lit0("2", NULL, "Card type Hitag 2"), arg_lit0("2", NULL, "Card type Hitag 2"),
arg_lit0("s", NULL, "Card type Hitag S"), arg_lit0("s", NULL, "Card type Hitag S"),
@ -243,9 +243,12 @@ static int CmdLFHitagEload(const char *Cmd) {
bool use_htm = arg_get_lit(ctx, 5); bool use_htm = arg_get_lit(ctx, 5);
CLIParserFree(ctx); CLIParserFree(ctx);
uint8_t n = (use_ht1 + use_ht2 + use_hts + use_htm); if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) {
if (n != 1) { PrintAndLogEx(ERR, "error, specify only one Hitag type");
PrintAndLogEx(ERR, "error, only specify one Hitag type"); return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_hts + use_htm) == 0) {
PrintAndLogEx(ERR, "error, specify one Hitag type");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -288,16 +291,16 @@ static int CmdLFHitagEload(const char *Cmd) {
static int CmdLFHitagSim(const char *Cmd) { static int CmdLFHitagSim(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag sim", CLIParserInit(&ctx, "lf hitag sim",
"Simulate Hitag2 / HitagS transponder\n" "Simulate Hitag transponder\n"
"You need to `lf hitag eload` first", "You need to `lf hitag eload` first",
"lf hitag sim -2" "lf hitag sim -2"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("1", NULL, "simulate Hitag1"), arg_lit0("1", "ht1", "simulate Hitag 1"),
arg_lit0("2", NULL, "simulate Hitag2"), arg_lit0("2", "ht2", "simulate Hitag 2"),
arg_lit0("s", NULL, "simulate HitagS"), arg_lit0("s", "hts", "simulate Hitag S"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -305,10 +308,15 @@ static int CmdLFHitagSim(const char *Cmd) {
bool use_ht1 = arg_get_lit(ctx, 1); bool use_ht1 = arg_get_lit(ctx, 1);
bool use_ht2 = arg_get_lit(ctx, 2); bool use_ht2 = arg_get_lit(ctx, 2);
bool use_hts = arg_get_lit(ctx, 3); bool use_hts = arg_get_lit(ctx, 3);
bool use_htm = false; // not implemented yet
CLIParserFree(ctx); CLIParserFree(ctx);
if ((use_ht1 + use_ht2 + use_hts) > 1) { if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) {
PrintAndLogEx(ERR, "error, Only specify one Hitag type"); PrintAndLogEx(ERR, "error, specify only one Hitag type");
return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_hts + use_htm) == 0) {
PrintAndLogEx(ERR, "error, specify one Hitag type");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -523,67 +531,85 @@ static int CmdLFHitagInfo(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// TODO: iceman
// Hitag2 reader, problem is that this command mixes up stuff. So 26 give uid. 21 etc will also give you a memory dump !?
//
static int CmdLFHitagReader(const char *Cmd) { static int CmdLFHitagReader(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag reader", CLIParserInit(&ctx, "lf hitag read",
"Act like a Hitag Reader", "Read Hitag memory\n"
"Hitag S\n" "Crypto mode key format: ISK high + ISK low",
" lf hitag reader --01 --nrar 0102030411223344\n" "Hitag S, plain mode\n"
" lf hitag reader --02 -k 4F4E4D494B52\n" " lf hitag read --hts\n"
"Hitag 2\n" "Hitag S, challenge mode\n"
" lf hitag reader --21 -k 4D494B52\n" " lf hitag read --hts --nrar 0102030411223344\n"
" lf hitag reader --22 --nrar 0102030411223344\n" "Hitag S, crypto mode => use default key 4F4E4D494B52 (ONMIKR)\n"
" lf hitag reader --23 -k 4F4E4D494B52\n" " lf hitag read --hts --crypto\n"
" lf hitag reader --26\n" "Hitag S, long key = crypto mode\n"
" lf hitag read --hts -k 4F4E4D494B52\n\n"
"Hitag 2, password mode => use default key 4D494B52 (MIKR)\n"
" lf hitag read --ht2 --pwd\n"
"Hitag 2, providing a short key = password mode\n"
" lf hitag read --ht2 -k 4D494B52\n"
"Hitag 2, challenge mode\n"
" lf hitag read --ht2 --nrar 0102030411223344\n"
"Hitag 2, crypto mode => use default key 4F4E4D494B52 (ONMIKR)\n"
" lf hitag read --ht2 --crypto\n"
"Hitag 2, providing a long key = crypto mode\n"
" lf hitag read --ht2 -k 4F4E4D494B52\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0(NULL, "01", "HitagS, read all pages, challenge mode"), arg_lit0(NULL, "hts", "Hitag S"),
arg_lit0(NULL, "02", "HitagS, read all pages, crypto mode. Set key=0 for no auth"), arg_lit0(NULL, "ht2", "Hitag 2"),
arg_lit0(NULL, "21", "Hitag2, read all pages, password mode. def 4D494B52 (MIKR)"), arg_lit0(NULL, "pwd", "password mode"),
arg_lit0(NULL, "22", "Hitag2, read all pages, challenge mode"), arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
arg_lit0(NULL, "23", "Hitag2, read all pages, crypto mode. Key ISK high + ISK low. def 4F4E4D494B52 (ONMIKR)"), arg_lit0(NULL, "crypto", "crypto mode"),
arg_lit0(NULL, "25", "Hitag2, test recorded authentications (replay?)"),
arg_lit0(NULL, "26", "Hitag2, read UID"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"), arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"), // currently pm3 fw reads all the memory anyway
// arg_int1("p", "page", "<dec>", "page address to write to"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
// Hitag S bool use_ht1 = false; // not yet implemented
bool s01 = arg_get_lit(ctx, 1); bool use_hts = arg_get_lit(ctx, 1);
bool s02 = arg_get_lit(ctx, 2); bool use_ht2 = arg_get_lit(ctx, 2);
bool use_htm = false; // not yet implemented
// Hitag 2 bool use_plain = false;
bool h21 = arg_get_lit(ctx, 3); bool use_pwd = arg_get_lit(ctx, 3);
bool h22 = arg_get_lit(ctx, 4); uint8_t nrar[8];
bool h23 = arg_get_lit(ctx, 5); int nalen = 0;
bool h25 = arg_get_lit(ctx, 6); int res = CLIParamHexToBuf(arg_get_str(ctx, 4), nrar, sizeof(nrar), &nalen);
bool h26 = arg_get_lit(ctx, 7); if (res != 0) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool use_nrar = nalen > 0;
bool use_crypto = arg_get_lit(ctx, 5);
uint8_t key[6]; uint8_t key[6];
int keylen = 0; int keylen = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 8), key, sizeof(key), &keylen); res = CLIParamHexToBuf(arg_get_str(ctx, 6), key, sizeof(key), &keylen);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
// uint32_t page = arg_get_u32_def(ctx, 6, 0);
uint8_t nrar[8];
int nalen = 0;
res = CLIParamHexToBuf(arg_get_str(ctx, 9), nrar, sizeof(nrar), &nalen);
CLIParserFree(ctx); CLIParserFree(ctx);
if (res != 0) {
return PM3_EINVARG;
}
// sanity checks // sanity checks
if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) {
PrintAndLogEx(ERR, "error, specify only one Hitag type");
return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_hts + use_htm) == 0) {
PrintAndLogEx(ERR, "error, specify one Hitag type");
return PM3_EINVARG;
}
if (keylen != 0 && keylen != 4 && keylen != 6) { if (keylen != 0 && keylen != 4 && keylen != 6) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen); PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
@ -594,48 +620,73 @@ static int CmdLFHitagReader(const char *Cmd) {
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t foo = (s01 + s02 + h21 + h22 + h23 + h25 + h26); // complete options
if (keylen == 4) {
use_pwd = true;
}
if (keylen == 6) {
use_crypto = true;
}
if ((keylen == 0) && use_pwd) {
memcpy(key, "MIKR", 4);
keylen = 4;
}
if ((keylen == 0) && use_crypto) {
memcpy(key, "ONMIKR", 6);
keylen = 6;
}
// check coherence
uint8_t foo = (use_plain + use_pwd + use_nrar + use_crypto);
if (foo > 1) { if (foo > 1) {
PrintAndLogEx(WARNING, "Only specify one HITAG reader cmd"); PrintAndLogEx(WARNING, "Specify only one authentication mode");
return PM3_EINVARG; return PM3_EINVARG;
} else if (foo == 0) { } else if (foo == 0) {
PrintAndLogEx(WARNING, "Specify one HITAG reader cms"); if (use_hts) {
use_plain = true;
} else {
PrintAndLogEx(WARNING, "Specify one authentication mode");
return PM3_EINVARG;
}
}
if (use_hts && use_pwd) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Password mode");
return PM3_EINVARG;
}
if (use_ht2 && use_plain) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Plain mode");
return PM3_EINVARG; return PM3_EINVARG;
} }
hitag_function htf; hitag_function htf;
hitag_data htd; hitag_data htd;
memset(&htd, 0, sizeof(htd)); memset(&htd, 0, sizeof(htd));
uint16_t cmd;
if (use_hts && use_nrar) {
uint16_t cmd = CMD_LF_HITAG_READER;
if (s01) {
cmd = CMD_LF_HITAGS_READ; cmd = CMD_LF_HITAGS_READ;
htf = RHTSF_CHALLENGE; htf = RHTSF_CHALLENGE;
memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr)); memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr));
} } else if (use_hts && use_crypto) {
if (s02) {
cmd = CMD_LF_HITAGS_READ; cmd = CMD_LF_HITAGS_READ;
htf = RHTSF_KEY; htf = RHTSF_KEY;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key)); memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
} } else if (use_ht2 && use_pwd) {
if (h21) { cmd = CMD_LF_HITAG_READER;
htf = RHT2F_PASSWORD; htf = RHT2F_PASSWORD;
memcpy(htd.pwd.password, key, sizeof(htd.pwd.password)); memcpy(htd.pwd.password, key, sizeof(htd.pwd.password));
} } else if (use_ht2 && use_nrar) {
if (h22) { cmd = CMD_LF_HITAG_READER;
htf = RHT2F_AUTHENTICATE; htf = RHT2F_AUTHENTICATE;
memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr)); memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr));
} } else if (use_ht2 && use_crypto) {
if (h23) {
htf = RHT2F_CRYPTO; htf = RHT2F_CRYPTO;
cmd = CMD_LF_HITAG_READER;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key)); memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
} } else {
if (h25) { PrintAndLogEx(WARNING, "Sorry, not yet implemented");
htf = RHT2F_TEST_AUTH_ATTEMPTS; return PM3_ENOTIMPL;
}
if (h26) {
htf = RHT2F_UID_ONLY;
} }
clearCommandBuffer(); clearCommandBuffer();
@ -653,21 +704,13 @@ static int CmdLFHitagReader(const char *Cmd) {
uint32_t id = bytes_to_num(resp.data.asBytes, 4); uint32_t id = bytes_to_num(resp.data.asBytes, 4);
uint8_t *data = resp.data.asBytes; uint8_t *data = resp.data.asBytes;
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
if (htf != RHT2F_UID_ONLY) {
// block3, 1 byte
printHitag2Configuration(data[4 * 3]); printHitag2Configuration(data[4 * 3]);
// print data
print_hex_break(data, 48, 4); print_hex_break(data, 48, 4);
printHitag2PaxtonDowngrade(data); printHitag2PaxtonDowngrade(data);
}
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdLFHitagCheckChallenges(const char *Cmd) { static int CmdLFHitagSCheckChallenges(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag cc", CLIParserInit(&ctx, "lf hitag cc",
@ -708,92 +751,169 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdLFHitag2CheckChallenges(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag ta",
"Test recorded authentications (replay?)",
"lf hitag ta"
);
clearCommandBuffer();
SendCommandMIX(CMD_LF_HITAG_READER, RHT2F_TEST_AUTH_ATTEMPTS, 0, 0, NULL, 0);
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (resp.oldarg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return PM3_ESOFT;
}
// FIXME: doegox: not sure what this fct does and what it returns...
return PM3_SUCCESS;
}
static int CmdLFHitagWriter(const char *Cmd) { static int CmdLFHitagWriter(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag writer", CLIParserInit(&ctx, "lf hitag wrbl",
"Act like a Hitag writer" "Write a page in Hitag memory\n"
"In password mode the default key is 4D494B52 (MIKR)\n" "Crypto mode key format: ISK high + ISK low",
"In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.", "Hitag S, plain mode\n"
"Hitag S\n" " lf hitag wrbl --hts -p 6 -d 01020304\n"
" lf hitag writer --03 --nrar 0102030411223344 -p 3 -d 01020304\n" "Hitag S, challenge mode\n"
" lf hitag writer --04 -k 4F4E4D494B52 -p 3 -d 01020304\n" " lf hitag wrbl --hts --nrar 0102030411223344 -p 6 -d 01020304\n"
"Hitag 2\n" "Hitag S, crypto mode => use default key 4F4E4D494B52 (ONMIKR)\n"
" lf hitag writer --24 -k 4F4E4D494B52 -p 3 -d 01020304\n" " lf hitag wrbl --hts --crypto -p 6 -d 01020304\n"
" lf hitag writer --27 -k 4D494B52 -p 3 -d 01020304\n" "Hitag S, long key = crypto mode\n"
" lf hitag wrbl --hts -k 4F4E4D494B52 -p 6 -d 01020304\n\n"
"Hitag 2, password mode => use default key 4D494B52 (MIKR)\n"
" lf hitag wrbl --ht2 --pwd -p 6 -d 01020304\n"
"Hitag 2, providing a short key = password mode\n"
" lf hitag wrbl --ht2 -k 4D494B52 -p 6 -d 01020304\n"
"Hitag 2, challenge mode\n"
" lf hitag wrbl --ht2 --nrar 0102030411223344 -p 6 -d 01020304\n"
"Hitag 2, crypto mode => use default key 4F4E4D494B52 (ONMIKR)\n"
" lf hitag wrbl --ht2 --crypto -p 6 -d 01020304\n"
"Hitag 2, providing a long key = crypto mode\n"
" lf hitag wrbl --ht2 -k 4F4E4D494B52 -p 6 -d 01020304\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0(NULL, "03", "HitagS, write page, challenge mode"), arg_lit0(NULL, "hts", "Hitag S"),
arg_lit0(NULL, "04", "HitagS, write page, crypto mode. Set key=0 for no auth"), arg_lit0(NULL, "ht2", "Hitag 2"),
arg_lit0(NULL, "24", "Hitag2, write page, crypto mode."), arg_lit0(NULL, "pwd", "password mode"),
arg_lit0(NULL, "27", "Hitag2, write page, password mode"),
arg_int1("p", "page", "<dec>", "page address to write to"),
arg_str0("d", "data", "<hex>", "data, 4 hex bytes"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"), arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_int1("p", "page", "<dec>", "page address to write to"),
arg_str1("d", "data", "<hex>", "data, 4 hex bytes"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
// Hitag S bool use_ht1 = false; // not yet implemented
bool s03 = arg_get_lit(ctx, 1); bool use_hts = arg_get_lit(ctx, 1);
bool s04 = arg_get_lit(ctx, 2); bool use_ht2 = arg_get_lit(ctx, 2);
bool use_htm = false; // not yet implemented
// Hitag 2 bool use_plain = false;
bool h24 = arg_get_lit(ctx, 3); bool use_pwd = arg_get_lit(ctx, 3);
bool h27 = arg_get_lit(ctx, 4); uint8_t nrar[8];
int nalen = 0;
uint32_t page = arg_get_u32_def(ctx, 5, 0); int res = CLIParamHexToBuf(arg_get_str(ctx, 4), nrar, sizeof(nrar), &nalen);
uint8_t data[4];
int dlen = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 6), data, sizeof(data), &dlen);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
bool use_nrar = nalen > 0;
bool use_crypto = arg_get_lit(ctx, 5);
uint8_t key[6]; uint8_t key[6];
int keylen = 0; int keylen = 0;
res = CLIParamHexToBuf(arg_get_str(ctx, 7), key, sizeof(key), &keylen); res = CLIParamHexToBuf(arg_get_str(ctx, 6), key, sizeof(key), &keylen);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t nrar[8]; uint32_t page = arg_get_u32_def(ctx, 7, 0);
int nalen = 0;
res = CLIParamHexToBuf(arg_get_str(ctx, 8), nrar, sizeof(nrar), &nalen);
CLIParserFree(ctx);
uint8_t data[4];
int dlen = 0;
res = CLIParamHexToBuf(arg_get_str(ctx, 8), data, sizeof(data), &dlen);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
CLIParserFree(ctx);
// sanity checks // sanity checks
if (dlen != sizeof(data)) { if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) {
PrintAndLogEx(WARNING, "Wrong DATA len expected 4, got %d", dlen); PrintAndLogEx(ERR, "error, specify only one Hitag type");
return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_hts + use_htm) == 0) {
PrintAndLogEx(ERR, "error, specify one Hitag type");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (keylen != 0 && keylen != 6 && keylen != 4) { if (keylen != 0 && keylen != 4 && keylen != 6) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen); PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
return PM3_EINVARG; return PM3_EINVARG;
} }
if (dlen != sizeof(data)) {
PrintAndLogEx(WARNING, "Wrong DATA len expected 4, got %d", dlen);
return PM3_EINVARG;
}
if (nalen != 0 && nalen != 8) { if (nalen != 0 && nalen != 8) {
PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 8, got %d", nalen); PrintAndLogEx(WARNING, "Wrong NR/AR len expected 0 or 8, got %d", nalen);
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t foo = (s03 + s04 + h24 + h27); // complete options
if (keylen == 4) {
use_pwd = true;
}
if (keylen == 6) {
use_crypto = true;
}
if ((keylen == 0) && use_pwd) {
memcpy(key, "MIKR", 4);
keylen = 4;
}
if ((keylen == 0) && use_crypto) {
memcpy(key, "ONMIKR", 6);
keylen = 6;
}
// check coherence
uint8_t foo = (use_plain + use_pwd + use_nrar + use_crypto);
if (foo > 1) { if (foo > 1) {
PrintAndLogEx(WARNING, "Only specify one HITAG write cmd"); PrintAndLogEx(WARNING, "Specify only one authentication mode");
return PM3_EINVARG; return PM3_EINVARG;
} else if (foo == 0) { } else if (foo == 0) {
PrintAndLogEx(WARNING, "Specify one HITAG write cmd"); if (use_hts) {
use_plain = true;
} else {
PrintAndLogEx(WARNING, "Specify one authentication mode");
return PM3_EINVARG;
}
}
if (use_hts && use_pwd) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Password mode");
return PM3_EINVARG;
}
if (use_ht2 && use_plain) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Plain mode");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -801,29 +921,33 @@ static int CmdLFHitagWriter(const char *Cmd) {
hitag_data htd; hitag_data htd;
memset(&htd, 0, sizeof(htd)); memset(&htd, 0, sizeof(htd));
if (s03) { if (use_hts && use_nrar) {
htf = WHTSF_CHALLENGE; htf = WHTSF_CHALLENGE;
memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr)); memcpy(htd.auth.NrAr, nrar, sizeof(htd.auth.NrAr));
memcpy(htd.auth.data, data, sizeof(data)); memcpy(htd.auth.data, data, sizeof(data));
} PrintAndLogEx(INFO, "Authenticating to Hitag S in Challenge mode");
if (s04) { } else if (use_hts && use_crypto) {
htf = WHTSF_KEY; htf = WHTSF_KEY;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key)); memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
memcpy(htd.crypto.data, data, sizeof(data)); memcpy(htd.crypto.data, data, sizeof(data));
} PrintAndLogEx(INFO, "Authenticating to Hitag S in Crypto mode");
if (h24) { } else if (use_ht2 && use_pwd) {
htf = WHT2F_CRYPTO;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
memcpy(htd.crypto.data, data, sizeof(data));
}
if (h27) {
htf = WHT2F_PASSWORD; htf = WHT2F_PASSWORD;
memcpy(htd.pwd.password, key, sizeof(htd.pwd.password)); memcpy(htd.pwd.password, key, sizeof(htd.pwd.password));
memcpy(htd.crypto.data, data, sizeof(data)); memcpy(htd.crypto.data, data, sizeof(data));
PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Password mode");
} else if (use_ht2 && use_crypto) {
htf = WHT2F_CRYPTO;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
memcpy(htd.crypto.data, data, sizeof(data));
PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Crypto mode");
} else {
PrintAndLogEx(WARNING, "Sorry, not yet implemented");
return PM3_ENOTIMPL;
} }
uint16_t cmd = CMD_LF_HITAGS_WRITE;
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_LF_HITAGS_WRITE, htf, 0, page, &htd, sizeof(htd)); SendCommandMIX(cmd, htf, 0, page, &htd, sizeof(htd));
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 4000) == false) { if (WaitForResponseTimeout(CMD_ACK, &resp, 4000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
@ -841,56 +965,132 @@ static int CmdLFHitag2Dump(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag dump", CLIParserInit(&ctx, "lf hitag dump",
"Read all card memory and save to file" "Read all Hitag 2 card memory and save to file\n"
"In password mode the default key is 4D494B52 (MIKR)\n" "Crypto mode key format: ISK high + ISK low",
"In crypto mode the default key is 4F4E4D494B52 (ONMIKR) format: ISK high + ISK low.", "Password mode => use default key 4D494B52 (MIKR)\n"
"lf hitag dump -k 4F4E4D494B52\n" " lf hitag dump --pwd\n"
"Short key = password mode\n"
" lf hitag dump -k 4D494B52\n" " lf hitag dump -k 4D494B52\n"
"Challenge mode\n"
" lf hitag dump --nrar 0102030411223344\n"
"Crypto mode => use default key 4F4E4D494B52 (ONMIKR)\n"
" lf hitag dump --crypto\n"
"Long key = crypto mode\n"
" lf hitag dump -k 4F4E4D494B52\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("f", "file", "<fn>", "specify file name"), arg_lit0(NULL, "pwd", "password mode"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"), arg_str0(NULL, "nrar", "<hex>", "nonce / answer reader, 8 hex bytes"),
arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "key, 4 or 6 hex bytes"),
arg_str0("f", "file", "<fn>", "specify file name"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0; bool use_ht1 = false; // not yet implemented
char filename[FILE_PATH_SIZE] = {0}; bool use_hts = false; // not yet implemented
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); bool use_ht2 = true;
bool use_htm = false; // not yet implemented
bool use_plain = false;
bool use_pwd = arg_get_lit(ctx, 1);
uint8_t nrar[8];
int nalen = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), nrar, sizeof(nrar), &nalen);
if (res != 0) {
CLIParserFree(ctx);
return PM3_EINVARG;
}
bool use_nrar = nalen > 0;
bool use_crypto = arg_get_lit(ctx, 3);
uint8_t key[6]; uint8_t key[6];
int keylen = 0; int keylen = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), key, sizeof(key), &keylen); res = CLIParamHexToBuf(arg_get_str(ctx, 4), key, sizeof(key), &keylen);
if (res != 0) { if (res != 0) {
CLIParserFree(ctx); CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
uint8_t nrar[8]; int fnlen = 0;
int nalen = 0; char filename[FILE_PATH_SIZE] = {0};
res = CLIParamHexToBuf(arg_get_str(ctx, 3), nrar, sizeof(nrar), &nalen); CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx); CLIParserFree(ctx);
if (res != 0) {
// sanity checks
if ((use_ht1 + use_ht2 + use_hts + use_htm) > 1) {
PrintAndLogEx(ERR, "error, specify only one Hitag type");
return PM3_EINVARG;
}
if ((use_ht1 + use_ht2 + use_hts + use_htm) == 0) {
PrintAndLogEx(ERR, "error, specify one Hitag type");
return PM3_EINVARG;
}
if (keylen != 0 && keylen != 4 && keylen != 6) {
PrintAndLogEx(WARNING, "Wrong KEY len expected 0, 4 or 6, got %d", keylen);
return PM3_EINVARG;
}
// complete options
if (keylen == 4) {
use_pwd = true;
}
if (keylen == 6) {
use_crypto = true;
}
if ((keylen == 0) && use_pwd) {
memcpy(key, "MIKR", 4);
keylen = 4;
}
if ((keylen == 0) && use_crypto) {
memcpy(key, "ONMIKR", 6);
keylen = 6;
}
// check coherence
uint8_t foo = (use_plain + use_pwd + use_nrar + use_crypto);
if (foo > 1) {
PrintAndLogEx(WARNING, "Specify only one authentication mode");
return PM3_EINVARG;
} else if (foo == 0) {
if (use_hts) {
use_plain = true;
} else {
PrintAndLogEx(WARNING, "Specify one authentication mode");
return PM3_EINVARG;
}
}
if (use_hts && use_pwd) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Password mode");
return PM3_EINVARG;
}
if (use_ht2 && use_plain) { // not sure for the other types...
PrintAndLogEx(WARNING, "Chosen Hitag type does not have Plain mode");
return PM3_EINVARG; return PM3_EINVARG;
} }
hitag_function htf; hitag_function htf;
hitag_data htd; hitag_data htd;
memset(&htd, 0, sizeof(htd)); memset(&htd, 0, sizeof(htd));
if (use_ht2 && use_pwd) {
if (keylen == 6) {
htf = RHT2F_CRYPTO;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
PrintAndLogEx(INFO, "Authenticating in crypto mode");
} else {
htf = RHT2F_PASSWORD; htf = RHT2F_PASSWORD;
memcpy(htd.pwd.password, key, sizeof(htd.pwd.password)); memcpy(htd.pwd.password, key, sizeof(htd.pwd.password));
PrintAndLogEx(INFO, "Authenticating in password mode"); PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Password mode");
} else if (use_ht2 && use_crypto) {
htf = RHT2F_CRYPTO;
memcpy(htd.crypto.key, key, sizeof(htd.crypto.key));
PrintAndLogEx(INFO, "Authenticating to Hitag 2 in Crypto mode");
} else {
PrintAndLogEx(WARNING, "Sorry, not yet implemented");
return PM3_ENOTIMPL;
} }
uint16_t cmd = CMD_LF_HITAG_READER; uint16_t cmd = CMD_LF_HITAG_READER;
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd)); SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
@ -909,7 +1109,8 @@ static int CmdLFHitag2Dump(const char *Cmd) {
if (data == NULL) if (data == NULL)
return PM3_ESOFT; return PM3_ESOFT;
PrintAndLogEx(SUCCESS, "Dumping tag memory..."); uint32_t id = bytes_to_num(resp.data.asBytes, 4);
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
if (fnlen < 1) { if (fnlen < 1) {
char *fptr = filename; char *fptr = filename;
@ -917,8 +1118,16 @@ static int CmdLFHitag2Dump(const char *Cmd) {
FillFileNameByUID(fptr, data, "-dump", 4); FillFileNameByUID(fptr, data, "-dump", 4);
} }
// block3, 1 byte
printHitag2Configuration(data[4 * 3]);
// print data
print_hex_break(data, 48, 4); print_hex_break(data, 48, 4);
printHitag2PaxtonDowngrade(data);
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
pm3_save_dump(filename, data, 48, jsfHitag, 4); pm3_save_dump(filename, data, 48, jsfHitag, 4);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -982,16 +1191,20 @@ void annotateHitagS(char *exp, size_t size, const uint8_t *cmd, uint8_t cmdsize,
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"-----------", CmdHelp, IfPm3Hitag, "------------------------ " _CYAN_("General") " ------------------------"},
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
{"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"}, {"list", CmdLFHitagList, AlwaysAvailable, "List Hitag trace history"},
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("operations") " -----------------------"},
{"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"}, {"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"},
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag reader"},
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag writer"},
{"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag 2 tag"}, {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag 2 tag"},
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges"}, {"read", CmdLFHitagReader, IfPm3Hitag, "Read Hitag memory"},
{"wrbl", CmdLFHitagWriter, IfPm3Hitag, "Write a block (page) in Hitag memory"},
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication"},
{"cc", CmdLFHitagSCheckChallenges, IfPm3Hitag, "Hitag S: test all provided challenges"},
{"ta", CmdLFHitag2CheckChallenges, IfPm3Hitag, "Hitag 2: test all recorded authentications"},
{"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("simulation") " -----------------------"},
{"eload", CmdLFHitagEload, IfPm3Hitag, "Load Hitag dump file into emulator memory"},
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder"},
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };