Merge branch 'master' into 20260713-gdm

Signed-off-by: Iceman <iceman@iuse.se>
This commit is contained in:
Iceman
2026-07-15 16:48:51 +07:00
committed by GitHub
2 changed files with 98 additions and 1 deletions
+4 -1
View File
@@ -4,7 +4,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
## [unreleased][unreleased]
- Added `hf mf gdmgetblk/gdmgethidblk/gdmsethidblk/gdmsetuid/gdmwipe/gdmsetsig` ,improved `hf mf gdmparsecfg/gdmsetblk` and rename `hf mf gdmcfg` commands (@0x6r1an0y)
- Added `hf mf gdmgetblk/gdmgethidblk/gdmsethidblk/gdmsetuid/gdmwipe/gdmsetsig` (@0x6r1an0y)
- Changed `hf mf gdmparsecfg/gdmsetblk` (@0x6r1an0y)
- Renamed `hf mf gdmcfg` (@0x6r1an0y)
- Added `hf mfu aesgetuid` for retrieving the real UID when random ID is enabled, using the UIDRetrKey. (@lolbird123)
- Fixed `hf iclass view` reading past the end of dump files smaller than a picopass header, causing a heap out-of-bounds read and garbage/leaked heap data being printed as tag content (@munzzyy)
- Fixed `wiegand decode` returning facility code 16777339 instead of the encoded value for the IR56 (Inner Range 56-bit) format by masking the header sentinel bit off the facility code (@munzzyy)
- Fixed `lf em 4x05 dump` writing byte-swapped (corrupted) block data to the saved dump file (@munzzyy)
+94
View File
@@ -4899,6 +4899,8 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) {
return result;
}
static int CmdHF14AMfUAESAuthChk(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu aeschk",
@@ -5024,6 +5026,97 @@ out:
return PM3_SUCCESS;
}
static int CmdHF14AMfUAESGetUID(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu aesgetuid",
"Retreives real UID on Mifare Ultralight AES tags when random ID is enabled.\n"
"Uses key index 1 (UIDRetrKey).\n"
"If no key is specified, null key will be tried.\n",
"hf mfu aesgetuid\n"
"hf mfu aesgetuid --key <16 hex bytes>\n"
"hf mfu aesgetuid --key <16 hex bytes> --schann"
);
void *argtable[] = {
arg_param_begin,
arg_str0(NULL, "key", "<hex>", "AES key (16 hex bytes)"),
arg_lit0("l", NULL, "Swap entered key's endianness"),
arg_lit0(NULL, "schann", "use secure channel. Must have key"),
arg_int0("r", "retries", "<n>", "Number of retries (def: 0)"),
arg_lit0("n", "nocheck", "Skip checking tag answer correctness"),
arg_lit0("0", "read0", "Use fast READ0 (skip anticol)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int ak_len = 0;
uint8_t authentication_key[16] = {0};
uint8_t *auth_key_ptr = authentication_key;
CLIGetHexWithReturn(ctx, 1, authentication_key, &ak_len);
int key_index = 1;
bool swap_endian = arg_get_lit(ctx, 2);
bool keep_field_on = true;
bool use_schann = arg_get_lit(ctx, 3);
int retries = arg_get_int_def(ctx, 4, 0);
bool check_answer = !arg_get_lit(ctx, 5);
bool use_fastread0 = arg_get_lit(ctx, 6);
CLIParserFree(ctx);
if (ak_len == 0) {
// default to null key
ak_len = 16;
}
if (ak_len != 16) {
PrintAndLogEx(WARNING, "Invalid key length");
return PM3_EINVARG;
}
if (key_index < 0 || key_index > 2) {
PrintAndLogEx(WARNING, "Invalid key index");
return PM3_EINVARG;
}
// Swap endianness
if (swap_endian && ak_len) {
auth_key_ptr = SwapEndian64(authentication_key, ak_len, 16);
}
if (retries < 0 || retries > 10000) {
PrintAndLogEx(ERR, "Invalid retries (must be 0..10000)");
return PM3_EINVARG;
}
uint32_t auths = 0;
uint32_t ms = 0;
int result = ul3pass_authentication(auth_key_ptr, key_index, !keep_field_on, retries, &auths, &ms, use_schann, true, check_answer, use_fastread0, false, NULL, false, 0, NULL);
if (result == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )"
, key_type[key_index]
, sprint_hex_inrow(auth_key_ptr, ak_len)
);
} else {
PrintAndLogEx(WARNING, "Authentication with " _YELLOW_("%s") " ( " _RED_("fail") " )", key_type[key_index]);
return PM3_ESOFT;
}
if (retries > 0) {
PrintAndLogEx(INFO, "Time spent " _YELLOW_("%.1fs"), (float)(ms / 1000.0));
PrintAndLogEx(INFO, "Authentication attempts: %u", auths);
PrintAndLogEx(INFO, "Speed: %.1f auths/s", (float)(auths * 1000.0 / ms));
}
uint8_t data[8] = {0x00};
int status = ul_read(0, data, sizeof(data), use_schann);
if (status <= 0) {
DropField();
PrintAndLogEx(ERR, "Error: tag didn't answer to READ %i", status);
return PM3_ESOFT;
}
uint8_t uid[7] = {data[0], data[1], data[2], data[4], data[5], data[6], data[7]};
PrintAndLogEx(SUCCESS, "UID: " _GREEN_("%s"), sprint_hex(uid, 7));
return PM3_SUCCESS;
}
//DESBRUTE Translation: C2Pwn
typedef enum {
@@ -8137,6 +8230,7 @@ static command_t CommandTable[] = {
{"desbrute", CmdHF14AMfUCDesBrute, AlwaysAvailable, "Ultralight-C - 3DES key segment brute force"},
{"aesauth", CmdHF14AMfUAESAuth, IfPm3Iso14443a, "Ultralight-AES - Authentication"},
{"aeschk", CmdHF14AMfUAESAuthChk, IfPm3Iso14443a, "Ultralight-AES - Authentication dictionary check"},
{"aesgetuid", CmdHF14AMfUAESGetUID, IfPm3Iso14443a, "Ultralight-AES - Get UID when RID in use"},
{"setkey", CmdHF14AMfUSetKey, IfPm3Iso14443a, "Ultralight C/AES - Set 3DES/AES keys"},
{"dump", CmdHF14AMfUDump, IfPm3Iso14443a, "Dump MIFARE Ultralight family tag to binary file"},
{"incr", CmdHF14AMfUIncr, IfPm3Iso14443a, "Increments Ev1/NTAG counter"},