Skip to content

polyakovavv/copyfail

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

Обзор

Copy Fail (CVE-2026-31431) — это логическая уязвимость в ядре Linux, позволяющая локальному непривилегированному пользователю повысить привилегии до уровня суперпользователя (root). Уязвимость относится к классу Local Privilege Escalation (LPE), не требует сложных условий эксплуатации (таких как race condition или подбор адресов в памяти) и работает "из коробки" на большинстве дистрибутивов Linux, выпущенных после 2017 года.

Данный репозиторий содержит порт оригинального Python-эксплойта на язык C с подробными комментариями, пригодный для статической компиляции и использования в минимальных окружениях.


Содержание


Уязвимость

Суть уязвимости

Уязвимость возникает из-за логической ошибки в криптографической подсистеме ядра Linux, связанной с обработкой AF_ALG (интерфейса криптографического API ядра) и механизма страничного кэша (page cache).

Ошибка была внесена в 2017 году при добавлении оптимизации, которая убрала лишнюю буферизацию через выполнение операций блочного шифрования AEAD (Authenticated Encryption with Associated Data) по месту (in-place). Из-за некорректной обработки границ буферов в алгоритме authencesn (часть криптографического шаблона AEAD) возникает запись 4 байт за пределы выделенного буфера, что приводит к повреждению структур управления страничным кэшем.

В результате ядро может записать данные обратно в страничный кэш файла, даже если он был открыт только для чтения (O_RDONLY).

Механизм эксплуатации

  1. Непривилегированный пользователь открывает сокет AF_ALG и инициализирует AEAD-алгоритм authencesn(hmac(sha256),cbc(aes)).
  2. Через setsockopt() устанавливаются аномальные параметры:
    • Ключ специального формата (манипуляция буферами ядра).
    • Размер аутентификационного тега = 4 байта (вместо нормальных 16–32 байт для HMAC-SHA256).
  3. Через sendmsg() с control messages инициируется операция расшифрования.
  4. Системный вызов splice() перемещает данные из целевого файла (открытого O_RDONLY) в крипто-сокет.
  5. Из-за ошибки в authencesn страничный кэш файла повреждается, и "расшифрованные" данные записываются обратно в кэш.
  6. Ядро исполняет модифицированный setuid-файл из страничного кэша, что приводит к выполнению кода с правами root.

Затронутые системы

Компонент Описание
Ядро Linux Все версии с 2017 года до момента включения исправляющего патча
Подсистема crypto (модуль algif_aead)
Интерфейс AF_ALG — пользовательский доступ к крипто-API ядра
Системный вызов splice() в связке с сокетами AF_ALG

Уязвимые дистрибутивы (при использовании ядер с загруженным модулем algif_aead):

  • Ubuntu (все версии)
  • Debian (все версии)
  • RHEL / CentOS / Rocky / Alma Linux
  • SUSE / openSUSE
  • Fedora
  • Arch Linux
  • Прочие дистрибутивы на базе уязвимых ядер

Особая значимость: в контейнерных средах (Docker, LXC, Kubernetes) процессам внутри контейнера по умолчанию доступна подсистема AF_ALG, если модуль algif_aead загружен в ядре хоста. Это создаёт риск нарушения изоляции контейнера и получения контроля над хостовой машиной.

Проверка уязвимости:

# Проверить, загружен ли модуль algif_aead
lsmod | grep algif

# Проверить наличие AF_ALG в ядре
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)

Эксплойт

Особенности порта на C

Оригинальный эксплойт был написан на Python (≈732 байт). Данный порт на C имеет следующие особенности:

  • Статическая компиляция — работает в минимальных окружениях без Python.
  • Полная автономность — требуется только стандартная библиотека C и libz.
  • Подробные комментарии на русском языке — каждый шаг эксплуатации документирован.
  • Идентичное поведение — системные вызовы точно соответствуют Python-версии (проверено через strace).
  • Неблокирующий recv() — предотвращает зависание, повторяя поведение try/except из Python.

Ключевые отличия от Python-версии, выявленные при портировании:

Параметр Python C (этот порт)
Флаг sendmsg() MSG_MORE MSG_MORE
Флаг splice() 0 0
Смещение в pipe NULL NULL
Размер ключа 40 байт 40 байт
cmsg_len 20/36/20 20/36/20 (жёстко)
Создание pipe pipe2(fds, O_CLOEXEC) pipe2(fds, O_CLOEXEC)
recv() Блокирующий с try/except Неблокирующий (O_NONBLOCK)

Компиляция

# Требуется libz (zlib1g-dev или zlib-devel)
gcc -o copyfail copyfail.c -lz -static -Wall -O2

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

./copyfail

При успешной эксплуатации будет запущена пропатченная версия /usr/bin/su, предоставляющая root-доступ без запроса пароля.

Ожидаемый вывод:

================================================================
  CVE-2026-31431 'Copy Fail' Exploit
================================================================

[+] /usr/bin/su открыт
[+] 40 чанков
[*] 40/40 ок

# id
uid=0(root) gid=0(root) groups=0(root)

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

Пошаговый разбор

Ниже приведён детальный разбор каждого шага эксплойта с указанием соответствующих системных вызовов:

Шаг 1: Создание AF_ALG сокета

socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(sock, {sa_family=AF_ALG, salg_type="aead", 
     salg_name="authencesn(hmac(sha256),cbc(aes))"}, 88);

Создаётся сокет для доступа к криптографическому API ядра. Алгоритм authencesn (Authenticated Encryption with Sequence Numbers) — это составной AEAD-алгоритм, использующий AES-CBC для шифрования и HMAC-SHA256 для аутентификации.

Шаг 2: Установка уязвимых параметров

setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, 40);
setsockopt(sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
  • Ключ: 40 байт специального формата, манипулирующих внутренними буферами ядра.
  • Размер аутентификационного тега: 4 байта. Нормальное значение для HMAC-SHA256 — 16–32 байта. Аномально маленькое значение приводит к переполнению буфера в ядре.

Шаг 3: Инициализация операции расшифрования

accept(sock, NULL, NULL);  // conn_sock
sendmsg(conn_sock, {payload="AAAA"+data, 
        cmsg=[(SOL_ALG, 3, 4 нуля),        // ALG_SET_OP = DECRYPT
              (SOL_ALG, 2, 0x10+19нулей),  // ALG_SET_IV
              (SOL_ALG, 4, 0x08+3нуля)]},  // ALG_SET_AEAD_ASSOCLEN
        MSG_MORE);

Создаётся соединение для операции. Через sendmsg() с control messages (CMSG) устанавливаются параметры:

  • Операция: расшифрование (ALG_OP_DECRYPT = 0).
  • IV: 20 байт (вместо нормальных 16 для AES).
  • Ассоциированные данные: 8 байт (без реальной передачи данных).

Все эти аномалии создают несоответствия в управлении памятью ядра.

Шаг 4: Перемещение данных через splice()

pipe2(pipe_fds, O_CLOEXEC);
splice(target_fd, &src_off, pipe_fds[1], NULL, o, 0);
splice(pipe_fds[0], NULL, conn_sock, NULL, o, 0);

splice() — системный вызов для перемещения данных между файловыми дескрипторами без копирования через userspace. Данные перемещаются на уровне ядра через механизм pipe.

  1. splice(target_fd -> pipe): данные из целевого файла (/usr/bin/su) попадают в pipe.
  2. splice(pipe -> conn_sock): данные из pipe поступают в крипто-сокет как "зашифрованный текст".

Ключевой момент: в Python (и в данном порте) смещение для pipe передаётся как NULL, что позволяет ядру автоматически управлять позицией.

Шаг 5: Финализация и игнорирование ошибки

fcntl(conn_sock, F_SETFL, O_NONBLOCK);
recv(conn_sock, buf, 8 + t, 0);

Вызов recv() заставляет ядро завершить криптографическую операцию. В нормальном режиме здесь вернулись бы расшифрованные данные, но из-за аномальных параметров возвращается ошибка EBADMSG (Python) или EAGAIN (C с O_NONBLOCK). Ошибка игнорируется — повреждение страничного кэша уже произошло на этапе splice().

Почему страничный кэш изменяется

Страничный кэш (page cache) — это кэш содержимого файлов в оперативной памяти. Когда процесс открывает файл через O_RDONLY, ядро разрешает только чтение из этого кэша. Однако уязвимость позволяет обойти это ограничение:

  1. Несоответствие размеров буферов: authsize=4 вместо 16–32 создаёт буферы неправильного размера.
  2. Переполнение буфера: при "расшифровании" данные пишутся за пределы выделенного буфера.
  3. Повреждение счётчика ссылок: переполнение затрагивает структуры управления страницами (page reference count).
  4. Запись в кэш: ядро, думая, что страница свободна, записывает туда "расшифрованные" данные.
  5. Игнорирование O_RDONLY: проверка прав доступа происходит на уровне VFS при вызове write(), но splice() работает на уровне страничного кэша напрямую, минуя эти проверки.

Изменения происходят только в оперативной памяти, а не на диске. Это делает атаку труднообнаружимой стандартными средствами контроля целостности. После перезагрузки или очистки страничного кэша следы атаки исчезают.


Устранение уязвимости

Основной способ

Обновить ядро Linux до версии, содержащей исправление.

Временные меры

Отключить модуль algif_aead:

# Запретить загрузку модуля
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/algif_aead.conf

# Выгрузить модуль (если загружен)
sudo rmmod algif_aead

Дополнительные рекомендации:

  • Ограничить локальный доступ пользователей.
  • Использовать мониторинг целостности ядра и системы.
  • Применять принцип минимальных привилегий.
  • В контейнерных средах запретить доступ к AF_ALG через seccomp-профили.

Изменяется ли файл /usr/bin/su на диске?

Нет. Изменения происходят только в страничном кэше (оперативная память). Содержимое файла на диске остаётся неизменным. После перезагрузки системы страничный кэш очищается, и файл возвращается к исходному состоянию.

Можно ли обнаружить эксплуатацию?

Обнаружение возможно через:

  • Мониторинг системных вызовов (auditd, strace).
  • Анализ аномалий в использовании AF_ALG сокетов.
  • Контроль целостности файлов в памяти (не на диске).

Стандартные средства контроля целостности (AIDE, Tripwire) не обнаружат изменений, так как файл на диске остаётся неизменным.

Дисклеймер

Данный код предоставляется исключительно в образовательных и исследовательских целях. Автор не несёт ответственности за любое использование данного кода в противоправных целях. Использование эксплойта без явного разрешения владельца системы является незаконным и может повлечь уголовную ответственность.

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

About

Copy Fail (CVE-2026-31431)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors