Contents

Пълен курс по етичен хакинг: от нула до експерт
Хаквайте като Black Hat хакери. Тестване за проникване, Kali Linux, WiFi и уеб хакинг, както и хакерският начин на мислене зад тях.
Уязвимост на 2 години в ядрото на Linux позволи на процес от вътрешността на контейнер да получи root достъп на хост машината. 82 процента от потребителите на контейнери използват Kubernetes в производствена среда. Един експлойт, започващ абсолютно без никакви права. Той спечели конкурса на Google за хакване на ядрото през юли и донесе награда от 71 337 долара.
Контейнерите поемат голяма част от модерната инфраструктура и този дял продължава да нараства. Преди три години той беше 66 процента. Облачни приложения, уебсайтове, които се разширяват при пристигане на трафик, AI работни товари, които се появяват и отново изчезват, вътрешни инструменти, които никога не напускат компанията: всичко това са контейнери. И причината компаниите да са готови да пуснат код, на когото нямат доверие, в контейнер, е че контейнерът трябва да държи този код изолиран от всичко останало на машината.
Контейнерът не е отделен компютър. Той не е виртуална машина със собствена операционна система. Той е набор от обикновени процеси, изпълняващи се на същото ядро като всичко останало на тази машина, изолирани с namespaces, cgroups и seccomp филтри. Оградата се изгражда от ядрото. Пробиете ли ядрото, ограда вече няма.
Процес вътре в контейнера, изпълняван от стандартен потребител без специални права, задейства грешка в ядрото и го превзема. Оттам той става root на хоста. Не root вътре в контейнера, което означава много малко, тъй като контейнерът е фикция, поддържана от ядрото. Root на физическата машина отдолу. От тази позиция атакуващият достига до останалите контейнери на този хост, самата среда за изпълнение на контейнери (container runtime) и, при клъстер, възела (node), към който той принадлежи.
Преди една година показах как изолацията на контейнерите се срива: привилегирован флаг, открит API, тайни на разположение в открит вид. И трите са грешни конфигурации, изоставени от kогото и да било. Тази уязвимост не се нуждае от нищо от това. Стандартен контейнер и една грешка в ядрото.
Грешката се намира в ъгъл от ядрото, на който се обръща много малко внимание. Сокетите от тип Unix domain sockets — сокетите, които два процеса на една и съща машина използват, за да си комуникират — могат да пренасят повече от данни. Те могат да пренасят отворен файл. Предавате файлов дескриптор на друг процес в съобщение, наречено SCM_RIGHTS, и на получаващата страна този процес вече има отворения файл с абсолютно същите права за достъп, каквито сте имали вие.
Услуга предава своите активни връзки на мениджъра на услуги по този начин, преди да се рестартира, и ги получава обратно след това, така че нищо да не се губи, докато тя не работи. Браузър предава на своя renderer в изолирана среда единия край на нова двойка сокети по този начин, така че този renderer да може да поиска от помощен процес нещата, които изолираната среда му пречи да прави сам. Механизмът е по-стар от повечето код около него и се изпълнява постоянно на машини, където не привлича никакво внимание.
Предаването на файлови дескриптори по този начин създава един проблем. Сокет може да изпрати файлов дескриптор за друг сокет. Два сокета могат да се окажат държащи дескриптор един за друг. Сега нито един от тях не може да бъде почистен, защото всеки държи другия жив, а нито един процес не използва нито един от двата. Това е циклично рефериране (reference cycle) и то източва памет от ядрото, докато машината не се рестартира.
Затова ядрото изпълнява инструмент за събиране на отпадъци (garbage collector) за Unix сокети. То изгражда граф. Сокет с дескриптори в процес на изпращане става struct unix_vertex, а дескриптор в процес на изпращане става struct unix_edge, сочещ към получаващия сокет. Collector-ът обхожда този граф, търсейки групи от сокети, които сочат само един към друг и към нищо отвън. Тези групи се наричат силно свързани компоненти (strongly connected components). Ако нищо извън дадена група все още не се нуждае от нея, collector-ът я освобождава.
Изграждането на този граф от нулата всеки път би било скъпо, затова ядрото кешира намерените компоненти. Даден върхови елемент (vertex) пази указател към пръстен от останалите върхове в своя компонент, наречен scc_entry. При следващото преминаване бързият път обхожда този кеширан пръстен, вместо да изчислява каквото и да е отново.
Две неща се объркват и те трябва да се случат едновременно.
Първото е таймингът. Когато процес изпрати съобщение с файлов дескриптор в него, ядрото публикува новия реброви елемент (edge) в графа, преди да постави съобщението в опашката за получаване. unix_add_edges() се изпълнява първи, __skb_queue_tail() втори, а между тях кодът освобождава unix_gc_lock. Това отваря прозорец, в който инструментът за събиране на отпадъци може да види връзка, която е била обявена, но все още не е доставена.
Второто е почистването. Когато даден край изчезне, unix_del_edge() премества върха в списък със свободни елементи. То никога не премахва този връх от пръстена scc_entry, в който е бил кеширан. Върхът се освобождава. Пръстенът все още сочи към него.
Съществуват два компонента и единият сочи към другия. Процес изпраща на сокет съобщение, съдържащо самия него, и в същия момент и двата сокета биват затворени. Затварянето приключва първо. Collector-ът се изпълнява и маркира двойката като мъртва, но саморефериращият се край спира единия от двата сокета от почистване. При следващото преминаване collector-ът избира бързия път през кеширания пръстен, следва остарелия указател и чете и записва в памет, която вече е върната на ядрото.
Това е уязвимост от тип use-after-free в паметта на ядрото, достъпна от локален потребител с обикновен акаунт. Оценката е 7.8, вектор AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. Локален достъп, ниска сложност, ниски привилегии, не се изисква взаимодействие. Веднъж след като преминете, можете да прочетете какво има на тази машина, да го промените и да я изключите.
Това е достъпно от Linux 6.10, пуснат на 14 юли 2024 г. Две години и три седмици преди да бъде внедрена корекцията за сигурност. И тъй като collector-ът беше портнат обратно (backported) в стабилните клонове, ядрата от 6.1.141 и 6.6.93 нататък също я съдържат, въпреки че кодът е написан за много по-късно ядро.
Къмитът, който внесе уязвимостта, беше корекция за почистване на кода. През март 2024 г. поддържащият кода на Unix сокетите замени стария алгоритъм за събиране на отпадъци (garbage collection) с описания по-горе. Три файла бяха променени, 64 реда бяха добавени, 258 реда бяха премахнати. Полета като inflight, link и gc_flags бяха премахнати от struct unix_sock, а функциите unix_inflight() и unix_notinflight() изчезнаха напълно. 194 реда по-малко в кода на ядрото, вършещи същата работа по-бързо. Но също така липсваше един list_del.
Експлойтът е дело на Zhenpeng Lin, а това име има тежест в тази област. Той е защитил докторската си степен в Северозападния университет. През 2022 г. публикува DirtyCred — техника, която заменя непривилегировани обекти с идентификационни данни в ядрото с привилегировани такива и превръща широк клас от уязвимости в ядрото в root достъп. През същата година той публикува GREBE — система за определяне доколко дадена уязвимост в ядрото всъщност може да бъде експлоатирана. В момента той работи в DepthFirst, фирмата, стояща зад това изследване.
Уязвимостта беше открита от dfs-large1 — модел, който фирмата създаде върху GLM 5.2 и след това дообучи с подкрепящо обучение (reinforcement learning) в собствена среда за агенти. Той е обучен да изпълнява три задачи едновременно: да намира уязвимости в приложения, да ги открива в системен код от ниско ниво и да преценява дали потенциалното откритие е основателно. Те са въвели глоба за натрупания бюджет спрямо броя върнати констатации, така че моделът губи точки при нагаждания и предположения.
Докато фирмата работеше по това, някой друг откри същата уязвимост независимо и ръчно. Kyle Zeng я докладва на екипа по сигурността на ядрото и неговото име фигурира в къмита:
Доктор по философия от Щатския университет на Аризона, основен разработчик на angr, поддържащ how2heap. Победител в Pwn2Own през 2022, 2023 и 2024 г. През август 2022 г. той взе първата максимална награда в историята на програмата kCTF — 91 337 долара, и е осъществявал бягство от контейнери в Google Kubernetes Engine пет отделни пъти, използвайки четири различни техники.
Модел и изследовател с такъв рекорд откриха една и съща дупка в рамките на няколко седмици един от друг, в код, който бе стоял недокоснат в продължение на две години.
Корекцията беше написана от човека, който е създал уязвимостта. Kuniyuki Iwashima поддържа кода за Unix сокети. Той е автор на пренаписването от март 2024 г. от адрес на Amazon и на корекцията от 4 август 2026 г. от адрес на Google. Един и същ поддържащ разработчик, един и същ файл, с разлика от две години.
Един ред. Премахване на върха от пръстена, преди той да изчезне.
Този един ред получи отзив два дни по-късно и то не от човек. Пощенският списък за мрежовия стек на ядрото бе започнал да прекарва корекциите през AI рецензент това лято. На 6 август поддържащият мрежовия стек препрати неговия отговор в нишката ръчно, с бележка най-отгоре, че това е рецензия, генерирана от изкуствен интелект.
Рецензията остави самата корекция без промяна и се насочи към брояча, който проследява колко циклични компонента все още съдържа графът. Бързият път намалява този брояч без проверка, така че остатъчен пръстен може да намали стойността, докато цикличните компоненти са все още там. И ако два остатъчни пръстена се появят при едно преминаване, докато броячът е на 1, второто намаляване води до превъртане на unsigned long до ULONG_MAX. Това блокира графа в циклично състояние и оттогава нататък изпращането през fd използва бавния синхронен път.
Тридесет минути по-късно авторът на корекцията отговори: добра забележка, изглежда Claude в момента е по-добър от Gemini. Той добави втори ред, if (list_empty(&scc)) cyclic_sccs--;, така че броячът да намалява само когато компонентът е празен.
Модел откри уязвимостта и модел рецензира корекцията за сигурност, за един и същ патч, в една и съща седмица. Човекът, написал както уязвимостта, така и корекцията, сравни публично двата модела в пощенския списък.
Експлойтът не беше публикуван веднага в интернет. На 24 юли 2026 г. той бе изпратен в kernelCTF — програмата, която плаща фиксирана сума за работещ експлойт срещу защитена целева система на ядрото. Заявката спечели своето място, фирмата бе уведомена на 5 август и тя докладва уязвимостта на екипа по сигурността на ядрото същия ден. Корекцията в основния клон (upstream) влезе на 6 август. Идентификаторът CVE беше публикуван на 26 август.
Заявката е публична: pull request 431 в репозиторито security-research, отворен на 14 септември срещу целта lts-6.12.95, съдържащ изходния код, описанието и предварително компилиран бинарен файл. На 18 септември инженер добави важния етикет vuln OK, което означава, че човек е потвърдил ръчно, че експлойтът прави това, което твърди.
Ядрото беше коригирано на 6 август. Ubuntu все още не е пуснала обновяването. Изследването и работещият експлойт станаха публични на 22 септември. Към 24 септември собственият тракър на Ubuntu изглежда така:
- → 26.04: дванадесет пакета на ядрото са уязвими, като основният е маркиран като в процес на разработка
- → 24.04: четиринадесет пакета на ядрото са уязвими, включително
linux-gke - → 22.04: стандартното ядро не е засегнато, но
linux-hwe-6.8,linux-ibm-6.8иlinux-oracle-6.8са уязвими
Именно на този последен ред повечето отразявания сгрешиха и в двете посоки. Ако стартирате 22.04 със стандартното ядро, вие сте извън риска. Ако стартирате 22.04 с ядрото за поддръжка на нов хардуер (hardware enablement kernel), което е точно това, което инсталирате, когато машината ви е по-нова от версията на дистрибуцията, тогава сте засегнати. Една и съща дистрибуция, един и същ номер на версията, противоположен отговор.
Публикуваните експлойти са предназначени за Ubuntu 26.04 върху 7.0.0-31-generic и Ubuntu 24.04 върху 6.8.0-139-generic и са твърдо кодирани за тези версии. Те проверяват низа на версията и прекратяват работа, ако той не съвпада. Това обаче дава по-малко успокоение, отколкото изглежда, тъй като изходният код е публично достъпен.
Още един детайл в тази двойка. Вторият експлойт покрива CVE-2026-52910 — уязвимост от тип use-after-free в кода на reuseport за класически BPF програми в net/core/sock_reuseport.c. В Ubuntu 26.04 тази уязвимост вече е отстранена в 7.0.0-31.31. Което е точно версията, към която е насочен първият експлойт. Машината, в която са влезли, е имала инсталирана едната корекция за сигурност, но не и другата.
За изследователите това е нещо по-голямо от един лош месец за една дистрибуция. Бариерата за излизане от контейнер през ядрото е паднала толкова ниско, че трябва да предположите, че атакуващият може да излезе, когато си поиска. Те са преброили 5,976 уникални Linux kernel CVEs, публикувани през 2026 г. до средата на септември. Само на август се падат 1,650, което е повече от четвърт от общия брой за годината. А от 36-те, публикувани публично от kernelCTF, 13 са достъпни от обикновени непривилегировани интерфейси — именно такъв тип интерфейс се намира в контейнерните образи, използвани в момента.
Те искат индустрията да спре да третира споделеното ядро като граница за код, на който нямате доверие, и да премести тази работа към microVM. Firecracker и Kata Containers дават на всеки работен товар собствено малко ядро, така че експлойтът на ядрото струва на атакуващия само неговия собствен инстанс и нищо извън него. Това е разликата между загубата на една задача и загубата на машината, на която се е изпълнявала тази задача.
Какво да направите, ако това засяга нещо, което изпълнявате:
- → Проверете ядрото, което използвате:
uname -r - → 6.10 или по-ново ви поставя в засегнатия обхват, както и 6.1 с версия .141 или по-висока, или 6.6 с версия .93 или по-висока
- → Коригираните версии са
6.12.111,6.18.53,7.1.10и7.2и по-нови - → На 22.04 разберете дали използвате стандартното ядро или ядро за хардуерна съвместимост (hardware enablement kernel), тъй като отговорът се различава
- → Не изпълнявайте код, на който нямате доверие, в контейнер на хост, който е важен за вас, докато ядрото на този хост е без инсталирани корекции за сигурност
- → Следете страницата на дистрибуцията за това CVE, вместо да чакате да получите имейл
Изпълнете uname -r на вашата собствена машина тази вечер и вижте дали ядрото, на което се доверявате, е сред засегнатите.