Szybki tutorial o zabezpieczeniach w NFC Knox Meetup 02 Michał Leszczyński CERT Polska
Szybki tutorial o zabezpieczeniach w NFC Knox Meetup 02 Michał Leszczyński CERT Polska
Szybki tutorial o pewnych rzeczach związanych z NFC Knox Meetup 02 Michał Leszczyński CERT Polska
Michał Leszczyński Specjalista IT Security w CERT Polska monk@cert.pl icedev.pl @icedevml
Wprowadzenie
Czym jest RFID, a czym NFC? RFID - generyczna radiowa identyfikacja obiektu NFC - konkretna technologia komunikacji na paśmie 13.56 MHz
Rodzaje kart RFID Unique - 125 khz Karty 13.56 MHz kompatybilne z ISO 14443-3: Sony FeliCa MIFARE Classic MIFARE DESFire MIFARE Ultralight
Rodzaje zabezpieczeń brak uwierzytelnianie schematem challenge-response podpisy CMAC uprawnienia dostępowe
Challenge-response ze wspólnym sekretem 1. A->B: Wysyła losowy ciąg bajtów 2. B->A: Podpisuje ten ciąg bajtów kluczem i odsyła podpis 3. A: Sprawdza poprawność podpisu
Cipher-based Message Authentication Code algorytm konstrukcji podpisu cyfrowego na bazie szyfru blokowego
Uprawnienia dostępowe bity dostępu - limitowany odczyt/zapis danego sektora lub pliku różne poziomy dostępu dla różnych kluczy
No dobrze, ale...
No dobrze, ale... Mifare Classic natomiast Źródło: https://www.cs.virginia.edu/~kn5f/mifare.cryptanalysis.htm
Mifare Classic jeden z najbardziej popularnych rodzajów kart w Polsce używa autorskiego algorytmu CRYPTO1, zoptymalizowanego pod kątem implementacji w sprzęcie bezpieczeństwo kryptograficzne CRYPTO1 jest bliskie zeru całe szczęście są lepsze standardy kart...
Mifare DESFire
Mifare DESFire - struktura operuje w koncepcie aplikacji - każda aplikacja może mieć swoje klucze dostępowe (o różnych poziomach dostępu) oraz pliki posługując się kluczem głównym można tworzyć aplikacje szyfrowanie DES/3DES/AES, podpisy CMAC obsługa APDU - telefon z Androidem jest w stanie te karty przeczytać/skonfigurować
Mifare DESFire - typowy scenariusz wybranie aplikacji po numerze np. select C0FFEE wzajemne uwierzytelnienie z aplikacją za pomocą challenge-response (podrobiona karta nie będzie w stanie uwierzytelnić się czytnikowi) odczytanie określonego pliku i sprawdzenie poprawności podpisu (zależnie od ustawień treść pliku jest jawna/jawna z podpisem lub szyfrowana z podpisem, z założenia podrobiona karta nie będzie w stanie poprawnie zaszyfrować, ani podpisać)
Stos protokołów NFC ISO 14443-3 - norma opisująca inicjalizację i antykolizję kart tzn. od początku do momentu wybrania karty ISO 14443-4 - norma opisująca protokół transmisyjny tzn. wszystko po wybraniu karty aż do przejścia w docelowy protokół standard Mifare DESFire - wewnętrzny własnościowy protokół ISO 7816-4 - norma opisująca ramki Application Protocol Data Unit
Mifare DESFire - komunikacja (ISO 14443-3) Welcome R: 26 C: 44 03 [CRC] Select R: 93 20 C: CE 7E 09 C3 7A [CRC] R: 93 70 CE 7E 09 C3 7A C: 20 [CRC]
Mifare DESFire - komunikacja (ISO 14443-4) Request Answer To Select R: E0 50 ^^ bajt parametru, koduje FSDI oraz CID C: 06 75 77 81 [CRC] ^^ ^^ ^^ informacje o wspieranych opcjach transmisji
Mifare DESFire - komunikacja (protokół DESFire) Select application R: 02 5A EE FF C0 [CRC] C: 02 91 00 [CRC] Authentication R: 03 1A 00 [CRC] C: 03 AF 5D 99 4C E0 85 F2 40 89 [CRC] * RndB_enc: 5D 99 4C E0 85 F2 40 89 * RndB: 4F D1 B7 59 42 A8 B8 E1 * RndB_rot: D1 B7 59 42 A8 B8 E1 4F * RndA: 84 9B 36 C5 F8 BF 4A 09 * RndAB: 84 9B 36 C5 F8 BF 4A 09 D1 B7 59 42 A8 B8 E1 4F * RndAB_enc: 21 D0 AD 5F 2F D9 74 54 A7 46 CC 80 56 7F 1B 1C
Mifare DESFire - komunikacja (protokół DESFire) R: 02 AF 21 D0 AD 5F 2F D9 74 54 A7 46 CC 80 56 7F 1B 1C [CRC] C: 02 00 91 3C 6D ED 84 22 1C 41 [CRC] * RndA_enc: 91 3C 6D ED 84 22 1C 41 * RndA_dec: 9B 36 C5 F8 BF 4A 09 84 * RndA: 84 9B 36 C5 F8 BF 4A 09 R: sprawdzenie czy RndA zgadza się z tym, które zostało wygenerowane w poprzednim kroku * SessKey: 84 9A 36 C4 4E D0 B6 58 84 9A 36 C4 4E D0 B6 58 (DES) ^^^^^^^^^^^ ^^^^^^^^^^^ RndA[:4] RndB[:4]
Czytanie kart na Androidzie
Komunikacja z kartami Androidem? Skoro nowoczesne smartfony posiadają moduły NFC, to czy da się je skomunikować z kartami? Tak, ale...
DESFire Tool
Komunikacja z kartami Androidem? NfcAdapter.enableReaderMode - dostarczamy callback, który zostanie wywołany w momencie wykrycia nowej karty przez smartfona. Po otrzymaniu callbacka możemy komunikować się z kartą poprzez APDU.
Komunikacja z kartami Androidem? AndroidManifest.xml <uses-permission android:name="android.permission.nfc" /> <uses-feature android:name="android.hardware.nfc" android:required="true" /> Activity class MainActivity extends NfcAdapter.ReaderCallback { public void oncreate() { nfcadapter = NfcAdapter.getDefaultAdapter(activity); } public void onresume() { super.onresume(); nfcadapter.enablereadermode(this, this, NfcAdapter.FLAG_READER_NFC_A NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null) }... }
Komunikacja z kartami Androidem? Activity class MainActivity extends NfcAdapter.ReaderCallback {... } public void ontagdiscovered(tag tag) { IsoDep isodep = IsoDep.get(tag); isodep.connect(); byte[] msg = Utils.hexStringToByteArray("00A4040007A0000002471001"); byte[] response = isodep.transceive(msg); //... dalsze polecenia... log(response); isodep.close(); }
Application Protocol Data Unit Przykładowo: 00 A4 04 00 05 F0DEADBEEF 00 czyli: wybierz aplikację ID: F0DEADBEEF
Application Protocol Data Unit Przykładowo: 48454C4C4F 9000 czyli: HELLO + status OK
Wybrane komendy w DESFire Wybierz aplikację 5A ID aplikacji Uwierzytelnianie (zależnie od trybu) Lista ID plików 0A, 1A, AA ID klucza uwierzytelniającego 6A Odczyt pliku 8D ID pliku, długość, offset Zapis pliku 3D ID pliku, długość, offset, dane Kredyt 0C ID pliku, wartość Debet DC ID pliku, wartość
Emulacja kart na Androidzie
Emulacja karty na Androidzie? Android 4.4+ posiada funkcję Host-Based Card Emulation (HCE). W tym trybie telefon zachowuje się jak karta zgodna ISO 14443 i obsługuje komendy APDU (ISO 7816-4). https://developer.android.com/reference/android/nfc/cardemulation/hostapduservice
Emulacja karty na Androidzie? manifests/androidmanifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="poc.nfc.nfcpoc"> <uses-feature android:name="android.hardware.nfc.hce" android:required="true" /> <uses-permission android:name="android.permission.nfc" /> <application...>... <service android:name=".cardservice" android:exported="true" android:permission=android.permission.bind_nfc_service"> <intent-filter> <action android:name="android.nfc.cardemulation.action.host_apdu_service"/> <category android:name="android.intent.category.default"/> </intent-filter> <meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/aid_list"/> </service> </application> </manifest>
Emulacja karty na Androidzie? res/xml/aid_list.xml <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/app_name" android:requiredeviceunlock="false"> <aid-group android:description="@string/app_name" android:category="other"> <aid-filter android:name="f0deadbeef"/> </aid-group> </host-apdu-service>
Emulacja karty na Androidzie? poc/nfc/nfcpoc/cardservice.java public class CardService extends HostApduService { private static final byte[] SELECT_APDU = HexStringToByteArray("00A4040005F0DEADBEEF00"); private static final byte[] UNKNOWN_CMD_SW = HexStringToByteArray("0000"); @Override public byte[] processcommandapdu(byte[] commandapdu, Bundle extras) { if (Arrays.equals(SELECT_APDU, commandapdu)) { ByteArrayOutputStream os = new ByteArrayOutputStream(); } } try { os.write("hello world!".getbytes()); os.write(new byte[] {(byte)0x90, 0x00}); return os.tobytearray(); } catch (IOException e) { e.printstacktrace(); return UNKNOWN_CMD_SW; } } else { return UNKNOWN_CMD_SW; }
Live demo
Czytnik kart na Arduino void setup() { Serial.begin(9600); nfc.begin(); uint32_t versiondata = nfc.getfirmwareversion(); if (! versiondata) { Serial.println("Didn't find PN53x board"); while (1); // halt } // Got ok data, print it out! Serial.println("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX); Serial.println("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC); Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC); } // configure board to read RFID tags nfc.samconfig();
Czytnik kart na Arduino void loop() { uint8_t responselength = 32; success = nfc.inlistpassivetarget(); if(success) { uint8_t selectapdu[] = { 0x00, /* CLA */ 0xA4, /* INS */ 0x04, /* P1 */ 0x00, /* P2 */ 0x05, /* Length of AID */ 0xF0, 0xDE, 0xAD, 0xBE, 0xEF, /* AID defined on Android App */ 0x00 /* Le */ }; uint8_t response[32]; success = nfc.indataexchange(selectapdu, sizeof(selectapdu), response, &responselength); } } if(success) { if (responselength > 2 && response[responselength-2] == 0x90 && response[responselength-1] == 00) { response[responselength-2] = 0; Serial.println((const char*)response); }
Podsumowanie