Format string attack
Format string attack - Atak komputerowy będący względnie nową techniką wykorzystywania błędów programistycznych w aplikacjach. Błędnie napisana aplikacja może być przy wykorzystaniu tej techniki usunięta z listy procesów przez system operacyjny (tzw. crash) lub zmuszona do wykonania kodu dostarczonego przez napastnika.
Historia
Pierwsze informacje na temat błędnego wykorzystania funkcji wykorzystujących ciągi formatujące pojawiły się w wynikach analizy kodu źródłowego powłoki csh w 1990 przy wykorzystaniu techniki automatycznego testowania aplikacji (tzw. fuzzingu) na Uniwersytecie Wisconsin ([Miller,Fredriksen,So 1990]).
Przez wiele lat niewłaściwe wykorzystanie funkcji operujących na ciągach formatujących było uważane za błąd, nie umożliwiający jednak przejęcia kontroli nad aplikacją. W 2000 roku Przemysław Frasunek przedstawił na liście dyskusyjnej Bugtraq po raz pierwszy exploit wykorzystujący błędy tego typu w szeroko stosowanym serwerze usługi FTP [1]. Kod źródłowy exploita pokazywał technikę umożliwiającą przejęcie kontroli nad aplikacją przy wykorzystaniu błędnego wywołania funkcji syslog().
Pierwsze, udane wykorzystanie tego błędu programistycznego szybko zaowocowało kolejnymi exploitami wykorzystującymi błędy w instniejących implementacjach aplikacji. Podatnymi na atak z wykorzystaniem błędu format bug okazały się tak szeroko stosowane w internecie aplikacje, jak: ProFTPD, su czy też serwer SSH[2].
Obecnie format bugi są coraz rzadziej spotykane w dostępnym oprogramowaniu ze względu na znacznie rozpowszechnienie wiedzy o skutkach i unikaniu tego typu błędów oraz dosyć łatwe techniki wykrywania tej klasy błędów.
Szczegóły techniczne
Atakujący wykorzystuje błędny sposób przekazywania argumentów do funkcji operujących na ciągach formatujących, takich jak printf(), w języku C. W przypadku posiadania przez napastnika kontroli nad ciągiem formatującym może on wykorzystać niektóre z dyrektyw takiego ciągu do zapisania dowolnych obszarów pamięci procesu. Zwykle wykorzystywana jest tutaj mało znana i sporadycznie wykorzystwana dyrektywa %n, zapisująca pod obszar pamięci wskazywany przez kolejny argument (który powinien znajdować się na stosie procesu) liczbę dotychczas zapisanych przez atakowaną funkcję znaków. Umiejętne użycie dyrektywy %n oraz dyrektyw określających liczbę znaków do wypisania, np. %<liczba>s, spowoduje odwołanie się pod z pozoru przypadkowy adres z obszaru stosu programu, i w wielu sytuacjach pozwoli na nadpisanie odpowiednio wybranych obszarów pamięci, w tym danych kontrolnych procesu.
Najczęstszy schemat wykorzystania podatności polega na nadpisaniu wskaźnika powrotu z funkcji (wartości na stosie), zastępując go wskaźnikiem do kodu (znajdującego na stosie, stercie lub w sekcji kodu procesu). W takim przypadku atak ten jest bardzo podobny do sposobu wykorzystania błędu przepełnienia bufora. Możliwe jest także nadapisanie danych (zmiennych), co może prowadzić do korzystnych z punktu widzenia atakującego zmian w przepływie sterowania procesu (np. eskalacji uprawnień).
Błędy tego typu mogą zostać w pewnych sytuacjach pośrednio wykorzystane bez wykorzystania dyrektywy %n. Wykorzystanie dyrektywy %s może doprowadzić do ujawnienia zawartości pamięci procesu uprzywilejowanego, w tym np. haseł; w innym scenariuszu, możliwe jest doprowadzenie do skopiowania do bufora (np. funkcją sprintf()) więcej danych, niż przewidział programista.
Najpopularniejsze z podatnych na atak funkcji i rodzin funkcji:
- printf()
- syslog()
- err()
- warn()
- setproctitle()
Obrona
Sposób obrony przez tego typu atakiem jest bardzo prosty. W tworzonym kodzie należy unikać przekazywania ciągów formatujących dostarczonych przez użytkownika do funkcji wykorzystujących ciągi formatujące (np. printf()) oraz takich, które takie funkcje wewnętrznie wykorzystują (np. syslog()). W ogólnym przypadku sprowadza się to zamiany wywołań typu:
printf(string);
na
printf("%s", string);
Dodatkowo, możliwe jest zabezpieczenie zamkniętego oprogramowania przez taką zmianę funkcji bibliotecznych, by odrzucać relatywnie mało przydatną dyrektywę %n we wszystkich odwołaniach do biblioteki. Zmniejsza to znacznie ryzyko pomyślnego ataku, chociaż - jak zaznaczono wcześniej - nie chroni przed wszystkimi jego wariantami. W niektórych przypadkach pomocne mogą być algorytmy ochrony stosu przed wykonywaniem znajdującego się na nim kodu na architekturach sprzętowych, które tego nie uniemożliwiają (np. IA-32), a także inne sposoby utrudniające wykonywanie przemyconego do pamięci procesu kodu (np. losowe ułożenie wirtualnej przestrzeni adresowej procesu).