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

View File

@@ -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 <uid>]
script run hf_mfu_setuid [-h] [-b] [-2] [-u <uid>]
]]
arguments = [[
-h : this help
-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
@@ -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

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) {
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", "<hex>", "Start value of CLASS (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, "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_lit0("v", "verbose", "Verbose output"),
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(NULL, "p1", "<hex>", "Start value of P1 (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("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
};
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_("<Enter>") " 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.

View File

@@ -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));