Temat PassWindow nie daje mi spokoju. Przedstawię tu ogólną koncepcję jak do tematu się można zabrać. Nie jest to jeszcze funkcjonalny łamacz, ale jako PoC wystarczy.
PassWindow II: walczący z kreskami (i to dość skutecznie)
Ilustracja na początek
Na początek obrazek ilustrujący to, o czym będzie dalej. Na poniższym obrazku przedstawiona jest maska (kolor czerwony), dwa wzorki oraz rezultat nałożenia maski na wzorek, czyli wynikowe hasło. Tu hasła są dwa, 689252 oraz 092259.

Co ma intruz
Załóżmy, że intruzowi udało się zainstalować malware na komputerze swojej ofiary. Nie jest to "tradycyjny" keylogger, lecz narzędzie potrafiące nieco więcej, czyli poza przechwytywaniem wpisywanych danych, może ono również robić zrzuty ekranu. W rezultacie intruz dysponuje wzorkiem, który wyświetlony został użytkownikowi oraz hasłem, które użytkownik wpisał. To, czego intruz nie wie i szuka, to jak wygląda (lub może z dużym prawdopodobieństwem) wyglądać maska.
Jak to ugryźć
Jak reprezentować cyfry i kreski
Pierwsza sprawa, to jak przekształcić kreski na coś, z czego wygodniej korzysta się w skryptach. Ponieważ kresek do stworzenia cyfry jest maksymalnie siedem, to logiczne wydaje się reprezentowanie wzorku w postaci następującej: 01100000, gdzie pierwsze 0 jest zawsze 0, bo to jest nadmiarowy jeden bit, przez 1 oznaczana jest krawędź, która jest (pełna), przez 0 ta, której nie ma (jest pusta). Punkt startowy to kreska górna, następnie zgodnie z ruchem wskazówek zegara, przy czym na ostatniej pozycji jest kreska w środku. W ten sposób dwa pierwsze elementy maski można przedstawić jako: 01100000, 00001010.
Na tej samej zasadzie można określić możliwe reprezentacje cyfr od 0 do 9, przy czym należy uwzględnić, że niektóre z nich mogą mieć więcej niż jedną reprezentację. Na przykładach z obrazka widać na przykład dwie reprezentacje cyfry 9.
Mamy wzorek, mamy hasło, co dalej
Można spróbować następującego podejścia:
- sprawdzić jakie cyfry mogą być reprezentowane na każdej pozycji,
- określić wszystkie możliwe układy możliwych do zaprezentowania cyfr dające znane hasło,
Jak ustalić jakie cyfry mogą być reprezentowane na poszczególnych pozycjach? Odpowiedź na to pytanie jest trywialna. Otóż na określonej pozycji mogą być reprezentowane wszystkie cyfry oprócz tych, które nie mogą być reprezentowane. Wystarczy więc dla danego elementu sprawdzić czy dana cyfra NIE MOŻE na niej wystąpić. A cyfra nie będzie mogła wystąpić, jeśli we wzorku znajduje się kreska w miejscu, gdzie reprezentacja cyfry kreski nie zawiera. Czyli przykładowo wzorek typu 01000000 (kreska u góry) wyklucza wystąpienie na tej pozycji cyfry 1 oraz 4. Rezultatem tego kroku będzie lista, której elementami będą zbiory dopuszczalnych (możliwych do uzyskania) cyfr na danej pozycji wzorku.
Drugi krok, to sprawdzenie na ile sposobów znane (bo podsłuchane) hasło może być reprezentowane przy pomocy znanego wzorku. Tu przydatna jest obserwacja ograniczeń, które ta metoda uwierzytelnienia narzuca. W tym wypadku szczególnie przydatny jest fakt, że liczby nie mogą być reprezentowane obok siebie. Dlaczego? Prosty przykład: 133. A może 188?
Nie wnikając w szczegóły w jaki sposób zostało to zrobione, dla pierwszego wzorku otrzymuje się następujące wartości:
[0, 2, 4, 6, 11, 15] (...) [1, 3, 5, 8, 11, 15] (...) [2, 4, 7, 11, 13, 15] (...) [5, 7, 9, 11, 13, 15]
Tych wartości jest oczywiście więcej, ale na chwilę obecną nie jest to istotne. Istotne jest natomiast to, że ostatnia cyfra reprezentowana jest ZAWSZE (oczywiście zawsze w tym przypadku) na ostatniej pozycji. Ponieważ jest to cyfra 2, wiadomo już NA PEWNO, których kresek maska NA PEWNO nie może mieć wypełnionych na tej pozycji. Wiadomo również, które kreski MUSZĄ być wypełnione w masce. Jest jeszcze kilka kresek, które MOGĄ, ALE NIE MUSZĄ być wypełnione, nie można (bo nie widzę w tej chwili podstaw ku temu) by zakładać, że kreski na masce i we wzorku nie mogą się nakładać na siebie. Oznacza to, że te kreski, które są wypełnione we wzorku MOGĄ być również wypełnione w masce. Może lepiej będzie można sobie to uświadomić na przykładzie poniższego obrazka:

Na czarno oznaczone zostały kreski, które NA PEWNO występują w masce, na czerwono (kontur) te kreski, które NA PEWNO w masce nie mogą wystąpić, kolorem szarym (wypełnienie) oznaczone są natomiast te kreski, które mogą, ale nie muszą być wypełnione.
Dla drugiego wzorku i drugiego hasła otrzymuje się kolejny ciekawy zestaw (tym razem całość):
[0, 2, 4, 7, 9, 11] [0, 2, 4, 7, 9, 12] [0, 2, 4, 7, 9, 13] [0, 2, 4, 7, 9, 14] [0, 2, 4, 7, 9, 15] [0, 2, 5, 7, 9, 11] [0, 2, 5, 7, 9, 12] [0, 2, 5, 7, 9, 13] [0, 2, 5, 7, 9, 14] [0, 2, 5, 7, 9, 15] [0, 3, 5, 7, 9, 11] [0, 3, 5, 7, 9, 12] [0, 3, 5, 7, 9, 13] [0, 3, 5, 7, 9, 14] [0, 3, 5, 7, 9, 15] [1, 3, 5, 7, 9, 11] [1, 3, 5, 7, 9, 12] [1, 3, 5, 7, 9, 13] [1, 3, 5, 7, 9, 14] [1, 3, 5, 7, 9, 15]
Na pierwszy rzut oka widać, że tym razem cyfry 2 2 oraz 5 muszą wystąpić na pozycjach 5, 7 i 9 (indeksowanie od 0).
UWAGA: tu przyznaję się do błędu, na w rzeczywistości pewne są pozycje 7 i 9, pierwsza cyfra 2 mogła wystąpić na pozycjach 4 lub 5, ale na początku to przeoczyłem i teraz już nie będę tego poprawiał, potraktujmy to jako podążenie tropem jednej możliwości.
To pozwala z kolei wprowadzić następujące aktualizacje do możliwej maski:

W takim razie uzupełnijmy pierwszy otrzymany wzorek o pewne informacje uzyskane w tej chwili, czyli o te kreski, które NA PEWNO zawiera maska będąca w posiadaniu klienta, w rezultacie otrzymuje się mniej więcej coś takiego (na granatowo zaznaczone są pewne kreski z maski):

W ten sposób uzyskana została trzeci wzorek, dla którego hasło jest znane, bo jest takie samo, jak dla pierwszego, czyli 689252. Powtarzając dla tego wzorku operację wykonaną wcześniej otrzymuje się następujące możliwości:
[0, 2, 4, 6, 11, 15] [0, 2, 4, 6, 13, 15] [0, 2, 4, 11, 13, 15] [0, 2, 7, 11, 13, 15] [0, 2, 9, 11, 13, 15] [0, 3, 7, 11, 13, 15] [0, 3, 9, 11, 13, 15] [0, 4, 7, 11, 13, 15] [0, 4, 9, 11, 13, 15] [0, 5, 7, 11, 13, 15] [0, 5, 9, 11, 13, 15] [0, 6, 9, 11, 13, 15] [0, 7, 9, 11, 13, 15] [1, 3, 7, 11, 13, 15] [1, 3, 9, 11, 13, 15] [1, 4, 7, 11, 13, 15] [1, 4, 9, 11, 13, 15] [1, 5, 7, 11, 13, 15] [1, 5, 9, 11, 13, 15] [1, 6, 9, 11, 13, 15] [1, 7, 9, 11, 13, 15] [2, 4, 7, 11, 13, 15] [2, 4, 9, 11, 13, 15] [2, 5, 7, 11, 13, 15] [2, 5, 9, 11, 13, 15] [2, 6, 9, 11, 13, 15] [2, 7, 9, 11, 13, 15] [5, 7, 9, 11, 13, 15]
Wciąż jedynym "ustabilizowanym" znakiem jest 2 na pozycji 15, więc na razie nic więcej nie udało się uzyskać. Z drugiej jednak strony na pozycjach 5, 7 i 9 mamy informację nie tylko na temat tego, czy jakaś kreska jest, ale również na temat, że jakiejś kreski NA PEWNO nie ma. Można sprawdzić, czy dzięki temu pewnych możliwości z powyższej listy nie uda się wykluczyć... Dla przypomnienia, hasło, którego szukamy to 689252.
Na początek zajmijmy się pozycją 5. Według powyższej rozpiski na pozycji tej mogą wystąpić następujące cyfry 6 lub 8. Na razie nie widać żadnej przesłanki, która którąkolwiek z tych cyfr mogłaby wykluczyć. Na pozycji 7 występują z kolei cyfry 8 oraz 9. Tu również cyfr tych wykluczyć nie można. Brak postępu. Na pozycji 9 występuje wyłącznie cyfra 9 i tu również nie można w żaden sposób posunąć się do przodu. Ślepy trop, przynajmniej w tym przypadku.
Poza pozycjami 5,7,9 oraz 15 pewne informacje mamy również na temat pozycji 4, 6, 8, 10 i 14 (bo poszczególne pozycje "łączą się" ściankami, czyli prawa ścianka pozycji n jest jednocześnie lewą ścianką na pozycji n+1).
Na pozycji 4 może występować 8 lub 9 i niestety, żadnej z nich nie można wykluczyć. Na pozycji 6 wystąpić może 8 lub 2, pod warunkiem, że w masce znajdą się wszystkie trzy poziome kreski i, jak się okazuje, możemy taką ewentualność wykluczyć. Dlaczego? W drugim wzorku znane liczby wystąpiły na pozycji 5 i 7, jeśli maska zawierałaby te trzy pionowe kreski, to na pozycji 6 powstałaby cyfra 5, a założenia cyfry nie mogą występować obok siebie. W związku z tym zbiór możliwych rozwiązań redukujemy o przypadki, gdy na pozycji 6 występuje jakaś cyfra. Zbiór zawęża się do następującej postaci:
[0, 2, 4, 11, 13, 15] [0, 2, 7, 11, 13, 15] [0, 2, 9, 11, 13, 15] [0, 3, 7, 11, 13, 15] [0, 3, 9, 11, 13, 15] [0, 4, 7, 11, 13, 15] [0, 4, 9, 11, 13, 15] [0, 5, 7, 11, 13, 15] [0, 5, 9, 11, 13, 15] [0, 7, 9, 11, 13, 15] [1, 3, 7, 11, 13, 15] [1, 3, 9, 11, 13, 15] [1, 4, 7, 11, 13, 15] [1, 4, 9, 11, 13, 15] [1, 5, 7, 11, 13, 15] [1, 5, 9, 11, 13, 15] [1, 7, 9, 11, 13, 15] [2, 4, 7, 11, 13, 15] [2, 4, 9, 11, 13, 15] [2, 5, 7, 11, 13, 15] [2, 5, 9, 11, 13, 15] [2, 7, 9, 11, 13, 15] [5, 7, 9, 11, 13, 15]
Tak, w ten prosty (i mam nadzieję, że poprawny) sposób uzyskana została pewność, że na pozycji 11 występuje cyfra 2 a na pozycji 13 cyfra 5. Pozwala to dokonać aktualizacji pewnych informacji o masce do następującej postaci.

Teraz na odmianę uzupełnię drugi wzorek o pewne informacje o masce, co doprowadza obrazek do następującej postaci:

Przypominam, że dla tego wzorku hasło to 092259. Od razu widać, że ostatnia cyfra 9 powinna wystąpić na pozycji 13, co z kolei pozwala zredukować wcześniej uzyskany zbiór rozwiązań dla tego wzorku do postaci:
[0, 2, 5, 7, 9, 13] [0, 3, 5, 7, 9, 13] [1, 3, 5, 7, 9, 13]
Oznacza to, że cyfra 0 może wystąpić na pozycji 0 lub 1, cyfra 9 na pozycji 2 lub 3. Czy ta informacja do czegoś się przydaje? Można spróbować stworzyć maski dla wszystkich trzech powyższych przypadków i nałożyć je na pierwszy wzorek, ten, dla którego hasło to 689252. Na początek jednak przypadek, gdy 0 występuje na pozycji 0 a 9 na pozycji 2.

Przypominam, że "pewne" pozycje to 11, 13 i 15. Do ustalenia pozostaje umieszczenie cyfr 6, 8 i 9, dla których jest kilka możliwości. Patrząc jednak na ten (niezbyt czytelny, przyznaję) rysunek, można zakładać, że cyfra 9 wystąpi na pozycji 9. Dlaczego? Dlatego, że ona już tam NA PEWNO jest, kwestią dyskusyjną jest tylko to, czy składa się z 5 z 6 kresek. Skoro na pozycji 9 znajduje się 9, to na pozycji 7 MUSI znajdować się 8. Musi, bo tam już jest 9, a skoro hasło zawiera tylko jedną 9 (a ta, jest na pozycji 9), to na pozycji 7 musi być 8 właśnie. Na pozycji 6 z kolei jest już NA PEWNO 6 (która mogłaby być jeszcze 8, ale znane hasło na to nie pozwala). Tym sprytnym sposobem udaje się wykonać kolejne uzupełnienia informacji o masce, co doprowadza ją do następującej postaci:

Przy okazji wprowadzam drobną zmianę w sposobie prezentacji przypuszczalnej maski, teraz czarny kontur oznacza kreski, które na pewno są w masce, szary te, które mogą być, a kresek, których na pewno nie ma, po prostu nie ma.
Teraz jeszcze raz nałożenie na siebie pierwszego wzorku oraz aktualnej (przypuszczalnej) postaci maski:

Można usunąć jeszcze kilka kresek, których na pewno maska zawierać nie może, bo gdyby je zawierała, pojawiłyby się niedopuszczalne cyfry, nałożenie obrazków po poprawce:

Analogiczną operację teraz można wykonać w połączeniu z drugim wzorkiem, najpierw nałożenie na siebie aktualnej wersji maski i znanego wzorku, jeszcze raz przypominam hasło 092259:

Dwójki pojawiające się na 11 i 15 pozycji nie są istotne, ciemny szary kontur oznacza kreski, które mogą, ale nie muszą wystąpić w masce. Z tego nałożenia już widać, że na pewno nie występują wszystkie (bo pojawiłyby się niechciane 2), ale nie wiadomo jeszcze, które z tych kresek można usunąć.
Brakuje jeszcze cyfr 0 oraz 9, które muszą wystąpić na pozycjach 0 oraz 2. 9 nie może wystąpić na pozycji 3 bo brakuje jednej pionowej kreski, tak więc musi wystąpić na pozycji 2. Skoro tak, to 0 nie może wystąpić na pozycji 0, bo cyfry nie mogą się stykać. W efekcie znowu można zaktualizować przypuszczalną maskę:

I można tak dalej, ale powoli zaczyna robić się to nudne... Jeszcze nałożenie aktualnego wyobrażenia maski i rzeczywistej maski wykorzystanej w przykładach:

Jakość powyższego rysunku nie jest może najlepsza, ale mniej więcej widać o co chodzi. Czerwone kreski (wypełnienie) to miejsca, które są wypełnione na masce (tajnej masce użytkownika). Jeśli są w czarnej obwódce, oznacza to, że już na podstawie moich wcześniejszych rozważań uznałem, że taka kreska w masce NA PEWNO istnieje. Obwódka ciemnoszara oznacza, że istnienie kreski w tym miejscu jest możliwe. Jasnoszara obwódka natomiast oznacza przypadek, w którym na podstawie posiadanych informacji nie można (być może można, ale ja tego nie zrobiłem) wyciągnąć wniosków odnośnie tego, czy w masce kreska istnieje, czy też nie. Tam, gdzie nie ma obwódki, uznałem, że kreski na pewno nie ma.
I bardzo krótkie podsumowanie
Jak na niewielką ilość danych wejściowych (tylko dwie pary wzorek i hasło) i użycie bardzo zaawansowanych narzędzi hakerskich (głównie Inkscape, oraz kilka pomocniczych skryptów w Pythonie) to PassWindow bardzo słabo się spisuje...
Mogłem się gdzieś pomylić, gdzieś pójść na skróty, ale warto pamiętać: Attacks always get better; they never get worse. I tym optymistycznym akcentem kończę swoje zainteresowanie PassWindow. Kreska na drogę...
Postanowiłem jednak dopisać drobne uzupełnienie odnośnie poprzedniego wpisu dotyczącego łamania PassWindow.Po pierwsze z dużą dozą podejrzliwości podchodzę do rozwiązań, które mają być bezpieczne, nawet w przypadku, gdy system klienta został skompromitowa
Przesłany: Sep 04, 17:00