Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
page_inject — CVE-2026-31431-killed page-cache эксплойт — выполнение кода в контейнерах, совместно использующих один и тот же слой образа | Kitploit
Инструменты/GitHubGitHub/sgkdev/page_inject
Анализ уязвимостейЭксплуатацияПост-эксплуатацияТестирование на ПроникновениеRed TeamingПобег из КонтейнераЭксплуатация Бинарных Файлов
GitHubsgkdev/page_inject

page_inject

CVE-2026-31431-killed page-cache эксплойт — выполнение кода в контейнерах, совместно использующих один и тот же слой образа

Репозиторий
7414694 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

page_inject — межконтейнерный эскейп через AF_ALG aead

Межконтейнерный эксплойт уязвимости AF_ALG aead — переход из одного скомпрометированного контейнера во все соседние контейнеры, использующие тот же слой образа libc.so.6.

Это примитив эскейпа: он запускается изнутри непривилегированного контейнера, который атакующий уже скомпрометировал, и использует 4-байтовую ошибку произвольной записи при ротации ESN в authencesn из AF_ALG (CVE-2026-31431), чтобы внедрить постоянный хук read() в страницы page-cache файла libc.so.6. Поскольку в Docker / containerd файлы нижних слоёв overlayfs опираются на общие inode, эти страницы видны каждому соседнему контейнеру, созданному из того же образа: хук срабатывает и в их процессах, и атакующий получает выполнение команд в каждом из них.

Модель угроз

  • Атакующий имеет доступ к shell в одном контейнере (назовём его victim) на хосте, где работают другие контейнеры (siblings) из того же образа, что и victim.
  • victim работает в стандартной конфигурации Docker/k8s: непривилегированный uid внутри пользовательского пространства имён контейнера, профиль seccomp по умолчанию, профиль AppArmor по умолчанию, без специальных capabilities, без bind-монтирований хоста.
  • victim имеет только:
    • доступ на чтение к своей libc (/usr/lib/x86_64-linux-gnu/libc.so.6 или туда, куда её устанавливает дистрибутив)
    • стандартное семейство системных вызовов socket(AF_ALG, ...)
    • стандартные системные вызовы splice / vmsplice
    • доступ на запись в каталог, к которому можно применить chmod +x (например, /tmp)
  • Ядро должно быть уязвимо к CVE-2026-31431 (любая сборка algif_aead + authencesn до исправления-отката в апстриме).

На этом всё. Никаких специальных CAP_*, никакого доступа к файловой системе хоста. Атакующий помещает самодостаточный статически слинкованный бинарник в контейнер, запускает его — и повреждение page-cache, а следовательно и хук, становится видимым для всех соседних контейнеров.

Как эксплойт собирается в цепочку

  1. Идентичность страниц page-cache. В контейнере на overlayfs путь /usr/lib/.../libc.so.6 обслуживается ext4-inode нижнего слоя образа. Каждый контейнер, запущенный из того же образа, разделяет этот нижележащий inode, а page-cache ядра индексируется по нижележащему inode — не по overlay и не по пространству имён. Поэтому одна 4-байтовая запись в страницу page-cache видна всем процессам соседних контейнеров, у которых эта страница отображена через mmap.

  2. Уязвимость AF_ALG aead превращает одну такую запись во множество. algif_aead сцепляет пользовательский RX iovec с хвостовыми authsize байтами сцепленного TX SGL, а при ротации ESN в authencesn 4 байта поля seq_high из AAD размещаются в dst[assoclen + cryptlen] — то есть в первом байте этого сцепленного чужого хвоста. Сцепленная страница — это страница page-cache файла, к которому атакующий имеет только доступ на чтение, но шифр всё равно копирует в неё байты, не помечая страницы как dirty. (Подробнее о механике — в crypto/algif_aead.c и crypto/authencesn.c.)

  3. Инициализация вызываемого примитива. Первым делом page_inject разворачивает зону A — закодированную на asm повторную реализацию той же схемы AF_ALG (write_cache.asm), размещённую в кармане секции .text libc. Это превращает 4-байтовую запись в обычный call из любого будущего кода хука — без необходимости настраивать сокет для каждого вызова.

  4. Установка хука. Затем инжектор записывает зону C (zone_c.asm) в карман секции .text libc и патчит первые 7–12 байт read() переходом E9 disp32 на неё. Вытесняемые байты пролога точно эмулируются в быстром пути зоны C (распознаются три разных пролога glibc — см. «Обработка пролога read()» ниже). Теперь хук активен в page-cache libc.

  5. Распространение хука. В каждом соседнем контейнере процессы постоянно вызывают read() (демоны журналирования, healthcheck-скрипты, cat /etc/hostname — что угодно). При первом таком вызове внутри соседнего контейнера перехваченный пролог прыгает в зону C, которая:

    • выполняет stat("/") для корневого inode контейнера (стабильный идентификатор для каждого пространства имён) и использует его как ключ слота контейнера;
    • сканирует таблицу слотов в поисках существующей записи с этим ключом;
    • если записи нет, регистрирует ключ и fork()-ает долгоживущего дочернего процесса командного цикла, который опрашивает область CMD на предмет команд;
    • возвращается к read()+N, так что вызывающий код ничего не замечает. Исходный процесс соседнего контейнера продолжает работать. С этого момента у атакующего есть демон внутри этого контейнера.
  6. Канал команд. Атакующий использует тот же бинарник page_inject в режиме --shell, чтобы записывать команды в область CMD региона слотов. Дочерний процесс хука каждого зарегистрированного соседнего контейнера опрашивает её, запускает /bin/sh -c <cmd>, захватывает stdout/stderr в область OUTPUT, сигнализирует о завершении и возвращается к опросу. Shell показывает вывод. Поскольку каждая запись в CMD/OUTPUT тоже идёт через примитив уязвимости, никаких особых привилегий не требуется.

  7. Снятие хука. По завершении работы unhook восстанавливает исходные байты пролога read() и обнуляет таблицу слотов; дочерние процессы хуков при следующей итерации видят пустой слот и завершаются сами. Сами изменения page-cache чистые (ядро никогда не помечало изменённые страницы как dirty), поэтому как только все контейнеры с отображённой через mmap libc остановлены, drop_caches полностью восстанавливает кэш — на диске не остаётся никаких следов.

Сборка

Инжектор собирается вне контейнера-жертвы — как правило, на собственной машине разработки атакующего, — потому что в большинстве продакшен-образов контейнеров нет компилятора. Достаточно стандартного окружения разработки Linux x86_64 с gcc (с поддержкой статической линковки -static) и nasm.

make            # assembles .asm sources via gen_arrays.sh, links static page_inject
make shellcode  # also produces inspectable .bin flat binaries
make clean      # removes generated files and the binary

Результат сборки — единый статически слинкованный ELF (./page_inject), который запускается на любом современном ядре Linux x86_64.

Доставка и использование (из контейнера-жертвы)

Получив shell в victim, атакующий загружает бинарник в доступный для записи каталог (обычно /tmp):

# inside the compromised container, attacker session
victim$ ./page_inject

Без аргументов page_inject использует путь по умолчанию /usr/lib/x86_64-linux-gnu/libc.so.6 (расположение Debian/Ubuntu после объединения каталогов). В других дистрибутивах libc лежит по другому пути; можно либо передать его явно, либо использовать --root /, чтобы просканировать встроенную таблицу путей от корня контейнера:

# Fedora / Rocky / CentOS
victim$ ./page_inject /usr/lib64/libc.so.6

# Arch
victim$ ./page_inject /usr/lib/libc.so.6

# Auto-detect, regardless of distro:
victim$ ./page_inject --root /

Оба варианта запуска делают одно и то же: разбирают ELF внутриконтейнерной libc, устанавливают хук в её page-cache, ~30 секунд наблюдают за таблицей слотов, пока регистрируются соседние контейнеры, и в качестве проверки работоспособности однократно выполняют id в первом зарегистрировавшемся соседнем контейнере.

После начальной установки можно войти в интерактивную командную оболочку и управлять любым зарегистрированным соседним контейнером:

victim$ ./page_inject --shell --no-bootstrap
=== page-cache shell ===
Containers (3):
  [0] 0x0018598d  <- target
  [1] 0x001859ab
  [2] 0x001859cd

inject:0018598d> exec id
uid=0(root) gid=0(root) groups=0(root)
inject:0018598d> target 0x001859ab
inject:001859ab> exec hostname
1ccd66abee9d
inject:001859ab> exec cat /etc/shadow
root:$6$.....
inject:001859ab> unhook
... read() prologue restored, slot table zeroed ...
Скачать инструмент