Jak załatano backdoora w routerach D-Link DWR?

Korzystając z chwili wolnego czasu chciałbym przedstawić nieco inne spojrzenie na badanie firmware’u. Tym razem nie będę szukał podatności 😉

W tym poście skupię się na analizie zmian dokonanych w kodzie oprogramowania serwera htttpd w serii routerów D-Link DWR celem zablokowania możliwości administracji urządzeniem poprzez tylną furtkę.

Krótkie przypomnienie

Jeżeli pamietasz czego dotyczyła opisywana przeze mnie sytuacja możesz śmiało pominąć ten akapit. W przypadku chęci zgłębienia problemu zapraszam przeczytania tego posta.

W oprogramowaniu rodziny routerów serii DWR, oprogramowanie dostarczane przez firmę Amit Network, zawiera dodatkowe ukryte konto. Konto wdzięcznie nazywa się “guest” i posiada taką samą flagę uprawnień (innymi słowy, takie same uprawnienia), jak najwyżej uprzywilejowane konto w systemie czyli “admin”.

Przydział flagi uprawnień (zmienna user_login_id) kontu “admin”… (kliknij aby powiększyć)

…oraz flaga konta “guest”

Abstrachując całkowicie od uprawnień tego konta, posiada ono jeszcze jeden “smaczek” – nie posiada hasła. Jedynym sposobem na jego zmianę jest ręczna modyfikacja zawartości pamięci urządzenia. Ten fakt, w połączeniu z podatnością na ataki CSRF umożliwiał napastnikom na pełną modyfikację ustawień urządzenia po zwabieniu użytkownika na specjalnie spreparowaną stronę.

Najnowsza wersja oprogramowania, będąca przedmiotem tego posta, ma zablokowaną możliwość korzystania z backdoora, oraz zaimplementowaną obsługę tokenów zapobiegającą atakom CSRF.

Zatem, jak to na chwilę obecną wygląda?

Żadne zmiany w procesie walidacji nazwy użytkownika i hasła nie nastąpiły. Po pomyślnej walidacji i przydzieleniu flag uprawnień pojawił się kawałek kodu odpowiedzialny za zerowanie flag uprawnień, jeżeli nazwą konta jest “guest” lub “user” (konto user zostało pominięte w poprzednich postach z racji poprawnie przydzielonych uprawnień oraz obecności tylko na dwóch modelach urządzeń z całej serii).

Zerowanie flagi uprawnień dla kont “guest” i “user”.

Kolejnym krokiem jest walidacja flag uprawnień ostatniego użytkownika panelu administracyjnego oraz konta, na które zostało zgłoszone żądanie zalogowania. Jeżeli to konto posiada uprawnienia administracyjne (tzn. flaga last_logged_user_login_id > 4, flagi kont “zwykłych” zawierają się w przedziale 2-3), funkcja przechodzi do walidacji user_login_id tym samym kryterium.

Sprawdzenie flag ostatnio zalogowanego użytkownika i konta, na które użytkownik próbuje się zalogować.

Jeżeli poświadczenia dotyczą konta zwyczajnego użytkownika, funkcja przechodzi do końcowego etapu i sprawdzany jest user_login_id, na podstawie którego następuje zalogowanie do panelu administracyjnego.

W przeciwnym wypadku porównywane są adresy IP poprzedniego i nowego użytkownika. Powodzenie operacji porównania powoduje przejście do sprawdzenia user_login_id i właściwej operacji logowania.

Porównanie adresów IP.

Kiedy adres IP użytkownika żądającego dostęp do panelu administracyjnego jest różny od IP ostatnio zalogowanego użytkownika, wykonywany jest poniższy fragment kodu:

Funkcja rtime() jest tu “podpuchą”, gdyż nie chodzi o linuksową funkcję rtime(), lecz o autorską, której zadaniem jest zupełnie co innego – zwrócenie czasu działania urządzenia.

Spójrzmy zatem jak ona wygląda:

Funkcja rtime().

Funkcja jest bardzo prosta. Wywołuje funkcję sysinfo(), celem uzyskania uptime’u w strukturze pod wskaźnikiem sysinfo_struct_pointer i zwraca pierwsze pole tej struktury (uptime).

Kolejnym krokiem jest pobranie z pamięci czasu pracy urządzenia (w sekundach) w momencie logowania administratora, oraz określenie długości jego sesji, poprzez odjęcie od uptime’u pobranej wcześniej wartości. Jeżeli wartość ta przekroczy timeout_value następuje wylogowanie administratora, z komunikatem w logach:

Wylogowanie użytkownika po przekroczeniu timeout’u.

W sytuacji kiedy timeout_value nie zostanie przekroczone, flaga uprawnień user_login_id zostanie zmieniona na 1 oraz pojawi się odpowiedni wpis o próbie logowania:

Zmiana user_login_id oraz komunikat w logach.

Następnie sprawdzana jest wartość flagi user_login_id:

Walidacja user_login_id.

Jeżeli jest mniejsza od 2 (niezalogowany użytkownik) następuje zablokowanie dostępu do panelu administratora i oczywiście wpis do logów.

Kod odpowiedzialny za właściwe logowanie do panelu administratora. (kliknij aby powiększyć)

W przeciwnym wypadku, oczywiście autoryzacja przebiega pomyślnie i można korzystać z panelu administratora z najwyższymi uprawnieniami.