CVE-2026-23111: Vienas šauktukas — ir neprivilegijuotas vartotojas gauna root
CVE-2026-23111: Vienas šauktukas — ir neprivilegijuotas vartotojas gauna root
Įsivaizduokite: jūsų serveryje dirba paprastas vartotojas. Jokio sudo, jokių ypatingų teisių, negali skaityti /root, negali liesti sisteminių failų. Po kelių sekundžių — jau root. Ne todėl, kad nulaužė kažką sudėtingo. Todėl, kad vienas kūrėjas Linux branduolyje atsitiktinai įrašė šauktuką ten, kur jo visiškai neturėjo būti.
CVE-2026-23111 — use-after-free tipo pažeidžiamumas Linux branduolio nf_tables posistemyje, Ubuntu vertinamas CVSS 7.8 (High). Jis leidžia neprivilegijuotam vartotojui gauti root teises Debian ir Ubuntu sistemose. Veikiantis viešas išnaudojimas jau paskelbtas — Exodus Intelligence tyrėjo Oliver Sieber, su >99% stabilumu neapkrautoje sistemoje, o FuzzingLabs PoC pasirodė dar balandį. Patvirtintų naudojimo realioje aplinkoje (in the wild) atvejų publikacijos metu nėra, tačiau pataisymas išleistas vasarį — tie, kurie neatnaujino, jau kelis mėnesius gyvena šalia viešo išnaudojimo.
KAS YRA NF_TABLES
Nftables — Linux branduolio posistemis, pakeitęs iptables. Visa šiuolaikinė Linux ugniasienė veikia per jį: paketų filtravimas, NAT, srauto žymėjimas. Naudojate nft tiesiogiai, firewalld ar nftables per systemd — po gaubtu visur tas pats variklis. Daugumoje šiuolaikinių serverių nf_tables veikia pagal nutylėjimą, net jei niekada nesukonfigūravote ugniasienės taisyklių rankiniu būdu.
nf_tables viduje objektai išdėstyti hierarchiškai: lentelės turi grandines (chains), grandinės turi taisykles, taisyklės sudarytos iš išraiškų. Svarbiausia struktūra šiam pažeidžiamumui suprasti — verdict map, nuosprendžių žemėlapis. Tai atitikmenų lentelė: paketas → veiksmas (priimti, atmesti ar peršokti į kitą grandinę). Galite įsivaizduoti ją kaip maršruto lentelę, tik ne adresams, o sprendimams apie paketo likimą. Verdict map gali turėti įprastus elementus su konkrečiais raktais ir specialų catchall elementą — pakaitalą, kuris suveikia kai paketas neatitinka nieko kito, savotišką taisyklę „viskas kita — daryti štai taip”. Klaida ir slėpėsi būtent jame.
Kad ruleset pakeitimai būtų taikomi atomiškai — be lenktynių su gyvuoju srautu — branduolys naudoja kartų kaukių (generation mask) mechanizmą. Pakeitimai kaupiami „kitoje kartoje” ir vienu perjungimu tampa aktyvūs. Jei paketinė operacija (batch) baigiasi klaida, branduolys paleidžia atšaukimo fazę (abort phase), kuri turi pilnai viską atkurti. Apversta logika slėpėsi būtent tame atkūrime.
KAIP VEIKIA KLAIDA
Klaida — vienas simbolis: šauktukas sąlygoje funkcijoje nft_map_catchall_activate(). Ši funkcija vykdoma abort fazės metu, kad reaktyvuotų verdict map catchall elementus, deaktyvuotus atšaukiamos transakcijos metu.
Teisinga logika: praleisti jau aktyvius elementus, apdoroti neaktyvius. Lygiai taip parašyta analogiška funkcija įprastiems elementams — nft_mapelem_activate(). Catchall versijoje sąlyga apversta: funkcija praleisdavo neaktyvius ir apdorodavo aktyvius — tiksliai priešingai nei reikia. Vienas ! simbolis apvertė visą logiką aukštyn kojomis.
Pasekmės konkrečios. Kai verdict map su NFT_GOTO tipo catchall elementu (nurodančiu grandinę) ištrinamas, grandinės nuorodų skaitliukas (chain->use) sumažinamas — tai normalu, nuoroda pašalinama. Abort fazėje skaitliukas turėtų būti atkurtas, nes ištrynimas atšaukiamas. Dėl apverstos sąlygos atkūrimas nevyksta — kiekvienas abort ciklas visam laikui sumažina chain->use. Kai skaitliukas pasiekia nulį, branduolys mano, kad niekas nebenukreipta į grandinę, DELCHAIN sėkmingai atliekamas ir atlaisvina atmintį — kol kiti objektai ją vis dar nurodo. Tai ir yra use-after-free: prieiga prie jau atlaisvintos atminties.
KAIP TAI IŠNAUDOJAMA
Privilegijų nereikia — tik prieiga prie user namespaces ir nf_tables, pagal nutylėjimą įjungta Debian ir Ubuntu. Ubuntu 24.04 turi papildomų apribojimų namespace kūrimui, tačiau žinomas apėjimas per aa-exec -p trinity -- unshare -Urmin /bin/sh — ši komanda paleidžia shell naujame namespace apeinant AppArmor profilį, kuris paprastai riboja namespace kūrimą.
Ataka sudaryta iš keturių paketų (batches). 1-as paketas: ištrinti pipapo tipo verdict map su catchall elementu, tada tyčia sukelti klaidą tame pačiame pakete — tai paleidžia abort fazę ir sumažina grandinės nuorodų skaitliuką jo neatkuriant. 2-as paketas: išsiųsti bet kurią sėkmingą operaciją generation cursor perjungimui — be šio žingsnio kitas paketas neveiks teisingai. 3-ias paketas: vėl ištrinti verdict map — dabar catchall elementas aktyvus naujojo kartos atžvilgiu, grandinės nuorodų skaitliukas pasiekia nulį. 4-as paketas: ištrinti grandinę — tai pavyksta, nes skaitliukas lygus nuliui, nors bazinė grandinė vis dar turi taisyklę, nurodančią ją. Use-after-free gautas.
Toliau prasideda darbas su branduolio krūva (heap). NFT_MSG_GETRULE užklausa taisyklei, nurodančiai atlaisvintą grandinę, iškviečia nft_verdict_dump() — ji skaito grandinės pavadinimą kaip eilutę iš jau atlaisvintos atminties. Įdėjus ten seq_operations struktūrą per open("/proc/self/stat", 0), užpuolikas gauna rodiklio į branduolio kodą nutekėjimą ir apskaičiuoja branduolio bazinį adresą, apeidamas KASLR. Tada nuteka krūvos adresai, per blob_gen_0 atlaisvintos grandinės manipuliavimą perima valdymo srautą ir vykdoma ROP grandinė. Rezultatas: commit_creds(&init_cred) suteikia procesui root teises, switch_task_namespaces() ant PID 1 sugriauna namespace izoliaciją, ir užpuolikas tampa root serverio lygmenyje.
KAS NUTINKA TOLIAU — PRIKLAUSO NUO KONFIGŪRACIJOS
Išnaudojimas veikia Debian Bookworm ir Trixie, Ubuntu 22.04 LTS ir Ubuntu 24.04 LTS — su nedideliais ROP gadžetų skirtumais tarp branduolio versijų, nes funkcijų poslinkiai ir duomenų struktūros skiriasi tarp skirtingų kompiliacijų. Išnaudojimo stabilumas — >99% neapkrautoje sistemoje ir apie 80% esant Apache benchmark apkrovai. Du nepriklausomi tyrėjų kolektyvai rado skirtingus kelius iki root iš to paties pažeidžiamumo — tai reiškia, kad užblokavus vieną kelią kitas lieka atviras.
Papildomos apsaugos priemonės padeda, bet nėra pilna apsauga. Jei SELinux veikia enforcing režimu, FuzzingLabs variante reikalingas papildomas žingsnis: selinux_state.enforcing nustatymas į nulį per ROP grandinę. ASLR neapsaugo — jį apeina branduolio bazinio adreso nutekėjimas, kuris įvyksta dar prieš bet kokį valdymo srauto perėmimą. Tikra apsauga yra tik dviem atvejais: branduolio pataisymas arba visiškas neprivilegijuotų user namespaces išjungimas.
REALUS ATAKOS SCENARIJUS
Pažeidžiamumas nenaudojamas nuotoliniu būdu — reikalingas vietinis shell. Todėl jis ypač pavojingas kaip antros stadijos ataka: RCE per pažeistą žiniatinklio programą duoda shell www-data vardu, o CVE-2026-23111 per kelias sekundes paverčia tą shell į root. Užpuolikas visiškai kontroliuoja serverį: skaito /etc/shadow, ištraukia SSH raktus, perima srautą, modifikuoja sisteminių tarnybų dvejetainius failus. Konteinerinė izoliacija subyra per switch_task_namespaces() iškvietimą ant PID 1 — užpuolikas išeina už konteinerio namespace izoliacijos ribų ir atsiduria serverio lygmenyje.
Didžiausia rizika gresia daugiavartotojiniams serveriams, VPS su bendromis branduolio kopijomis, CI/CD runneriams ir bendro naudojimo hostingo aplinkoms — visur, kur neprivilegijuoti vartotojai ar darbo krūviai gali kurti namespaces. Bendro naudojimo hostinge viena pažeista svetainė tampa įėjimo tašku visam serveriui ir visoms gretimosioms svetainėms. Debesų serveryje su multi-tenant branduoliu — tai konteinerio pabėgimo galimybė.
LAIKO JUOSTA
Exodus Intelligence aptiko pažeidžiamumą 2025 m. pradžioje nf_tables posistemio tyrimo metu. 2026 m. vasario 5 d. pataisymas pateko į Linux branduolio upstream (komitas f41c5d151078c5348271ffaf8e7410d96f2d82f8) — pašalinta viena eilutė su apversta sąlyga, tą pačią dieną priskirtas CVE-2026-23111. 2026 m. balandžio 16 d. FuzzingLabs (Alexis ir Lyes), ruošdamiesi Pwn2Own Berlin 2026, nepriklausomai atkartojo pažeidžiamumą ir paskelbė pilną PoC su techniniu aprašu. 2026 m. birželio 8 d. Exodus Intelligence (Oliver Sieber) išleido išsamų writeup su veikiančiu išnaudojimu, patvirtintu Debian Bookworm, Trixie, Ubuntu 22.04 LTS ir 24.04 LTS.
Tarpas tarp pataisymo (vasario 5 d.) ir pirmojo viešo veikiančio išnaudojimo (balandžio 16 d.) buvo vos 70 dienų. Per tą laiką neatnaujintos sistemos jau turėjo prieš save veikiantį išnaudojimą viešai paskelbtą. Birželio mėnesį, kai pasirodė antrasis išsamesnis writeup, šis tarpas viršijo keturis mėnesius — tai reiškia, kad visa tą laiką neatnaujintų sistemų administratoriai dirbo su žinoma viešai atskleista spraga.
KODĖL TAI SVARBU
Linux branduolio LPE per nf_tables — ne nauja istorija. CVE-2022-1015, CVE-2022-1016, CVE-2022-32250, CVE-2023-32233 — šis posistemis turi turtingą CVE istoriją, ir kaskart pagal panašią schemą: sudėtingas transakcinis mechanizmas, retas vykdymo kelias, corner case kurio niekas netestavo. CVE-2026-23111 puikiai įsilieja: komanda, pasirinkusi nf_tables Pwn2Own Berlin 2026 būtent todėl, kad menkai žinojo posistemį, nedelsiant rado išnaudojamą klaidą. Tai ne nesėkmė — tai sukauptos techninės skolos simptomas saugumui kritiškame kode.
CVE-2026-23111 pasirodė ryškaus Linux LPE pažeidžiamumų antplūdžio fone. Pastaraisiais mėnesiais tyrėjai atskleidė Copy Fail (CVE-2026-31431) — klaidą copy-on-write mechanizme, Dirty Frag ir jo variantą Fragnesia (CVE-2026-46300) — heap fragmentation XFRM ESP-in-TCP posistemyje, DirtyDecrypt ir devynerių metų senumo ptrace pažeidžiamumą (CVE-2026-46333). Skirtingi posistemiai, skirtingos technikos — bet viena nuolatinė schema: neprivilegijuotas atsparos taškas viduje, root serveryje išorėje. Bendras vardiklis daugumai šių pažeidžiamumų — user namespaces, atveriančios neprivilegijuotiems vartotojams prieigą prie branduolio sąsajų. Organizacijos, neturinčios tiesioginės operacinės būtinybės neprivilegijuotiems user namespaces, turėtų rimtai apsvarstyti jų išjungimą pagal nutylėjimą.
PAPILDOMAS APSAUGOS SLUOKSNIS
Kartu su branduolio pataisymu verta apsvarstyti dar vieną požiūrį — atakos paviršiaus mažinimą užblokuojant nenaudojamus branduolio modulius. Dauguma serverių paleidžia tūkstančius modulių, nors realiai naudoja tik kelis šimtus. Kiekvienas nenaudojamas modulis yra potencialus vektorius kitam LPE atskleidimui. modulejail tai sprendžia paprastai: nuskaito šiuo metu įkeltų modulių sąrašą ir sukuria modprobe.d juodąjį sąrašą visiems kitiems. Jei modulis šiuo metu nereikalingas — jis nebus įkeltas.
Svarbus apribojimas: modulejail reikia paleisti tik tada, kai sistema pasiekė darbinę būseną — visos tarnybos paleistos, visos failų sistemos sumontuotos, visi reikalingi tvarkyklės įkelti. Paleidus per anksti rizikuojama į juodąjį sąrašą įtraukti modulius, kurie vėliau gali prireikti. Atšaukimas rankinis: ištrinti /etc/modprobe.d/modulejail-blacklist.conf ir perkrauti serverį.
Įdiegimas Debian/Ubuntu sistemose:
sudo apt install modulejail
RHEL/Fedora/Alma/Rocky sistemose:
sudo dnf install modulejail
Paleidimas pasiekus darbinę būseną — konservatyvus profilis skirtas serveriams:
sudo modulejail
modulejail netaiso pažeidžiamumų ir netikrina CVE duomenų bazių — tai atakos paviršiaus mažinimo įrankis, o ne branduolio atnaujinimų pakaitalas. Naudokite jį kaip papildomą sluoksnį po to, kai branduolys jau atnaujintas.
ATNAUJINIMAS
Pataisymas upstream nuo 2026 m. vasario 5 d., distribucijos išleido atnaujintus branduolio paketus. Debian ir Ubuntu sistemose atnaujinimas paleidžiamas įprasta komanda — apt update sinchronizuoja paketų sąrašus su repozitorijomis, apt upgrade įdiegia visus galimus atnaujinimus, įskaitant naują branduolį:
sudo apt update && sudo apt upgrade
Po naujo branduolio įdiegimo būtinas perkrovimas — atnaujintas paketas yra diske, tačiau sistema toliau veikia su senu branduoliu atmintyje iki paleidimo iš naujo. Komanda reboot tvarkingai užbaigia visus procesus ir pakrauna sistemą su nauju branduoliu:
sudo reboot
Po perkrovimo patikrinkite, kad sistema tikrai veikia su atnaujintu branduoliu — komanda uname -r išveda veikiančio branduolio versiją. Ubuntu ir Debian saugumo pataisymai dažnai atgaline data perkeliami (backport) nekeičiant pagrindinės versijos numerio, todėl versija gali atrodyti kaip anksčiau, bet kompiliavimo data bus naujesnė. Norėdami įsitikinti, kad paketas aktualus, patikrinkite kompiliavimo datą komanda apt-cache policy linux-image-$(uname -r) — eilutėje Installed turėtų būti data po 2026 m. vasario:
uname -r
apt-cache policy linux-image-$(uname -r)
Jei šiuo metu atnaujinti neįmanoma, laikina priemonė — išjungti neprivilegijuotus user namespaces. Tai blokuoja išnaudojimo vektorių, nes užpuolikas nebegalės sukurti izoliuoto namespace darbui su nf_tables be privilegijų. Šalutinis poveikis: nebeveiks rootless konteineriai (rootless Docker, Podman, LXC), kai kurie naršyklių sandbox ir kūrimo įrankiai. Debian ir Ubuntu reikalingi abu parametrai — kernel.unprivileged_userns_clone išjungia user namespace kūrimą branduolio lygiu, user.max_user_namespaces nustatomas į nulį:
sudo sysctl -w kernel.unprivileged_userns_clone=0
sudo sysctl -w user.max_user_namespaces=0
Šios reikšmės nustatomos iš naujo po perkrovimo. Kad išliktų nuolat, pridėkite eilutes į sysctl konfigūracijos failą — branduolys jas automatiškai perskaitys paleidimo metu:
kernel.unprivileged_userns_clone=0
user.max_user_namespaces=0
RHEL tipo sistemose parametras kernel.unprivileged_userns_clone neegzistuoja — ten pakanka tik user.max_user_namespaces=0. Debian ir Ubuntu reikalingi abu: nustačius tik vieną, antrasis parametras palieka vektorių iš dalies atvirą.
IŠVADOS
Vienas simbolis abort fazės sąlygoje — ir neprivilegijuotas vartotojas gauna root. Ne todėl, kad ataka sudėtinga, o todėl, kad nf_tables transakcines logikos corner case metų metus niekas netestavo, o user namespaces atvėrė prie jo prieigą be jokių privilegijų. Veikiantis viešas išnaudojimas su 99% stabilumu jau egzistuoja, patvirtintų naudojimo realioje aplinkoje atvejų kol kas nėra — tačiau tas langas užsidaro.
Sistemos administratoriams: atnaujinkite branduolį ir perkraukite serverį. Tai vienintelis patikimas sprendimas. Jei negalima nedelsiant — išjunkite neprivilegijuotus user namespaces kaip laikiną priemonę, žinant, kad tai paveiks konteinerines darbo krūvas. Prioritetas visų pirma bendro naudojimo hostingo serveriams, konteinerių hostams ir CI/CD runneriams — ten neprivilegijuotas shell greičiausiai virsta root. Debesų aplinkų su multi-tenant branduoliais teikėjams — tai aukščiausio prioriteto užduotis dabar.
