Backdoor i parę “ciekawostek” w serii routerów D-Link DWR – Reverse Engineering tylnej furtki

Z racji tego, że nie wszyscy mogą być zainteresowani procesem analizy tylnej furki, postanowiłem wydzielić tą część i przedstawić w osobnym poście. Opis reszty podatności routerów z serii DWR znajdziesz tutaj.

Dla formalności jeszcze raz:

Podatne urządzenia wraz z wersjami oprogramowania

Warto dodać, że urządzenia DWR-113, DWR-712, DWR-755, DWR-927 nie były dostępne w oficjalnej sprzedaży w Polsce.

Co piszczy w httpd?

Po rozpakowaniu firmware binwalkiem (polecam bardzo!) i załadowaniu binarki serwera hostującego panel administacyjny w IDA (ścieżka: /usr/sbin/httpd) zostaniemy uraczeni takim spisem ciągów tekstowych w pliku:

Pierwsze dwa tropy! Interesująca funkcja do_login() oraz dodatkowy string “guest” o niezidentyfikowanym przeznaczeniu.

Funkcja do_login() wywoływana jest jednokrotnie w kodzie httpd, z funkcji o początku w adresie 0x40B630 (wywołanie następuje w 0x40B914).

do_login() przyjmuje jeden parametr, który jest jednocześnie parametrem funkcji jej wywołującej, w rejestrze $a0. Procedura po zakończeniu swojego działania zwraca liczbę całkowitą, która określa uprawnienia użytkownika (o tym później). Jeżeli jest ona równa 0, uwierzytelnianie zostaje zakończone niepowodzeniem.

Na początku swojego działania do_login() blokuje dla siebie mutex’a, następnie zmiennej, która jest flagą uprawnień usera (zwaną przeze mnie user_login_id) przypisywane jest 0.

Funkcje open_csman(), read_csman(), write_csman() są składowymi biblioteki CSMan, która odpowiada za realizację RPC za pomocą socketów.

Na potrzeby posta, wystarczy wiedzieć, że open_csman() otwiera kanał komunikacji z procesem określanym w źródłach jako CSMan Server. Funkcja read_csman() wczytuje dane bufora w pamięci do wskazanego bufora w argumencie, a write_csman(), co oczywiste, umieszcza dane w buforze.

read_csman() oraz write_csman() przyjmują następujące argumenty (w kolejności wywoływania):

Głodnych wiedzy zachęcam do przejrzenia funkcji bibliotecznych w paczce z komponentami na licencji GPL. Nie próbujcie Google’ować – Google nie rozumie problemu 😉

Zwracaną przez open_csman() wartością, w przypadku powodzenia, jest indeks socketu w tablicy socketów.

Kolejnym interesującym krokiem jest sposób walidacji poświadczeń. Na początku zerowany jest bufor pomocniczy na nazwę użytkownika (helper_username_buffer) i wczytywany jest do niego string za pomocą read_csman().

Jeżeli operacja się powiedzie – pierwszy bajt bufora jest różny od zera, następuje porównanie zmiennej username z helper_username_buffer a potem walidacja haseł za pomocą funkcji strcmp().

Kiedy hasło podane przez usera i zapisane w pamięci urządzenia jest takie samo, funkcja zwraca zero. Wówczas następuje przypisanie do flagi uprawnień user_login_id wartości 7, co powoduje przypisanie najwyższego poziomu uprawnień (deklaracja w pliku wsif.h, widoczne w komentarzach na screenie).

Następnie sprawdzana jest flaga ustawiona przed chwilą. W przypadku wartości różnej od 7 następuje kolejne sprawdzenie nazwy użytkownika, tym razem dla konta “guest”.

Uwierzytelnienie rozpoczyna się od weryfikacji zgodności nazwy użytkownika, następnie za pomocą wywołania funkcji read_csman() bufor, zwany przeze mnie, empty_password_buffer (32 znaki hasła + znak końca ciągu) jest “wypełniany pustką” spod offsetu 0x37F. Na końcu ciągi są porównywane za pomocą funkcji strcmp().

Tak jak poprzednio, w przypadku zwrócenia przez funkcję wartości zero (zgodności stringów), fladze uprawnień user_login_id przypisywana jest wartość określająca najwyższe uprawnienia czyli 7.

Teraz mamy już z górki 😉 Ostatnim sprawdzeniem jakie na nas czeka, jest porównanie wartości user_login_id z zerem. Każda wartość flagi różna od zera spowoduje zalogowanie do webowego panelu administratora.

Końcówka funkcji do_login() to, jak wspominałem opisując jej wywołanie, zwrócenie flagi uprawnień user_login_id. Następnie “sprzątanie” czyli zwolnienie mutex’a, zamykanie kanału komunikacji z procesem CSMan Server i przywrócenie stanu rejestrów z przed wywołania funkcji.