Przepełnienie bufora: przyczyny, skuteczne metody rozwiązania problemu i potrzebna ochrona

Wszyscy programiści są świadomi potencjalnego zagrożenia przepełnieniem bufora w swoich programach. Istnieje wiele zagrożeń związanych z nim, zarówno w nowym, jak i starym, niezależnie od liczby wprowadzonych poprawek. Hakerzy mogą użyć tego błędu, implementując kod, który został zaprojektowany specjalnie w celu spowodowania przepełnienia początkowej części zbioru danych, a następnie zapisania pozostałych na adres pamięci w sąsiedztwie przepełnienia. Dane mogą zawierać kod wykonywalny, który pozwala intruzom uruchamiać większe i bardziej złożone programy lub zapewniać im dostęp do systemu. Błędy są bardzo trudne do znalezienia i naprawienia, ponieważ kod tego kodu składa się z milionów linii. Korekta tych błędów jest dość skomplikowana, a także podatna na błędy, co komplikuje proces eliminacji.


Definicja przepełnienia bufora

Zanim zaczniesz szukać przepełnienia, musisz wiedzieć, co on reprezentuje. Jak sama nazwa wskazuje, te luki dotyczą buforów lub alokacji pamięci w językach, które zapewniają bezpośredni niski poziom dostępu do czytania i pisania. Podczas używania języków C i Asembler, czytanie lub pisanie takich dystrybucji nie pociąga za sobą automatycznych kontroli granicznych. W związku z tym, jeśli wykryte zostanie przepełnienie stosu bufora w tej aplikacji, nie ma możliwości sprawdzenia możliwości umieszczenia liczby bajtów w rozpatrywanym buforze. W takich przypadkach program może "przepełnić" swoją pojemność. To prowadzi do faktu, że danenagrane po wypełnieniu, przepisać zawartość następujących adresów stosu i przeczytać dodatkowe. Przepełnienie może wystąpić przypadkowo z powodu błędów użytkownika.


Zdarza się, że jest to spowodowane tym, że złośliwy podmiot wysyła ostrożnie stworzone złośliwe oprogramowanie do programu, który następnie próbuje utrzymać go w niewystarczającym buforze. Jeśli wykryje to przepełnienie stosu bufora w tej aplikacji, nadmiarowe dane są przechowywane w sąsiednich, zastępując wszelkie dostępne dane. Zwykle zawierają punkt zwrotny dla wykorzystanej funkcji, adres, pod którym proces powinien iść dalej. Osoba atakująca może ustawić nowe wartości, aby wskazywały na wybrany adres. Atakujący zazwyczaj ustawia nowe wartości, aby wskazać, gdzie znajduje się ładunek. Zmienia to sposób działania procesu i natychmiast przenosi złośliwe zarządzanie kodami. Korzystanie z przepełnienia bufora umożliwia atakującemu monitorowanie lub zamykanie procesu lub modyfikowanie jego wewnętrznych zmiennych. To naruszenie ma miejsce w 25 najniebezpieczniejszych błędach oprogramowania na świecie (2009 r. CWE /SANS 25 najbardziej niebezpiecznych błędów programistycznych) i jest zdefiniowane jako CWE-120 w słowniku tłumaczeń słabych lokalizacji systemu. Pomimo tego, że są dobrze przestudiowani, nadal szkodzą popularnym programom.

Prosty wektor bufora

Podczas pracy z kodem źródłowym należy zwrócić szczególną uwagę na miejsca, w których używane są bufory i modyfikować je. Na szczególną uwagę zasługują funkcje związane z wnioskiem dostarczonym przez użytkownika lubinne zewnętrzne źródło, ponieważ zapewniają prosty wektor do użycia, gdy zostanie wykryte przepełnienie stosu buforów. Na przykład, gdy użytkownik umieści na pytanie „tak” lub „nie”, wskazane jest, aby zachować ciąg danych użytkownika w małym buforze do napisu „Tak”, jak pokazano w poniższym przykładzie.
Patrząc na kod, jasne jest, że kontrola graniczna nie jest wykonywana. Jeśli użytkownik wprowadzi "możliwy", wówczas program zawiesi zadanie i nie zadaje mu odpowiedzi, która jest zapisana w buforze niezależnie od jego długości. W tym przykładzie, jako odpowiedź użytkownika jest tylko deklarowane wartości zmiennych na stosie będzie wartość adresu lub lokalizacji powrotnej w pamięci, gdzie powraca program po wykonaniu zadać pytanie. Oznacza to, że jeśli użytkownik wprowadza cztery bajty danych, wystarczy dowodzić klienta przepełnienia bufora jest prawidłowy adres zwrotny do zmiany. Spowoduje to program, aby wyjść z funkcji w innym kodem punktu niż początkowo przewidywano, co może prowadzić do tego, co będzie się zachowywał w niebezpieczny i niezamierzona. Jeśli pierwszy krok do wykrywania przepełnienia bufora w kodzie źródłowym mieć wiedzę o tym, jak one działają, drugim krokiem jest zbadanie wejście zewnętrzne i manipulacji bufora, trzeci etap jest potrzeba, aby zobaczyć, jakie funkcje są podatne na ten problem i że może działać jako „czerwone flagi » Funkcja get jest świetna do nagrywania poza buforem dostarczonym do niego. W rzeczywistości ta jakość rozciąga się na całą rodzinę powiązanych funkcji, w tym strcpy, strcmp i printf /sprintf, gdziekolwiekjedną z tych funkcji jest podatność na przepełnienie.

Usunięcie z bazy kodów

Jeśli w kodzie źródłowym zostanie znalezione przepełnienie stosu bufora, konieczne będzie konsekwentne usuwanie z bazy danych. Aby to zrobić, musisz znać bezpieczne metody pracy. Najłatwiejszym sposobem uniknięcia tych luk jest użycie języka, który na nie nie pozwala. Język C ma te luki ze względu na bezpośredni dostęp do pamięci i brak ścisłego wpisywania obiektów. Języki, które nie mają tych aspektów, zazwyczaj nie są dostępne. To jest Java, Python i .NET, wraz z innymi językami i platformami, które nie wymagają specjalnych kontroli lub zmian. Oczywiście nie zawsze można całkowicie zmienić język programowania. W tym przypadku do pracy z przepełnieniem bufora poleceń wykorzystywane są bezpieczne metody. W przypadku funkcji przetwarzania linii wiele dyskusji dotyczyło dostępnych metod, które są bezpieczne w użyciu i których należy unikać. Funkcje strcpy i strcat kopiują ciąg do bufora i dodają zawartość do siebie. Te dwie metody pokazują niebezpieczne zachowanie, ponieważ nie sprawdzają granic bufora docelowego i nie wykonują rekordu na zewnątrz, jeśli jest wystarczająco dużo bajtów, aby to zrobić.

Ochrona alternatywna

Jedną z często proponowanych alternatyw są wersje powiązane, które są zapisane w maksymalnym rozmiarze bufora docelowego. Na pierwszy rzut oka wygląda to na idealne rozwiązanie. Niestety te funkcje mają mały niuans, który powoduje problemy. Gdy limit zostanie osiągnięty, jeśli ostatni znak nie zostanie umieszczony w ostatnim bajcie, podczas odczytywania bufora występują poważne błędy.

W tymUproszczony przykład pokazuje niebezpieczeństwo strun, nie kończą się na zero. Kiedy foo znajduje się w normalnym buforze, kończy się zerem, ponieważ ma dodatkową przestrzeń. To najlepsza opcja do rozwoju wydarzeń. Jeśli bajty w przepełnieniu bufora na stosie znajdą się w innym buforze znaków lub innym łańcuchu wydruku, funkcja drukowania będzie kontynuowała czytanie do momentu, aż zostanie osiągnięty znak końca tego wiersza. Wadą jest to, że język C nie zapewnia standardowej, bezpiecznej alternatywy dla tych funkcji. Niemniej jednak jest pozytywna - dostępność kilku implementacji dla konkretnej platformy. OpenBSD udostępnia strlcpy i strlcat, które działają podobnie do strn, z tym wyjątkiem, że obcinają ciąg jeden znak wcześniej, aby zwolnić miejsce na zero. Podobnie Microsoft zapewnia własną bezpieczną implementację często używanych funkcji przetwarzania ciągów: strcpy_s, strcat_s i sprintf_s. Korzystanie z bezpiecznych alternatyw wymienionych powyżej jest najlepsze. Jeśli nie jest to możliwe, wykonaj ręczne sprawdzanie obramowania i zerowe zakończenie podczas przetwarzania buforów ciągów.

Luki kompilacji

W przypadku, gdy niebezpieczna funkcja pozostawia otwartą możliwość przepełnienia bufora C, wtedy nie wszystko zostaje utracone. Po uruchomieniu programu kompilatory często tworzą losowe wartości, znane jako kanarki i umieszczają je w stosie, więc stanowią zagrożenie. Sprawdzanie wartości kanału w stosunku do jego pierwotnej wartości może decydować o przepełnieniu bufora w systemie Windows. Jeśli wartość została zmieniona, program zostanie zamknięty lub przejdzie w stan błędu, ale nie potencjalniezmieniony adres zwrotny.
Niektóre współczesne systemy operacyjne zapewniają dodatkową ochronę przed przepełnieniem buforów w postaci nieosiągalnych stosów i losowej alokacji przestrzeni adresowej (ASLR). Niewykonywalne układanie w stos - Zapobieganie danych (DEP) - oznacza stosy, aw niektórych przypadkach inne struktury jako obszary, w których kod nie zostanie wykonany. Oznacza to, że atakujący nie może zaimplementować kodu exploita w stosie i czekać na jego pomyślne wykonanie. Przed naprawieniem przepełnienia bufora, rozpakuj go na komputerze ASLR. Został zaprojektowany w celu ochrony przed programowanymi powrotami jako ścieżką bypassu do nierealizowalnych stosów, gdzie istniejące fragmenty kodu są łączone w łańcuch w oparciu o stronniczość ich adresów. Działa poprzez randomizację obszarów pamięci w strukturach, tak aby ich przesunięcie było trudniejsze do zdefiniowania. Gdyby ta ochrona istniała pod koniec lat osiemdziesiątych, można by było zapobiec robakowi Morris. Wynika to z faktu, że działał on częściowo poprzez wypełnienie bufora w kodzie exploita opartym na palcu UNIX, a następnie przepełnienie go w celu zmiany adresu zwrotnego i wskazania pełnego bufora. ASLR i DEP komplikują precyzyjną definicję adresu, który zostanie określony, podczas gdy wykonanie tego obszaru pamięci jest zupełnie nie na miejscu. Czasami usterka przechodzi przez szczeliny otwarte, aby atakować przepełnienia bufora, pomimo obecności elementów sterujących na poziomie programowania, kompilatora lub systemu operacyjnego.

Analiza zasięgu statycznego

W sytuacji przepełnienia bufora występują dwa kluczowe zadania. Najpierw musisz zidentyfikować lukę izmień podstawę kodu, aby rozwiązać problem. Po drugie, zapewnij zastąpienie wszystkich wersji kodu błędu przepełnienia bufora. Najlepiej, jeśli zacznie się od automatycznej aktualizacji wszystkich systemów podłączonych do Internetu. Nie można założyć, że taka aktualizacja zapewni wystarczające pokrycie. Organizacje lub osoby fizyczne mogą korzystać z oprogramowania w systemach z ograniczonym dostępem do Internetu, wymagających ręcznych aktualizacji. Oznacza to, że wiadomości aktualizacyjne muszą być rozpowszechniane wśród administratorów, którzy mogą z nich korzystać, a łata powinna być łatwo dostępna do pobrania. Tworzenie i dystrybucja poprawek są wykonywane jak najbliżej wykrycia luki w zabezpieczeniach, co minimalizuje czas wystąpienia luki w zabezpieczeniach. Dzięki wykorzystaniu bezpiecznych funkcji przetwarzania bufora i odpowiednich funkcji zabezpieczeń kompilatora i systemu operacyjnego można stworzyć niezawodną ochronę przed buforem przepełnienia. W świetle tych kroków konsekwentna identyfikacja niedociągnięć jest decydującym krokiem zapobiegającym wyzyskowi. Łączenie ciągów źródłowych w poszukiwaniu potencjalnych zagrożeń może być wyczerpujące. Ponadto zawsze istnieje możliwość, że ludzkie oczy mogą ominąć coś ważnego. Narzędzia do analizy statycznej służą do zapewnienia jakości kodu, zostały zaprojektowane specjalnie w celu wykrywania luki w zabezpieczeniach podczas programowania. Analiza zasięgu statycznego powoduje ustawienie "czerwonych etykiet" dla potencjalnych przepełnień bufora. Następnie są one traktowane i poprawiane osobno, tak aby nie szukać w bazie danych. Te narzędzia są ww połączeniu z regularnymi kontrolami i wiedzą, jak eliminować przepełnienia, pozwalają zidentyfikować i wyeliminować większość braków przed ukończeniem oprogramowania.

Wykonywanie ataków root'a

Błędy kodowania są zwykle przyczyną przepełnienia bufora. Typowe błędy w tworzeniu aplikacji, które mogą do niego prowadzić, to brak możliwości przydzielenia wystarczająco dużych buforów i brak mechanizmu do sprawdzania tych problemów. Takie błędy są szczególnie problematyczne w językach C /C ++, które nie mają wbudowanej ochrony przed przepełnieniem i często podlegają atakom przepełnienia bufora. W niektórych przypadkach atakujący wprowadza złośliwy kod do pamięci, która została uszkodzona przez przepełnienie stosu buforów. W innych przypadkach po prostu wykorzystaj zalety uszkodzenia sąsiedniej pamięci. Na przykład program, który prosi o hasło użytkownika, aby umożliwić mu dostęp do systemu. W poniższym kodzie prawidłowe hasło zapewnia uprawnienia root. Jeśli hasło jest nieprawidłowe, program nie daje uprawnień użytkownika.
W powyższym przykładzie program zapewnia użytkownikowi uprawnienia root, nawet jeśli podał błędne hasło. W tym przypadku atakujący dostarcza dane wejściowe, których długość jest większa niż bufor może pomieścić, tworząc przepełnienia, zastępując pamięć liczby całkowitej. Dlatego mimo nieprawidłowego hasła wartość pass staje się niezerowa, a atakujący otrzymuje prawa root.

Atak strefy czasowej

Bufor to tymczasowy obszar przechowywania. Gdy aplikacja lub proces systemowy umieszcza więcej danych niż byłoprzeznaczony do przechowywania, dodatkowe przelewy. To powoduje, że niektóre z nich przenikają do innych buforów, uszkadzając lub zastępując dane. W ataku z przepełnieniem dodatkowe dane zawierają specjalne instrukcje dotyczące działań popełnionych przez hakera lub złośliwego użytkownika, na przykład powodują odpowiedź, która uszkadza pliki, modyfikuje dane lub ujawnia dane osobowe. Atakujący wykorzystuje exploita przepełnienia, aby użyć programu, który oczekuje wkładu użytkownika. Istnieją dwa typy bufora przepełnienia: stos i stos. Skumulowane pakiety są trudne do wykonania i najmniej powszechne, atakując aplikację, wypełniając przestrzeń zarezerwowaną dla programu. Stack to przestrzeń pamięci używana do przechowywania danych wprowadzanych przez użytkownika. Takie przekroczenie jest częstsze u atakującego, który używa programów. Współczesne kompilatory zwykle zapewniają możliwość sprawdzania przepełnienia podczas kompilacji /kompilacji, ale podczas wykonywania bardzo trudno jest sprawdzić ten problem bez żadnego dodatkowego mechanizmu ochrony dla obsługi wyjątków.
Warianty programu:
  • Wpisz: 12345678 (8 bajtów), program działa bez awarii.
  • Wpisz: 123456789 (9 bajtów), pojawi się komunikat "Błąd segmentacji", program zostanie zakończony.
  • Luka w zabezpieczeniach wynika z przepełnienia, jeśli parametr wejściowy użytkownika argv przekracza 8 bajtów. W przypadku systemu 32-bitowego (4 bajty) wypełniają pamięć podwójnym słowem (32-bitowe). Wielkość znaków to 1 bajt, więc jeśli zażądasz bufora o 5 bajtach,system przydzieli 2 podwójne słowa (8 bajtów). Dlatego kiedy wprowadzisz więcej niż 8 bajtów, Bufor będzie pełny. Podobne standardowe funkcje, które są technicznie mniej wrażliwe, istnieją. Na przykład: strncpy (), strncat () i memcpy (). Problem z tymi cechami polega na tym, że odpowiedzialność za określenie rozmiaru bufora spoczywa na programistach, a nie na kompilatorze. Każdy programista C /C ++ powinien znać problem przed rozpoczęciem kodowania. Wiele wygenerowanych problemów w większości przypadków można zabezpieczyć przed przepełnieniem.

    Zagrożenia w C /C ++

    C Użytkownicy powinni unikać niebezpiecznych funkcji, które nie sprawdzają granicę, jeśli nie są pewni, co granice nie zostały przekroczone. Funkcje, których w większości przypadków należy unikać w celu zapewnienia ochrony, obejmują funkcje strcpy. Powinny one zostać zastąpione funkcjami takimi jak strncpy. Unikaj używania funkcji strlen, jeśli użytkownik ma pewność, że zostanie znaleziony ostateczny symbol NIL. scanf rodzina (): scanf
    , fscanf
    , sscanf
    , vscanf
    , vsscanf
    i vfscanf
    - niebezpieczna do użytku, nie jest używany do przesyłania danych w jednym rzędzie bez maksymalnej kontroli długość, "format% s" jest szczególnie częstym błędem. Oficjalnie funkcja snprintf () jest standardową klasyfikację C ISO 1990. Systemy te nie chronią przed przepełnienia bufora, po prostu wywołać Sprintf bezpośrednio. Wiadomym jest, że obecna wersja Linux snprintf działa prawidłowo, to jest rzeczywiście obserwowane limitu. Obliczona wartość snprintf () również jest różna. W wersji 2 specyfikacji UNIX (SUS) i standardowe C99 różnią że powraca snprintf (). NiektóreWersje snprintf nie gwarantują, że ciąg zakończy się na NIL, a jeśli łańcuch jest zbyt długi, nie będzie w ogóle zawierać NIL. Biblioteka glib ma g_snprintf () z sekwencyjną semantyką return, zawsze kończy się NIL i, co najważniejsze, zawsze bierze pod uwagę długość bufora.

    Przepełnienie bufora portu komunikacyjnego

    Czasami port szeregowy zgłasza bufor przepełnienia. Ten problem może być spowodowany kilkoma czynnikami. Obejmują one szybkość komputera, szybkość przesyłania danych, rozmiar portu szeregowego FIFO i rozmiar urządzenia FIFO, który przesyła dane do portu szeregowego. Zarządzanie przepływem będzie czekać, aż pewna liczba bajtów pojawi się w buforze, zanim procesor wyśle ​​wiadomość lub sygnał do innego urządzenia, aby zatrzymać transfer. Przy wyższych szybkościach transmisji, port szeregowy otrzyma kilka bajtów od momentu osiągnięcia poziomu kontroli przepływu bufora i zatrzymania urządzenia. Te dodatkowe bajty będą większe, jeśli proces o wysokim priorytecie kontroluje procesor docelowy w czasie rzeczywistym. Ponieważ przepełnienie bufora portu komunikacyjnego ma wyższy priorytet niż przerwanie karty VISA, procesor nie podejmie żadnej akcji, dopóki nie zostanie ukończony w czasie rzeczywistym. Domyślne ustawienia VISA i Windows dla 16-bajtowych FIFO to 14 bajtów, pozostawiając 2 bajty w FIFO, gdy urządzenie próbuje wysłać wiadomość ze źródła. Przy wyższych prędkościach na wolnych komputerach można uzyskać więcej niż 4 bajty na razport szeregowy prosi procesor, wysyłając sygnał o zakończeniu transmisji. Aby rozwiązać problem po wykryciu przepełnienia stosu w systemie Windows 10, musisz otworzyć Menedżera urządzeń. Następnie znajdź port COM, dla którego ustawienia zostały zmienione i otwórz właściwości. Następnie kliknij zakładkę "Zaawansowane", pojawi się suwak, który zmienia rozmiar przeładowania schowka, aby UART szybciej przełączał zarządzanie strumieniem. Domyślna wartość w większości przypadków jest wystarczająca. Jeśli jednak wystąpi błąd przepełnienia bufora, wartość maleje. Spowoduje to wysłanie większej liczby przerw do procesora ponownej próby UART.

    Metody bezpiecznego rozwoju

    Bezpieczne techniki rozwoju obejmują rutynowe testy w celu wykrycia i eliminacji przepełnienia. Najbardziej niezawodny sposób na uniknięcie lub uniemożliwienie korzystania z automatycznej ochrony językowej. Kolejną poprawką jest sprawdzanie granic podczas wykonywania, co zapobiega przepełnieniu przez automatyczne sprawdzanie, czy dane zapisane w buforze mieszczą się w dopuszczalnych granicach. Veracode wykrywa luki w kodzie, takie jak bufory przepełnienia, więc programiści eliminują je, zanim zostaną użyte. Opatentowana przez Veracode technologia do zabezpieczania statycznych zabezpieczeń binarnych (SAST) jest unikatowa w branży, analizując ją, włączając w to komponenty open source i inne, bez konieczności uzyskiwania do niej dostępu. SAST uzupełnia symulacje zagrożeń i przeglądów kodu przez programistów szybciej i przy mniejszych nakładach.wykrywanie błędów i pominięć w kodzie z powodu automatyzacji. Z reguły działa na wczesnych etapach cyklu rozwoju oprogramowania, ponieważ łatwiej i taniej rozwiązać problemy przed przystąpieniem do wdrożenia produkcyjnego. SAST wykrywa krytyczne luki, takie jak implementacja SQL, cross-site scripting (XSS), błąd przepełnienia bufora, nieprzetworzony status błędu i potencjalne rogi. Ponadto technologia binarna SAST dostarcza użytecznych informacji, które definiują priorytety w zależności od wagi i zapewniają szczegółową instrukcję korekcji. Luka w przepełnieniu bufora istnieje już od prawie trzech dekad, ale nadal jest uciążliwa. Hakerzy z całego świata nadal domyślnie uważają to za swoją taktykę ze względu na ogromną liczbę responsywnych aplikacji internetowych. Programiści i programiści podejmują ogromne wysiłki, aby zwalczyć tę plagę technologii informatycznych, wymyślając nowe i nowe sposoby. Główną ideą ostatniego podejścia jest implementacja narzędzia łatki, które tworzy wiele kopii adresów zwrotnych w stosie, a następnie losuje położenie wszystkich kopii oprócz liczby. Wszystkie duplikaty są aktualizowane i sprawdzane równolegle, tak że wszelkie rozbieżności między nimi wskazują na próbę ataku i powodują wyjątek.

    Powiązane publikacje