Luka root w jądrze Linux i odmowa usługi w systemd

Badacze bezpieczeństwa z firmy Qualys ujawnili szczegóły dwóch luk wpływających na jądro Linux oraz menedżer systemowy systemd. Luka w jądrze (CVE-2021-33909) pozwala lokalnemu użytkownikowi doprowadzić do wykonania kodu z uprawnieniami root poprzez manipulacje katalogami o bardzo dużym poziomie zagnieżdżenia.

Zagrożenie związane z tą luką potęguje fakt, że badaczom udało się przygotować działające exploity, które funkcjonują w Ubuntu 20.04/20.10/21.04, Debian 11 oraz Fedora 34 w konfiguracji domyślnej. Zaznaczono, że inne dystrybucje nie były testowane, ale teoretycznie również są podatne na ten problem i mogą stać się celem ataku. Pełny kod exploitów ma zostać opublikowany po powszechnym usunięciu problemu, a na razie dostępny jest jedynie prototyp o ograniczonej funkcjonalności, powodujący awarię systemu. Problem występuje od lipca 2014 roku i dotyczy wersji jądra od 3.16 wzwyż. Usunięcie luki zostało skoordynowane ze społecznością i włączone do jądra 19 lipca. Główne dystrybucje przygotowały już aktualizacje pakietów z nowym jądrem (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch).

Luka wynika z braku sprawdzenia wyniku konwersji typu size_t na int przed wykonaniem operacji w kodzie seq_file, który odpowiada za tworzenie plików z sekwencji wpisów. Brak takiej kontroli może prowadzić do zapisu poza granicami bufora podczas tworzenia, montowania i usuwania struktury katalogów o bardzo dużym poziomie zagnieżdżenia (rozmiar ścieżki przekracza 1 GB). W efekcie atakujący może doprowadzić do zapisania 10-bajtowego ciągu „//deleted” z przesunięciem „- 2 GB — 10 bajtów”, wskazującym na obszar bezpośrednio poprzedzający przydzielony bufor.

Przygotowany exploit wymaga do działania 5 GB pamięci i 1 miliona wolnych inode. Jego działanie sprowadza się do utworzenia za pomocą wywołania mkdir() hierarchii około miliona zagnieżdżonych katalogów, aby osiągnąć długość ścieżki pliku przekraczającą 1 GB. Następnie ten katalog jest montowany przez bind-mount w oddzielnej przestrzeni nazw identyfikatorów użytkowników (user namespace), po czym uruchamiana jest funkcja rmdir() w celu jego usunięcia. Równolegle tworzony jest wątek ładujący niewielki program eBPF, który zostaje zablokowany po etapie weryfikacji pseudokodu eBPF, ale przed jego kompilacją JIT.

W nieuprzywilejowanej przestrzeni nazw identyfikatorów użytkowników otwierany jest plik /proc/self/mountinfo i rozpoczyna się odczyt długiej ścieżki katalogu zamontowanego za pomocą bind-mount, co prowadzi do zapisania ciągu „//deleted” w obszarze przed początkiem bufora. Pozycja zapisu tego ciągu jest dobierana tak, aby nadpisał on instrukcję w już zweryfikowanym, ale jeszcze nieskompilowanym programie eBPF.

Następnie na poziomie programu eBPF niekontrolowany zapis poza buforem zostaje przekształcony w kontrolowaną możliwość odczytu i zapisu do innych struktur jądra poprzez manipulację strukturami btf i map_push_elem. W efekcie exploit określa położenie bufora modprobe_path[] w pamięci jądra i nadpisuje w nim ścieżkę „/sbin/modprobe”, co pozwala zainicjować uruchomienie dowolnego pliku wykonywalnego z uprawnieniami root w przypadku wykonania wywołania request_module(), które jest realizowane na przykład podczas tworzenia gniazda netlink.

Badacze przedstawili kilka metod obejścia zabezpieczeń, które są skuteczne wyłącznie wobec konkretnego exploitu, ale nie usuwają samego problemu. Zaleca się ustawienie parametru „/proc/sys/kernel/unprivileged_userns_clone” na wartość 0, aby zablokować montowanie katalogów w odrębnej przestrzeni nazw identyfikatorów użytkowników, a także „/proc/sys/kernel/unprivileged_bpf_disabled” na 1, aby uniemożliwić ładowanie programów eBPF do jądra.

Co istotne, analizując alternatywny wariant ataku związany z wykorzystaniem mechanizmu FUSE zamiast bind-mount do montowania dużego katalogu, badacze natrafili na kolejną podatność (CVE-2021-33910), która dotyczy menedżera systemowego systemd. Okazało się, że przy próbie montowania przez FUSE katalogu o długości ścieżki przekraczającej 8 MB dochodzi do wyczerpania pamięci stosu w procesie inicjalizacji (PID1) i awarii, która wprowadza system w stan „panic”.

Problem wynika z tego, że systemd śledzi i analizuje zawartość /proc/self/mountinfo oraz przetwarza każdy punkt montowania w funkcji unit_name_path_escape(), w której wykonywana jest operacja strdupa(), umieszczająca dane na stosie zamiast w pamięci przydzielanej dynamicznie. Ponieważ maksymalny rozmiar stosu jest ograniczony przez RLIMIT_STACK, przetwarzanie zbyt długiej ścieżki do punktu montowania prowadzi do awarii procesu PID1 i zatrzymania działania systemu. Do ataku można wykorzystać prosty moduł FUSE w połączeniu z użyciem jako punktu montowania katalogu o bardzo głębokiej strukturze, którego ścieżka przekracza 8 MB.

Problem występuje od wersji systemd 220 (kwiecień 2015), został już usunięty w głównym repozytorium systemd i poprawiony w dystrybucjach (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch). Warto zauważyć, że w wydaniu systemd 248 exploit nie działa z powodu błędu w kodzie systemd, który powoduje awarię podczas przetwarzania /proc/self/mountinfo. Co ciekawe, podobna sytuacja miała miejsce już w 2018 roku, gdy podczas próby napisania exploita dla podatności CVE-2018-14634 w jądrze Linux badacze z Qualys natrafili na trzy krytyczne luki w systemd.

Źródło: opennet.ru

Kup niezawodny hosting stron z ochroną DDoS, serwery VPS VDS 🔥 Kup niezawodny hosting stron z ochroną DDoS, serwery VPS VDS - ProHoster