From 71fc3e18d97a24897d8f6020d03ec56d84c1fcb3 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 2 Sep 2020 12:16:11 +0200 Subject: [PATCH] fixing return codes for Autopwn, added staticnested to autopwn --- armsrc/mifarecmd.c | 13 +-- client/src/cmdhfmf.c | 197 +++++++++++++++++++++++---------- client/src/mifare/mifarehost.c | 13 +-- 3 files changed, 145 insertions(+), 78 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index b32953cd7..8169a3393 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -906,7 +906,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 set_tracing(true); // statistics on nonce distance - int16_t isOK = 0; + int16_t isOK = PM3_SUCCESS; #define NESTED_MAX_TRIES 12 if (calibrate) { // calibrate: for first call only. Otherwise reuse previous calibration LED_B_ON(); @@ -922,7 +922,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 // Test if the action was cancelled if (BUTTON_PRESS() || data_available()) { - isOK = -2; + isOK = PM3_EOPABORTED; break; } @@ -977,7 +977,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 } else { unsuccessful_tries++; if (unsuccessful_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) - isOK = -3; + isOK = PM3_EFAILED; } } } @@ -1003,7 +1003,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 // Test if the action was cancelled if (BUTTON_PRESS() || data_available()) { - isOK = -2; + isOK = PM3_EOPABORTED; break; } @@ -1092,12 +1092,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 memcpy(payload.nt_b, &target_nt[1], 4); memcpy(payload.ks_b, &target_ks[1], 4); - LED_B_ON(); reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); - LED_B_OFF(); - - if (DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); set_tracing(false); diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index b08913712..1e351a913 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -1306,19 +1306,19 @@ static int CmdHF14AMfNested(const char *Cmd) { if (cmdp == 'o') { int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true); switch (isOK) { - case -1 : + case PM3_ETIMEOUT: PrintAndLogEx(ERR, "Command execute timeout\n"); break; - case -2 : + case PM3_EOPABORTED: PrintAndLogEx(WARNING, "Button pressed. Aborted.\n"); break; - case -3 : + case PM3_EFAILED: PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break; - case -4 : + case PM3_ESOFT: PrintAndLogEx(FAILED, "No valid key found"); break; - case -5 : + case PM3_SUCCESS: key64 = bytes_to_num(keyBlock, 6); // transfer key to the emulator @@ -1366,7 +1366,6 @@ static int CmdHF14AMfNested(const char *Cmd) { PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); if (res == PM3_SUCCESS) { - // all keys found PrintAndLogEx(SUCCESS, "Fast check found all keys"); goto jumptoend; } @@ -1376,7 +1375,6 @@ static int CmdHF14AMfNested(const char *Cmd) { PrintAndLogEx(SUCCESS, "enter nested key recovery"); // nested sectors -// int iterations = 0; bool calibrate = true; for (trgKeyType = 0; trgKeyType < 2; ++trgKeyType) { @@ -1387,28 +1385,26 @@ static int CmdHF14AMfNested(const char *Cmd) { int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate); switch (isOK) { - case -1 : + case PM3_ETIMEOUT: PrintAndLogEx(ERR, "Command execute timeout\n"); break; - case -2 : + case PM3_EOPABORTED: PrintAndLogEx(WARNING, "button pressed. Aborted.\n"); break; - case -3 : + case PM3_EFAILED : PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is not predictable).\n"); break; - case -4 : //key not found + case PM3_ESOFT: + //key not found calibrate = false; -// iterations++; continue; - case -5 : + case PM3_SUCCESS: calibrate = false; -// iterations++; e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); continue; - default : PrintAndLogEx(ERR, "Unknown error.\n"); } @@ -1940,6 +1936,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { bool slow = false; bool legacy_mfchk = false; int prng_type = PM3_EUNDEF; + int has_staticnonce = 2; bool verbose = false; bool has_filename = false; bool errors = false; @@ -2061,33 +2058,43 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { free(e_sector); return prng_type; } + + // check if tag doesn't have static nonce + has_staticnonce = detect_classic_static_nonce(); // print parameters if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= SETTINGS =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " ======================="); PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sectors_cnt); PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), know_target_key ? "True" : "False"); PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), blockNo); PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), keyType ? 'B' : 'A'); PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key))); - PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD"); + + if (has_staticnonce) + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s & STATIC"), prng_type ? "WEAK" : "HARD"); + else + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD"); + PrintAndLogEx(INFO, " dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "NONE"); PrintAndLogEx(INFO, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk ? "True" : "False"); - PrintAndLogEx(INFO, _YELLOW_("======================= SETTINGS =======================")); + + PrintAndLogEx(INFO, "========================================================================"); } // Start the timer t1 = msclock(); // check the user supplied key - if (know_target_key == false) + if (know_target_key == false) { PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail"); - else { + } else { if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START KNOWN KEY ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START KNOWN KEY ATTACK") " ======================="); } + if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) == PM3_SUCCESS) { - PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -2139,9 +2146,14 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { } } } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP KNOWN KEY ATTACK =======================")); - if (num_found_keys == sectors_cnt * 2) + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP KNOWN KEY ATTACK") " ======================="); + } + + if (num_found_keys == sectors_cnt * 2) { goto all_found; + } } bool load_success = true; @@ -2150,9 +2162,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 6, &key_cnt); if (res != PM3_SUCCESS || key_cnt == 0 || keyBlock == NULL) { PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)"); - if (keyBlock != NULL) + if (keyBlock != NULL) { free(keyBlock); - + } load_success = false; } } @@ -2172,7 +2184,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { } // Use the dictionary to find sector keys on the card - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START DICTIONARY ATTACK =======================")); + if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("START DICTIONARY ATTACK") " ======================="); if (legacy_mfchk) { // Check all the sectors @@ -2229,7 +2241,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { lastChunk = false; } // end strategy } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP DICTIONARY ATTACK =======================")); + if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DICTIONARY ATTACK") " ======================="); // Analyse the dictionary attack @@ -2245,13 +2257,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { know_target_key = true; blockNo = i; keyType = j; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -2264,10 +2276,17 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Check if at least one sector key was found if (know_target_key == false) { // Check if the darkside attack can be used - if (prng_type) { - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START DARKSIDE ATTACK =======================")); + if (prng_type && has_staticnonce == false) { + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " ======================="); + } + isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64); - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP DARKSIDE ATTACK =======================")); + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DARKSIDE ATTACK") " ======================="); + } + switch (isOK) { case -1 : PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); @@ -2293,7 +2312,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Store the keys e_sector[blockNo].Key[keyType] = key64; e_sector[blockNo].foundKey[keyType] = 'S'; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -2333,7 +2352,7 @@ noValidKeyFound: if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) { e_sector[i].Key[j] = bytes_to_num(tmp_key, 6); e_sector[i].foundKey[j] = 'R'; - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -2348,7 +2367,7 @@ noValidKeyFound: if (current_key_type_i == 1) { if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START READ B KEY ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " ======================="); PrintAndLogEx(INFO, "reading B key: sector: %3d key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); @@ -2375,48 +2394,61 @@ noValidKeyFound: e_sector[current_sector_i].foundKey[current_key_type_i] = 'A'; e_sector[current_sector_i].Key[current_key_type_i] = key64; num_to_bytes(key64, 6, tmp_key); - PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", current_sector_i, current_key_type_i ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - if (verbose) PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c (reading the B key was not possible, maybe due to insufficient access rights) ", + if (verbose) { + PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A' ); + PrintAndLogEx(INFO, " -- reading the B key was not possible, maybe due to access rights?"); + + } + + } + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP READ B KEY ATTACK") " ======================="); } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP READ B KEY ATTACK =======================")); } } // Use the nested / hardnested attack skipReadBKey: if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) { - if (prng_type && (! nested_failed)) { + + if (prng_type && (nested_failed == false) && (has_staticnonce == false)) { uint8_t retries = 0; if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START NESTED ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); } tryNested: isOK = mfnested(FirstBlockOfSector(blockNo), keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key, calibrate); + switch (isOK) { - case -1 : + case PM3_ETIMEOUT: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); free(e_sector); return PM3_ESOFT; - case -2 : + } + case PM3_EOPABORTED: { PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); free(e_sector); - return PM3_ESOFT; - case -3 : + return PM3_EOPABORTED; + } + case PM3_EFAILED: { PrintAndLogEx(FAILED, "Tag isn't vulnerable to Nested Attack (PRNG is probably not predictable)."); PrintAndLogEx(FAILED, "Nested attack failed --> try hardnested"); goto tryHardnested; - case -4 : //key not found + } + case PM3_ESOFT: { + // key not found calibrate = false; // this can happen on some old cards, it's worth trying some more before switching to slower hardnested if (retries++ < MIFARE_SECTOR_RETRY) { @@ -2428,21 +2460,27 @@ tryNested: goto tryHardnested; } break; - case -5 : + } + case PM3_SUCCESS: { calibrate = false; e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); e_sector[current_sector_i].foundKey[current_key_type_i] = 'N'; break; - default : + } + default: { PrintAndLogEx(ERR, "unknown Error.\n"); free(e_sector); return PM3_ESOFT; + } } - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP NESTED ATTACK =======================")); + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP NESTED ATTACK") " ======================="); + } + } else { tryHardnested: // If the nested attack fails then we try the hardnested attack if (verbose) { - PrintAndLogEx(INFO, _YELLOW_("======================= START HARDNESTED ATTACK =======================")); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " ======================="); PrintAndLogEx(INFO, "sector no: %3d, target key type: %c, Slow: %s", current_sector_i, current_key_type_i ? 'B' : 'A', @@ -2453,14 +2491,17 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack DropField(); if (isOK) { switch (isOK) { - case 1 : + case 1: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); break; - case 2 : + } + case 2: { PrintAndLogEx(NORMAL, "\nButton pressed. Aborted."); break; - default : + } + default: { break; + } } free(e_sector); return PM3_ESOFT; @@ -2471,8 +2512,48 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack e_sector[current_sector_i].Key[current_key_type_i] = foundkey; e_sector[current_sector_i].foundKey[current_key_type_i] = 'H'; - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP HARDNESTED ATTACK =======================")); + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP HARDNESTED ATTACK") " ======================="); + } } + + if (has_staticnonce) { + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " ======================="); + PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", + current_sector_i, + current_key_type_i ? 'B' : 'A'); + } + + isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(current_sector_i), current_key_type_i, tmp_key); + DropField(); + switch (isOK) { + case PM3_ETIMEOUT: { + PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); + free(e_sector); + return PM3_ESOFT; + } + case PM3_EOPABORTED: { + PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); + free(e_sector); + return PM3_EOPABORTED; + } + case PM3_SUCCESS: { + e_sector[current_sector_i].Key[current_key_type_i] = bytes_to_num(tmp_key, 6); + e_sector[current_sector_i].foundKey[current_key_type_i] = 'C'; + break; + } + default: { + break; + } + } + + if (verbose) { + PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP STATIC NESTED ATTACK") " ======================="); + } + } + // Check if the key was found if (e_sector[current_sector_i].foundKey[current_key_type_i]) { PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]", @@ -2554,14 +2635,7 @@ all_found: free(e_sector); return PM3_SUCCESS; } -/* -static int CmdHF14AMfNestedFixed(const char *Cmd){ - if (strlen(Cmd) < 3) return usage_hf14_fixednested(); - - return PM3_SUCCESS; -} -*/ /* static int randInRange(int min, int max) { return min + (int)(rand() / (double)(RAND_MAX) * (max - min + 1)); @@ -3461,6 +3535,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto _YELLOW_("R") ":Reused / " _YELLOW_("N") ":Nested / " _YELLOW_("H") ":Hardnested / " + _YELLOW_("C") ":statiCnested / " _YELLOW_("A") ":keyA " ")" ); diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index f50e77bce..31b88bec9 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -418,9 +418,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, return PM3_ETIMEOUT; } - if (resp.status != PM3_SUCCESS) - return PM3_ESOFT; - struct p { int16_t isOK; uint8_t block; @@ -433,8 +430,9 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, } PACKED; struct p *package = (struct p *)resp.data.asBytes; - // error during nested - if (package->isOK) return package->isOK; + // error during nested on device side + if (package->isOK != PM3_SUCCESS) + return package->isOK; memcpy(&uid, package->cuid, sizeof(package->cuid)); @@ -450,7 +448,6 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, memcpy(&statelists[1].nt_enc, package->nt_b, sizeof(package->nt_b)); memcpy(&statelists[1].ks1, package->ks_b, sizeof(package->ks_b)); - // calc keys pthread_t thread_id[2]; @@ -543,7 +540,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, package->keytype ? 'B' : 'A', sprint_hex(resultKey, 6) ); - return -5; + return PM3_SUCCESS; } float bruteforce_per_second = (float)(i + max_keys) / ((msclock() - start_time) / 1000.0); @@ -558,7 +555,7 @@ out: free(statelists[0].head.slhead); free(statelists[1].head.slhead); - return -4; + return PM3_ESOFT; }