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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-88776 — Технический разбор CVE-2026-88776 — целочисленное переполнение (integer underflow) без предварительной аутентификации в парсере записей Oracle TNS компонента nsppe NetScaler, приводящее к записи за границами буфера и падению пакетного движка. | Kitploit
Инструменты/GitHubGitHub/scyrix-llc/cve-2026-88776
Криминалистика памятиАнализ уязвимостейЭксплуатацияОбратная инженерияСетевая безопасностьАнализ Бинарных ФайловСтатьи и Исследования
GitHubscyrix-llc/cve-2026-88776

CVE-2026-88776

Технический разбор CVE-2026-88776 — целочисленное переполнение (integer underflow) без предварительной аутентификации в парсере записей Oracle TNS компонента nsppe NetScaler, приводящее к записи за границами буфера и падению пакетного движка.

Репозиторий
21328 дней назадЕщё не проверено

Популярное

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

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

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

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

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

CVE-2026-88776: NetScaler nsppe (Pre-Auth OOB Write)

Целочисленное переполнение вниз в парсере записей DataStream / Oracle TNS

Краткое описание

NetScaler умеет балансировать нагрузку баз данных Oracle. Направьте на него vserver типа ORACLE, и пакетный движок сам начнёт говорить на протоколе Oracle TNS, разбирая клиентский трафик встроенным обработчиком. Этот обработчик хранит небольшой конечный автомат для каждого соединения, чтобы помнить, где он находится внутри записи TNS.

Одно из этих состояний означает «я в середине записи, придут ещё байты». Когда приходит следующий сегмент, обработчик читает его длину и вычитает 10, потому что 10 байт каждого сегмента — это заголовок.

Никто не задался вопросом, что произойдёт, если сегмент короче 10 байт.

Отправьте такой. Сегмент-огрызок длиной от 1 до 9 байт попадает в это состояние, длина становится отрицательной, и поскольку длина хранится в беззнаковом 16-битном регистре, она не становится отрицательной. Она заворачивается в нечто огромное, вплоть до примерно 64 КБ. Затем обработчик с радостью выполняет memcpy такого объёма данных из вашего пакета в фиксированный буфер размером 0x748 байт в .bss. Движок не является PIE, поэтому адрес, который затаптывается, никогда не меняется.

Вам не нужно логиниться. Вам даже не нужна база данных за vserver, потому что само устройство отвечает на рукопожатие TNS. Вся атака — это один TCP-разговор.

Обе половины были продемонстрированы вживую:

  • Запустите завернутую длину, и пакетный движок умирает с SIGSEGV, выводя из строя dataplane устройства примерно на минуту. Детерминированно, воспроизводимо, зацикливаемо.
  • Настройте длину, и вы получите тихую версию. Байты атакующего ложатся поверх глобальных переменных, находящихся рядом со scratch-буфером, а движок продолжает работать. Это примитив записи, а не просто падение.

Первопричина

Конечный автомат и как им управлять

Обработчик хранит своё состояние для каждого соединения по адресу [pcb+0x15a]. Большинство состояний скучны. То, что имеет значение здесь, — это 0x1F4, что означает «середина записи, ожидание продолжения», и вы направляете соединение в него, используя не что иное, как обычные байты протокола:

record type 6 -> deep-parser state 6 -> byte 0x03 (TTIFUN)
  -> state 0x126 -> TTC function byte 0x5e (OALL8)
  -> jump table 0x23589e0, index 0x59 -> writer at bfe27b:
       [pcb+0x15a] = 0x1F4

Следующий пакет на этом соединении затем диспетчеризуется по 0x1F4, через bd49a7 в bd5362, и попадает сюда:

bd5432: memset(0x30a7e60, 0, 0x748)    ; scratch region (ends 0x30a85a8)
bd5445: mov   rcx,[rbp-0x208]          ; inbound packet buffer
bd544c: movzx eax,WORD [rcx+0xf2]      ; u16 wire length of the segment
bd5453: add   eax,0xfffffff6           ; len = len - 10   <== THE UNDERFLOW
bd5456: mov   WORD [0x30a8476],ax      ; wrapped length PERSISTED to .bss
bd545d: movzx edx,ax                   ; memcpy length (1..9 -> 0xfff7..0xffff)
bd5460: mov   rsi,[rcx+0xe8]
bd5467: add   rsi,0xa                  ; src = payload + 10
bd546b: mov   edi,0x30a8075            ; dst = FIXED .bss global
bd5470: call  1b075e0                  ; memcpy: up to ~64 KB OOB write
bd5475: mov   BYTE [0x30a8478],1

Читается как предложение. Взять длину сегмента. Вычесть 10. Сохранить результат, передать его в memcpy, готово. Ни в какой момент никто не спрашивает, является ли «длина минус 10» всё ещё числом, которое имеет смысл.

Защита, которой нет

Мы подсчитали каждое обращение к этому полю длины в данной функции. Тридцать. Ровно одно из них — проверка, по адресу bd4083, и всё, что она делает, — это сравнение с нулём. Сегмент нулевой длины отклоняется. Любая другая длина, включая от 1 до 9, проходит прямиком в вычитание.

Код явно полагает, что к моменту выполнения состояния 0x1F4 конечный автомат уже доставит достаточно полную запись. Конечный автомат ничего подобного не обещал. Укороченный сегмент, пришедший отдельным пакетом, удовлетворяет всем условиям диспетчеризации и оказывается на пять байт короче.

Самое раздражающее то, что производитель знает об этом классе ошибок. В другом месте того же самого бинарника sub_119c940 выполняет ту же самую арифметику «длина минус константа» и ограждает её через cmp eax,0x3f9 / ja. Безопасный шаблон лежал прямо здесь. Просто в этом месте его не применили.

Что происходит при переполнении

Назначение, 0x30a8075, находится внутри буферной области размером 0x748 байт, перед которой есть лишь 0x533 байта легитимного пространства. Переполненное копирование выходит за её пределы в соседние глобальные переменные DataStream и согласования — вашими байтами. А сама переполненная длина сохраняется в 0x30a8476, откуда её позже считывает и доверяет ей другой код. Это второй канал повреждения, на шаг удалённый от memcpy.


Триггер

Настройка — это одна строка конфигурации, стандартное развёртывание DataStream:

add lb vserver v ORACLE <ip> 1521

Бэкенд не нужен. Устройство само завершает TNS и формирует собственный пакет Accept, включая строку вендора "Netscaler" и всё остальное.

Диалог состоит из четырёх шагов:

1. TNS Connect (version 0x13A)
     <- the appliance answers Resend(11), then Accept(2), 32 bytes, v0x139

2. one complete, benign TTC round-trip
     (some builds like to glue your runt onto the previous segment;
      this resets the segmentation so the runt lands alone)

3. the arming segment: a TNS Data packet whose declared length is
     actual + 32, carrying TTC bytes {03 5E} (TTIFUN / OALL8)
     -> the state machine latches [pcb+0x15a] = 0x1F4, mid-record

4. the runt: 1-9 bytes, sent as its own TCP segment
     -> passes the zero check, dispatches on 0x1F4
     -> length - 10 wraps
     -> memcpy(0x30a8075, payload+10, ~0xFFF6)
     -> the packet engine dies

Шаги с 1 по 3 — это чистый диалог. Шаг 4 — пять байт.


Наблюдаемое поведение при сбое

Это срабатывало дважды на устройстве 14.1-73.30, на одной и той же машине, одной и той же сборке, в двух независимых запусках. Оба раза пакетный движок получал SIGSEGV с соответствующим core dump, ns.log фиксировал сигнал 11 в этом окне, а dataplane простаивал в течение примерно 60-секундного тёплого перезапуска.

Негативный контроль прошёл в обоих запусках. Запустите идентичный диалог, но сделайте финальный сегмент связным и длиной 10 байт — и ничего не произойдёт. Движок его обработает и продолжит работу. Единственная переменная, которая имеет значение, — это длина огрызка.

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