mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-17 18:50:32 +08:00
added trace extract, it extracts auth challengens in MFU-C/ICLASS/DESFIRE and prints it.
This commit is contained in:
parent
e6a14bf869
commit
57d0397436
2 changed files with 347 additions and 6 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Added `trace extract` - extract authentication parts from trace (@iceman1001)
|
||||||
- Added luascript `hf_mf_ultimatecard.lua` - Script for Ultimate Magic Card (GEN4) (@startrk1995)
|
- Added luascript `hf_mf_ultimatecard.lua` - Script for Ultimate Magic Card (GEN4) (@startrk1995)
|
||||||
- Added new tool `brute_key` - MIFARE DESFire Telenot access AES recovery (@x41sec)
|
- Added new tool `brute_key` - MIFARE DESFire Telenot access AES recovery (@x41sec)
|
||||||
- Fixed `hf mfu dump -k` - insert PWD in dump (@doegox)
|
- Fixed `hf mfu dump -k` - insert PWD in dump (@doegox)
|
||||||
|
|
|
@ -79,6 +79,299 @@ static bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, ui
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
static uint8_t calc_pos(uint8_t *d){
|
||||||
|
// PCB [CID] [NAD] [INF] CRC CRC
|
||||||
|
uint8_t pos = 1;
|
||||||
|
if ((d[0] & 0x08) == 0x08) // cid byte following
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
if ((d[0] & 0x04) == 0x04) // nad byte following
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t extract_uid[10] = {0};
|
||||||
|
static uint8_t extract_uidlen = 0;
|
||||||
|
static uint8_t extract_epurse[8] = {0};
|
||||||
|
|
||||||
|
#define SKIP_TO_NEXT(a) (TRACELOG_HDR_LEN + (a)->data_len + TRACELOG_PARITY_LEN((a)))
|
||||||
|
|
||||||
|
static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t *trace) {
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (is_last_record(tracepos, traceLen)) {
|
||||||
|
return traceLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
uint16_t data_len = hdr->data_len;
|
||||||
|
uint8_t *frame = hdr->frame;
|
||||||
|
|
||||||
|
// sanity check tracking position is less then available trace size
|
||||||
|
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) {
|
||||||
|
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu64 " larger than reported tracelen %u",
|
||||||
|
tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr),
|
||||||
|
traceLen
|
||||||
|
);
|
||||||
|
return traceLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trace position
|
||||||
|
tracepos += SKIP_TO_NEXT(hdr);
|
||||||
|
|
||||||
|
// sanity check data frame length
|
||||||
|
if (data_len == 0) {
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract MFC
|
||||||
|
switch (frame[0]) {
|
||||||
|
case MIFARE_AUTH_KEYA: {
|
||||||
|
if (data_len > 3) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MIFARE_AUTH_KEYB: {
|
||||||
|
if (data_len > 3) {
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract MFU-C
|
||||||
|
switch (frame[0]) {
|
||||||
|
case MIFARE_ULC_AUTH_1: {
|
||||||
|
if (data_len != 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// time to skip to next
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
|
if (next_hdr->data_len != 11) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_hdr->frame[0] != MIFARE_ULC_AUTH_2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "MFU-C AUTH");
|
||||||
|
PrintAndLogEx(INFO, "3DES %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||||
|
|
||||||
|
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
|
|
||||||
|
if (next_hdr->frame[0] == MIFARE_ULC_AUTH_2 && next_hdr->data_len == 19) {
|
||||||
|
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + 1, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract iCLASS
|
||||||
|
// --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b
|
||||||
|
|
||||||
|
if (hdr->isResponse == false) {
|
||||||
|
|
||||||
|
uint8_t c = frame[0] & 0x0F;
|
||||||
|
switch (c) {
|
||||||
|
case ICLASS_CMD_SELECT: {
|
||||||
|
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
|
if (next_hdr->data_len != 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(extract_uid, next_hdr->frame, 8);
|
||||||
|
extract_uidlen = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ICLASS_CMD_READCHECK: {
|
||||||
|
|
||||||
|
// get epurse
|
||||||
|
if (frame[1] == 2 && data_len == 2) {
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
|
if (next_hdr->data_len < 8) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(extract_epurse, next_hdr->frame, 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ICLASS_CMD_CHECK: {
|
||||||
|
// get macs
|
||||||
|
if (data_len == 9) {
|
||||||
|
if (extract_uidlen == 8) {
|
||||||
|
PrintAndLogEx(INFO, "hf iclass lookup --csn %s " NOLF, sprint_hex_inrow(extract_uid, extract_uidlen));
|
||||||
|
PrintAndLogEx(NORMAL, "--epurse %s " NOLF, sprint_hex_inrow(extract_epurse, 8));
|
||||||
|
PrintAndLogEx(NORMAL, "--macs %s " NOLF, sprint_hex_inrow(frame + 1, 8) );
|
||||||
|
PrintAndLogEx(NORMAL, "-f iclass_default_keys.dic");
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract UID
|
||||||
|
switch (frame[0]) {
|
||||||
|
case ISO14443A_CMD_ANTICOLL_OR_SELECT: {
|
||||||
|
// 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
|
||||||
|
// 93 50 = Bit oriented anti-collision (usage: 9350+ up to 5bytes, 9350 answer - up to 5bytes UID+BCC)
|
||||||
|
// 93 70 = Select (usage: 9370+5bytes 9370 answer - answer: 1byte SAK)
|
||||||
|
if (frame[1] == 0x70) {
|
||||||
|
if (frame[2] == 0x88) {
|
||||||
|
memcpy(extract_uid, frame + 3, 3);
|
||||||
|
extract_uidlen = 3;
|
||||||
|
} else {
|
||||||
|
memcpy(extract_uid, frame + 2, 4);
|
||||||
|
extract_uidlen = 4;
|
||||||
|
PrintAndLogEx(INFO, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid, extract_uidlen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ISO14443A_CMD_ANTICOLL_OR_SELECT_2: {
|
||||||
|
// 95 20 = Anticollision of cascade level2
|
||||||
|
// 95 50 = Bit oriented anti-collision level2
|
||||||
|
// 95 70 = Select of cascade level2
|
||||||
|
if (frame[1] == 0x70) {
|
||||||
|
if (frame[2] == 0x88) {
|
||||||
|
memcpy(extract_uid + extract_uidlen, frame + 3, 3);
|
||||||
|
extract_uidlen += 3;
|
||||||
|
} else {
|
||||||
|
memcpy(extract_uid + extract_uidlen, frame + 2, 4);
|
||||||
|
extract_uidlen += 4;
|
||||||
|
PrintAndLogEx(INFO, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid, extract_uidlen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ISO14443A_CMD_ANTICOLL_OR_SELECT_3: {
|
||||||
|
// 97 20 = Anticollision of cascade level3
|
||||||
|
// 97 50 = Bit oriented anti-collision level3
|
||||||
|
// 97 70 = Select of cascade level3
|
||||||
|
if (frame[1] == 0x70) {
|
||||||
|
memcpy(extract_uid + extract_uidlen, frame + 2, 4);
|
||||||
|
extract_uidlen += 4;
|
||||||
|
PrintAndLogEx(INFO, "UID... " _YELLOW_("%s"), sprint_hex_inrow(extract_uid, extract_uidlen));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract DESFIRE
|
||||||
|
if ((frame[0] & 0xC0) != 0x00) {
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PCB [CID] [NAD] [INF] CRC CRC
|
||||||
|
uint8_t pos = calc_pos(frame);
|
||||||
|
uint8_t long_jmp = (data_len > 6) ? 4 : 1;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 2; i++, pos++) {
|
||||||
|
|
||||||
|
switch (frame[pos]) {
|
||||||
|
|
||||||
|
case MFDES_AUTHENTICATE: {
|
||||||
|
// Assume wrapped or unwrapped
|
||||||
|
PrintAndLogEx(INFO, "AUTH NATIVE (keyNo %d)", frame[pos + long_jmp]);
|
||||||
|
|
||||||
|
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||||
|
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
if (next_hdr->data_len < 7) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, "DES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||||
|
|
||||||
|
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
|
||||||
|
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||||
|
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||||
|
}
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
break; // AUTHENTICATE_NATIVE
|
||||||
|
}
|
||||||
|
case MFDES_AUTHENTICATE_ISO: {
|
||||||
|
|
||||||
|
// Assume wrapped or unwrapped
|
||||||
|
PrintAndLogEx(INFO, "AUTH ISO (keyNo %d)", frame[pos + long_jmp]);
|
||||||
|
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||||
|
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
if (next_hdr->data_len < 7) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tdea = 8;
|
||||||
|
if (next_hdr->data_len > 20) {
|
||||||
|
tdea = 16;
|
||||||
|
PrintAndLogEx(INFO, "3TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "2TDEA 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, tdea));
|
||||||
|
}
|
||||||
|
|
||||||
|
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
|
||||||
|
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||||
|
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, (tdea<<1)));
|
||||||
|
}
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
|
||||||
|
break; // AUTHENTICATE_STANDARD
|
||||||
|
}
|
||||||
|
case MFDES_AUTHENTICATE_AES: {
|
||||||
|
// Assume wrapped or unwrapped
|
||||||
|
PrintAndLogEx(INFO, "AUTH AES (keyNo %d)", frame[pos + long_jmp]);
|
||||||
|
if (hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||||
|
|
||||||
|
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
if (next_hdr->data_len < 7) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PrintAndLogEx(INFO, "AES 1499999999 %s " NOLF, sprint_hex_inrow(next_hdr->frame + 1, 8));
|
||||||
|
|
||||||
|
next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
tracepos += TRACELOG_HDR_LEN + next_hdr->data_len + TRACELOG_PARITY_LEN(next_hdr);
|
||||||
|
|
||||||
|
if (next_hdr->frame[pos] == MFDES_ADDITIONAL_FRAME) {
|
||||||
|
PrintAndLogEx(NORMAL, "%s", sprint_hex_inrow(next_hdr->frame + pos + long_jmp, 16));
|
||||||
|
}
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MFDES_AUTHENTICATE_EV2F: {
|
||||||
|
if (hdr->isResponse == false) {
|
||||||
|
PrintAndLogEx(INFO, "AUTH EV2 First");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MFDES_AUTHENTICATE_EV2NF: {
|
||||||
|
if (hdr->isResponse == false) {
|
||||||
|
PrintAndLogEx(INFO, "AUTH EV2 Non First");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tracepos;
|
||||||
|
}
|
||||||
|
|
||||||
static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol) {
|
static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol) {
|
||||||
// sanity check
|
// sanity check
|
||||||
|
@ -150,8 +443,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t end_of_transmission_timestamp = 0;
|
uint32_t end_of_transmission_timestamp = 0;
|
||||||
uint32_t duration;
|
|
||||||
uint16_t data_len;
|
|
||||||
uint8_t topaz_reader_command[9];
|
uint8_t topaz_reader_command[9];
|
||||||
char explanation[40] = {0};
|
char explanation[40] = {0};
|
||||||
uint8_t mfData[32] = {0};
|
uint8_t mfData[32] = {0};
|
||||||
|
@ -159,11 +450,14 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
|
tracelog_hdr_t *first_hdr = (tracelog_hdr_t *)(trace);
|
||||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
|
||||||
duration = hdr->duration;
|
uint32_t duration = hdr->duration;
|
||||||
data_len = hdr->data_len;
|
uint16_t data_len = hdr->data_len;
|
||||||
|
|
||||||
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) {
|
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) {
|
||||||
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu64 " larger than reported tracelen %u", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen);
|
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu64 " larger than reported tracelen %u",
|
||||||
|
tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr),
|
||||||
|
traceLen
|
||||||
|
);
|
||||||
return traceLen;
|
return traceLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,6 +885,50 @@ static int SanityOfflineCheck( bool useTraceBuffer ){
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static int CmdTraceExtract(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "trace extract",
|
||||||
|
"Extracts protocol authentication challenges from trace buffer\n",
|
||||||
|
"trace extract\n"
|
||||||
|
"trace extract -1\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_lit0("1", "buffer", "use data from trace buffer"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
bool use_buffer = arg_get_lit(ctx, 1);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
clearCommandBuffer();
|
||||||
|
|
||||||
|
if (use_buffer == false) {
|
||||||
|
download_trace();
|
||||||
|
} else if (gs_traceLen == 0) {
|
||||||
|
PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace.");
|
||||||
|
PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`"));
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%lu") " bytes)", gs_traceLen);
|
||||||
|
if (gs_traceLen == 0) {
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tracepos = 0;
|
||||||
|
|
||||||
|
while (tracepos < gs_traceLen) {
|
||||||
|
tracepos = extractChallenges(tracepos, gs_traceLen, gs_trace);
|
||||||
|
|
||||||
|
if (kbd_enter_pressed())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdTraceLoad(const char *Cmd) {
|
static int CmdTraceLoad(const char *Cmd) {
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -800,7 +1138,8 @@ int CmdTraceList(const char *Cmd) {
|
||||||
if (use_buffer == false) {
|
if (use_buffer == false) {
|
||||||
download_trace();
|
download_trace();
|
||||||
} else if (gs_traceLen == 0) {
|
} else if (gs_traceLen == 0) {
|
||||||
PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace, consider using 'trace load' or removing parameter '-1'");
|
PrintAndLogEx(FAILED, "You requested a trace list in offline mode but there is no trace.");
|
||||||
|
PrintAndLogEx(FAILED, "Consider using " _YELLOW_("`trace load`") " or removing parameter " _YELLOW_("`-1`"));
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,6 +1278,7 @@ int CmdTraceList(const char *Cmd) {
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"extract", CmdTraceExtract, AlwaysAvailable, "Extract authentication challenges found in trace"},
|
||||||
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
||||||
{"load", CmdTraceLoad, AlwaysAvailable, "Load trace from file"},
|
{"load", CmdTraceLoad, AlwaysAvailable, "Load trace from file"},
|
||||||
{"save", CmdTraceSave, AlwaysAvailable, "Save trace buffer to file"},
|
{"save", CmdTraceSave, AlwaysAvailable, "Save trace buffer to file"},
|
||||||
|
|
Loading…
Reference in a new issue