Merge pull request #1943 from 0xdeb/legic_info

Legic info command for other sources, out of bounds memory
This commit is contained in:
Iceman 2023-03-19 18:37:10 +01:00 committed by GitHub
commit 48d9503a5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 127 additions and 40 deletions

View file

@ -33,6 +33,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Add Mifare Classic EV1 signature write support to gen4 magic tag lua script (@augustozanellato)
- Added XOR key extraction and flag to Guardall G-Prox II (@GuruSteve)
- Changed verbiage on `hf iclass info` KeyAccess area to be congruent with AA1 and AA2 areas (@GuruSteve)
- Added `hf legic info` command for other sources: `hf legic einfo`, `hf legic view` (@0xdeb)
-
## [Nitride.4.16191][2023-01-29]

View file

@ -57,54 +57,28 @@ static bool legic_xor(uint8_t *data, uint16_t cardsize) {
return true;
}
/*
* Output BigBuf and deobfuscate LEGIC RF tag data.
* This is based on information given in the talk held
* by Henryk Ploetz and Karsten Nohl at 26c3
*/
static int CmdLegicInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic info",
"Gets information from a LEGIC Prime tag like systemarea, user areas, etc",
"hf legic info");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
static int decode_and_print_memory(uint16_t card_size, const uint8_t *input_buffer) {
int i = 0, k = 0, segmentNum = 0, segment_len = 0, segment_flag = 0;
int crc = 0, wrp = 0, wrc = 0;
uint8_t stamp_len = 0;
uint16_t datalen = 0;
char token_type[6] = {0, 0, 0, 0, 0, 0};
int dcf = 0;
int bIsSegmented = 0;
int return_value = PM3_SUCCESS;
// tagtype
legic_card_select_t card;
if (legic_get_type(&card) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed to identify tagtype");
return PM3_ESOFT;
if (!(card_size == LEGIC_PRIME_MIM22 || card_size == LEGIC_PRIME_MIM256 || card_size == LEGIC_PRIME_MIM1024)) {
PrintAndLogEx(FAILED, "Bytebuffer is not any known legic card size! (MIM22, MIM256, MIM1024)");
return_value = PM3_EFAILED;
return PM3_EFAILED;
}
PrintAndLogEx(SUCCESS, "Reading full tag memory of " _YELLOW_("%d") " bytes...", card.cardsize);
// allocate receiver buffer
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
// copy input buffer into newly allocated buffer, because the existing code mutates the data inside.
uint8_t *data = calloc(card_size, sizeof(uint8_t));
if (!data) {
PrintAndLogEx(WARNING, "Cannot allocate memory");
return PM3_EMALLOC;
}
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
if (status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed reading memory");
free(data);
return status;
}
memcpy(data, input_buffer, card_size);
// Output CDF System area (9 bytes) plus remaining header area (12 bytes)
crc = data[4];
@ -217,9 +191,10 @@ static int CmdLegicInfo(const char *Cmd) {
uint32_t segCalcCRC = 0;
uint32_t segCRC = 0;
// Not Data card?
if (dcf > 60000)
// Not a data card by dcf or too small to contain data (MIM22)?
if (dcf > 60000 || card_size == LEGIC_PRIME_MIM22) {
goto out;
}
PrintAndLogEx(SUCCESS, _CYAN_("ADF: User Area"));
PrintAndLogEx(NORMAL, "------------------------------------------------------");
@ -231,6 +206,13 @@ static int CmdLegicInfo(const char *Cmd) {
// decode segments
for (segmentNum = 1; segmentNum < 128; segmentNum++) {
// for decoding the segment header we need at least 4 bytes left in buffer
if ((i + 4) > card_size) {
PrintAndLogEx(FAILED, "Cannot read segment header, because the input buffer is too small. "
"Please check that the data is correct and properly aligned. ");
return_value = PM3_EOUTOFBOUND;
goto out;
}
segment_len = ((data[i + 1] ^ crc) & 0x0f) * 256 + (data[i] ^ crc);
segment_flag = ((data[i + 1] ^ crc) & 0xf0) >> 4;
wrp = (data[i + 2] ^ crc);
@ -277,6 +259,14 @@ static int CmdLegicInfo(const char *Cmd) {
i += 5;
// for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
"Please check that the data is correct and properly aligned. ");
return_value = PM3_EOUTOFBOUND;
goto out;
}
if (hasWRC) {
PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
PrintAndLogEx(NORMAL, "\nrow | data");
@ -330,7 +320,6 @@ static int CmdLegicInfo(const char *Cmd) {
} // end for loop
} else {
// Data start point on unsegmented cards
i = 8;
@ -340,7 +329,7 @@ static int CmdLegicInfo(const char *Cmd) {
bool hasWRC = (wrc > 0);
bool hasWRP = (wrp > wrc);
int wrp_len = (wrp - wrc);
int remain_seg_payload_len = (card.cardsize - 22 - wrp);
int remain_seg_payload_len = (card_size - 22 - wrp);
PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
wrp,
@ -348,6 +337,14 @@ static int CmdLegicInfo(const char *Cmd) {
(data[7] & 0x80) >> 7
);
// for printing the complete segment we need at least wrc + wrp_len + remain_seg_payload_len bytes
if ((i + wrc + wrp_len + remain_seg_payload_len) > card_size) {
PrintAndLogEx(FAILED, "Cannot read segment body, because the input buffer is too small. "
"Please check that the data is correct and properly aligned. ");
return_value = PM3_EOUTOFBOUND;
goto out;
}
if (hasWRC) {
PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc);
PrintAndLogEx(NORMAL, "\nrow | data");
@ -386,6 +383,55 @@ static int CmdLegicInfo(const char *Cmd) {
}
out:
free(data);
return (return_value);
}
/*
* Output BigBuf and deobfuscate LEGIC RF tag data.
* This is based on information given in the talk held
* by Henryk Ploetz and Karsten Nohl at 26c3
*/
static int CmdLegicInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic info",
"Gets information from a LEGIC Prime tag like systemarea, user areas, etc",
"hf legic info");
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
uint16_t datalen = 0;
// tagtype
legic_card_select_t card;
if (legic_get_type(&card) != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed to identify tagtype");
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Reading full tag memory of " _YELLOW_("%d") " bytes...", card.cardsize);
// allocate receiver buffer
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
if (!data) {
PrintAndLogEx(WARNING, "Cannot allocate memory");
return PM3_EMALLOC;
}
int status = legic_read_mem(0, card.cardsize, 0x55, data, &datalen);
if (status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Failed reading memory");
free(data);
return status;
}
decode_and_print_memory(card.cardsize, data);
free(data);
return PM3_SUCCESS;
}
@ -1174,6 +1220,41 @@ static int CmdLegicEView(const char *Cmd) {
return PM3_SUCCESS;
}
static int CmdLegicEInfo(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic einfo",
"It decodes and displays emulator memory",
"hf legic einfo\n"
);
void *argtable[] = {
arg_param_begin,
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
size_t card_size = LEGIC_PRIME_MIM256;
uint8_t *dump = calloc(card_size, sizeof(uint8_t));
if (dump == NULL) {
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
return PM3_EMALLOC;
}
PrintAndLogEx(INFO, "downloading emulator memory");
if (GetFromDevice(BIG_BUF_EML, dump, card_size, 0, NULL, 0, NULL, 2500, false) == false) {
PrintAndLogEx(WARNING, "Fail, transfer from device time-out");
free(dump);
return PM3_ETIMEOUT;
}
decode_and_print_memory(card_size, dump);
free(dump);
return PM3_SUCCESS;
}
static int CmdLegicWipe(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf legic wipe",
@ -1286,6 +1367,10 @@ static int CmdLegicView(const char *Cmd) {
PrintAndLogEx(INFO, "## | 0 1 2 3 4 5 6 7 8 9 A B C D E F | ascii");
PrintAndLogEx(INFO, "---+-------------------------------------------------+-----------------");
print_hex_break(dump, bytes_read, 16);
PrintAndLogEx(NORMAL, "");
decode_and_print_memory(bytes_read, dump);
free(dump);
return PM3_SUCCESS;
}
@ -1306,9 +1391,10 @@ static command_t CommandTable[] = {
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
{"eview", CmdLegicEView, IfPm3Legicrf, "View emulator memory"},
{"einfo", CmdLegicEInfo, IfPm3Legicrf, "Display deobfuscated and decoded emulator memory"},
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("utils") " ---------------------"},
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
{"view", CmdLegicView, AlwaysAvailable, "Display content from tag dump file"},
{"view", CmdLegicView, AlwaysAvailable, "Display deobfuscated and decoded content from tag dump file"},
{NULL, NULL, NULL, NULL}
};