diff --git a/README.md b/README.md index b8140e407..56af79cda 100644 --- a/README.md +++ b/README.md @@ -135,12 +135,6 @@ The separation from official Proxmark3 repo gives us a lot of freedom to create The official PM3-GUI from Gaucho will not work. The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers. -## The end - -- July 2018 [@herrmann1001](https://mobile.twitter.com/herrmann1001) -- updated Feb 2019 [@5w0rdfish](https://mobile.twitter.com/5w0rdFish) -- updated 2019 [@doegox](https://mobile.twitter.com/doegox) - # Donations Nothing says thank you as much as a donation. So if you feel the love, do feel free to become a iceman patron. For some tiers it comes with rewards. diff --git a/client/luascripts/hf_mfu_setuid.lua b/client/luascripts/hf_mfu_setuid.lua index 86bef09c3..f64d5cfab 100644 --- a/client/luascripts/hf_mfu_setuid.lua +++ b/client/luascripts/hf_mfu_setuid.lua @@ -4,26 +4,32 @@ local ansicolors = require('ansicolors') copyright = '' author = "Iceman" -version = 'v1.0.2' +version = 'v1.0.3' desc = [[ This script tries to set UID on a mifare Ultralight magic card which either - answers to chinese backdoor commands - brickable magic tag (must write in one session) + + It defaults to GEN1A type of uid changeable card. ]] example = [[ - -- backdoor magic tag + -- backdoor magic tag (gen1a) script run hf_mfu_setuid -u 11223344556677 - -- brickable magic tag + -- backdoor magic tag (gen1b) script run hf_mfu_setuid -b -u 11223344556677 + + -- brickable magic tag (gen2) + script run hf_mfu_setuid -2 -u 11223344556677 ]] usage = [[ -script run hf_mfu_setuid [-h] [-b] [-u ] +script run hf_mfu_setuid [-h] [-b] [-2] [-u ] ]] arguments = [[ -h : this help -u : UID (14 hexsymbols) - -b : write to brickable magic tag + -b : write to magic tag GEN1B + -2 : write to brickable magic tag GEN2 ]] local DEBUG = true @@ -65,23 +71,33 @@ local function help() end -- --- Set UID on magic command enabled -function magicUID(b0, b1, b2) +function magicUID(b0, b1, b2, isgen1a) - print('Using backdoor Magic tag function') + if isgen1a then + print('Using backdoor Magic tag (gen1a) function') + else + print('Using backdoor Magic tag (gen1b) function') + end -- write block 0 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A200'..b0) -- write block 1 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A201'..b1) -- write block 2 core.console('hf 14a raw -k -a -b 7 40') - core.console('hf 14a raw -k -a 43') + if isgen1a then + core.console('hf 14a raw -k -a 43') + end core.console('hf 14a raw -c -a A202'..b2) end -- @@ -113,10 +129,11 @@ function main(args) local tagtype = 1 -- Read the parameters - for o, a in getopt.getopt(args, 'hu:b') do + for o, a in getopt.getopt(args, 'hu:b2') do if o == 'h' then return help() end if o == 'u' then uid = a end if o == 'b' then tagtype = 2 end + if o == '2' then tagtype = 3 end end -- uid string checks @@ -137,10 +154,11 @@ function main(args) core.clearCommandBuffer() - if tagtype == 2 then + if tagtype == 3 then brickableUID(block0, block1, block2) else - magicUID(block0, block1, block2) + local is_gen1a = (tagtype == 1) + magicUID(block0, block1, block2, is_gen1a) end --halt diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index d4418ee62..150b49fee 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -2135,20 +2135,30 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } static uint16_t get_sw(uint8_t *d, uint8_t n) { - if (n < 2) + if (n < 2) { return 0; - + } n -= 2; return d[n] * 0x0100 + d[n + 1]; } +static uint64_t inc_sw_error_occurence(uint16_t sw, uint64_t all_sw[256][256]) { + uint8_t sw1 = (uint8_t)(sw >> 8); + uint8_t sw2 = (uint8_t)(0xff & sw); + if (sw1 == 0x90 && sw2 == 0x00) { + return 0; // Don't count successes. + } + if (sw1 == 0x6d && sw2 == 0x00) { + return 0xffffffffffffffffULL; // Always max "Instruction not supported". + } + return ++all_sw[sw1][sw2]; +} + static int CmdHf14AFindapdu(const char *Cmd) { - // TODO: What response values should be considerd "valid" or "instersting" (worth dispalying)? // TODO: Option to select AID/File (and skip INS 0xA4). // TODO: Validate the decoding of the APDU (not specific to this command, check // https://cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#chap5_3_2). // TODO: Check all cases (APDUs) with no data bytes (no/short/extended length). - // TODO: Option to blacklist instructions (or whole APDUs). CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a apdufind", "Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" @@ -2157,16 +2167,19 @@ static int CmdHf14AFindapdu(const char *Cmd) { "Tag must be on antenna before running.", "hf 14a apdufind\n" "hf 14a apdufind --cla 80\n" + "hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0\n" ); void *argtable[] = { arg_param_begin, - arg_str0("c", "cla", "", "Start value of CLASS (1 hex byte)"), - arg_str0("i", "ins", "", "Start value of INSTRUCTION (1 hex byte)"), - arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), - arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), - arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), - arg_lit0("v", "verbose", "Verbose output"), + arg_str0("c", "cla", "", "Start value of CLASS (1 hex byte)"), + arg_str0("i", "ins", "", "Start value of INSTRUCTION (1 hex byte)"), + arg_str0(NULL, "p1", "", "Start value of P1 (1 hex byte)"), + arg_str0(NULL, "p2", "", "Start value of P2 (1 hex byte)"), + arg_u64_0("r", "reset", "", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), + arg_u64_0("e", "error-limit", "", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 256."), + arg_strx0("s", "skip-ins", "", "Do not test an instructions (can be specifed multiple times)"), + arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2183,8 +2196,12 @@ static int CmdHf14AFindapdu(const char *Cmd) { int p2_len = 0; uint8_t p2_arg[1] = {0}; CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); - uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); // Reset every 5 minutes. - bool verbose = arg_get_lit(ctx, 6); + uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); + uint64_t error_limit = arg_get_u64_def(ctx, 6, 256); + int ignore_ins_len = 0; + uint8_t ignore_ins_arg[250] = {0}; + CLIGetHexWithReturn(ctx, 7, ignore_ins_arg, &ignore_ins_len); + bool verbose = arg_get_lit(ctx, 8); CLIParserFree(ctx); @@ -2211,6 +2228,9 @@ static int CmdHf14AFindapdu(const char *Cmd) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); bool inc_p1 = true; + bool skip_ins = false; + uint64_t all_sw[256][256] = {0}; + uint64_t sw_occurences = 0; uint64_t t_start = msclock(); uint64_t t_last_reset = msclock(); @@ -2218,12 +2238,25 @@ static int CmdHf14AFindapdu(const char *Cmd) { do { do { do { +retry_ins: // Exit (was the Enter key pressed)? if (kbd_enter_pressed()) { PrintAndLogEx(INFO, "User interrupted detected. Aborting"); goto out; } + // Skip/Ignore this instrctuion? + for (int i = 0; i < ignore_ins_len; i++) { + if (ins == ignore_ins_arg[i]) { + skip_ins = true; + break; + } + } + if (skip_ins) { + skip_ins = false; + continue; + } + if (verbose) { PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); } @@ -2233,38 +2266,47 @@ static int CmdHf14AFindapdu(const char *Cmd) { int command_n = sizeof(command); res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { - continue; + DropField(); + activate_field = true; + goto retry_ins; } + uint16_t sw = get_sw(response, response_n); + sw_occurences = inc_sw_error_occurence(sw, all_sw); // Was there and length error? If so, try with Le length (case 2 instad of case 1, // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU // with Le being 0x0100. - uint16_t sw = get_sw(response, response_n); bool command_with_le = false; if (sw == 0x6700) { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, - sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + if (sw_occurences < error_limit) { + PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, + sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); + } uint8_t command2[7] = {cla, ins, p1, p2, 0x00}; int command2_n = sizeof(command2); res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); if (res) { - continue; + DropField(); + activate_field = true; + goto retry_ins; } + sw = get_sw(response, response_n); + sw_occurences = inc_sw_error_occurence(sw, all_sw); command_with_le = true; } - // Check response. - sw = get_sw(response, response_n); - if (sw != 0x6a86 && - sw != 0x6986 && - sw != 0x6d00 - ) { + // Show response. + if (sw_occurences < error_limit) { + logLevel_t log_level = INFO; + if (sw == 0x9000) { + log_level = SUCCESS; + } if (command_with_le) { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, + PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X00\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } else { - PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, + PrintAndLogEx(log_level, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); } // Show response data. diff --git a/client/src/ui.c b/client/src/ui.c index 885910919..b7e63e7dd 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -657,7 +657,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { "\xe2\x96\x88", }; - uint8_t mode = session.supports_colors; + uint8_t mode = (session.emoji_mode == EMOJI); const char *block[] = {"#", "\xe2\x96\x88"}; // use a 3-byte space in emoji mode to ease computations @@ -689,11 +689,15 @@ void print_progress(size_t count, uint64_t max, barMode_t style) { char *cbar = calloc(collen, sizeof(uint8_t)); // Add colors - int p60 = unit * (width * 60 / 100); - int p20 = unit * (width * 20 / 100); - snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); - snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); + if (session.supports_colors) { + int p60 = unit * (width * 60 / 100); + int p20 = unit * (width * 20 / 100); + snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); + snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); + } else { + snprintf(cbar, collen, "%s", bar); + } size_t len = strlen(cbar) + 32; char *buffer = calloc(len, sizeof(uint8_t));