From 634f7e36468bc182217de9a111e9a1f94ed4a93a Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 13 Aug 2019 22:20:49 +0200 Subject: [PATCH 1/9] Add option to skip checking default keys --- src/mfoc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 0be0140..8e16bc8 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -132,13 +132,18 @@ int main(int argc, char *const argv[]) char line[20]; char * read; + bool do_clear=false; //Regexp declarations static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])"; struct slre_cap caps[2]; // Parse command line arguments - while ((ch = getopt(argc, argv, "hD:s:BP:T:S:O:k:t:f:")) != -1) { + while ((ch = getopt(argc, argv, "hCD:s:BP:T:S:O:k:t:f")) != -1) { switch (ch) { + case 'C': + defKeys=malloc(0); + defKeys_len=0; + break; case 'P': // Number of probes if (!(probes = atoi(optarg)) || probes < 1) { @@ -771,10 +776,11 @@ error: void usage(FILE *stream, int errno) { - fprintf(stream, "Usage: mfoc [-h] [-k key] [-f file] ... [-P probnum] [-T tolerance] [-O output]\n"); + fprintf(stream, "Usage: mfoc [-h] [-C] [-k key] [-f file] ... [-P probnum] [-T tolerance] [-O output]\n"); fprintf(stream, "\n"); fprintf(stream, " h print this help and exit\n"); // fprintf(stream, " B instead of 'A' dump 'B' keys\n"); + fprintf(stream, " C skip testing default keys\n"); fprintf(stream, " k try the specified key in addition to the default keys\n"); fprintf(stream, " f parses a file of keys to add in addition to the default keys \n"); // fprintf(stream, " D number of distance probes, default is 20\n"); From 27c8490fd2311891052a2bce25c03de611255c81 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Tue, 13 Aug 2019 22:21:39 +0200 Subject: [PATCH 2/9] Make -O parameter optional --- src/mfoc.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 8e16bc8..6622dea 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -131,7 +131,7 @@ int main(int argc, char *const argv[]) FILE * fp; char line[20]; char * read; - + bool do_clear=false; //Regexp declarations static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])"; @@ -187,7 +187,7 @@ int main(int argc, char *const argv[]) j += i; } } - break; + break; case 'k': // Add this key to the default keys p = realloc(defKeys, defKeys_len + 6); @@ -227,10 +227,10 @@ int main(int argc, char *const argv[]) } } - if (!pfDump) { - ERR("parameter -O is mandatory"); - exit(EXIT_FAILURE); - } + // if (!pfDump) { + // ERR("parameter -O is mandatory"); + // exit(EXIT_FAILURE); + // } // Initialize reader/tag structures mf_init(&r); @@ -748,13 +748,15 @@ int main(int argc, char *const argv[]) } // Finally save all keys + data to file - uint16_t dump_size = (t.num_blocks + 1) * 16; - if (fwrite(&mtDump, 1, dump_size, pfDump) != dump_size) { - fprintf(stdout, "Error, cannot write dump\n"); + if (pfDump) { + uint16_t dump_size = (t.num_blocks + 1) * 16; + if (fwrite(&mtDump, 1, dump_size, pfDump) != dump_size) { + fprintf(stdout, "Error, cannot write dump\n"); + fclose(pfDump); + goto error; + } fclose(pfDump); - goto error; } - fclose(pfDump); } free(t.sectors); @@ -788,7 +790,7 @@ void usage(FILE *stream, int errno) fprintf(stream, " P number of probes per sector, instead of default of 20\n"); fprintf(stream, " T nonce tolerance half-range, instead of default of 20\n (i.e., 40 for the total range, in both directions)\n"); // fprintf(stream, " s specify the list of sectors to crack, for example -s 0,1,3,5\n"); - fprintf(stream, " O file in which the card contents will be written (REQUIRED)\n"); + fprintf(stream, " O file in which the card contents will be written\n"); fprintf(stream, " D file in which partial card info will be written in case PRNG is not vulnerable\n"); fprintf(stream, "\n"); fprintf(stream, "Example: mfoc -O mycard.mfd\n"); From 64069b32310e4cbc4b5db82f6733393f883c9b28 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 00:31:41 +0200 Subject: [PATCH 3/9] Fix -C option --- src/mfoc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 6622dea..698e7b5 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -132,7 +132,7 @@ int main(int argc, char *const argv[]) char line[20]; char * read; - bool do_clear=false; + bool use_default_key=true; //Regexp declarations static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])"; struct slre_cap caps[2]; @@ -141,8 +141,7 @@ int main(int argc, char *const argv[]) while ((ch = getopt(argc, argv, "hCD:s:BP:T:S:O:k:t:f")) != -1) { switch (ch) { case 'C': - defKeys=malloc(0); - defKeys_len=0; + use_default_key=false; break; case 'P': // Number of probes @@ -349,6 +348,9 @@ int main(int argc, char *const argv[]) memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid)); // Iterate over all keys (n = number of keys) n = sizeof(defaultKeys) / sizeof(defaultKeys[0]); + if (!use_default_key) { + n=0; + } size_t defKey_bytes_todo = defKeys_len; key = 0; while (key < n || defKey_bytes_todo) { From 9f352d225801965ed3d3f544489ea50418b07881 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 00:32:32 +0200 Subject: [PATCH 4/9] Add key-reuse check --- .gitignore | 1 + debian/rules | 0 src/mfoc.c | 24 ++++++++++++++++++++++++ 3 files changed, 25 insertions(+) mode change 100755 => 100644 debian/rules diff --git a/.gitignore b/.gitignore index 1488245..a65cb6a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ src/mfoc src/mfoc.exe stamp-h1 *.o +.history/ diff --git a/debian/rules b/debian/rules old mode 100755 new mode 100644 diff --git a/src/mfoc.c b/src/mfoc.c index 698e7b5..27bf839 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -345,6 +345,28 @@ int main(int argc, char *const argv[]) fprintf(stdout, "\nTry to authenticate to all sectors with default keys...\n"); fprintf(stdout, "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found\n"); // Set the authentication information (uid) + bool did_hardnested=false; + check_keys: + if (did_hardnested) { + printf("\nChecking for key reuse...\n"); + int i=0; + defKeys_len=0; + free(defKeys); + defKeys=malloc(0); + for (int i=0;i Date: Wed, 14 Aug 2019 17:54:59 +0200 Subject: [PATCH 5/9] Fix sector/block conversion --- src/mfoc.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 27bf839..549b6c0 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -73,6 +73,30 @@ uint32_t unknownSector = 0; char unknownKeyLetter = 'A'; uint32_t unexpected_random = 0; + +// Sectors 0 to 31 have 4 blocks per sector. +// Sectors 32 to 39 have 16 blocks per sector. + +uint8_t block_to_sector(uint8_t block) +{ + uint8_t sector; + if(block < 128) { + return block >> 2; + } + block -= 128; + return 32 + (block >> 4); +} + +uint8_t sector_to_block(uint8_t sector) +{ + if (sector<32) { + return sector<<2; + } + sector -= 32; + + return 128+(sector<<4); +} + int main(int argc, char *const argv[]) { int ch, i, k, n, j, m; @@ -573,10 +597,10 @@ int main(int argc, char *const argv[]) mf_configure(r.pdi); mf_anticollision(t, r); - uint8_t blockNo = e_sector * 4; //Block + uint8_t blockNo = sector_to_block(e_sector); //Block uint8_t keyType = (t.sectors[e_sector].foundKeyA ? MC_AUTH_A : MC_AUTH_B); uint8_t *key = (t.sectors[e_sector].foundKeyA ? t.sectors[e_sector].KeyA : t.sectors[e_sector].KeyB);; - uint8_t trgBlockNo = j * 4; //block + uint8_t trgBlockNo = sector_to_block(j); //block uint8_t trgKeyType = (dumpKeysA ? MC_AUTH_A : MC_AUTH_B); mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType); did_hardnested=true; From 0313b7bcc50dec023e0945075aca0192d8819c41 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 17:56:59 +0200 Subject: [PATCH 6/9] Pick exploit sector starting from last sector --- src/mfoc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 549b6c0..73571ca 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -933,9 +933,10 @@ int find_exploit_sector(mftag t) return -1; } for (i = 0; i < t.num_sectors; i++) { - if ((t.sectors[i].foundKeyA) || (t.sectors[i].foundKeyB)) { - fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i); - return i; + int s=(t.num_sectors-i)-1; + if ((t.sectors[s].foundKeyA) || (t.sectors[s].foundKeyB)) { + fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", s); + return s; } } ERR("\n\nNo sector encrypted with the default key has been found, exiting.."); From aaaee56626455c41c4223434ecb13a576a96687e Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 18:28:07 +0200 Subject: [PATCH 7/9] Simplify Exploit sector picking --- src/mfoc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 73571ca..80f4f99 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -932,11 +932,10 @@ int find_exploit_sector(mftag t) fprintf(stdout, "\nWe have all sectors encrypted with the default keys..\n\n"); return -1; } - for (i = 0; i < t.num_sectors; i++) { - int s=(t.num_sectors-i)-1; - if ((t.sectors[s].foundKeyA) || (t.sectors[s].foundKeyB)) { - fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", s); - return s; + for (i = t.num_sectors-1; i>=0;--i) { + if ((t.sectors[i].foundKeyA) || (t.sectors[i].foundKeyB)) { + fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i); + return i; } } ERR("\n\nNo sector encrypted with the default key has been found, exiting.."); From ca8ab62bf737efad6f463de6ea107cd578e25a26 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 18:30:37 +0200 Subject: [PATCH 8/9] Remove second block_to_sector definition --- src/mfoc.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/mfoc.c b/src/mfoc.c index 80f4f99..6ee0d5d 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -77,16 +77,6 @@ uint32_t unexpected_random = 0; // Sectors 0 to 31 have 4 blocks per sector. // Sectors 32 to 39 have 16 blocks per sector. -uint8_t block_to_sector(uint8_t block) -{ - uint8_t sector; - if(block < 128) { - return block >> 2; - } - block -= 128; - return 32 + (block >> 4); -} - uint8_t sector_to_block(uint8_t sector) { if (sector<32) { From 7f2abb32c7d4225e6df4e3eaa5ee89bddd085cc9 Mon Sep 17 00:00:00 2001 From: Daniel Seiller Date: Wed, 14 Aug 2019 21:07:45 +0200 Subject: [PATCH 9/9] First check for key B, then A when selecting exploit sector --- src/mfoc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/mfoc.c b/src/mfoc.c index 6ee0d5d..545c6c6 100644 --- a/src/mfoc.c +++ b/src/mfoc.c @@ -923,7 +923,13 @@ int find_exploit_sector(mftag t) return -1; } for (i = t.num_sectors-1; i>=0;--i) { - if ((t.sectors[i].foundKeyA) || (t.sectors[i].foundKeyB)) { + if (t.sectors[i].foundKeyB) { + fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i); + return i; + } + } + for (i = t.num_sectors-1; i>=0;--i) { + if (t.sectors[i].foundKeyA) { fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i); return i; }