hf mf nested add some functionality (#403)
authorOleg Moiseenko <olegmsn@gmail.com>
Thu, 5 Oct 2017 11:37:51 +0000 (14:37 +0300)
committerpwpiwi <pwpiwi@users.noreply.github.com>
Thu, 5 Oct 2017 11:37:51 +0000 (13:37 +0200)
* Added nested auto mode. it checks known keys and then launches nested
* Check if we allready have all keys after nested

CHANGELOG.md
client/cmdhfmf.c

index da0e30add42d43cda04fb4a0be13f576153ffdf3..842c8bef37a6e90260e416fd23fc4972392b1fe6 100644 (file)
@@ -8,6 +8,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 ### Changed
 - Improved backdoor detection missbehaving magic s50/1k tag (Fl0-0)
 - Deleted wipe functionality from `hf mf csetuid` (Merlok)
+- Changed `hf mf nested` logic (Merlok)
+- Added `hf mf nested` mode: autosearch keys for attack (from well known keys) (Merlok)
 
 ### Fixed
 
@@ -19,6 +21,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
 - Added data fsktonrz, a fsk cleaning/demodulating routine for weak fsk signal. Note: follow this up with a `data rawdemod nr` to finish demoding your signal. (marshmellow)
 - Added lf em 410xbrute, LF EM410x reader bruteforce attack by simulating UIDs from a file (Fl0-0)
 - Added `hf mf cwipe` command. It wipes "magic Chinese" card. For 1a generation it uses card's "wipe" command. For gen1a and gen1b it uses a write command. (Merlok)
+- Added to `hf mf nested` source key check before attack (Merlok)
+- Added to `hf mf nested` after attack it checks all found keys on non-open sectors (Merlok)
 
 ## [3.0.1][2017-06-08]
 
index aafbce2afa12990873e7422daf4fc65f56ebc073..295f22b74efffc5f4f7a325ffa1b2ca80981136d 100644 (file)
@@ -222,6 +222,28 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo)
        }\r
 }\r
 \r
+static int ParamCardSizeSectors(const char c) {\r
+       int numBlocks = 16;\r
+       switch (c) {\r
+               case '0' : numBlocks = 5; break;\r
+               case '2' : numBlocks = 32; break;\r
+               case '4' : numBlocks = 40; break;\r
+               default:   numBlocks = 16;\r
+       }\r
+       return numBlocks;\r
+}\r
+\r
+static int ParamCardSizeBlocks(const char c) {\r
+       int numBlocks = 16 * 4;\r
+       switch (c) {\r
+               case '0' : numBlocks = 5 * 4; break;\r
+               case '2' : numBlocks = 32 * 4; break;\r
+               case '4' : numBlocks = 32 * 4 + 8 * 16; break;\r
+               default:   numBlocks = 16 * 4;\r
+       }\r
+       return numBlocks;\r
+}\r
+\r
 int CmdHF14AMfDump(const char *Cmd)\r
 {\r
        uint8_t sectorNo, blockNo;\r
@@ -238,14 +260,7 @@ int CmdHF14AMfDump(const char *Cmd)
        UsbCommand resp;\r
 \r
        char cmdp = param_getchar(Cmd, 0);\r
-       switch (cmdp) {\r
-               case '0' : numSectors = 5; break;\r
-               case '1' :\r
-               case '\0': numSectors = 16; break;\r
-               case '2' : numSectors = 32; break;\r
-               case '4' : numSectors = 40; break;\r
-               default:   numSectors = 16;\r
-       }\r
+       numSectors = ParamCardSizeSectors(cmdp);\r
 \r
        if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') {\r
                PrintAndLog("Usage:   hf mf dump [card memory]");\r
@@ -516,6 +531,7 @@ typedef struct {
 } sector_t;\r
 \r
 \r
+# define NESTED_KEY_COUNT 15\r
 int CmdHF14AMfNested(const char *Cmd)\r
 {\r
        int i, j, res, iterations;\r
@@ -526,10 +542,12 @@ int CmdHF14AMfNested(const char *Cmd)
        uint8_t trgKeyType = 0;\r
        uint8_t SectorsCnt = 0;\r
        uint8_t key[6] = {0, 0, 0, 0, 0, 0};\r
-       uint8_t keyBlock[14*6];\r
+       uint8_t keyBlock[NESTED_KEY_COUNT * 6];\r
        uint64_t key64 = 0;\r
-       bool transferToEml = false;\r
+       \r
+       bool autosearchKey = false;\r
 \r
+       bool transferToEml = false;\r
        bool createDumpFile = false;\r
        FILE *fkeys;\r
        uint8_t standart[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};\r
@@ -540,66 +558,90 @@ int CmdHF14AMfNested(const char *Cmd)
        if (strlen(Cmd)<3) {\r
                PrintAndLog("Usage:");\r
                PrintAndLog(" all sectors:  hf mf nested  <card memory> <block number> <key A/B> <key (12 hex symbols)> [t,d]");\r
+               PrintAndLog(" all sectors autosearch key:  hf mf nested  <card memory> * [t,d]");\r
                PrintAndLog(" one sector:   hf mf nested  o <block number> <key A/B> <key (12 hex symbols)>");\r
                PrintAndLog("               <target block number> <target key A/B> [t]");\r
+               PrintAndLog(" ");\r
                PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");\r
-               PrintAndLog("t - transfer keys into emulator memory");\r
-               PrintAndLog("d - write keys to binary file");\r
+               PrintAndLog("t - transfer keys to emulator memory");\r
+               PrintAndLog("d - write keys to binary file dumpkeys.bin");\r
                PrintAndLog(" ");\r
                PrintAndLog("      sample1: hf mf nested 1 0 A FFFFFFFFFFFF ");\r
                PrintAndLog("      sample2: hf mf nested 1 0 A FFFFFFFFFFFF t ");\r
                PrintAndLog("      sample3: hf mf nested 1 0 A FFFFFFFFFFFF d ");\r
                PrintAndLog("      sample4: hf mf nested o 0 A FFFFFFFFFFFF 4 A");\r
+               PrintAndLog("      sample5: hf mf nested 1 * t");\r
                return 0;\r
        }\r
 \r
+       // <card memory>\r
        cmdp = param_getchar(Cmd, 0);\r
-       blockNo = param_get8(Cmd, 1);\r
-       ctmp = param_getchar(Cmd, 2);\r
-\r
-       if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {\r
-               PrintAndLog("Key type must be A or B");\r
-               return 1;\r
+       if (cmdp == 'o' || cmdp == 'O') {\r
+               cmdp = 'o';\r
+               SectorsCnt = 1;\r
+       } else {\r
+               SectorsCnt = ParamCardSizeSectors(cmdp);\r
        }\r
+               \r
+       // <block number>. number or autosearch key (*)\r
+       if (param_getchar(Cmd, 1) == '*') {\r
+               autosearchKey = true;\r
 \r
-       if (ctmp != 'A' && ctmp != 'a')\r
-               keyType = 1;\r
+               ctmp = param_getchar(Cmd, 2);\r
+               transferToEml |= (ctmp == 't' || ctmp == 'T');\r
+               createDumpFile |= (ctmp == 'd' || ctmp == 'D');\r
 \r
-       if (param_gethex(Cmd, 3, key, 12)) {\r
-               PrintAndLog("Key must include 12 HEX symbols");\r
-               return 1;\r
-       }\r
+               PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c ", SectorsCnt, transferToEml?'y':'n', createDumpFile?'y':'n');\r
+       } else {\r
+               blockNo = param_get8(Cmd, 1);\r
 \r
-       if (cmdp == 'o' || cmdp == 'O') {\r
-               cmdp = 'o';\r
-               trgBlockNo = param_get8(Cmd, 4);\r
-               ctmp = param_getchar(Cmd, 5);\r
+               ctmp = param_getchar(Cmd, 2);\r
                if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {\r
-                       PrintAndLog("Target key type must be A or B");\r
+                       PrintAndLog("Key type must be A or B");\r
                        return 1;\r
                }\r
+\r
                if (ctmp != 'A' && ctmp != 'a')\r
-                       trgKeyType = 1;\r
-       } else {\r
+                       keyType = 1;\r
 \r
-               switch (cmdp) {\r
-                       case '0': SectorsCnt = 05; break;\r
-                       case '1': SectorsCnt = 16; break;\r
-                       case '2': SectorsCnt = 32; break;\r
-                       case '4': SectorsCnt = 40; break;\r
-                       default:  SectorsCnt = 16;\r
+               if (param_gethex(Cmd, 3, key, 12)) {\r
+                       PrintAndLog("Key must include 12 HEX symbols");\r
+                       return 1;\r
                }\r
-       }\r
 \r
-       ctmp = param_getchar(Cmd, 4);\r
-       if              (ctmp == 't' || ctmp == 'T') transferToEml = true;\r
-       else if (ctmp == 'd' || ctmp == 'D') createDumpFile = true;\r
+               // check if we can authenticate to sector\r
+               res = mfCheckKeys(blockNo, keyType, true, 1, key, &key64);\r
+               if (res) {\r
+                       PrintAndLog("Can't authenticate to block:%3d key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));\r
+                       return 3;\r
+               }\r
 \r
-       ctmp = param_getchar(Cmd, 6);\r
-       transferToEml |= (ctmp == 't' || ctmp == 'T');\r
-       transferToEml |= (ctmp == 'd' || ctmp == 'D');\r
+               // one sector nested\r
+               if (cmdp == 'o') { \r
+                       trgBlockNo = param_get8(Cmd, 4);\r
 \r
-       if (cmdp == 'o') {\r
+                       ctmp = param_getchar(Cmd, 5);\r
+                       if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {\r
+                               PrintAndLog("Target key type must be A or B");\r
+                               return 1;\r
+                       }\r
+                       if (ctmp != 'A' && ctmp != 'a')\r
+                               trgKeyType = 1;\r
+\r
+                       ctmp = param_getchar(Cmd, 6);\r
+                       transferToEml |= (ctmp == 't' || ctmp == 'T');\r
+                       createDumpFile |= (ctmp == 'd' || ctmp == 'D');\r
+               } else {\r
+                       ctmp = param_getchar(Cmd, 4);\r
+                       transferToEml |= (ctmp == 't' || ctmp == 'T');\r
+                       createDumpFile |= (ctmp == 'd' || ctmp == 'D');\r
+               }\r
+\r
+               PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c ", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n');\r
+       }\r
+\r
+       // one-sector nested\r
+       if (cmdp == 'o') { // ------------------------------------  one sector working\r
                PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');\r
                int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);\r
                if (isOK) {\r
@@ -630,6 +672,7 @@ int CmdHF14AMfNested(const char *Cmd)
                                else\r
                                        num_to_bytes(key64, 6, &keyBlock[10]);\r
                                mfEmlSetMem(keyBlock, sectortrailer, 1);\r
+                               PrintAndLog("Key transferred to emulator memory.");\r
                        }\r
                } else {\r
                        PrintAndLog("No valid key found");\r
@@ -657,13 +700,14 @@ int CmdHF14AMfNested(const char *Cmd)
                num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6));\r
                num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6));\r
                num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6));\r
+               num_to_bytes(0x1a2b3c4d5e6f, 6, (uint8_t*)(keyBlock + 14 * 6));\r
 \r
                PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);\r
                for (i = 0; i < SectorsCnt; i++) {\r
                        for (j = 0; j < 2; j++) {\r
                                if (e_sector[i].foundKey[j]) continue;\r
 \r
-                               res = mfCheckKeys(FirstBlockOfSector(i), j, true, 6, keyBlock, &key64);\r
+                               res = mfCheckKeys(FirstBlockOfSector(i), j, true, NESTED_KEY_COUNT, keyBlock, &key64); \r
 \r
                                if (!res) {\r
                                        e_sector[i].Key[j] = key64;\r
@@ -671,6 +715,32 @@ int CmdHF14AMfNested(const char *Cmd)
                                }\r
                        }\r
                }\r
+               \r
+               // get known key from array\r
+               bool keyFound = false;\r
+               if (autosearchKey) {\r
+                       for (i = 0; i < SectorsCnt; i++) {\r
+                               for (j = 0; j < 2; j++) {\r
+                                       if (e_sector[i].foundKey[j]) {\r
+                                               // get known key\r
+                                               blockNo = i * 4;\r
+                                               keyType = j;\r
+                                               num_to_bytes(e_sector[i].Key[j], 6, key);\r
+                                               \r
+                                               keyFound = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if (keyFound) break;\r
+                       }               \r
+\r
+                       // Can't found a key....\r
+                       if (!keyFound) {\r
+                               PrintAndLog("Can't found any of the known keys.");\r
+                               return 4;\r
+                       }\r
+                       PrintAndLog("--auto key. block no:%3d, key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));\r
+               }\r
 \r
                // nested sectors\r
                iterations = 0;\r
@@ -707,10 +777,71 @@ int CmdHF14AMfNested(const char *Cmd)
                        }\r
                }\r
 \r
-               printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);\r
+               // print nested statistic\r
+               PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations);\r
+               PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);\r
+               \r
+               // check if we have unrecognized keys\r
+               bool notFoundKeys = false;\r
+               for (i = 0; i < SectorsCnt; i++) {\r
+                       for (j = 0; j < 2; j++) {\r
+                               if (!e_sector[i].foundKey[j]) {\r
+                                       notFoundKeys = true;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if (notFoundKeys) break;\r
+               }               \r
+               \r
+               if (notFoundKeys) {\r
+                       PrintAndLog("-----------------------------------------------\n");\r
+                       PrintAndLog("We have unrecognized keys. Trying to check if we have this keys on key buffer...");\r
+\r
+                       // fill keyBlock with known keys\r
+                       int cnt = 0;\r
+                       for (i = 0; i < SectorsCnt; i++) {\r
+                               for (j = 0; j < 2; j++) {\r
+                                       if (e_sector[i].foundKey[j]) {\r
+                                               // try to insert key to keyBlock                                                \r
+                                               if (cnt < NESTED_KEY_COUNT) {\r
+\r
+                                                       // search for dublicates\r
+                                                       bool dubl = false;\r
+                                                       for (int v = 0; v < NESTED_KEY_COUNT; v++) {\r
+                                                               if (e_sector[i].Key[j] == bytes_to_num((uint8_t*)(keyBlock + v * 6), 6)) {\r
+                                                                       dubl = true;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                                       \r
+                                                       // insert\r
+                                                       if (!dubl) {\r
+                                                               num_to_bytes(e_sector[i].Key[j], 6, (uint8_t*)(keyBlock + cnt * 6));\r
+                                                               cnt++;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
 \r
-               PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations);\r
-               //print them\r
+                       // try to auth with known keys to not recognized sectors keys\r
+                       PrintAndLog("Testing keys. Sector count=%d known keys count:%d", SectorsCnt, cnt);\r
+                       for (i = 0; i < SectorsCnt; i++) {\r
+                               for (j = 0; j < 2; j++) {\r
+                                       if (e_sector[i].foundKey[j]) continue;\r
+\r
+                                       res = mfCheckKeys(FirstBlockOfSector(i), j, true, cnt, keyBlock, &key64); \r
+\r
+                                       if (!res) {\r
+                                               e_sector[i].Key[j] = key64;\r
+                                               e_sector[i].foundKey[j] = 1;\r
+                                       }\r
+                               }\r
+                       }                       \r
+                       \r
+               } // if (notFoundKeys)\r
+               \r
+               // print result\r
                PrintAndLog("|---|----------------|---|----------------|---|");\r
                PrintAndLog("|sec|key A           |res|key B           |res|");\r
                PrintAndLog("|---|----------------|---|----------------|---|");\r
@@ -720,7 +851,7 @@ int CmdHF14AMfNested(const char *Cmd)
                }\r
                PrintAndLog("|---|----------------|---|----------------|---|");\r
 \r
-               // transfer them to the emulator\r
+               // transfer keys to the emulator memory\r
                if (transferToEml) {\r
                        for (i = 0; i < SectorsCnt; i++) {\r
                                mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);\r
@@ -730,6 +861,7 @@ int CmdHF14AMfNested(const char *Cmd)
                                        num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);\r
                                mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);\r
                        }\r
+                       PrintAndLog("Keys transferred to emulator memory.");\r
                }\r
 \r
                // Create dump file\r
@@ -946,13 +1078,7 @@ int CmdHF14AMfChk(const char *Cmd)
 \r
        if (param_getchar(Cmd, 0)=='*') {\r
                blockNo = 3;\r
-               switch(param_getchar(Cmd+1, 0)) {\r
-                       case '0': SectorsCnt =  5; break;\r
-                       case '1': SectorsCnt = 16; break;\r
-                       case '2': SectorsCnt = 32; break;\r
-                       case '4': SectorsCnt = 40; break;\r
-                       default:  SectorsCnt = 16;\r
-               }\r
+               SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0));\r
        }\r
        else\r
                blockNo = param_get8(Cmd, 0);\r
@@ -1854,17 +1980,6 @@ int CmdHF14AMfCSetUID(const char *Cmd)
        return 0;\r
 }\r
 \r
-static int ParamGetCardSize(const char c) {\r
-       int numBlocks = 16 * 4;\r
-       switch (c) {\r
-               case '0' : numBlocks = 5 * 4; break;\r
-               case '2' : numBlocks = 32 * 4; break;\r
-               case '4' : numBlocks = 32 * 4 + 8 * 16; break;\r
-               default:   numBlocks = 16 * 4;\r
-       }\r
-       return numBlocks;\r
-}\r
-\r
 int CmdHF14AMfCWipe(const char *Cmd)\r
 {\r
        int res, gen = 0;\r
@@ -1885,7 +2000,7 @@ int CmdHF14AMfCWipe(const char *Cmd)
        if ((gen != 1) && (gen != 2)) \r
                return 1;\r
        \r
-       numBlocks = ParamGetCardSize(param_getchar(Cmd, 0));\r
+       numBlocks = ParamCardSizeBlocks(param_getchar(Cmd, 0));\r
 \r
        char cmdp = 0;\r
        while(param_getchar(Cmd, cmdp) != 0x00){\r
Impressum, Datenschutz