Merge remote-tracking branch 'origin/master' into emrtd

This commit is contained in:
Ave
2020-12-28 20:39:38 +03:00
4 changed files with 109 additions and 51 deletions

View File

@@ -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 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 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 # 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. 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.

View File

@@ -4,26 +4,32 @@ local ansicolors = require('ansicolors')
copyright = '' copyright = ''
author = "Iceman" author = "Iceman"
version = 'v1.0.2' version = 'v1.0.3'
desc = [[ desc = [[
This script tries to set UID on a mifare Ultralight magic card which either This script tries to set UID on a mifare Ultralight magic card which either
- answers to chinese backdoor commands - answers to chinese backdoor commands
- brickable magic tag (must write in one session) - brickable magic tag (must write in one session)
It defaults to GEN1A type of uid changeable card.
]] ]]
example = [[ example = [[
-- backdoor magic tag -- backdoor magic tag (gen1a)
script run hf_mfu_setuid -u 11223344556677 script run hf_mfu_setuid -u 11223344556677
-- brickable magic tag -- backdoor magic tag (gen1b)
script run hf_mfu_setuid -b -u 11223344556677 script run hf_mfu_setuid -b -u 11223344556677
-- brickable magic tag (gen2)
script run hf_mfu_setuid -2 -u 11223344556677
]] ]]
usage = [[ usage = [[
script run hf_mfu_setuid [-h] [-b] [-u <uid>] script run hf_mfu_setuid [-h] [-b] [-2] [-u <uid>]
]] ]]
arguments = [[ arguments = [[
-h : this help -h : this help
-u <UID> : UID (14 hexsymbols) -u <UID> : 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 local DEBUG = true
@@ -65,23 +71,33 @@ local function help()
end end
-- --
--- Set UID on magic command enabled --- 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 -- write block 0
core.console('hf 14a raw -k -a -b 7 40') 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) core.console('hf 14a raw -c -a A200'..b0)
-- write block 1 -- write block 1
core.console('hf 14a raw -k -a -b 7 40') 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) core.console('hf 14a raw -c -a A201'..b1)
-- write block 2 -- write block 2
core.console('hf 14a raw -k -a -b 7 40') 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) core.console('hf 14a raw -c -a A202'..b2)
end end
-- --
@@ -113,10 +129,11 @@ function main(args)
local tagtype = 1 local tagtype = 1
-- Read the parameters -- 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 == 'h' then return help() end
if o == 'u' then uid = a end if o == 'u' then uid = a end
if o == 'b' then tagtype = 2 end if o == 'b' then tagtype = 2 end
if o == '2' then tagtype = 3 end
end end
-- uid string checks -- uid string checks
@@ -137,10 +154,11 @@ function main(args)
core.clearCommandBuffer() core.clearCommandBuffer()
if tagtype == 2 then if tagtype == 3 then
brickableUID(block0, block1, block2) brickableUID(block0, block1, block2)
else else
magicUID(block0, block1, block2) local is_gen1a = (tagtype == 1)
magicUID(block0, block1, block2, is_gen1a)
end end
--halt --halt

View File

@@ -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) { static uint16_t get_sw(uint8_t *d, uint8_t n) {
if (n < 2) if (n < 2) {
return 0; return 0;
}
n -= 2; n -= 2;
return d[n] * 0x0100 + d[n + 1]; 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) { 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: Option to select AID/File (and skip INS 0xA4).
// TODO: Validate the decoding of the APDU (not specific to this command, check // 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). // 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: Check all cases (APDUs) with no data bytes (no/short/extended length).
// TODO: Option to blacklist instructions (or whole APDUs).
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 14a apdufind", CLIParserInit(&ctx, "hf 14a apdufind",
"Enumerate APDU's of ISO7816 protocol to find valid CLS/INS/P1P2 commands.\n" "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.", "Tag must be on antenna before running.",
"hf 14a apdufind\n" "hf 14a apdufind\n"
"hf 14a apdufind --cla 80\n" "hf 14a apdufind --cla 80\n"
"hf 14a apdufind --cla 80 --error-limit 20 --skip-ins a4 --skip-ins b0\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("c", "cla", "<hex>", "Start value of CLASS (1 hex byte)"), arg_str0("c", "cla", "<hex>", "Start value of CLASS (1 hex byte)"),
arg_str0("i", "ins", "<hex>", "Start value of INSTRUCTION (1 hex byte)"), arg_str0("i", "ins", "<hex>", "Start value of INSTRUCTION (1 hex byte)"),
arg_str0(NULL, "p1", "<hex>", "Start value of P1 (1 hex byte)"), arg_str0(NULL, "p1", "<hex>", "Start value of P1 (1 hex byte)"),
arg_str0(NULL, "p2", "<hex>", "Start value of P2 (1 hex byte)"), arg_str0(NULL, "p2", "<hex>", "Start value of P2 (1 hex byte)"),
arg_u64_0("r", "reset", "<number>", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"), arg_u64_0("r", "reset", "<number>", "Minimum secondes before resetting the tag (to prevent timeout issues). Default is 5 minutes"),
arg_lit0("v", "verbose", "Verbose output"), arg_u64_0("e", "error-limit", "<number>", "Maximum times an status word other than 0x9000 or 0x6D00 is shown. Default is 256."),
arg_strx0("s", "skip-ins", "<hex>", "Do not test an instructions (can be specifed multiple times)"),
arg_lit0("v", "verbose", "Verbose output"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@@ -2183,8 +2196,12 @@ static int CmdHf14AFindapdu(const char *Cmd) {
int p2_len = 0; int p2_len = 0;
uint8_t p2_arg[1] = {0}; uint8_t p2_arg[1] = {0};
CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len); CLIGetHexWithReturn(ctx, 4, p2_arg, &p2_len);
uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60); // Reset every 5 minutes. uint64_t reset_time = arg_get_u64_def(ctx, 5, 5 * 60);
bool verbose = arg_get_lit(ctx, 6); 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); CLIParserFree(ctx);
@@ -2211,6 +2228,9 @@ static int CmdHf14AFindapdu(const char *Cmd) {
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit"); PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
bool inc_p1 = true; 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_start = msclock();
uint64_t t_last_reset = msclock(); uint64_t t_last_reset = msclock();
@@ -2218,12 +2238,25 @@ static int CmdHf14AFindapdu(const char *Cmd) {
do { do {
do { do {
do { do {
retry_ins:
// Exit (was the Enter key pressed)? // Exit (was the Enter key pressed)?
if (kbd_enter_pressed()) { if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "User interrupted detected. Aborting"); PrintAndLogEx(INFO, "User interrupted detected. Aborting");
goto out; 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) { if (verbose) {
PrintAndLogEx(INFO, "Status: [ CLA " _GREEN_("%02X") " INS " _GREEN_("%02X") " P1 " _GREEN_("%02X") " P2 " _GREEN_("%02X") " ]", cla, ins, p1, p2); 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); int command_n = sizeof(command);
res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n); res = ExchangeAPDU14a(command, command_n, activate_field, keep_field_on, response, sizeof(response), &response_n);
if (res) { 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, // 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 // https://stackoverflow.com/a/30679558). Le = 0x00 will get interpreted as extended length APDU
// with Le being 0x0100. // with Le being 0x0100.
uint16_t sw = get_sw(response, response_n);
bool command_with_le = false; bool command_with_le = false;
if (sw == 0x6700) { if (sw == 0x6700) {
PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2, if (sw_occurences < error_limit) {
sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); PrintAndLogEx(INFO, "Got response for APDU \"%02X%02X%02X%02X\": %04X (%s)", cla, ins, p1, p2,
PrintAndLogEx(INFO, "Resending current command with Le = 0x0100 (extended length APDU)"); 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}; uint8_t command2[7] = {cla, ins, p1, p2, 0x00};
int command2_n = sizeof(command2); int command2_n = sizeof(command2);
res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n); res = ExchangeAPDU14a(command2, command2_n, activate_field, keep_field_on, response, sizeof(response), &response_n);
if (res) { 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; command_with_le = true;
} }
// Check response. // Show response.
sw = get_sw(response, response_n); if (sw_occurences < error_limit) {
if (sw != 0x6a86 && logLevel_t log_level = INFO;
sw != 0x6986 && if (sw == 0x9000) {
sw != 0x6d00 log_level = SUCCESS;
) { }
if (command_with_le) { 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)); sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
} else { } 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)); sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
} }
// Show response data. // Show response data.

View File

@@ -657,7 +657,7 @@ void print_progress(size_t count, uint64_t max, barMode_t style) {
"\xe2\x96\x88", "\xe2\x96\x88",
}; };
uint8_t mode = session.supports_colors; uint8_t mode = (session.emoji_mode == EMOJI);
const char *block[] = {"#", "\xe2\x96\x88"}; const char *block[] = {"#", "\xe2\x96\x88"};
// use a 3-byte space in emoji mode to ease computations // 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)); char *cbar = calloc(collen, sizeof(uint8_t));
// Add colors // Add colors
int p60 = unit * (width * 60 / 100); if (session.supports_colors) {
int p20 = unit * (width * 20 / 100); int p60 = unit * (width * 60 / 100);
snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar); int p20 = unit * (width * 20 / 100);
snprintf(cbar + strlen(cbar), collen - strlen(cbar), _CYAN_("%.*s"), p20, bar + p60); snprintf(cbar, collen, _GREEN_("%.*s"), p60, bar);
snprintf(cbar + strlen(cbar), collen - strlen(cbar), _YELLOW_("%.*s"), unit * width - p60 - p20, bar + p60 + p20); 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; size_t len = strlen(cbar) + 32;
char *buffer = calloc(len, sizeof(uint8_t)); char *buffer = calloc(len, sizeof(uint8_t));