Zdalne wykonywanie kodu (RCE), wyjaśnione: co to jest i jak temu zapobiec

zdalne wykonywanie kodu (RCE) to klasa luk/luk w zabezpieczeniach oprogramowania. Luki w zabezpieczeniach RCE umożliwią złośliwemu podmiotowi wykonanie dowolnego kodu NA zdalnej maszynie przez sieć LAN, WAN lub internet. RCE należy do szerszej klasy luk arbitralnego wykonywania kodu (Ace). Ponieważ Internet staje się wszechobecny, wpływ luk w RCE szybko rośnie. Tak więc RCE są obecnie prawdopodobnie najważniejszym rodzajem luki w zabezpieczeniach ACE.

ponieważ tak jest, chcieliśmy bardziej szczegółowo przyjrzeć się różnym rodzajom luk w zabezpieczeniach RCE i możliwym środkom zaradczym.

klasyfikacja RCE według pochodzenia

większość, jeśli nie wszystkie, znanych luk w RCE ma niewielką liczbę przyczyn.

dynamiczne wykonywanie kodu

dynamiczne wykonywanie kodu jest najczęściej wektorem ataku prowadzącym do RCE. Większość języków programowania ma jakiś sposób generowania kodu za pomocą kodu i wykonywania go na miejscu. Jest to bardzo potężna koncepcja, która pomaga rozwiązać wiele złożonych problemów. Jednak złośliwa strona trzecia może łatwo nadużywać jej, aby uzyskać możliwości RCE.

często kod generowany w czasie wykonywania jest oparty na pewnych danych wejściowych użytkownika. Najczęściej kod zawiera To wejście w jakiejś formie. Złośliwy aktor, zdając sobie sprawę, że dynamiczne generowanie kodu wykorzysta dane wejściowe, może dostarczyć poprawny kod jako dane wejściowe do ataku na Twoją aplikację. Jeśli Dane wejściowe użytkownika nie zostaną sprawdzone, kod ten zostanie wykonany na komputerze docelowym.

Ogólnie rzecz biorąc, dynamiczne wykonywanie kodu powoduje dwie główne klasy luk w zabezpieczeniach RCE: bezpośrednią i pośrednią.

Direct

w przypadku bezpośredniego dynamicznego wykonywania kodu złośliwy podmiot jest świadomy, że jego wejście będzie używane w generowaniu kodu.

pośrednie

przypadek pośredni, ponownie, sprowadza się do dynamicznego generowania kodu, w tym wejść użytkownika. Dane wejściowe użytkownika przechodzą jednak przez jedną lub więcej warstw. Niektóre warstwy mogą nawet przekształcić to wejście, zanim skończy się ono dynamicznym generowaniem kodu. Ponadto dynamiczne generowanie kodu może być efektem ubocznym, a nie głównym zastosowaniem danych wejściowych. W związku z tym nie jest oczywiste dla użytkownika dostarczającego dane wejściowe, że dane wejściowe będą używane jako element składowy fragmentu kodu do wykonania na zdalnej maszynie.

Deserializacja

Deserializacja jest bardzo dobrym przykładem tego scenariusza. Pozornie żadne dynamiczne generowanie kodu nie powinno mieć miejsca na deserializacji. Tak jest w rzeczywistości, gdy serializowany obiekt zawiera tylko pola danych typów prymitywnych lub innych obiektów tego rodzaju. Sprawy stają się jednak bardziej skomplikowane, gdy metody/funkcje obiektu są serializowane. Deserializacja wtedy zazwyczaj zawierać jakaś forma dynamiczny kod generowanie.

można by pomyśleć, że języki dynamiczne są jedynym miejscem, gdzie serializacja funkcji ma sens. Wtedy problem będzie miał ograniczony zakres. Ale jest to również przydatny scenariusz w statycznych językach. Jest to nieco trudniejsze do osiągnięcia w języku statycznym, ale zdecydowanie nie niemożliwe.

dość często implementacja składa się z deserializacji generowanych obiektów/funkcji proxy. Generowanie obiektów / funkcji w czasie wykonywania jest przypadkiem dynamicznego generowania kodu. Tak więc, jeśli dane do deserializacji pochodzą z żądania złożonego przez zdalną maszynę, złośliwy aktor może je zmodyfikować. Starannie wykonane serializowane fragmenty kodu mogą być wstrzykiwane, które oszukują dynamiczne generowanie kodu, aby je wykonać, gdy są wywoływane w ramach deserializacji.

bezpieczeństwo pamięci

inną przyczyną luk w RCE jest bezpieczeństwo pamięci. Bezpieczeństwo pamięci oznacza uniemożliwienie kodu dostępu do części pamięci, których nie zainicjował lub nie otrzymał jako wejście. Intuicyjnie można oczekiwać, że brak bezpieczeństwa pamięci spowoduje nieautoryzowany dostęp do danych. Jednak system operacyjny i podstawowy sprzęt używają pamięci do przechowywania rzeczywistego kodu wykonywalnego. Metadane dotyczące wykonania kodu są również przechowywane w pamięci. Uzyskanie dostępu do tego rodzaju pamięci może skutkować ACE i ewentualnie RCE. Jakie są główne przyczyny problemów z bezpieczeństwem pamięci?

błędy w projektowaniu oprogramowania

błędy w projektowaniu oprogramowania to rodzaj luki w zabezpieczeniach pamięci, w której występuje błąd w projekcie jakiegoś komponentu bazowego. Najczęściej jest to kompilator, interpreter lub maszyna wirtualna, lub potencjalnie jądro systemu operacyjnego lub biblioteki. Istnieje wiele różnych wad, które należą do tej klasy. Przyjrzymy się dokładniej temu, co jest prawdopodobnie najczęstsze.

przepełnienie bufora lub przeciążenie bufora

przepełnienie bufora (znane również jako przeciążenie bufora) jest dość prostą i dobrze znaną techniką naruszającą bezpieczeństwo pamięci. Wykorzystuje błąd projektu lub błąd do zapisu do komórek pamięci, które podążają za faktycznym końcem bufora pamięci. Sam bufor jest zwracany z uzasadnionego wywołania publicznego API. Bufor służy jednak tylko jako punkt początkowy do obliczania fizycznych adresów pamięci prywatnych wartości pól / elementów licznika jakiegoś obiektu lub programu. Ich względne położenie względem bufora jest dobrze znane lub można się domyślić. Badanie kodu, jeśli jest dostępny, lub debugowanie wykonania programu w czasie wykonywania może pomóc złośliwemu podmiotowi uzyskać względne pozycje.

tak więc przepełnienie bufora pozwala na modyfikację pamięci, która powinna być niedostępna z założenia. Bufor ten może znajdować się w przestrzeni adresowej innej maszyny i być modyfikowany przez wywołanie zdalnego API. To umożliwi dostęp do pamięci zdalnej maszyny. Oczywiście istnieją różne sposoby wykorzystania tego typu dostępu w oprzyrządowaniu RCE. Ogólne założenie jest takie, że jeśli istnieje luka przepełnienia bufora, to RCE jest możliwe. Właściciele kodu powinni więc jak najszybciej naprawić przepełnienia buforów, na długo przed wystąpieniem rzeczywistego ataku RCE.

zakres

najczęściej przepełnienie bufora jest celem kodu C/C++, ponieważ te języki nie mają wbudowanych sprawdzeń rozmiaru bufora. Wiele innych popularnych frameworków i technologii używa bibliotek C/C++ głęboko pod powierzchnią, co automatycznie czyni je podatnymi na tego rodzaju ataki.

JS jest tego dobrym przykładem, ponieważ oprócz tego, że jest oparty na C/C++, JavaScript runtime pozwala również na natywne dodatki C/C++. Z tego powodu atakujący może ostrożnie tworzyć żądania do węzła.serwer js powoduje przepełnienie bufora i w ten sposób modyfikuje pamięć systemową na dotkniętej maszynie, powodując wykonanie dowolnego kodu.

wady konstrukcyjne sprzętu

co ciekawe, naruszenia bezpieczeństwa pamięci mogą wystąpić również z powodu wad konstrukcyjnych sprzętu. Choć mniej powszechne i trudniejsze do znalezienia, takie luki zwykle mają bardzo duży wpływ.

odbijanie ataków RCE

chociaż wynik każdego ataku RCE jest taki sam pod względem kodu wykonującego atak, wektory ataku mają bardzo inny charakter. Blokowanie ich wszystkich wymaga znacznego wysiłku. Co więcej, wysiłek rośnie wraz ze stosem technologii. Wszystkie wektory ataku opisane w tym poście są agnostyczne technologicznie. Wszystkie implementacje są jednak specyficzne dla technologii, podobnie jak mechanizmy obronne.

tak więc tradycyjnym podejściem oszczędzającym czas jest monitorowanie ruchu w sieci pod kątem podejrzanych treści zamiast monitorowania każdego punktu końcowego za pomocą określonej technologii. Zapora sieciowa (WAF) zazwyczaj wykonuje to zadanie. Pozwala to zaoszczędzić czas, ale ma również swoją cenę—WAF jest wąskim gardłem wydajności sieci i brakuje mu wszystkich podstawowych informacji dostępnych w rzeczywistym punkcie końcowym lub na poziomie aplikacji i użytkownika. Dlatego analiza ruchu WAF nigdy nie może być doskonała. Heurystyka jest nieunikniona bez pełnych danych, więc albo nie pojawią się wszystkie zagrożenia, albo pojawią się fałszywe alarmy, albo najczęściej oba.

poruszanie się wewnątrz aplikacji: Podejście Sqreen

sqreen rozwiązuje te niedociągnięcia w zakresie WAF, nie zwiększając kosztów rozwoju dla użytkownika końcowego, przenosząc widoczność wewnątrz aplikacji, zapewniając pełniejszą ochronę dzięki specyficznemu dla danej technologii ZGRZYTARCE i wbudowanemu modułowi WAF. RASP i WAF Sqreen działają wewnątrz rzeczywistej aplikacji internetowej, interfejsu API lub mikroserwisu odbierającego ruch sieciowy. Nie wymaga jednak żadnej modyfikacji kodu. Wykorzystuje punkty oprzyrządowania specyficzne dla każdej technologii (np. JVM API dla Java, V8 API dla Node.js itp.) aby zmodyfikować kod przed wykonaniem w trybie runtime. Dzięki temu jest w stanie monitorować i modyfikować zdarzenia systemowe i sieciowe, mając jednocześnie pełny kontekst wszystkiego, co dzieje się wewnątrz aplikacji.

w ten sposób Sqreen może wykryć, że aplikacja używa komponentów ze znanymi problemami z bezpieczeństwem pamięci. Może również wykryć rzeczywiste dane wejściowe użytkownika, które trafiają do dynamicznych zdarzeń wykonania kodu. Oczywiście jest to lepsze podejście do wykrywania i zapobiegania RCE w porównaniu z tradycyjnym WAF, który ma dostęp tylko do ruchu sieciowego.

najwyraźniej RCE jest bardzo silnym wektorem ataku. Ale na szczęście można się bronić również przed atakami RCE. Powyższe informacje mogą naprawdę pomóc w budowaniu strategii obrony. Jeśli interesują Cię inne wektory ataków i szczegóły, sprawdź nasze poprzednie posty na temat SQL injection, XXE i LFI.

Leave a Reply