Kategorie
Bezpieczeństwo Publicystyka Zrób to sam

Szyfrowanie dokumentów numerem PESEL nie chroni ich zawartości

Od kilku miesięcy mBank zapowiada, że wkrótce wyciągi i inne dokumenty dostarczane klientom pocztą elektroniczną będą miały postać plików PDF opatrzonych hasłem. Ich zawartość ma być dzięki temu chroniona przed osobami postronnymi, które w ten czy inny sposób weszłyby w ich posiadanie. Postanowiłem sprawdzić, jak można zabrać się do łamania owego zabezpieczenia.

W niniejszym artykule pokazuję, że użycie numeru PESEL jako hasła do dokumentu PDF nie ma żadnego sensu. Na zwykłym domowym komputerze atak siłowy potrwa zaledwie kilkanaście sekund. Jeśli jednak ustawisz hasło samodzielnie, podniesiesz próg trudności ataku z sekund do milionów lat.

Krok pierwszy – generujemy (prawie) wszystkie numery PESEL

Na stronach serwisu gov.pl czytamy: “Numer PESEL to jedenastocyfrowy symbol numeryczny, który pozwala na łatwą identyfikację osoby, która go posiada”. Dalej możemy dowiedzieć się, że PESEL składa się z sześciocyfrowej daty, czterocyfrowego numeru porządkowego (parzystość ostatniej cyfry niesie informację o płci osoby) i cyfry kontrolnej sprawdzającej poprawność całego numeru.

Aby przeprowadzić atak siłowy, przydadzą nam się wszystkie możliwe numery PESEL. Będę atakował swój własny dokument szyfrowany moim numerem, więc dla uproszczenia wezmę pod uwagę przedział zawierający moją datę urodzenia – półwiecze 1950-2000.

Pod adresem https://gist.github.com/tomekziel/5f95c9bb7274d037916d52df492ffc32 znajdziesz program w języku C#, generujący komplet 186 milionów numerów PESEL z tego okresu. Program działa jednowątkowo i jest pozbawiony jakichkolwiek optymalizacji, mimo to do ukończenia roboty wystarcza mu niespełna 80 sekund. Plik wynikowy ma 2.25 GB.

Krok drugi – bierzemy na warsztat PDF z MOPS-u

Jako pierwszy do analizy trafił dokument z wrocławskiego MOPS-u, w którym czytam, że prezydent miasta Wrocławia przyznał moim zstępnym świadczenie Dobry Start, znane również jako „piórnikowe”. Szyfrowanie pliku PDF przydaje się tu o tyle, że sam e-mail nie jest przesyłany w sposób gwarantujący poufność (hej, Surfland Systemy Komputerowe SA, da się robić tę robotę lepiej)

Najpierw upewniamy się, że plik rzeczywiście jest zaszyfrowany. Próba łamania zwykłego PDF-a byłaby zawstydzająca.

Gdy podejrzymy zawartość w trybie tekstowym, w nagłówku zauważamy ciąg znaków „%PDF-1.4” – dowiadujemy się z niego, że dokument został zapisany w niemal dwudziestoletnim formacie PDF 1.4.

Do kolejnego kroku będziemy potrzebować tzw. skrótu hasła, którym zaszyfrowano plik PDF. Jedna z możliwości jego pozyskania to użycie skryptu pdf2john.py z pakietu John the Ripper. Jeśli nie dbamy o poufność łamanego dokumentu, możemy użyć tego samego kodu w wersji online na stronie onlinehashcrack.com.

Odzyskany skrót (hasz) ma postać podobną do tej:

$pdf$2*3*128*-4*1*16*3d492eda53e▮▮▮▮▮ce8477943*32*04b7ddb4▮▮▮▮▮966cd3a1b0af02f28bf4e5e4e758▮▮▮▮e56fffa0108*32*6b76fcc9271b▮▮▮▮▮455100e02d21a075e48af8b1e2c1▮▮▮▮39c378ab

Zapisujemy ten ciąg znaków do pliku.

Krok trzeci – łamiemy hasło

Do siłowego złamania hasła użyjemy programu hashcat pobranego ze strony hashcat.net – jest to szeroko znane i powszechnie używane narzędzie do atakowania kilkuset formatów szyfrów i funkcji skrótu. Co ważne, hashcat potrafi zaprząc do pracy karty graficzne, dzięki czemu obliczenia są w wielkim stopniu zrównoleglane.

Program wywołujemy komendą

hashcat.exe -m 10500 plikzhaszem.txt pesele.txt

Parametr -m 10500 oznacza format PDF 1.4-1.6.

Device #1: CUDA SDK Toolkit installation NOT detected.
CUDA SDK Toolkit installation required for proper device support and utilization
Falling back to OpenCL Runtime

Hashcat na początku skarży się, że nie odnalazł sterowników CUDA pozwalających osiągnąć pełną wydajność na kartach z chipem Nvidia. Doinstalowałem. Wydajność obliczeń z wykorzystaniem CUDA była o połowę… niższa, niż wariant OpenCL. No cóż. Zostaję przy OpenCL.

Następnie widzimy kolejno informacje o karcie graficznej, skrócie do złamania, zastosowanych optymalizacjach i wymaganiach pamięciowych.

OpenCL API (OpenCL 1.2 CUDA 10.2.131) - Platform #1 [NVIDIA Corporation]
Device #1: GeForce GTX 1660 SUPER, 4992/6144 MB (1536 MB allocatable), 22MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 32
Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Applicable optimizers applied:
Zero-Byte
Not-Iterated
Single-Hash
Single-Salt
Watchdog: Temperature abort trigger set to 90c
Host memory required for this attack: 450 MB

Potem hashcat wczytuje przez kilka sekund plik z potencjalnymi hasłami

Dictionary cache hit:
Filename..: pesele.txt
Passwords.: 186000000
Bytes.....: 2418000000
Keyspace..: 186000000
Runtime...: 8 secs

Bieżący status operacji możemy przywołać klawiszem „s”

[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit =>

Session..........: hashcat
Status...........: Running
Hash.Name........: PDF 1.4 - 1.6 (Acrobat 5 - 8)
Hash.Target......: $pdf$2*3*128*-4*1*16*3d492eda53e49bcfb1d17b0ce84779...c378ab
Time.Started.....: Mon Sep 07 23:22:42 2020 (4 secs)
Time.Estimated...: Mon Sep 07 23:23:08 2020 (22 secs)
Guess.Base.......: File (pesele.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  6934.1 kH/s (60.25ms) @ Accel:1024 Loops:35 Thr:64 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 27394048/186000000 (14.73%)
Rejected.........: 0/27394048 (0.00%)
Restore.Point....: 27394048/186000000 (14.73%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:35-70
Candidates.#1....: 57051240486 -> 57100158397
Hardware.Mon.#1..: Temp: 43c Fan: 44% Util: 69% Core:1965MHz Mem:6801MHz Bus:16

Widzimy, że program pracuje od 4 sekund, przebił się przez ponad 14.7% skrótów i skończy za jakieś 22 sekundy. Wydajność ataku siłowego w tej całkowicie niezoptymalizowanej konfiguracji oprogramowania to 6.9 milionów haszy na sekundę (całoroczna paczka PESEL-i jest sprawdzana w pół sekundy). Kilka chwil później mamy wynik:

$pdf$2*3*128*-4*1*16*3d492eda53e▮▮▮▮▮ce8477943*32*04b7ddb4▮▮▮▮▮966cd3a1b0af02f28bf4e5e4e758▮▮▮▮e56fffa0108*32*6b76fcc9271b▮▮▮▮▮455100e02d21a075e48af8b1e2c1▮▮▮▮39c378ab: [TUTAJ MÓJ PESEL]

Session..........: hashcat
Status...........: Cracked
Hash.Name........: PDF 1.4 - 1.6 (Acrobat 5 - 8)
Hash.Target......: $pdf$2*3*128*-4*1*16*3d492eda53e49bcfb1d17b0ce84779...c378ab
Time.Started.....: Mon Sep 07 23:22:42 2020 (16 secs)
Time.Estimated...: Mon Sep 07 23:22:58 2020 (0 secs)
Guess.Base.......: File (pesele.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  6872.8 kH/s (61.34ms) @ Accel:1024 Loops:35 Thr:64 Vec:1
Recovered........: 1/1 (100.00%) Digests
Progress.........: 10XXXXX92/186000000 (XX.91%)
Rejected.........: 0/109576192 (0.00%)
Restore.Point....: 108134400/186000000 (58.14%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:35-70
Candidates.#1....: XXXXXX44003 -> XXXXXX61913
Hardware.Mon.#1..: Temp: 44c Fan: 44% Util: 66% Core:1965MHz Mem:6801MHz Bus:16

Started: Mon Sep 07 23:22:40 2020
Stopped: Mon Sep 07 23:22:59 2020

Cała operacja łamania PDF-a zaszyfrowanego numerem PESEL trwała na domowym sprzęcie 19 sekund. Gdy spytałem na Twitterze o wasze przewidywania, głosy kształtowały się następująco:

Dokument z mBanku i dwie niespodzianki

Widząc, jak łatwy jest atak siłowy na dokument chroniony PESEL-em, wczoraj w mBanku ręcznie włączyłem sobie szyfrowanie wyciągów 10-znakowym hasłem. Dziś rano dostałem wyciąg z karty kredytowej, więc od razu miałem drugi egzemplarz szyfrowanego PDF-a do zbadania. I tutaj pojawiły się małe problemy.

Gdy przepuściłem wyciąg z mBanku przez skrypt pdf2john.py, otrzymałem hasz… odrzucany przez hashcata (niespodzianka pierwsza). Okazuje się, że rozwijana przez społeczność wersja “jumbo” pakietu John the Ripper zawiera analogiczne narzędzie, ale napisane w Perlu (pdf2john.pl). Informacja dla ciekawych – narzędzie to jest dostępne standardowo w dystrybucji Kali Linux. Tym razem otrzymałem poprawny hasz, wyglądający mniej-więcej tak:

$pdf$5*5*256*3796*1*16*5158cb700▮▮▮▮▮758b16d9b634*48*49bd▮▮▮▮▮25a28cad4▮▮▮▮▮431158d43d10e▮▮▮▮▮c0f4811cf190965e33e7aea92dcf5af6b6533fe9592*48*ff1720a3024a586▮▮▮▮▮41abb03cc2f714f65e8▮▮▮▮▮76b98bbd24f321eb679cb6fc7fb032725▮▮▮▮▮a3*32*42d039d7▮▮▮▮▮14a7e4451d11340ef2a174ebedf395c3e551a6aadf212bf6*32*e51db300▮▮▮▮▮5c62ba23812e1bace3a7▮▮▮▮▮0fde0bbcb2a680ceb2c2

I tu się trochę zdziwiłem (niespodzianka druga), bo po pierwsze ten hasz jest znacznie dłuższy, po drugie zaś zaczyna się od identyfikatora $pdf$5*5. Identyfikator ten jest w formatach hashcata przypisany do standardu PDF 1.7 Level 3 (szyfrowanego szyfrem AES), tymczasem nagłówek i tego pliku zawiera sygnaturę %PDF-1.4. Jak widać standardy sobie a życie sobie – dostarczony dokument rzeczywiście jest w wersji PDF 1.7.

Gdy zobaczyłem, że owa używana przez mBank wersja standardu PDF zadebiutowała w Adobe Acrobat 9, przypomniała mi się dawna afera związana ze znaczącym obniżeniem siły szyfrowania plików z tej wersji programu. Chwila grzebania w archiwalnych newsach pozwoliła odnaleźć doniesienia prasowe na ten temat. Hmmm, stukrotna różnica w ataku siłowym. Spróbujmy.

Jak oszacować czas łamania hasła

Gdy spojrzymy na stronę mBanku, zobaczymy następujący zestaw wymagań dotyczących hasła:

Wielkie i małe litery oraz cyfry (trzy z czterech grup) to razem 62 różne znaki. Dziesięć znaków z tej grupy (minimalna długość hasła) można ułożyć na 839299365868340224 różnych sposobów. Sporo. Jeśli będziemy je próbować w tempie 6.8 mln kombinacji na sekundę (tyle hashcat osiągał łamiąc PDF-a z MOPS), sprawdzimy wszystkie po około czterech tysiącach lat.

No to teraz zobaczmy, jak hashcat radzi sobie z PDF-em z mBanku. Linia komend będzie wyglądała następująco:

hashcat.exe -1 ?l?u?d -m 10600 -a 3 Szyfrowane-wyciagi.hash ?1?1?1?1?1?1?1?1?1?1

-m 10600 to oznaczenie formatu PDF 1.7 Level 3 (Acrobat 9), -a 3 to łamanie wg podanego wzorca, -1 ?l?u?d to definicja znaku z zestawu „duże i małe litery plus cyfry”, zaś seria sekwencji ?1 to dziesięciokrotne użycie zdefiniowanego wzorca znaku.

Jesteśmy gotowi do łamania hasła.

[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit =>

Session..........: hashcat
Status...........: Running
Hash.Name........: PDF 1.7 Level 3 (Acrobat 9)
Hash.Target......: $pdf$5*5*256*3796*1*16*5158cb7003735ea584c1758b16d9...ceb2c2
Time.Started.....: Tue Sep 08 23:08:24 2020 (10 secs)
Time.Estimated...: Fri Sep 08 22:29:06 2034 (13 years, 364 days)
Guess.Mask.......: ?1?1?1?1?1?1?1?1?1?1 [10]
Guess.Charset....: -1 ?l?u?d, -2 Undefined, -3 Undefined, -4 Undefined
Guess.Queue......: 1/1 (100.00%)
Speed.#2.........:  1899.9 MH/s (11.90ms) @ Accel:32 Loops:32 Thr:1024 Vec:1
Recovered........: 0/1 (0.00%) Digests
Progress.........: 18662555648/839299365868340224 (0.00%)
Rejected.........: 0/18662555648 (0.00%)
Restore.Point....: 0/3521614606208 (0.00%)
Restore.Sub.#2...: Salt:0 Amplifier:25888-25920 Iteration:0-32
Candidates.#2....: SF1eranere -> cITv541234
Hardware.Mon.#2..: Temp: 51c Fan: 44% Util: 99% Core:1965MHz Mem:6801MHz Bus:16

Czy też to widzicie? Mój domowy komputer ze średniej półki łamie tego PDF-a w tempie bliskim DWÓCH MILIARDÓW haseł na sekundę. Hashcat szacuje, że takie zadanie zajmie mu 14 lat.

14 lat pracy jednego domowego komputera to bardzo mało lat pracy komputerów w serwerowniach Amazona. Oszacujmy to sobie – wiedząc, że maszyna EC2 typu p3.16xlarge z ośmioma sztukami kart graficznych NVIDIA Tesla V100 łamie 60 miliardów takich haseł na sekundę, możemy przeszukać wszystkie potencjalne 10-znakowe hasła w pół roku, wydając na to jakieś 70.000 dolarów. Za około 100.000 dolarów możemy to mieć policzone w kilka dni, bo wynajmiemy więcej maszyn na krótszy okres i nie dostaniemy zniżek za długi okres najmu. Potęga chmury obliczeniowej!

Ciekawostka – w roku 2008 na domowym komputerze dało się łamać 300 tysięcy haseł na sekundę. Przebyliśmy długą drogę.

Czy mBank zrobił coś źle?

Z całą pewnością wysyłanie szyfrowanych wyciągów akurat w formacie PDF 1.7 Level 3 nie było najwspanialszym wyborem, bo łamanie pozostałych wersji PDF jest jakieś 300 razy trudniejsze.

Przyznam, że nie do końca rozumiem ideę przymusowego szyfrowania wyciągów – a już zwłaszcza używanie numeru PESEL jako hasła, bo w takiej sytuacji ochrona poufności dokumentu jest żadna. OK, szyfrowane wyciągi dostępne są dla chętnych od wielu lat, jak ktoś chce to niech używa. Tymczasem wszyscy pozostali będą przywykać do faktu, że dostają dokumenty, których nie jest w stanie przeskanować antywirus w serwisie pocztowym, zaś przy ich otwieraniu trzeba podać PESEL. Stąd już tylko krok do otworzenia złośliwego załącznika użytego w ataku celowanym (PESEL raz ujawniony w bazie KRS albo innym miejscu pozostanie jawny na zawsze).

Ciekawostka – mBank nie pozwala ustawić hasła do wyciągów na takie, jakim logujemy się do serwisu transakcyjnego. Odwrotna sytuacja jest jednak możliwa – da się przestawić hasło dostępowe na to, którym szyfrowane są wyciągi. Spytałem przedstawicieli banku, czy to celowe działanie, czy przeoczenie, ale nie dostałem odpowiedzi.

Co mam teraz robić?

Jeśli do tej pory brak szyfrowania wyciągów ci nie przeszkadzał, nic się nie zmienia. Obowiązkowy PESEL w roli hasła do pliku PDF wprowadzi pewną uciążliwość, bezpieczeństwa nie podniesie, poza tym wszystko zostanie jak jest.

Jeśli przywiązujesz wagę do szyfrowania wyciągów, ustaw hasło 15-znakowe lub dłuższe, generowane losowo, korzystające z dużych/małych liter, cyfr i znaków specjalnych. Prędzej słońce zgaśnie, niż ktoś je złamie metodą siłową.

Hasła w prawdziwym życiu

Jeśli używasz tego samego hasła w różnych miejscach, to jego długość i złożoność nie ma znaczenia. Mogło wyciec dawno temu, tylko jeszcze o tym nie wiesz.

Jeśli używasz hasła, które już kiedyś komuś wyciekło, to jego długość i złożoność nie ma znaczenia. I tak każdy atakujący używa ataku siłowego jako ostateczność, zawsze wcześniej przeprowadzany jest atak słownikowy, jak ten z listą numerów PESEL powyżej.

Jeśli używasz menedżera haseł, to twoje hasła są niepowtarzalne a przed atakiem siłowym będą się bronić przez gazyliony lat. Jeśli nie używasz – zacznij. Jeśli nie wiesz jak – zajrzyj tutaj.



O autorze: zawodowy programista od 2003 roku, pasjonat bezpieczeństwa informatycznego. Rozwijał systemy finansowe dla NBP, tworzył i weryfikował zabezpieczenia bankowych aplikacji mobilnych, brał udział w pracach nad grą Angry Birds i wyszukiwarką internetową Microsoft Bing.

7 odpowiedzi na “Szyfrowanie dokumentów numerem PESEL nie chroni ich zawartości”

Poruszasz mega ważne tematy, w zrozumiały sposób dla nieinformatyków. Dziękuję. Może kiedyś napiszesz o vpn (czy warto instalować)?

Instaluj VNP, gdy:
a) wymaga tego pracodawca / klient
b) potrzebujesz udawać, że jesteś w innym kraju (zakupy, streamingi, cokolwiek)
c) nie ufasz swojemu dostawcy internetu i chcesz, żeby nie wiedział zupełnie niczego o twoim ruchu sieciowym
c*) nie ufasz swoim ogarniętym technicznie rodzicom i chcesz, żeby nie wiedzieli zupełnie niczego o twoim ruchu sieciowym

Tyle mi przychodzi do głowy tak na szybko.

Miałem z mbankiem lepszy ubaw.

Kiedy przeczytalem o tym szyfrowaniu wyciągów, zapytałem grzecznie w pomocy techincznej, dlaczego nie można tego zrobić całego szyfrowania powiadomień i wyciągów nie zrobić sensownie, tzn tak, jak np na Facebooku czy bugzilli Firefoxa.
Czyli po krócte czemu nie mogę dodać w serwisie transakcyjnym klucza publicznego GPG i niech szyfrują wyciagi i maile moim kluczem.

Było to ze dwa latka temu, na początku brak odpowiedzi, odpowiedzieli po pół roku, że mogą stosować TYLKO metody szyfrowania spełniające najwyższe standardy bezpieczeństwa…..

Jak się gimbaza za administrowanie systemami bankowymi bierze, to potem takie mamy rezultaty.

Jak ktoś tam jeszcze ma konto, to radzę tych „administratorów” zapytać, dlaczego nie mają w domenie mbank.pl podpisu DNSSEC,
a klasa adresowa IP strony mbanku nie jest podpisana przez RPKI.
Pewnie będą mieli jeszcze śmieszniejsze wytłumaczenie.

Pozdro

GPG miało od zawsze ten sam problem: przyzerowa adopcja rozwiązania w społeczeństwie. Idea jest fajna, ale samo rozwiązanie jest skomplikowane koncepcyjnie w pełnym wariancie. W wariancie minimalnym także nie jest proste dla laików. Znacznie prostsze jest ustawienie długiego, losowego hasła i trzymanie go w Keepass* lub podobnym rozwiązaniu. I jest to rozwiązanie dostępne nawet dla laików.

Dodatkowo w zeszłym roku pojawił się problem z serwerami https://gist.github.com/rjhansen/67ab921ffb4084c865b3618d6955275f Więc uważam, że dobrze się stało, że mbank nie inwestował w niszowe rozwiązanie oparte na problematycznym, przestarzałym software.

Fajny artykuł. AliorBank przesyła do klientów dokumenty kredytowe (np. harmonogram spłat – z danymi klienta) zabezpieczone 5 ostatnimi cyframi umowy – na moim leciwym laptoku hashcat ~2 sekundy

„Jeśli używasz hasła, które już kiedyś komuś wyciekło, to jego długość i złożoność nie ma znaczenia. I tak każdy atakujący używa ataku siłowego jako ostateczność, zawsze wcześniej przeprowadzany jest atak słownikowy, jak ten z listą numerów PESEL powyżej.”

Powyższe stwierdzenie nie jest prawdziwe. Tj. atakujący faktycznie używają przede wszystkim słowników, ale nie jest tak, że hasło, które komuś wyciekło automatycznie jest dla wszystkich spalone. Oczywiście pod warunkiem, że nie wyciekło nam, bo powiązanie np. po mailu to zupełnie inna sprawa.

Atak słownikowy to nadal metoda siłowa, tylko o zawężonym zakresie i „wolne” hashe skutecznie go ograniczają. Było to widać przy okazji wycieku z Benchmark.pl https://zaufanatrzeciastrona.pl/post/wyciek-danych-uzytkownikow-serwisu-benchmark-pl/ – dla haseł solonych bcrypt udało się złamać tylko najprostsze hasła, klasy top 100 czy top 1000 najpopularniejszych – sprawdzenie pełnego słownika jest zbyt wolne.

Oczywiście w długim okresie (albo wrzucając odpowiednio dużo kasy) wszystko da się złamać, ale czy sprawdzenie słownika potrwa godzinę czy kilkaset lat (albo: czy kosztuje 1 dolara czy milion) to jednak spora różnica.

To prawda, ale do takich rozważań wchodzi z kolei inna zmienna – czy atak jest wycelowany w jedną osobę, czy też mamy do czynienia z przesiewaniem miliona wyciekniętych kont w poszukiwaniu użytkowników ze słabym hasłem.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *