Niekontrolowany ciąg formatu — Uncontrolled format string

Niekontrolowany ciąg formatu to rodzaj luki w oprogramowaniu wykrytej około 1989 roku, która może zostać wykorzystana w lukach bezpieczeństwa . Pierwotnie uważane za nieszkodliwe, exploity wykorzystujące ciąg formatujący mogą zostać wykorzystane do awarii programu lub wykonania szkodliwego kodu. Problem wynika z użycia niesprawdzonych danych wejściowych użytkownika jako parametru ciągu formatującego w niektórych funkcjach C, które wykonują formatowanie, takich jak printf(). Złośliwy użytkownik może wykorzystać %si %xsformatować tokeny między innymi do drukowania danych ze stosu wywołań lub ewentualnie innych lokalizacji w pamięci. Można również zapisać dowolne dane w dowolnych lokalizacjach za pomocą %ntokena formatu, który rozkazuje printf()i podobne funkcje zapisu liczby bajtów sformatowanych w adresie przechowywanym na stosie.

Detale

Typowy exploit wykorzystuje kombinację tych technik, aby przejąć kontrolę nad wskaźnikiem instrukcji (IP) procesu, na przykład poprzez wymuszenie nadpisania przez program adresu funkcji bibliotecznej lub adresu zwrotnego na stosie wskaźnikiem do jakiegoś złośliwego oprogramowania. kod powłoki . Parametry dopełniania specyfikatorów formatu są używane do kontrolowania liczby bajtów wyjściowych, a %xtoken służy do usuwania bajtów ze stosu, aż do osiągnięcia samego początku ciągu formatu. Początek ciągu formatu jest tworzony tak, aby zawierał adres, który %ntoken formatu może następnie zastąpić adresem złośliwego kodu do wykonania.

Jest to powszechna luka, ponieważ błędy formatu były wcześniej uważane za nieszkodliwe i powodowały luki w wielu popularnych narzędziach. Projekt CVE firmy MITRE wymienia około 500 programów podatnych na zagrożenia według stanu na czerwiec 2007 r., a analiza trendów plasuje go na 9. najczęściej zgłaszanym typie podatności w latach 2001-2006.

Błędy łańcucha formatującego pojawiają się najczęściej, gdy programista chce wypisać łańcuch zawierający dane dostarczone przez użytkownika (albo do pliku, do bufora, albo do użytkownika). Programista może omyłkowo napisać printf(buffer)zamiast printf("%s", buffer). Pierwsza wersja interpretuje bufferjako ciąg formatujący i analizuje wszelkie instrukcje formatowania, które może zawierać. Druga wersja po prostu wyświetla ciąg znaków na ekranie, zgodnie z zamierzeniami programisty. Obie wersje zachowują się identycznie w przypadku braku specyfikatorów formatu w ciągu, co ułatwia deweloperowi niezauważenie błędu.

Błędy formatowania powstają, ponieważ konwencje przekazywania argumentów w języku C nie są bezpieczne dla typów . W szczególności varargsmechanizm pozwala funkcjom akceptować dowolną liczbę argumentów (np. printf) przez " zdejmując " tyle argumentów ze stosu wywołań, ile chcą, ufając, że wczesne argumenty wskazują, ile dodatkowych argumentów ma zostać usuniętych i jakiego typu .

Błędy ciągów formatujących mogą wystąpić w innych językach programowania poza C, takich jak Perl, chociaż pojawiają się one rzadziej i zwykle nie można ich wykorzystać do wykonania kodu wybranego przez atakującego.

Historia

Błędy formatowania zostały po raz pierwszy zauważone w 1989 r. podczas testów fuzz przeprowadzonych na Uniwersytecie Wisconsin, które wykryły „efekt interakcji” w powłoce C (csh) między mechanizmem historii poleceń a procedurą błędu, która zakładała bezpieczne wprowadzanie ciągów.

Wykorzystywanie błędów format string jako wektor ataku została odkryta we wrześniu 1999 roku przez Tymm Twillman podczas audytu bezpieczeństwa w ProFTPD demon. Audyt wykrył, snprintfże dane wygenerowane przez użytkowników były przekazywane bezpośrednio bez ciągu formatu. Rozległe testy z wymyślonymi argumentami do funkcji w stylu printf wykazały, że użycie tego do eskalacji uprawnień jest możliwe. Doprowadziło to do pierwszego ogłoszenia we wrześniu 1999 r. na liście dyskusyjnej Bugtraq dotyczącej tej klasy luk w zabezpieczeniach, w tym podstawowego exploita. Jednak dopiero po kilku miesiącach społeczność zajmująca się bezpieczeństwem zdała sobie sprawę z pełnych niebezpieczeństw związanych z lukami w ciągach formatu, gdy zaczęły pojawiać się exploity dla innego oprogramowania korzystającego z tej metody. Pierwsze exploity, które ujawniły problem (poprzez zapewnienie zdalnego dostępu do roota poprzez wykonanie kodu), zostały opublikowane jednocześnie na liście Bugtraq w czerwcu 2000 roku przez Przemysława Frasunek i osobę posługującą się pseudonimem tf8 . Wkrótce po nich nastąpiło wyjaśnienie, wysłane przez osobę posługującą się pseudonimem lamagra . „Błędy formatowania” zostały umieszczone na liście Bugtraq przez Pascala Bouchareine'a w lipcu 2000 r. Nowatorski artykuł Tima Newshama „Format String Attacks” został opublikowany we wrześniu 2000 r., a inne szczegółowe opracowania techniczne zostały opublikowane we wrześniu 2001 r., takie jak Exploiting Format String Vulnerabilities , przez zespół Teso .

Zapobieganie w kompilatorach

Wiele kompilatorów może statycznie sprawdzać ciągi formatu i generować ostrzeżenia o niebezpiecznych lub podejrzanych formatach. W GNU Compiler Collection odpowiednie flagi kompilatora to -Wall, -Wformat, -Wno-format-extra-args, -Wformat-security, -Wformat-nonliteral, i -Wformat=2.

Większość z nich jest przydatna tylko do wykrywania złych ciągów formatu, które są znane w czasie kompilacji. Jeśli ciąg formatu może pochodzić od użytkownika lub ze źródła zewnętrznego dla aplikacji, aplikacja musi zweryfikować ciąg formatu przed jego użyciem. Należy również zachować ostrożność, jeśli aplikacja generuje lub wybiera ciągi formatujące w locie. Jeśli używana jest biblioteka GNU C, -D_FORTIFY_SOURCE=2parametr może służyć do wykrywania określonych typów ataków występujących w czasie wykonywania. -Wformat-nonliteralWyboru jest bardziej rygorystyczne.

Wykrycie

W przeciwieństwie do wielu innych problemów związanych z bezpieczeństwem, główną przyczynę luk w ciągach formatujących można stosunkowo łatwo wykryć w plikach wykonywalnych skompilowanych na platformie x86: w przypadku printffunkcji -family prawidłowe użycie oznacza oddzielny argument dla ciągu formatującego i argumenty, które mają być sformatowane. Błędne użycie takich funkcji można wykryć, po prostu licząc liczbę argumentów przekazanych do funkcji; „niedobór argumentów” jest zatem silnym wskaźnikiem, że funkcja została niewłaściwie wykorzystana.

Wykrywanie w plikach binarnych skompilowanych na x86

Zliczanie liczby argumentów jest często łatwiejsze na x86 ze względu na konwencję wywoływania, w której wołający usuwa argumenty, które zostały wepchnięte na stos, dodając do wskaźnika stosu po wywołaniu, więc proste sprawdzenie korekty stosu daje liczbę argumenty przekazywane do printffunkcji -family.'

Zobacz też

Bibliografia

Dalsza lektura

Zewnętrzne linki