W trzeciej części artykułu skupiliśmy się na niskopoziomowych zabawach z pamięcią i analizie zawartości Flash.
Dane w poprzednich częściach artykułu zbierane były wraz z ich kontekstem. Mogliśmy wyciągnąć interesujące nas dane z konkretnych miejsc w systemie itp. lub też obserwować jakie dane czy zasoby system używa podczas rozmaitych operacji. Podejście takie ma niestety swoje ograniczenia – część danych jest zabezpieczona przed dostępem do nich z poziomu system, więc nie udało nam się do nich dostać z pomocą niewielkiej ilości narzędzi z jakich mogliśmy skorzystać np. w systemie.
Co możemy zrobić więcej? Albo też: co moglibyśmy zrobić, gdyby nie udało nam się znaleźć portu UART w urządzeniu lub te z domyślne dane uwierzytelniania by nie działały? Dokładnie odpowiedź na to pytanie będzie tematem tej części cyklu. Przyjrzymy się jak uzyskać dane bezpośrednio z interfejsu SPI pamięci Flash. Z jednej strony nie poznamy wtedy tego w jakim kontekście są tam zapisane, ale z drugiej strony jest to metoda, która zawsze działa. Chodzi tutaj o fizyczne zgranie całej zawartości pamięci Flash w urządzeniu.
Nasz plan na ten artykuł jest bardzo prosty – zgrywamy zawartość pamięci Flash i ją dekompresujemy, co pozwala nam na analizę jej zawartości, Zewnętrzny układ Flash do którego posiadamy kartę katalogową jest stanowczo naszym sprzymierzeńcem w tym zakresie.
Zgrywanie zawartości pamięci na dysk
Tak jak pisaliśmy w części trzeciej artykułu znamy rozkład wyprowadzeń układu scalonego, będącego pamięcią Flash w tym urządzeniu. Dzięki temu nie musimy zgadywać który z pinów układu za co odpowiada:
Znamy też zestaw instrukcji tego układu scalonego, więc możemy się z nim skomunikować wykorzystując do tego dowolne urządzenie, które jest w stanie komunikować się z wykorzystaniem interfejsy SPI.
Z wcześniejszych doświadczeń wiemy, że po włączeniu zasilania routera Ralink rozpocznie komunikację z pamięcią Flash, co zasadniczo może nam uniemożliwić komunikację z tym układem z wykorzystaniem zewnętrznego interfejsu. Musimy niedopuścić do tego, aby CPU urządzenia wystartował – jak to zrobić? To zależy od detali konstrukcji układu.
Czy musimy odlutować układ Flash? (trochę teorii)
Idealnie by było, gdybyśmy wylutowali układ pamięci z routera i podłączyli go do programatora lub interfejsu w izolowanych od reszty urządzenia warunkach. Daje nam to pełną kontrolę nad układem i usuwa wszelkie źródła zakłóceń podczas transmisji. Niestety takie rozwiązania wymaga dodatkowego wyposażenia, umiejętności i czasu. Spróbujmy czy obejdziemy się bez tego.
Inną opcją jest zapewnienie warunków, w których Ralink nie zostanie aktywowany i pozostanie w trybie standby. Mikrokontrolery często wyposażone są w pin resetu, które wymuszają przejście w tryb wyłączenia gdy na nim znajdzie się stan niski. Często wykorzystuje się go do resetowania układu bez konieczności odłączania zasilania od systemu. Niestety – nie mamy dostępu do kompletnej karty katalogowej Ralinka, więc nie wiemy gdzie znajduje się reset, a poziom skomplikowania układu i systemów wokół niego sprawia, że identyfikacja tego konkretnego pinu nie jest możliwa (a przynajmniej prosta). Szukamy dalej…
A co by się stało, gdyby zasilić tylko jeden układ? Czy to w ogóle możliwe? Z jednej strony, istnieje obawa, że jeśli podłączymy do układu zasilanie tylko do jednego układu – w sposób stanowczo nie przewidziany w projekcie, to możemy uszkodzić nasz router. Moglibyśmy wcześniej zanalizować układ zasilania, aby sprawdzić czy takie zachowanie nie spowoduje jego uszkodzenia, ale to sporo pracy. Jako że urządzenie jest tanie i łatwo dostępne możemy podejść trochę bardziej beztrosko do naszych działań i po prostu sprawdzić co się stanie. Wiemy jakie zasilanie potrzebne jest do działania pamięci – co najmniej 3 V – więc podłączmy takie zasilanie do układu i sprawdźmy co się stanie. Istnieje szansa że nic się nie stanie, albo że w ten sposób zasilony zostanie także główny układ systemu i router normalnie wystartuje… jednakże warto spróbować.
Zasilanie do pamięci podłączamy obserwując wizualnie płytkę jak i analizując dane wysyłane przez UART przez Ralinka. Na płytce zapala się kilka LEDów… jednakże poza tym nic się nie dzieje – na porcie UART nie wykrywamy żadnych danych, co oznacza, że raczej układ ten nie działa. Oczywiście, cały czas musimy pamiętać, że elektrycznie wpięty jest on w interfejs SPI, co oznacza że może on w jakiś sposób wpływać na transmisję. Pamiętajmy o tym zwłaszcza gdy w dalszym oku analizy zawartości pamięci zaczniemy obserwować coś niepokojącego. Jeśli tak będzie, to musimy odlutować układ Flash (lub same wyprowadzenia interfejsu SPI) albo w inny sposób odizolować je od pozostałej części urządzenia.
Wiemy, że diody LED i inne element statyczne urządzenia nie będą komunikowały się z pamięcią Flash, więc ich działanie w żaden sposób nas nie martwi (tak długo jak dostarczamy dostatecznie dużego prądu do układu). Najwygodniej jest wykorzystać zasilacz laboratoryjny, który zaoferuje pod dostatkiem prądu dla wszystkich komponentów na PCB. Jeśli nie mamy takiego zasilacza wykorzystać możemy inne źródła zasilania pod warunkiem, że dadzą one dostatecznie duży prąd, który starczy i dla układu pamięci i dla innych elementów na PCB.
Podłączanie SPI do zewnętrznego interfejsu
W momencie gdy wiemy już, że nie musimy wylutowywać nic z układu możemy podłączyć do systemu dowolne urządzenie, która ’gada’ po SPI. Wtedy też możemy rozpocząć zgrywanie zawartości pamięci Flash. Wykorzystać możemy dowolny mikrokontroler lub dedykowany mostek SPI-USB albo dowolny inny układ. W opisywanym projekcie wykorzystana zostanie przejściówka oparta o FT232H, który wspiera m.in. SPI jak i inne niskopoziomowe protokoły komunikacyjne.
Znamy rozkład wyprowadzeń tak naszej pamięci Flash jak i wykorzystanego mostka USB-SPI, więc bez problemu możemy podłączyć system w całość:
Kiedy sprzętowa część jest już gotowa możemy zabrać się za odczyt danych
Zrzut danych z pamięci
Potrzebne nam będzie jakieś oprogramowanie dedykowane do zgrywania danych po stronie komputera, które dogada się z mostkiem USB-SPI i zapisze odczytane dane jako plik binarny. Napisanie samodzielnie takiego oprogramowania nie powinno być nawet problematyczne, jednakże wygodniej skorzystać będzie z wsparcia dostępnego w sieci i wykorzystać dowolny program do komunikacji z pamięciami Flash, na przykład flashrom.
Program flashrom jest dosyć stary i posiada szereg błędów, aczkolwiek posiada wbudowane wsparcie tak dla układu FT232H jako mastera sieci jak i dla pamięci FL064PIF jako slave. Autor artykułu miał pewne problemy z uruchomieniem tego programu na OS X czy na Ubuntu VM, jednakże na Raspberry Pi (pod Raspbianem) program uruchomił się bez problemów:
Sukces! Udało nam się zgrać zawartość pamięci Flash routera, więc teraz możemy rozpocząć przygotowywanie danych do analizy.
Podział pliku binarnego
Mając przed sobą plik binarny mamy spore wyzwanie, szczególnie jeśli niewiele o nim wiemy. W naszym przypadku nie jest tak źle – nasze oprogramowanie zidentyfikowało pewne informacje na temat tego pliku, jednakże głównie dlatego, że ma on nagłówek we wspieranym formacie. W sytuacji w której nie wiemy o zrzuconym pliku nic, najpierw musimy zastosować inne oprogramowanie, na przykład binwalk, który pomoże nam odnaleźć w pliku pewne informacje na których nam zależy.
Binwalk to bardzo przydatne narządzie stworzone przez hackerów z grupy /dev/ttyS0; z pewnością trzeba poznać ich i ich osiągnięcia, jeśli jest się zainteresowanym tego rodzaju niskopoziomową inżynierią wsteczną i hackerstwem na poziomie sprzętowym.
Jednakże w naszym przypadku na początku już wiemy coś o pliku. Dodatkowo mamy pewne informacje o działaniu systemu, które zebraliśmy wcześnie, między innymi mapę pamięci, jaką zebraliśmy w części drugiej. Ta mapa pamięci, jaką wyciągnęliśmy z informacji z komendy debug, zgadza się z tym co zidentyfikował w pliku binwalk. Pozwala nam to podzielić plik binarny na mniejsze kawałki, w celu łatwiejszej ich analizy:
Mając plik binarny i poszczególne zakresy adresów możemy bez problemu podzielić go na cztery segmenty. Do komendy dd podajemy poszczególne parametry: wielkość bloków (bs w bajtach), offset skip w blokach) i rozmiar (count, także w blokach). Wszystkie wartości podawane są jako dziesiętne, możemy do ich przeliczenia z hexa wykorzystać kalkulator albo też skonwertować je w linii komend wykorzystując konstrukcję $(()):
[source=bash]$ dd if=spidump.bin of=bootloader.bin bs=1 count=$((0x020000))
131072+0 records in
131072+0 records out
131072 bytes transferred in 0.215768 secs (607467 bytes/sec)
$ dd if=spidump.bin of=mainkernel.bin bs=1 count=$((0x13D000-0x020000)) skip=$((0x020000))
1167360+0 records in
1167360+0 records out
1167360 bytes transferred in 1.900925 secs (614101 bytes/sec)
$ dd if=spidump.bin of=mainrootfs.bin bs=1 count=$((0x660000-0x13D000)) skip=$((0x13D000))
5386240+0 records in
5386240+0 records out
5386240 bytes transferred in 9.163635 secs (587784 bytes/sec)
$ dd if=spidump.bin of=protect.bin bs=1 count=$((0x800000-0x660000)) skip=$((0x660000))
1703936+0 records in
1703936+0 records out
1703936 bytes transferred in 2.743594 secs (621060 bytes/sec)[/source]
W ten sposób wygenerowaliśmy cztery pliki binarne:
* bootloader.bin: U-boot czyli bootloader systemu. Nie jest on skompresowany, ponieważ na tym etapie ładowania Ralink nie wie jak dekompresować dane, więc muszą one być zapisywane i odczytywane bezpośrednio.
* mainkernel.bin: Jądro Linuksa. Podstawowy element firmware, odpowiedzialny za kontrolę sprzętu w systemie. Ten fragment skompresowany jest algorytmem lzma.
* mainrootfs.bin: System plików, który zawiera wiele ważnych plików binarnych i konfiguracyjnych, W pamięci zapisany jest jako system squashfs skompresowany z wykorzystaniem algorytmu lzma.
* protect.bin: Pozostałe dane o których częściowo pisaliśmy w części trzeciej artykułu. Nie są one w żaden sposób skompresowane.
Ekstrakcja danych
Po rozdzieleniu całego zrzutu pamięci Flash na cztery podstawowe segmenty możemy każdy z nich z osobna zanalizować.
Bootloader
Binwalk podczas analizy pliku odnalazł nagłówek uImage i automatycznie go zdekodował. U-Boot wykorzystuje te nagłówki, aby identyfikować poszczególne rejony pamięci w systemie. Są to te same dane jakie binwalk wyświetlił nam przed podziałem pliku na fragmenty, gdyż nagłówek ten znajduje się na początku zrzutu.
Jako że praca bootloadera nie interesuje nas za bardzo to nie marnujmy więcej czasu na analizę tego pliku i przejdźmy dalej.
Jądro systemu – Kernel
Kompresja jest czymś z czym musimy sobie poradzić zanim rozpoczniemy dalszą pracę z plikiem i analizę jego zawartości. Binwalk potwierdził, że w tym przypadku mamy do czynienia z algorytmem lzma, tak jak odkryliśmy już w części drugiej artykułu. Algorytm ten to bardzo popularny sposób kompresowania danych w systemach wbudowanych. Jeśli przeskanujemy na szybko ten plik:
[source=bash]strings mainkernel.bin | less [/source]
To możemy potwierdzić że w binarce tej nie znajduje się zawartość którą odczytać można ludzkim okiem. Rozpakujmy cały plik. W tym celu wykorzystać możemy dowolny program, jaki posiada wbudowany algorytm lzma, może to być 7zip czy zip. Jednakże okazało się to być problematyczne w naszym przypadku – żaden z wymienionych programów nie był w stanie poprawnie zidentyfikować naszego pliku:
[source=bash]$ xz --decompress mainkernel.bin
xz: mainkernel.bin: File format not recognized[/source]
Najpewniej nagłówek uImage uniemożliwia programowi zrozumienie pliku, więc musimy go wyciąć. Wiemy że zajmuje od 64 bajty i dane lzma zaczynają się w adresie 0x40. Zatem skopiujmy dalej wszystko poza pierwszymi 64 bajtami danych:
I gdy teraz spróbujemy dekompresować dane:
[source=bash]$ xz --decompress mainkernel_noheader.lzma
xz: mainkernel_noheader.lzma: Compressed data is corrupt[/source]
Tym razem nasz program rozpoznał dane jako lzma, ale nie jest w stanie ich dekodować. Czemu? Najpewniej winne jest to, że chcemy dekodować cały obszar pamięci Flash, gdzie znajduje się kernel, ale mało prawdopodobne jest, że skompresowany obraz jądra systemu zajmuje dokładnie 100% tego obszaru. Usuńmy z końca nieużywany fragment pamięci i spróbujmy z tak zmodyfikowanym plikiem binarnym jeszcze raz podejść do algorytmu dekompresji:
Wydaje się, że xz rozpakował dane poprawne. Widać to chociażby dzięki temu, że w zdekompresowanych danych wiać komendy zapisane jako stringi ASCII. A skoro już tutaj jesteśmy spójrzmy w te dane, czy nie znajdziemy tam nic szczególnie interesującego.
Wpisy nazwane Wi-Fi Easy oraz Secure Key Derivation wyglądają bardzo obiecująco, ale są to jedynie wpisane ‘na sztywbi’ dane wynikające z specyfikacji Wi-Fi Protected Setup. Daleko od tego do jakiegokolwiek algorytmu generacji hasła, którym tak bardzo jesteśmy zainteresowani.
Na tym etapie wiemy już, że jesteśmy w stanie poprawnie dekompresować pliki, tak więc możemy kontynuować analizę zebranych danych ze zrzutu pamięci Flash.
System plików
Segment pamięci zawierający główny system plików nie ma nagłówka uImage, ponieważ jest on zależny od jądra systemu, a nie od bootloadera.
System plików SquashFS jest bardzo popularny w urządzeniach wbudowanych. Istnieje wiele różnych wersji i wariacji tego systemu plików, a dodatkowo część producentów, którzy z niego korzystają wprowadza własne zmiany i sygnatury, przez ci jeszcze ciężej jest analizować tego rodzaju dane. Okazać się zatem może, że aby z powodzeniem obejrzeć pliki będziemy musieli sprawdzić jaka wersja unsquashfs działa w naszym przypadku i/lub zmodyfikować sygnatury w pliku. W naszych danych sygnatura ta wygląda następująco:
Jako że jest to bardzo popularny system plików, a znajdowanie odpowiedniej konfiguracji wersji i sygnatur jest dosyć męczącym zajęciem, to w sieci dostępnych jest szereg narzędzi do tego, między innymi skrypt który działać ma w OS X (jest to fork projektu Firmware Modification Kit), który zawiera w sobie kilka wersji unsquashfs wywoływane pojedynczym skryptem unsquashfs_all.sh. Spróbujmy czy w naszym wypadku zadziała poprawnie:
Czyż to nie było proste? Albo po prostu mieliśmy trochę szczęścia – tak wersja jak i sygnatura systemu plików z naszego routera są wspierane przez algorytmy dekompresji w wykorzystanym przez nas narzędziu. Teraz mamy dostęp do wszystkich plików binarnych i konfiguracyjnych jakie obecne były w routerze, a także dowiązań symbolicznych itp. Wszystko ładnie zaprezentowane i uporządkowane:
W kompletnym drzewie katalogów widzimy, że mamy wszystkie pliki systemu (oprócz oczywiście plików generowanych podczas jego działania, jak te zgromadzone w folderze /var/). Wykorzystując zebrane wcześniej informacje możemy rozpocząć poszukiwania ciekawych plików binarnych w systemie:
Jeśli zainteresowani jesteśmy poszukiwaniem wszelkich dziur w systemach sieciowych i ich zabezpieczeniach, to posiadanie wszystkich biharek i plików konfiguracyjnych z danego urządzenia może być bardzo pomocne w tego rodzaju działaniach.
Pozostałe - dane chronione
Tak jak objaśnialiśmy w części trzeciej artykułu, część danych pozostaje w pamięci, bo musi pozostać dostępny po kolejnych resetach systemu. Dane te nie są skompresowane, ponieważ są one edytowane z poziomu systemu. Jak pamiętamy są to głównie dane konfiguracyjne itp. Aby bliżej przyjrzeć się zawartości tego rejonu pamięci skorzystajmy z komendy Springs:
Zawartość tego segmentu wydaje się składać z pliku curcfg,xml, logów i kilku luźnych kawałków stringów. Te dane już analizowaliśmy w części trzeciej, więc nie ma tutaj nic interesującego i wartego dalszego omawiania.
Dalsze kroki
Na tym etapie wszystkie dane jakie były do zebrania w routerze są już u nas. Teraz zastanówmy się jak je wykorzystać. Jednym z pomysłów mogłoby być na przykład dostanie się do routera poprzez port UART, gdyby okazało się, że dane do logowania nie są łatwe do zgadnięcia.
Jeśli nie jesteśmy w stanie zgrać zrzutu pamięci Flash z urządzenia, a bardzo chcemy pobawić się w tego rodzaju inżynierię wsteczną możemy zainteresować się aktualizacjami firmware, jakie czasami dostarcza producent. W tych plikach często znajdują się kompletne bloki pamięci, które ładowane są do pamięci Flash przez system operacyjny routera. Mogą w nich znajdować się jakieś interesujące dla nas dane.
W kolejnej części artykułu skupimy się jeszcze nad innymi plikami binarnymi, jakie wydobyć można z analizowanego routera i spróbujemy zobaczyć akie ciekawe i potencjalnie użyteczne informacje one zawierają.
Źródło: http://jcjc-dev.com/2016/06/08/reversing-huawei-4-dumping-flash/
Dane w poprzednich częściach artykułu zbierane były wraz z ich kontekstem. Mogliśmy wyciągnąć interesujące nas dane z konkretnych miejsc w systemie itp. lub też obserwować jakie dane czy zasoby system używa podczas rozmaitych operacji. Podejście takie ma niestety swoje ograniczenia – część danych jest zabezpieczona przed dostępem do nich z poziomu system, więc nie udało nam się do nich dostać z pomocą niewielkiej ilości narzędzi z jakich mogliśmy skorzystać np. w systemie.
Co możemy zrobić więcej? Albo też: co moglibyśmy zrobić, gdyby nie udało nam się znaleźć portu UART w urządzeniu lub te z domyślne dane uwierzytelniania by nie działały? Dokładnie odpowiedź na to pytanie będzie tematem tej części cyklu. Przyjrzymy się jak uzyskać dane bezpośrednio z interfejsu SPI pamięci Flash. Z jednej strony nie poznamy wtedy tego w jakim kontekście są tam zapisane, ale z drugiej strony jest to metoda, która zawsze działa. Chodzi tutaj o fizyczne zgranie całej zawartości pamięci Flash w urządzeniu.
Nasz plan na ten artykuł jest bardzo prosty – zgrywamy zawartość pamięci Flash i ją dekompresujemy, co pozwala nam na analizę jej zawartości, Zewnętrzny układ Flash do którego posiadamy kartę katalogową jest stanowczo naszym sprzymierzeńcem w tym zakresie.
Zgrywanie zawartości pamięci na dysk
Tak jak pisaliśmy w części trzeciej artykułu znamy rozkład wyprowadzeń układu scalonego, będącego pamięcią Flash w tym urządzeniu. Dzięki temu nie musimy zgadywać który z pinów układu za co odpowiada:
Znamy też zestaw instrukcji tego układu scalonego, więc możemy się z nim skomunikować wykorzystując do tego dowolne urządzenie, które jest w stanie komunikować się z wykorzystaniem interfejsy SPI.
Z wcześniejszych doświadczeń wiemy, że po włączeniu zasilania routera Ralink rozpocznie komunikację z pamięcią Flash, co zasadniczo może nam uniemożliwić komunikację z tym układem z wykorzystaniem zewnętrznego interfejsu. Musimy niedopuścić do tego, aby CPU urządzenia wystartował – jak to zrobić? To zależy od detali konstrukcji układu.
Czy musimy odlutować układ Flash? (trochę teorii)
Idealnie by było, gdybyśmy wylutowali układ pamięci z routera i podłączyli go do programatora lub interfejsu w izolowanych od reszty urządzenia warunkach. Daje nam to pełną kontrolę nad układem i usuwa wszelkie źródła zakłóceń podczas transmisji. Niestety takie rozwiązania wymaga dodatkowego wyposażenia, umiejętności i czasu. Spróbujmy czy obejdziemy się bez tego.
Inną opcją jest zapewnienie warunków, w których Ralink nie zostanie aktywowany i pozostanie w trybie standby. Mikrokontrolery często wyposażone są w pin resetu, które wymuszają przejście w tryb wyłączenia gdy na nim znajdzie się stan niski. Często wykorzystuje się go do resetowania układu bez konieczności odłączania zasilania od systemu. Niestety – nie mamy dostępu do kompletnej karty katalogowej Ralinka, więc nie wiemy gdzie znajduje się reset, a poziom skomplikowania układu i systemów wokół niego sprawia, że identyfikacja tego konkretnego pinu nie jest możliwa (a przynajmniej prosta). Szukamy dalej…
A co by się stało, gdyby zasilić tylko jeden układ? Czy to w ogóle możliwe? Z jednej strony, istnieje obawa, że jeśli podłączymy do układu zasilanie tylko do jednego układu – w sposób stanowczo nie przewidziany w projekcie, to możemy uszkodzić nasz router. Moglibyśmy wcześniej zanalizować układ zasilania, aby sprawdzić czy takie zachowanie nie spowoduje jego uszkodzenia, ale to sporo pracy. Jako że urządzenie jest tanie i łatwo dostępne możemy podejść trochę bardziej beztrosko do naszych działań i po prostu sprawdzić co się stanie. Wiemy jakie zasilanie potrzebne jest do działania pamięci – co najmniej 3 V – więc podłączmy takie zasilanie do układu i sprawdźmy co się stanie. Istnieje szansa że nic się nie stanie, albo że w ten sposób zasilony zostanie także główny układ systemu i router normalnie wystartuje… jednakże warto spróbować.
Zasilanie do pamięci podłączamy obserwując wizualnie płytkę jak i analizując dane wysyłane przez UART przez Ralinka. Na płytce zapala się kilka LEDów… jednakże poza tym nic się nie dzieje – na porcie UART nie wykrywamy żadnych danych, co oznacza, że raczej układ ten nie działa. Oczywiście, cały czas musimy pamiętać, że elektrycznie wpięty jest on w interfejs SPI, co oznacza że może on w jakiś sposób wpływać na transmisję. Pamiętajmy o tym zwłaszcza gdy w dalszym oku analizy zawartości pamięci zaczniemy obserwować coś niepokojącego. Jeśli tak będzie, to musimy odlutować układ Flash (lub same wyprowadzenia interfejsu SPI) albo w inny sposób odizolować je od pozostałej części urządzenia.
Wiemy, że diody LED i inne element statyczne urządzenia nie będą komunikowały się z pamięcią Flash, więc ich działanie w żaden sposób nas nie martwi (tak długo jak dostarczamy dostatecznie dużego prądu do układu). Najwygodniej jest wykorzystać zasilacz laboratoryjny, który zaoferuje pod dostatkiem prądu dla wszystkich komponentów na PCB. Jeśli nie mamy takiego zasilacza wykorzystać możemy inne źródła zasilania pod warunkiem, że dadzą one dostatecznie duży prąd, który starczy i dla układu pamięci i dla innych elementów na PCB.
Podłączanie SPI do zewnętrznego interfejsu
W momencie gdy wiemy już, że nie musimy wylutowywać nic z układu możemy podłączyć do systemu dowolne urządzenie, która ’gada’ po SPI. Wtedy też możemy rozpocząć zgrywanie zawartości pamięci Flash. Wykorzystać możemy dowolny mikrokontroler lub dedykowany mostek SPI-USB albo dowolny inny układ. W opisywanym projekcie wykorzystana zostanie przejściówka oparta o FT232H, który wspiera m.in. SPI jak i inne niskopoziomowe protokoły komunikacyjne.
Znamy rozkład wyprowadzeń tak naszej pamięci Flash jak i wykorzystanego mostka USB-SPI, więc bez problemu możemy podłączyć system w całość:
Kiedy sprzętowa część jest już gotowa możemy zabrać się za odczyt danych
Zrzut danych z pamięci
Potrzebne nam będzie jakieś oprogramowanie dedykowane do zgrywania danych po stronie komputera, które dogada się z mostkiem USB-SPI i zapisze odczytane dane jako plik binarny. Napisanie samodzielnie takiego oprogramowania nie powinno być nawet problematyczne, jednakże wygodniej skorzystać będzie z wsparcia dostępnego w sieci i wykorzystać dowolny program do komunikacji z pamięciami Flash, na przykład flashrom.
Program flashrom jest dosyć stary i posiada szereg błędów, aczkolwiek posiada wbudowane wsparcie tak dla układu FT232H jako mastera sieci jak i dla pamięci FL064PIF jako slave. Autor artykułu miał pewne problemy z uruchomieniem tego programu na OS X czy na Ubuntu VM, jednakże na Raspberry Pi (pod Raspbianem) program uruchomił się bez problemów:
Sukces! Udało nam się zgrać zawartość pamięci Flash routera, więc teraz możemy rozpocząć przygotowywanie danych do analizy.
Podział pliku binarnego
Mając przed sobą plik binarny mamy spore wyzwanie, szczególnie jeśli niewiele o nim wiemy. W naszym przypadku nie jest tak źle – nasze oprogramowanie zidentyfikowało pewne informacje na temat tego pliku, jednakże głównie dlatego, że ma on nagłówek we wspieranym formacie. W sytuacji w której nie wiemy o zrzuconym pliku nic, najpierw musimy zastosować inne oprogramowanie, na przykład binwalk, który pomoże nam odnaleźć w pliku pewne informacje na których nam zależy.
Binwalk to bardzo przydatne narządzie stworzone przez hackerów z grupy /dev/ttyS0; z pewnością trzeba poznać ich i ich osiągnięcia, jeśli jest się zainteresowanym tego rodzaju niskopoziomową inżynierią wsteczną i hackerstwem na poziomie sprzętowym.
Jednakże w naszym przypadku na początku już wiemy coś o pliku. Dodatkowo mamy pewne informacje o działaniu systemu, które zebraliśmy wcześnie, między innymi mapę pamięci, jaką zebraliśmy w części drugiej. Ta mapa pamięci, jaką wyciągnęliśmy z informacji z komendy debug, zgadza się z tym co zidentyfikował w pliku binwalk. Pozwala nam to podzielić plik binarny na mniejsze kawałki, w celu łatwiejszej ich analizy:
Mając plik binarny i poszczególne zakresy adresów możemy bez problemu podzielić go na cztery segmenty. Do komendy dd podajemy poszczególne parametry: wielkość bloków (bs w bajtach), offset skip w blokach) i rozmiar (count, także w blokach). Wszystkie wartości podawane są jako dziesiętne, możemy do ich przeliczenia z hexa wykorzystać kalkulator albo też skonwertować je w linii komend wykorzystując konstrukcję $(()):
[source=bash]$ dd if=spidump.bin of=bootloader.bin bs=1 count=$((0x020000))
131072+0 records in
131072+0 records out
131072 bytes transferred in 0.215768 secs (607467 bytes/sec)
$ dd if=spidump.bin of=mainkernel.bin bs=1 count=$((0x13D000-0x020000)) skip=$((0x020000))
1167360+0 records in
1167360+0 records out
1167360 bytes transferred in 1.900925 secs (614101 bytes/sec)
$ dd if=spidump.bin of=mainrootfs.bin bs=1 count=$((0x660000-0x13D000)) skip=$((0x13D000))
5386240+0 records in
5386240+0 records out
5386240 bytes transferred in 9.163635 secs (587784 bytes/sec)
$ dd if=spidump.bin of=protect.bin bs=1 count=$((0x800000-0x660000)) skip=$((0x660000))
1703936+0 records in
1703936+0 records out
1703936 bytes transferred in 2.743594 secs (621060 bytes/sec)[/source]
W ten sposób wygenerowaliśmy cztery pliki binarne:
* bootloader.bin: U-boot czyli bootloader systemu. Nie jest on skompresowany, ponieważ na tym etapie ładowania Ralink nie wie jak dekompresować dane, więc muszą one być zapisywane i odczytywane bezpośrednio.
* mainkernel.bin: Jądro Linuksa. Podstawowy element firmware, odpowiedzialny za kontrolę sprzętu w systemie. Ten fragment skompresowany jest algorytmem lzma.
* mainrootfs.bin: System plików, który zawiera wiele ważnych plików binarnych i konfiguracyjnych, W pamięci zapisany jest jako system squashfs skompresowany z wykorzystaniem algorytmu lzma.
* protect.bin: Pozostałe dane o których częściowo pisaliśmy w części trzeciej artykułu. Nie są one w żaden sposób skompresowane.
Ekstrakcja danych
Po rozdzieleniu całego zrzutu pamięci Flash na cztery podstawowe segmenty możemy każdy z nich z osobna zanalizować.
Bootloader
Binwalk podczas analizy pliku odnalazł nagłówek uImage i automatycznie go zdekodował. U-Boot wykorzystuje te nagłówki, aby identyfikować poszczególne rejony pamięci w systemie. Są to te same dane jakie binwalk wyświetlił nam przed podziałem pliku na fragmenty, gdyż nagłówek ten znajduje się na początku zrzutu.
Jako że praca bootloadera nie interesuje nas za bardzo to nie marnujmy więcej czasu na analizę tego pliku i przejdźmy dalej.
Jądro systemu – Kernel
Kompresja jest czymś z czym musimy sobie poradzić zanim rozpoczniemy dalszą pracę z plikiem i analizę jego zawartości. Binwalk potwierdził, że w tym przypadku mamy do czynienia z algorytmem lzma, tak jak odkryliśmy już w części drugiej artykułu. Algorytm ten to bardzo popularny sposób kompresowania danych w systemach wbudowanych. Jeśli przeskanujemy na szybko ten plik:
[source=bash]strings mainkernel.bin | less [/source]
To możemy potwierdzić że w binarce tej nie znajduje się zawartość którą odczytać można ludzkim okiem. Rozpakujmy cały plik. W tym celu wykorzystać możemy dowolny program, jaki posiada wbudowany algorytm lzma, może to być 7zip czy zip. Jednakże okazało się to być problematyczne w naszym przypadku – żaden z wymienionych programów nie był w stanie poprawnie zidentyfikować naszego pliku:
[source=bash]$ xz --decompress mainkernel.bin
xz: mainkernel.bin: File format not recognized[/source]
Najpewniej nagłówek uImage uniemożliwia programowi zrozumienie pliku, więc musimy go wyciąć. Wiemy że zajmuje od 64 bajty i dane lzma zaczynają się w adresie 0x40. Zatem skopiujmy dalej wszystko poza pierwszymi 64 bajtami danych:
I gdy teraz spróbujemy dekompresować dane:
[source=bash]$ xz --decompress mainkernel_noheader.lzma
xz: mainkernel_noheader.lzma: Compressed data is corrupt[/source]
Tym razem nasz program rozpoznał dane jako lzma, ale nie jest w stanie ich dekodować. Czemu? Najpewniej winne jest to, że chcemy dekodować cały obszar pamięci Flash, gdzie znajduje się kernel, ale mało prawdopodobne jest, że skompresowany obraz jądra systemu zajmuje dokładnie 100% tego obszaru. Usuńmy z końca nieużywany fragment pamięci i spróbujmy z tak zmodyfikowanym plikiem binarnym jeszcze raz podejść do algorytmu dekompresji:
Wydaje się, że xz rozpakował dane poprawne. Widać to chociażby dzięki temu, że w zdekompresowanych danych wiać komendy zapisane jako stringi ASCII. A skoro już tutaj jesteśmy spójrzmy w te dane, czy nie znajdziemy tam nic szczególnie interesującego.
Wpisy nazwane Wi-Fi Easy oraz Secure Key Derivation wyglądają bardzo obiecująco, ale są to jedynie wpisane ‘na sztywbi’ dane wynikające z specyfikacji Wi-Fi Protected Setup. Daleko od tego do jakiegokolwiek algorytmu generacji hasła, którym tak bardzo jesteśmy zainteresowani.
Na tym etapie wiemy już, że jesteśmy w stanie poprawnie dekompresować pliki, tak więc możemy kontynuować analizę zebranych danych ze zrzutu pamięci Flash.
System plików
Segment pamięci zawierający główny system plików nie ma nagłówka uImage, ponieważ jest on zależny od jądra systemu, a nie od bootloadera.
System plików SquashFS jest bardzo popularny w urządzeniach wbudowanych. Istnieje wiele różnych wersji i wariacji tego systemu plików, a dodatkowo część producentów, którzy z niego korzystają wprowadza własne zmiany i sygnatury, przez ci jeszcze ciężej jest analizować tego rodzaju dane. Okazać się zatem może, że aby z powodzeniem obejrzeć pliki będziemy musieli sprawdzić jaka wersja unsquashfs działa w naszym przypadku i/lub zmodyfikować sygnatury w pliku. W naszych danych sygnatura ta wygląda następująco:
Jako że jest to bardzo popularny system plików, a znajdowanie odpowiedniej konfiguracji wersji i sygnatur jest dosyć męczącym zajęciem, to w sieci dostępnych jest szereg narzędzi do tego, między innymi skrypt który działać ma w OS X (jest to fork projektu Firmware Modification Kit), który zawiera w sobie kilka wersji unsquashfs wywoływane pojedynczym skryptem unsquashfs_all.sh. Spróbujmy czy w naszym wypadku zadziała poprawnie:
Czyż to nie było proste? Albo po prostu mieliśmy trochę szczęścia – tak wersja jak i sygnatura systemu plików z naszego routera są wspierane przez algorytmy dekompresji w wykorzystanym przez nas narzędziu. Teraz mamy dostęp do wszystkich plików binarnych i konfiguracyjnych jakie obecne były w routerze, a także dowiązań symbolicznych itp. Wszystko ładnie zaprezentowane i uporządkowane:
W kompletnym drzewie katalogów widzimy, że mamy wszystkie pliki systemu (oprócz oczywiście plików generowanych podczas jego działania, jak te zgromadzone w folderze /var/). Wykorzystując zebrane wcześniej informacje możemy rozpocząć poszukiwania ciekawych plików binarnych w systemie:
Jeśli zainteresowani jesteśmy poszukiwaniem wszelkich dziur w systemach sieciowych i ich zabezpieczeniach, to posiadanie wszystkich biharek i plików konfiguracyjnych z danego urządzenia może być bardzo pomocne w tego rodzaju działaniach.
Pozostałe - dane chronione
Tak jak objaśnialiśmy w części trzeciej artykułu, część danych pozostaje w pamięci, bo musi pozostać dostępny po kolejnych resetach systemu. Dane te nie są skompresowane, ponieważ są one edytowane z poziomu systemu. Jak pamiętamy są to głównie dane konfiguracyjne itp. Aby bliżej przyjrzeć się zawartości tego rejonu pamięci skorzystajmy z komendy Springs:
Zawartość tego segmentu wydaje się składać z pliku curcfg,xml, logów i kilku luźnych kawałków stringów. Te dane już analizowaliśmy w części trzeciej, więc nie ma tutaj nic interesującego i wartego dalszego omawiania.
Dalsze kroki
Na tym etapie wszystkie dane jakie były do zebrania w routerze są już u nas. Teraz zastanówmy się jak je wykorzystać. Jednym z pomysłów mogłoby być na przykład dostanie się do routera poprzez port UART, gdyby okazało się, że dane do logowania nie są łatwe do zgadnięcia.
Jeśli nie jesteśmy w stanie zgrać zrzutu pamięci Flash z urządzenia, a bardzo chcemy pobawić się w tego rodzaju inżynierię wsteczną możemy zainteresować się aktualizacjami firmware, jakie czasami dostarcza producent. W tych plikach często znajdują się kompletne bloki pamięci, które ładowane są do pamięci Flash przez system operacyjny routera. Mogą w nich znajdować się jakieś interesujące dla nas dane.
W kolejnej części artykułu skupimy się jeszcze nad innymi plikami binarnymi, jakie wydobyć można z analizowanego routera i spróbujemy zobaczyć akie ciekawe i potencjalnie użyteczne informacje one zawierają.
Źródło: http://jcjc-dev.com/2016/06/08/reversing-huawei-4-dumping-flash/
Fajne? Ranking DIY
