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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-8933 — Доказательство концепции на C для CVE-2026-8933 — локальное повышение привилегий в snap-confine с использованием замораживания cgroup, гонок символических ссылок и внедрения правил udev для выполнения команд от имени root. | Kitploit
Инструменты/GitHubGitHub/yifengchen-cc/cve-2026-8933
Повышение привилегийБезопасность контейнеровАнализ уязвимостейЭксплуатация
GitHubyifengchen-cc/cve-2026-8933

CVE-2026-8933

Доказательство концепции на C для CVE-2026-8933 — локальное повышение привилегий в snap-confine с использованием замораживания cgroup, гонок символических ссылок и внедрения правил udev для выполнения команд от имени root.

Репозиторий
14 дней назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2026-8933 — локальное повышение привилегий через snap-confine set-capabilities PoC

Воспроизвести бюллетень Qualys «Local Privilege Escalation in set-capabilities versions of snap-confine» (https://cdn2.qualys.com/advisory/2026/07/21/snap-confine-set-capabilities.txt).

Проверено на локальной машине (Ubuntu 25.10 / snapd 2.73+ubuntu25.10.1 / ядро 6.17): начиная с uid 1000, в итоге systemd-udevd выполняет команду от имени root, /tmp/pwned получает uid=0(root) gid=0(root) groups=0(root), что совпадает с эффектом, продемонстрированным в конце объявления.

Записи о подводных камнях в процессе воспроизведения и о том, почему при первой оценке было ошибочно решено, что «эксплуатация невозможна», см. в NOTES.md.

Файлы

ФайлОписание
poc.cПолный PoC (один файл)
MakefileСборка (линковка с установленной в системе libfuse3.so.3.17.4)
include/Заголовочные файлы libfuse3 3.17.4 (соответствуют системной библиотеке времени выполнения)
NOTES.mdЗаписи о подводных камнях + ретроспектива методологии анализа достижимости

Принцип уязвимости

cmd/snap-confine/mount-support.c (snapd 2.73):

sc_bootstrap_mount_namespace()      // 第 475 行起
  479:  mkdtemp("/tmp/snap.rootfs_XXXXXX")          <- 目录先归调用者所有
  491:  sc_do_mount(scratch, scratch, NULL, MS_BIND)
  498:  sc_do_mount("none", scratch, NULL, MS_UNBINDABLE)
  503:  sc_do_mount("none", scratch, "tmpfs", ...)
  504:  sc_replicate_base_rootfs(scratch, rootfs_dir, mounts)

sc_replicate_base_rootfs()
  330:  chown(scratch, 0, 0)
  418:  fd = open(full_path, O_CREAT | O_TRUNC, 0644)   <- 缺少 O_NOFOLLOW
  422:  fchown(fd, 0, 0)

Номера строк взяты из исходного кода snapd 2.73 на этой машине (cmd/snap-confine/mount-support.c). В бюллетене Qualys цитируется собственная копия файла, и соответствующие номера строк — 511 / 523 / 530 / 535 / 536 / 362 / 450 / 454 — операторы соответствуют один к одному, различаются только номера строк.

Локальный /usr/lib/snapd/snap-confine имеет mode=755 + файловые capabilities (а не setuid-root), поэтому он работает с euid атакующего, но при этом обладает почти root-овыми возможностями: создаваемые им каталоги и файлы в течение короткого времени принадлежат атакующему, а open() в строке 418 следует по символическим ссылкам.

Дизассемблирование подтверждает: на этой машине флаги open@plt равны 0x240 (O_CREAT|O_TRUNC, без O_NOFOLLOW); в исправленной версии 2.77.1 в той же точке — 0x20240.

Шесть шагов PoC

  1. Поместить snap-confine в собственный cgroup: systemd-run --user --scope --unit=snap.<snap>.<app>. Этот scope принадлежит текущему пользователю, cgroup.freeze доступен для записи, поэтому можно пропускать snap-confine по одному системному вызову за раз.
  2. Заморозить в правильной точке: при SNAPD_DEBUG=1 snap-confine печатает associated snap application process ... with device cgroup. Эта строка появляется после attach BPF-программы к device cgroup и до mkdtemp(). Нельзя замораживать раньше: BPF-верификатор при наличии freeze trap возвращает EAGAIN, и snap-confine просто завершается. stderr подключён к pty (не к каналу): иначе stdio будет блочно буферизован, и маркер часто сбрасывается только после mkdtemp() и bind mount. Кроме того, scope запускается с CPUQuota=1%: от маркера до mkdtemp() проходит всего несколько сотен микросекунд процессорного времени, что сравнимо с задержкой пробуждения перехватывающего процесса; ограничение растягивает это окно в реальном времени до миллисекунд, а после подтверждения заморозки cpu.max немедленно восстанавливается до 100%.
  3. Заменить scratch-каталог символьной ссылкой на наш собственный каталог: mount(2) следует по символьным ссылкам в целевом пути, поэтому bind/unbindable/tmpfs snap-confine все оказываются на <scratch>.dA, а цикл копирования по-прежнему использует scratch-каталог как строку.
  4. Дождаться монтирования tmpfs (ns_mount_count(sc, .dA) >= 2), затем перенаправить символьную ссылку на <scratch>.dB и поместить в dB символьные ссылки с теми же именами, что у обычных файлов верхнего уровня base rootfs, указывающие на /run/udev/rules.d/97-cve-2026-8933-<pid>-<rand>.rules. В этот момент разрешение пути в цикле копирования попадает в dB — обычный каталог, полностью контролируемый нами. tmpfs остаётся в dA и больше нам не мешает. Внимание: когда на .dA только 1 монтирование, это bind mount (/tmp сам по себе tmpfs, после bind fstype остаётся tmpfs); перенаправлять можно только после появления 2-го монтирования (настоящего tmpfs), иначе mount --make-unbindable в snap-confine завершится с EINVAL, так как путь больше не является корнем монтирования.
  5. Выиграть окно между open()/fchown(): цикл копирования для первого обычного файла выполняет open(O_CREAT|O_TRUNC) (следуя по символьной ссылке, создавая файл от имени root в /run/udev/rules.d), затем fchown(fd,0,0). В этот момент файл всё ещё принадлежит нам. PoC использует два средства одновременно:
    • основной путь: продолжать использовать freezer, пропуская примерно по одному системному вызову за раз; как только stat() увидит файл и uid всё ещё наш, немедленно chmod 0666 + записать правило udev (в этот момент snap-confine заморожен, окно «растянуто»);
    • запасной путь: несколько процессов-spinner в горячем цикле chmod() захватывают то же окно. После захвата spinner'ом файл принадлежит root, но имеет режим 0666 — биты режима сохраняются и после fchown(0,0), поэтому основной путь тоже может дописать его (в коде проверяется «можно ли писать», а не «являемся ли мы владельцем»).
  6. Запустить udev: профиль AppArmor snap-confine разрешает /run/udev/** rw. Монтирование/размонтирование файловой системы FUSE заставляет ядро отправить uevent add для подсистемы bdi, и systemd-udevd немедленно выполняет PROGRAM= из правила от имени root.

Использование

make
./poc --diagnose            # 只读自检,不改动任何系统状态
./poc                       #  exploit,默认最多 5 次尝试
./poc --attempts 8          # 增加尝试次数
./poc --file default256.png # 只用 base rootfs 里的这一个普通文件
sudo ./poc --cleanup        # 清理(仅在异常中断留下残留时需要)

Параметры:

ПараметрОписание
--snap NAMEКакой snap использовать для rootfs (по умолчанию firefox, также можно задать через переменную окружения CVE8933_SNAP)
--app NAMEПриложение этого snap (по умолчанию берётся первое из раздела apps: в meta/snap.yaml)
--file NAMEИспользовать только этот обычный файл из base rootfs; если совпадений нет — завершиться с ошибкой
--attempts NКоличество попыток (по умолчанию 5)
--step US / --step2 USВремя CPU на каждый фрагмент для двух этапов (в микросекундах), для отладки
--keepСохранять каталоги <scratch>.dA / .dB и символические ссылки (для отладки)
--diagnoseСамопроверка только для чтения
--cleanupОчистка исторических остатков (требуются права root)

Журнал записывается в /tmp/cve8933.log, отладочный вывод snap-confine — в /tmp/cve8933-debug.txt.

CVE8933_PAYLOAD_CMD='<shell-команда>' позволяет заменить тело payload (для демонстрации выполнения других root-команд); в этом случае автоматическая очистка не выполняется; пользовательская команда всё равно должна записать /tmp/pwned, иначе PoC посчитает, что на этот раз успеха не было.

Результаты практических испытаний

$ ./poc
[+] WIN: uid=0(root) gid=0(root) groups=0(root)
[+] exploit succeeded, evidence in /tmp/pwned

/tmp/cve8933.log — соответствующий успешный прогон (2026-10-23, повторный тест после изменений):

Скачать инструмент