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

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

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

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

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

Категории

Все категории
Loading categories
copy-fail-c — Кроссплатформенный порт на C уязвимости Copy Fail Linux LPE (CVE-2026-31431). Раскрыта 2026-04-29 компаниями Theori / Xint. | Kitploit
Инструменты/GitHubGitHub/tgies/copy-fail-c
Повышение привилегийФреймворки для эксплойтовАнализ уязвимостейЭксплуатацияСтатьи и ИсследованияОбучение и ОбразованиеРазработка Полезной НагрузкиЭксплуатация Бинарных Файлов
GitHubtgies/copy-fail-c

copy-fail-c

Кроссплатформенный порт на C уязвимости Copy Fail Linux LPE (CVE-2026-31431). Раскрыта 2026-04-29 компаниями Theori / Xint.

Репозиторий
44012131 месяц назадПроверено Kitploit

Популярное

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

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

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

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

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

Copy Fail (CVE-2026-31431) - Порт на C

English (en) ∙ 日本語 (ja) ∙ 简体中文 (zh-cn) ∙ 한국어 (ko) ∙ Русский (ru)

Кроссплатформенная реализация на C эксплойта Copy Fail для Linux (CVE-2026-31431). Уязвимость была раскрыта 29 апреля 2026 года исследователями Theori / Xint. Полное описание уязвимости, хронологию и процесс обнаружения Theori можно найти в официальном отчете на copy.fail.

Публично выпущенный Proof-of-Concept (PoC) представляет собой Python-скрипт размером 732 байта. Данный порт на C демонстрирует, что тот же самый эксплойт может быть написан на переносимом C, который компилируется под любую архитектуру, поддерживаемую nolibc, без использования специфичных для архитектуры шестнадцатеричных блоков (hex blobs) или встроенного ассемблера в исходном коде самого проекта.

Автор этого порта: Tony Gies [email protected]. Обнаружение и исходное раскрытие: Theori / Xint.

Структура репозитория

root@kitploit:~
copy-fail-c/
├── exploit.c           дроппер (вариант с мутацией бинарного файла)
├── exploit-passwd.c    дроппер (вариант с подменой UID в /etc/passwd)
├── vulnerable.c        неразрушающая проверка уязвимости
├── payload.c           сбрасываемая полезная нагрузка (setgid+setuid+execve sh)
├── utils.c, utils.h    общий примитив мутации page cache через AF_ALG/splice
├── Makefile            оркестрация сборки
├── nolibc/             код, заимствованный из torvalds/linux tools/include/nolibc
└── README.md           этот файл

После выполнения make:

root@kitploit:~
├── payload             крошечный статический ELF, встроенный в дроппер в виде байтов
├── payload.o           полезная нагрузка, обернутая в перемещаемый .o с помощью `ld -r -b binary`
├── exploit             дроппер, вариант с мутацией бинарного файла
├── exploit-passwd      дроппер, вариант с подменой UID в /etc/passwd
└── vulnerable          неразрушающая проверка уязвимости

exploit.c открывает целевой бинарный файл только для чтения, затем для каждого 4-байтового окна встроенной полезной нагрузки запускает одну фиктивную операцию AEAD-расшифровки через AF_ALG, где зашифрованный ввод поставляется через splice() из страниц кэша (page-cache) целевого файла. Оптимизация "на месте" (in-place) шаблона authencesn рассматривает исходные страницы, переданные через splice, одновременно как ввод шифротекста и место назначения для открытого текста, поэтому обреченная на неудачу расшифровка уже перезаписывает страницу кэша к тому моменту, когда проверка подлинности отклоняет запрос. После 4 * N итераций закэшированный образ целевого файла побайтово заменяется полезной нагрузкой. Выполнение execve() для целевого файла загружает мутировавшие страницы; inode на диске по-прежнему имеет бит setuid root, поэтому ядро предоставляет root-привилегии и запускает полезную нагрузку.

payload.c — это обычный переносимый C: setgid(0); setuid(0); execve("/bin/sh", ...). nolibc предоставляет _start, механизмы системных вызовов и работу с регистрами, специфичную для каждой архитектуры.

Второй вариант, exploit-passwd.c, мутирует четыре байта в кэше страниц файла /etc/passwd вместо образа setuid-бинарника. Ему не нужна встроенная полезная нагрузка, и он работает на системах, где путь с мутацией бинарного файла заблокирован, но его поверхность для успешной эксплуатации (cashout) гораздо уже.

vulnerable.c не является эксплойтом. Он создаёт в рабочей директории локальный файл testfile со строкой init, после чего запускает тот же примитив patch_chunk() против собственного кэша страниц этого файла, пытаясь перезаписать байты строкой vulnerable. Если прочитанное содержимое совпадает, работающее ядро находится в зоне действия CVE-2026-31431. Inode на диске не модифицируется; testfile удаляется при выходе, и мутация кэша страниц исчезает вместе с ним. Запускается без привилегий. Возвращает код выхода 100 при наличии уязвимости, 0 если примитив выполнился, но мутация не сработала, 2 если семейство сокетов AF_ALG или шаблон authencesn недоступны и состояние патча нельзя определить, и 1 для других ошибок выполнения.

Сборка

По умолчанию (нативно для архитектуры хоста):

root@kitploit:~
make

Кросс-компиляция под aarch64 (или любую другую архитектуру Linux, для которой установлен кросс-тулчейн):

root@kitploit:~
make CC=aarch64-linux-gnu-gcc LD=aarch64-linux-gnu-ld

Архитектуры, поддерживаемые включенной (vendored) версией nolibc (в соответствии с апстримом): x86_64, i386, arm, aarch64, riscv32/64, mips, ppc, s390x, loongarch, m68k, sh, sparc. nolibc осуществляет диспетчеризацию на основе макросов архитектуры компилятора, поэтому достаточно выбрать правильные CC/LD.

Требования для сборки:

  • Компилятор C (cc, gcc или любой кросс-компилятор)
  • Линкер, поддерживающий ld -r -b binary (подходят как binutils ld, так и lld)
  • Заголовочные файлы ядра UAPI, предоставляющие linux/if_alg.h и <asm/unistd.h> (Debian/Ubuntu: linux-libc-dev; для кросс-компиляции: обычно подтягиваются пакетом кросс-тулчейна)

Наборы заголовков старше Linux 5.6 не содержат __kernel_old_time_t и struct __kernel_old_timespec, которые использует включённый (vendored) nolibc. compat.h (принудительно включаемый в сборку полезной нагрузки) предоставляет их при отсутствии, поэтому сборка проходит и со старым linux-libc-dev. На заголовках 5.6 и новее он не даёт никакого эффекта.

Зависимости от внешних библиотек отсутствуют. Полезная нагрузка (payload) собирается автономно (freestanding) с использованием nolibc; дроппер линкуется с системной libc только для использования fprintf и perror.

Архитектурные решения

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

nolibc

nolibc/ — это крошечная замена libc от ядра, состоящая только из заголовочных файлов, скопированная из tools/include/nolibc/ репозитория torvalds/linux. Она предоставляет _start, переносимый макрос syscall() и встроенные обертки системных вызовов, причем соглашения о регистрах для конкретных архитектур закодированы в nolibc/arch-*.h. Сборка полезной нагрузки с флагами -nostdlib -static -ffreestanding -Inolibc создает крошечный статический ELF, который обращается к ядру напрямую, не подтягивая код запуска glibc, инициализацию TLS или механизмы stack-canary. Результат, после упаковки и удаления заголовков секций (то и другое описано ниже): ~720 байт на x86_64, ~1.2 КБ на aarch64 по сравнению с ~17 КБ для того же payload.c, слинкованного с musl-static, или ~700 КБ с glibc-static.

ld -r -b binary для встраивания

Makefile превращает собранный ELF-файл payload в payload.o с помощью команды ld -r -b binary -o payload.o payload. Линкер выводит входные байты "как есть" в качестве секции данных перемещаемого объектного файла и синтезирует три символа из имени входного файла:

root@kitploit:~
_binary_payload_start    адрес первого байта полезной нагрузки
_binary_payload_end      адрес байта, следующего за последним байтом полезной нагрузки
_binary_payload_size     абсолютный символ, значением которого является размер в байтах

exploit.c объявляет первые два символа как extern const unsigned char[] и вычисляет размер как _binary_payload_end - _binary_payload_start.

-Wl,-N и жесткий max-page-size

Полезная нагрузка статически линкуется с опциями -Wl,-N -Wl,-z,max-page-size=0x10, что сворачивает секции .text/.rodata/.data в единый сегмент LOAD с выравниванием файла по 16 байтам вместо значения по умолчанию (выравнивание по страницам ядра, 4 КБ на сегмент). Из-за этого ld выдает предупреждение об «RWX permissions» (разрешениях на чтение, запись и выполнение), которое носит исключительно информационный характер — защита памяти во время выполнения не имеет значения для данной узконаправленной программы. Без этого флага тот же код линкуется в файл размером ~13 КБ на x86_64 (в основном из-за заполнения нулями между сегментами); с ним размер составляет ~1.3 КБ перед удалением заголовков секций, описанным ниже.

Удаление заголовков секций

После линковки objcopy --strip-section-headers удаляет из полезной нагрузки таблицу заголовков секций и .shstrtab. Загрузчик ELF в ядре отображает программу только по её заголовкам программы (program headers), поэтому эти байты никогда не загружаются во время выполнения, а поскольку payload встраивается «как есть», они вдобавок увеличивают объём сброса и число итераций patch_chunk. Их удаление уменьшает полезную нагрузку на x86_64 с ~1.3 КБ до 720 байт (с 322 четырёхбайтовых итераций до 180). Остальное срезают два флага времени линковки: -Wl,--build-id=none убирает заметку build-id, а -fcf-protection=none убирает заметку x86 CET там, где её поддерживает компилятор.

Для удаления требуется binutils >= 2.40. При кросс-сборке objcopy для целевой архитектуры передаётся через OBJCOPY= (например, OBJCOPY=aarch64-linux-gnu-objcopy); если objcopy не может выполнить операцию, сборка выводит примечание и сохраняет корректную, но более крупную полезную нагрузку.

Варианты эксплойта и их жизнеспособность

В этом репозитории представлены два варианта эксплойта, которые используют один и тот же примитив мутации кэша страниц через AF_ALG/splice, но добиваются выполнения кода от имени root (cashout) по-разному. Профили их надежности неодинаковы, и эта разница имеет значение при анализе реальных моделей угроз.

Вариант с мутацией бинарного файла (exploit)

Мутирует кэш страниц целевого setuid-бинарника, внедряя байты полезной нагрузки, а затем выполняет (exec) этот бинарник. Ядро предоставляет root-привилегии на основе нетронутого бита setuid файла на диске, загружает поврежденный образ из памяти и запускает полезную нагрузку.

Работает везде, где злоумышленник может выполнить open(target, O_RDONLY) для любого root-setuid бинарника в системе. В той или иной степени блокируется в средах, где setuid-бинарники скрыты за директориями с ограниченными правами на чтение, а также в системах, спроектированных без использования setuid.

Вариант с подменой UID в /etc/passwd (exploit-passwd)

Мутирует четыре байта в кэше страниц файла /etc/passwd, чтобы установить поле UID текущего пользователя в «0000». Файл /etc/passwd доступен для чтения всем (world-readable) в любой стандартной системе Linux, поэтому сама мутация работает универсально. Однако превращение этого в выполнение кода от имени root зависит от того, будет ли какой-либо процесс со стороны root разрешать имя пользователя через getpwnam/getpwuid и действовать на основе полученного uid без перекрестной проверки. Существует множество таких потребителей; многие из них в целях защиты производят перекрестную проверку с представлением ядра о uid вызывающего процесса или с владельцем файла на диске, что ломает эту цепочку эксплуатации.

Матрица жизнеспособности эксплуатации

Смена вектора атаки (Pivot) после неудачи su

exploit-passwd выполняет su <user> после мутации как самый простой вариант эксплуатации. Это срабатывает против util-linux su, но терпит неудачу против shadow-utils su с ошибкой "Cannot determine your user name." (Невозможно определить имя пользователя). В этот момент мутация кэша страниц все еще активна, и возможен переход к любому другому способу эксплуатации (например, использование демона, разрешающего пользователей через getpwnam без перекрестных проверок). Выполните echo 3 > /proc/sys/vm/drop_caches от имени root, чтобы очистить поврежденный кэш страниц по завершении тестирования.

Уязвимые версии ядра

root@kitploit:~
Нижняя граница:  torvalds/linux 72548b093ee3   Август 2017 г., v4.14
                                              (Переработка AF_ALG iov_iter,
                                               которая представила примитив
                                               записи на страницу файла через splice
                                               в scatterlist AEAD)

Верхняя граница: torvalds/linux a664bf3d603d   Апрель 2026 г., mainline
                                              (Отменяет оптимизацию algif_aead
                                               "на месте" (in-place) 2017 года;
                                               разделяет исходный и целевой scatterlist,
                                               чтобы страницы кэша (page-cache)
                                               больше не могли быть целевым адресом
                                               для записи при криптографической операции)

В промежутке: ядра всех основных дистрибутивов, в которые не был бэкпортирован (backport) патч. Ubuntu, RHEL, SUSE, Amazon Linux и Debian — все они были подтверждены как уязвимые в своих стандартных ядрах для облачных образов на момент раскрытия информации. Бэкпорты на уровне дистрибутивов начали выпускаться примерно 29 апреля 2026 года, параллельно с публичным раскрытием. Чтобы проверить, находится ли целевое ядро в уязвимом диапазоне, убедитесь, присутствует ли коммит a664bf3d603d (или его специфичный для дистрибутива бэкпорт) в логах git ядра или в changelog дистрибутива.

Коммерческая поддержка

По вопросам платного аудита безопасности, заказного портирования или непубличных уведомлений о безопасности обращайтесь к автору через его консалтинговую компанию Crash United, LLC.

Контакты: [email protected] · https://crashunited.com
GitHub: @tgies · X/Twitter: @me_irl

Лицензия и благодарности

Обнаружение и первоначальное раскрытие CVE-2026-31431: Theori / Xint. Публичный отчет: https://copy.fail/.

Данный порт на C: Tony Gies [email protected]

nolibc/: заимствовано (vendored) из дерева исходного кода ядра Linux; имеет двойное лицензирование LGPL-2.1-or-later ИЛИ MIT (см. nolibc/nolibc.h и SPDX-заголовки отдельных файлов).

Исходные коды дроппера и полезной нагрузки в этом репозитории выпущены на тех же условиях двойного лицензирования LGPL-2.1-or-later ИЛИ MIT, что и дерево nolibc, от которого они зависят. Это сделано для того, чтобы сохранить тривиальную совместимость лицензий для всех, кто решит включить этот каталог целиком в свои собственные разработки.

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

Скачать инструмент
Цель эксплуатации (Cashout)Требуется подготовка до rootПримечания
Создание сессии WSL2НетВызов setuid(getpwnam(default_user)->pw_uid) для каждой сессии в WSL не выполняет никаких проверок. Работает чисто.
util-linux suНетСнисходительная обработка идентификатора вызывающего процесса.
shadow-utils suДаПроверка идентификатора вызывающего через getpwuid(getuid()) завершается неудачей, так как мутация отвязывает реальный uid.
sshd (по умолчанию StrictModes yes)Да (отключить StrictModes)StrictModes требует, чтобы домашняя директория принадлежала root или pw->pw_uid. В результате мутации pw_uid становится равным 0, тогда как владелец на диске остается прежним (исходный uid); из-за этого несоответствия аутентификация отклоняется.
Локальная доставка почты MTA (postfix, exim и т.д.)Зависит от системыЗависит от проверки прав доступа к домашней директории агентом доставки (MDA). Требует тестирования для каждого конкретного MTA.