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

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

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

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

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

Категории

Все категории
Loading categories
harden-docker-seccomp — Смягчение последствий для CVE-2026-31431 ('Copy Fail') в Docker. Также включает шаблоны Kubernetes. | Kitploit
Инструменты/GitHubGitHub/devstuff/harden-docker-seccomp
Безопасность облачной инфраструктурыОборонительные ИнструментыБезопасность контейнеровАнализ уязвимостейАудит конфигурацииDevSecOps
GitHubdevstuff/harden-docker-seccomp

harden-docker-seccomp

Смягчение последствий для CVE-2026-31431 ('Copy Fail') в Docker. Также включает шаблоны Kubernetes.

Репозиторий
2144 месяцев назадЕщё не проверено

Популярное

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

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

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

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

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

harden-docker-seccomp

Идемпотентный скрипт для блокировки создания сокетов AF_ALG для всех контейнеров Docker на хосте в качестве меры смягчения для CVE-2026-31431 («Copy Fail»).

Предыстория

CVE-2026-31431 — это локальное повышение привилегий в криптографическом шаблоне authencesn ядра Linux, присутствующем в ядрах, собранных с 2017 года и до появления исправления в основной ветке (коммит a664bf3d603d). Непривилегированный пользователь может объединить операцию сокета AF_ALG с splice(), чтобы выполнить контролируемую запись 4 байт в page cache любого читаемого файла, нацелившись на setuid-бинарник для получения root-оболочки. Python-эксплойт размером 732 байта надёжно эксплуатирует эту уязвимость без гонок и дистрибутив-специфичных смещений на каждом крупном дистрибутиве Linux, поставляющем уязвимое ядро.

Обязательный первый шаг эксплойта — открытие сокета AF_ALG (socket(AF_ALG, SOCK_SEQPACKET, 0)). Блокировка этого системного вызова через seccomp предотвращает эксплуатацию даже на незапатченных ядрах. Встроенный профиль seccomp Docker по умолчанию не блокирует , и недостаточно — протестированные кластеры показали, что поды, допущенные в рамках PSS Restricted, всё ещё могли открывать сокеты .

AF_ALG
RuntimeDefault
AF_ALG

См. оригинальный отчёт исследователя на https://copy.fail и рекомендации CERT-EU на https://cert.europa.eu/publications/security-advisories/2026-005/ для полных технических деталей и доступности патчей по дистрибутивам.

Область применения этого инструмента

Этот скрипт охватывает глобальную конфигурацию демона Docker Engine. Для Kubernetes см. раздел Kubernetes ниже. Для bare-metal или VM-нагрузок (не контейнеризированных) вместо этого отключите модуль ядра algif_aead:

root@kitploit:~
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

Этот подход не влияет на dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS или SSH.

Как это работает

  1. Извлекает активный встроенный профиль seccomp Docker, проверяя HostConfig.SecurityOpt кратковременного контейнера. Это исключает любую зависимость от удалённого URL и гарантирует, что базовый профиль соответствует фактически установленной версии Docker. Загрузка с GitHub из moby/profiles используется как запасной вариант только если проверка контейнера ничего не даёт.

  2. Патчит профиль, удаляя socket из записи разрешённого списка Docker и добавляя его обратно с фильтром аргументов, который разрешает все семейства адресов, кроме AF_ALG (значение 38), используя SCMP_CMP_NE. Всё остальное поведение seccomp Docker по умолчанию сохраняется.

  3. Записывает пропатченный профиль атомарно в /etc/seccomp/docker-block-af-alg.json (временный файл + переименование). Пропускается, если содержимое на диске уже идентично.

  4. Обновляет /etc/docker/daemon.json, устанавливая "seccomp-profile" на путь пропатченного профиля. Оригинальный файл сохраняется в daemon.json.bak при первом изменении. Пропускается, если уже настроен корректно.

  5. Перезагружает dockerd через systemctl reload docker (SIGHUP — перезапуск не требуется). Пропускается, если ни один файл не изменился.

  6. Проверяет, что блокировка активна, запуская пробу внутри контейнера, независимо от того, были ли внесены какие-либо изменения на шагах выше.

Скрипт идемпотентен: многократный запуск даёт тот же результат и перезагружает Docker только когда что-то действительно изменилось.

Примечание: контейнеры --privileged обходят все профили seccomp независимо от этой конфигурации. Проверяйте ваши Compose-файлы и команды запуска привилегированных контейнеров отдельно.

Требования

  • Python 3.12+
  • Docker Engine (не Docker Desktop), работающий на хосте
  • CLI docker в PATH
  • curl в PATH (только запасной вариант)
  • systemctl (хост на systemd)
  • Root / sudo для записи в /etc/seccomp и /etc/docker, а также для systemctl reload docker

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

root@kitploit:~
# Применить меру смягчения и проверить (обычное использование)
sudo python3 harden-docker-seccomp.py

# Показать, что изменится, без записи чего-либо или перезагрузки Docker
sudo python3 harden-docker-seccomp.py --dry-run

# Повторно запустить только проверку контейнера (без изменений конфигурации)
python3 harden-docker-seccomp.py --verify-only

# Подробный вывод
sudo python3 harden-docker-seccomp.py --verbose

Ожидаемый вывод (первый запуск)

root@kitploit:~
INFO Written: /etc/seccomp/docker-block-af-alg.json
INFO Updated: /etc/docker/daemon.json
INFO Reloading Docker daemon (SIGHUP)…
INFO Docker daemon reloaded.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Ожидаемый вывод (последующие запуски)

root@kitploit:~
INFO Profile unchanged: /etc/seccomp/docker-block-af-alg.json
INFO daemon.json already configured correctly.
INFO No changes — Docker daemon reload not required.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

Коды выхода

КодЗначение
0Успех — мера смягчения активна
1Скрипт не запущен от root (при патчинге) или неисправимая ошибка
2Проверка не удалась — AF_ALG не заблокирован

Kubernetes

Поды Kubernetes используют ядро хоста, поэтому тот же примитив сокета AF_ALG доступен из любого пода на уязвимом узле. Seccomp RuntimeDefault недостаточно — протестированные кластеры показали, что поды, допущенные в рамках PSS Restricted, всё ещё могли открывать сокеты AF_ALG. Требуется профиль Localhost с явным правилом запрета.

Мера смягчения требует двух вещей: JSON-профиля, присутствующего в файловой системе каждого узла, и ссылки на него в каждом спецификации пода. Разделы ниже охватывают оба аспекта, включая глобальное внедрение профиля без изменения отдельных спецификаций подов.

Шаг 1 — Распространение профиля на каждый узел

Kubelet разрешает профили seccomp Localhost относительно своего корня seccomp, который по умолчанию находится в /var/lib/kubelet/seccomp. Профиль должен существовать по этому пути на каждом узле, который может планировать рабочую нагрузку.

Примените ConfigMap и DaemonSet из этого репозитория:

root@kitploit:~
kubectl apply -f templates/configmap-seccomp-profile.yaml
kubectl apply -f templates/daemonset-distribute-profile.yaml

DaemonSet запускает init-контейнер, который копирует профиль из ConfigMap в корень seccomp kubelet узла, а затем размещает минимальный pause-контейнер, чтобы под оставался видимым для мониторинга здоровья. Он переносит все taints, поэтому также запускается на control-plane узлах.

Нестандартный корень seccomp kubelet: RKE2 использует /var/lib/rancher/rke2/agent/kubelet/seccomp. Переопределите путь, установив NODE_SECCOMP_ROOT в env init-контейнера DaemonSet перед применением.

Проверьте наличие файла на узле:

root@kitploit:~
kubectl -n kube-system exec -it \
  $(kubectl -n kube-system get pod -l app.kubernetes.io/name=distribute-af-alg-seccomp \
    -o jsonpath='{.items[0].metadata.name}') -- \
  cat /var/lib/kubelet/seccomp/block-af-alg.json

Шаг 2 — Внедрение профиля в каждый под (без изменений спецификаций подов)

Вместо изменения отдельных спецификаций подов или Helm-чартов используйте мутирующий admission webhook для автоматического внедрения seccompProfile во время допуска. Предоставляются два варианта: Kyverno и OPA Gatekeeper.

Оба подхода внедряют профиль только когда под ещё не объявляет собственный, поэтому поды с явными профилями остаются нетронутыми.

Важно: Существующие запущенные поды не мутируются ретроактивно. После применения политики перезапустите ваши deployment'ы, чтобы подхватить внедрённый профиль:

root@kitploit:~
kubectl rollout restart deployment -A

Вариант A — Kyverno

Этот шаблон использует API MutatingPolicy (policies.kyverno.io/v1), который достиг GA в Kyverno 1.17. Устаревший API ClusterPolicy (kyverno.io/v1) был объявлен устаревшим в Kyverno 1.17 (январь 2026) и планируется к удалению в 1.20 (октябрь 2026); не используйте его для новых политик.

CEL-выражение matchConditions проверяет отсутствие seccompProfile перед мутацией, поэтому поды, уже объявляющие профиль, остаются нетронутыми.

root@kitploit:~
# Установка Kyverno (если ещё не установлен)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace

# Применение политики
kubectl apply -f templates/kyverno-mutate-seccomp.yaml

Проверьте, что новый под получает внедрённый профиль:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Ожидается: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

См. templates/kyverno-mutate-seccomp.yaml.

Вариант B — OPA Gatekeeper

CRD мутации Assign Gatekeeper использует условие pathTests для внедрения профиля только когда spec.securityContext.seccompProfile ещё не существует. Мутация стабильна с Gatekeeper 3.10+; флаг функции не требуется.

root@kitploit:~
# Установка Gatekeeper (если ещё не установлен)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper \
  --create-namespace

# Применение мутации
kubectl apply -f templates/gatekeeper-assign-seccomp.yaml

Проверка:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# Ожидается: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

См. templates/gatekeeper-assign-seccomp.yaml.

Gatekeeper против Kyverno: Подход Assign работает на уровне полей и требует включения мутационного webhook Gatekeeper. MutatingPolicy Kyverno с CEL matchCondition обрабатывает условие встроенно. Любой из них даёт тот же результат — предпочитайте тот, который уже развёрнут в вашем кластере.

Что это не покрывает

Поды с hostPID: true, hostNetwork: true или securityContext.privileged: true имеют повышенный доступ, который seccomp сам по себе полностью не сдерживает. Проверяйте такие рабочие нагрузки отдельно и удаляйте привилегии, где это возможно.

Примечания по дизайну шаблонов

ConfigMap как источник истины. JSON-профиль находится в configmap-seccomp-profile.yaml, а не встроен в DaemonSet или продублирован в файлах. DaemonSet монтирует его и копирует на узел. Обновление профиля означает редактирование одного ConfigMap и перезапуск подов DaemonSet — никакие другие файлы не меняются.

DaemonSet использует приоритет system-node-critical. Это гарантирует, что под распространения не будет вытеснен до планирования защищаемых рабочих нагрузок, что оставило бы узлы без файла профиля и поды в состоянии CreateContainerError.

Gatekeeper исключает kube-system и gatekeeper-system. Внедрение профиля Localhost в системные поды, которые могут предшествовать установке DaemonSet, рискует сломать ссылку на профиль, если файл ещё не присутствует на узле. Политика Kyverno не требует этого исключения, потому что Kyverno более корректно обрабатывает порядок webhook'ов, но правила exclude могут быть добавлены и там при необходимости.

Условное внедрение, а не переопределение. И CEL matchCondition MutatingPolicy Kyverno, и проверка пути MustNotExist Gatekeeper означают, что политика допуска действует только когда под не имеет существующего seccompProfile. Рабочие нагрузки, которые уже объявляют собственный профиль — включая те, которым легитимно нужен AF_ALG через собственный разрешённый список — остаются нетронутыми.

Ссылки

  • https://copy.fail — Оригинальный отчёт исследователя (Xint)
  • https://cert.europa.eu/publications/security-advisories/2026-005/ — Рекомендации CERT-EU
  • https://www.cve.org/CVERecord?id=CVE-2026-31431 — Запись CVE
  • https://security-tracker.debian.org/tracker/CVE-2026-31431 — Трекер безопасности Debian
  • https://docs.docker.com/engine/security/seccomp/ — Документация Docker по seccomp
  • https://github.com/moby/profiles — Канонический профиль seccomp Docker по умолчанию
  • https://kyverno.io/docs/kyverno-policies/ — Документация по политикам Kyverno
  • https://open-policy-agent.github.io/gatekeeper/website/docs/mutation/ — Документация по мутации Gatekeeper

Да, Claude сделал большую часть работы, вот чат

https://gist.github.com/devstuff/3ff3ca0139e2a2da7f1ee5875802f76f

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