Strona główna / Blog / NetScaler: DoS jako wyzwalacz, HA jako całość

Blog · case study

NetScaler CVE-2026-88779 + CVE-2026-88771: błąd „tylko DoS” posłużył za wyzwalacz roota, a implant przeżywa na drugim węźle HA

Dwa tygodnie temu pisałem, że CVE-2026-88779 to w świetle biuletynu Citrix odmowa usługi przy konfiguracji SAML i że nie ma podstaw, by przypisywać mu RCE. 19 października Rapid7 opublikował analizę realnej intruzji, w której ten sam błąd nie był celem, tylko narzędziem: crash parsera SAML wywołał restart urządzenia, a po restarcie crash handler call-home uruchomił jako root tekst wstrzyknięty wcześniej przez CVE-2026-88771. Drugi wniosek z tej analizy jest dla zespołów IR ważniejszy: implant zawierał logikę High Availability, czyli próbował skopiować się na węzeł partnerski i w razie potrzeby wymusić failover. Wyczyszczenie jednego węzła nie zamyka incydentu.

Źródło: Rapid7, „NetScaler Intrusions Chaining CVE-2026-88771 and CVE-2026-88779” (19.10.2026). Jedna kompromitacja NetScaler ADC zbadana na początku października 2026. Urządzenie działało na podatnym buildzie 14.1 (Rapid7 nie podaje numeru).
CVE-2026-88771 (CTX697096, 27.09.2026): RCE bez uwierzytelnienia przez niewłaściwą walidację wejścia (CWE-20), CVSS 4.0 9.5, konfiguracja domyślna. CISA KEV od 27.09.2026. Rapid7 nazywa go „pre-authentication log-poisoning/RCE issue”.
CVE-2026-88779 (CTX697174, 03.10.2026): przepełnienie pamięci prowadzące do DoS (CWE-119), CVSS 4.0 8.7 z wektorem VC:N/VI:N/VA:H, tylko przy konfiguracji SAML SP lub IdP. CISA KEV od 04.10.2026. Rapid7: „the separate SAML-parsing crash”.
Wersje naprawione (Citrix): dla 88779: 14.1-73.41, 13.1-64.28, 14.1-73.41 FIPS, 13.1-37.282 (FIPS i NDcPP). Dla 88771 progi są niższe: 14.1-73.37, 13.1-64.23, 14.1-73.37 FIPS, 13.1-37.279. Build zgodny z CTX697174 spełnia więc oba biuletyny.
Atrybucja: Rapid7 nie wskazuje aktora. Pisze, że aktywność pokrywa się z publicznymi doniesieniami o kampanii WHIPSHOT/SLAPSHOT wymierzonej w NetScaler.

Łańcuch: kto dostarcza komendę, a kto wyzwalacz

Rapid7 opisuje sekwencję, w której każda z podatności robi coś innego. Według raportu „the SAML parsing flaw supplies a crash/reboot condition, while the log-poisoning flaw supplies attacker-controlled command text”. Krok po kroku:

1. auth request, username = attacker text CVE-2026-88771 (log poisoning) 2. repeated nsaaad crashes CVE-2026-88779 (SAML parsing crash) 3. Pitboss reboot 4. call-home crash handler processes retained text 5. payload executes as root 6. first implant files, same second as step 5 (filesystem timestamps)

Tekst wstrzyknięty w pole nazwy użytkownika zaczynał się od pitboss PPE unexpectedly died NSPPE;fetch${IFS}-qo${IFS}/v ...;sh${IFS}/v;#. Rapid7 ostrożnie formułuje związek przyczynowy: wstrzyknięty tekst „caused or immediately preceded” powtarzające się crashe procesu nsaaad i restart Pitboss. Mocny jest natomiast dowód samego wykonania. Komenda, pętla crashy, restart, aktywność handlera i wykonanie jako root są skorelowane w niezależnych logach i znacznikach czasu plików, a pierwsze pliki implantu powstały w tej samej sekundzie co pierwsze zalogowane wykonanie po restarcie.

Najważniejsze zdanie raportu z perspektywy VE: ścieżka obsługi crashy działała jako „delayed and repeatable execution trampoline”, a łańcuch pozwolił uniknąć czekania 24h, aż wstrzyknięty payload się wykona. Restarty i wykonania handlera powtarzały się przez kilka dni, z wielu adresów infrastruktury. Operator mógł za każdym razem odświeżyć persistence, dograć nowe komponenty i kontynuować zbieranie danych.

Błąd DoS jako prymityw eksploatacji

Wszystkie formalne oceny CVE-2026-88779 są poprawne w swoich założeniach i wszystkie opisują ogniwo w izolacji:

source CVE-2026-88779 says Citrix CTX697174 memory overflow leading to DoS, CVSS 4.0 8.7, VA:H only NVD (CVSS 3.1) 7.5 HIGH, C:N/I:N/A:H CISA SSVC in NVD (04.10) exploitation active, automatable yes, technical impact partial CISA KEV (added 04.10) could allow for a denial of service, forensicTriage No Rapid7 (19.10) crash/reboot condition in a chain ending in root execution

Porównanie z KEV dla CVE-2026-88771 jest wymowne: tam forensicTriage ma wartość „Yes”, tu „No”. Polityka, która na podstawie tych pól decyduje, gdzie robić analizę powłamaniową, potraktuje restarty z 88779 jako problem dostępności, a nie ślad wykonania kodu. Tymczasem w opisanym przypadku restart był momentem wykonania kodu jako root. To ten sam mechanizm, który opisywałem przy FortiOS CVE-2025-61624 i dwóch Windows EoP z KEV: ocena ogniwa nie mówi nic o jego pozycji w łańcuchu. Nowe jest tu to, że ogniwem okazał się błąd, który z definicji „tylko” wyłącza usługę.

Co to zmienia w praktyce, w mojej ocenie (nie są to zalecenia Rapid7 ani Citrix):

  1. Historia restartów to materiał dowodowy, a nie tylko metryka SLA. W poprzednim wpisie pisałem, że nieoczekiwane restarty „same nie dowodzą ataku”. To nadal prawda, ale Rapid7 podaje teraz konkretny wzorzec do korelacji: crashe nsaaad, restarty Pitboss i rekordy wykonania ns_monuploadd_err.pl. Restart w oknie ekspozycji na urządzeniu z SAML wymaga sprawdzenia, co działo się zaraz po nim.
  2. Brak SAML nie usuwa ryzyka 88771. Warunek SAML dotyczy tylko 88779, czyli szybkiego wyzwalacza. Ze zdania Rapid7 o „czekaniu 24h” wnioskuję, że wstrzyknięty payload wykonałby się także bez restartu, tylko później. Raport nie opisuje jednak przebiegu ataku bez 88779, więc to interpretacja, a nie ustalenie.
  3. Restart urządzenia w trakcie IR to też uruchomienie handlera. Rapid7 zaleca zebranie ulotnych dowodów przed restartem lub przebudową, a w opisanym ataku zachowany w logach tekst był przetwarzany właśnie po restarcie. Czy restart przy aktualizacji do buildu naprawionego może ponownie uruchomić zachowany payload, raport nie mówi. Dlatego kolejność z wpisu z 29 września (najpierw dowody, potem patch) ma tu jeszcze jeden argument.

Co implant robił po wejściu

Skrót tego, co Rapid7 potwierdził na urządzeniu. Pełne listy są w raporcie, poniżej tylko elementy istotne dla oceny zakresu remediacji:

  • Webshelle PHP w trzech kopiach w /var/netscaler/logon/LogonPoint/custom/ (.slap.receiver, .ctxs.receiver, receiver.deb), z kopiami zapasowymi w /nsconfig/.slap/. Kanał poleceń przez cookie, wynik zwracany w treści odpowiedzi HTTP 404. Atakujący włączył PHP w Apache, kazał traktować pliki .deb jak PHP i zmapował adresy wyglądające na arkusze stylów (receiver.v2.min.css, receiver.v2.min.<hex>.css) na webshella.
  • Setuid shell: wielokrotne chmod 6555 /bin/sh, dzięki czemu webshell działający jako nieuprzywilejowany Apache uzyskuje efektywnie roota.
  • Proxy nsvmd (FreeBSD, Go) w /flash/.nsvm/, uruchamiane jako nsvmd -server v5v.in:443 -sni c.v5v.in, z watchdogiem co 45 s, wpisem w /nsconfig/rc.netscaler, cronem co 5 minut i codziennym restartem oraz flagą chflags uchg przeciw usunięciu.
  • Tunele i kanały poleceń: menedżer sesji w Perlu otwierający połączenia TCP do dowolnych hostów wewnętrznych, tunel HTTP w Pythonie (zbieżny według Rapid7 z narzędziami WHIPSHOT/SLAPSHOT), reverse agent odpytujący serwer co 15 s.
  • Rekonesans: statyczny binarny Go (/nsconfig/.slap/vc) skanujący RFC1918, DNS (z próbami transferu strefy), LDAP z anonimowym bind, usługi zarządzania i VMware vCenter.
  • Eksfiltracja: /nsconfig/ (w tym ns.conf.0 do ns.conf.4 i ns.conf.bak), /etc/httpd.conf, archiwa backupów. Według Rapid7 konfiguracja może ujawniać zaszyfrowane poświadczenia, dane bind LDAP/RADIUS, klucze prywatne SSL i materiał szyfrowania kluczy. Jedno archiwum zostało pobrane przez interfejs WWW odpowiedzią HTTP 200 o rozmiarze zgodnym z archiwum.
  • Odporność na sprzątanie: cron i hooki startowe są odtwarzane przy każdym uruchomieniu frameworka, więc kompromitacja przeżywa restarty, regenerację obrazu i usunięcie pojedynczych wpisów crona.

Para HA to jeden blast radius

Nowsza wersja droppera (1.sh) dodała według Rapid7 m.in. „HA recovery”. W kodzie znalazły się polecenia sync HA files all i force HA failover. Raport opisuje to tak: kod próbował zsynchronizować pliki implantu na węzeł partnerski HA i, gdy uznał to za stosowne, wymusić failover, aby aktywny stał się węzeł z implantem. Rapid7 podsumowuje, że logika synchronizacji i wymuszonego failoveru „attempted to preserve access across the appliance pair”.

Raport nie mówi, czy w badanym przypadku implant faktycznie znalazł się na drugim węźle ani czy failover został wymuszony. Opisuje możliwość wbudowaną w narzędzie. Dla planu remediacji to wystarczy, bo scenariusz jest łatwy do odtworzenia: zespół izoluje i przebudowuje węzeł aktywny, ruch przejmuje węzeł pasywny, który dostał kopię implantu przez synchronizację HA, a po powrocie przebudowanego węzła synchronizacja konfiguracji działa w drugą stronę. Ostatni krok to moja interpretacja mechanizmu HA, nie opis z raportu.

Warto zauważyć, że strona Citrix CTX694799 (kroki przy podejrzeniu kompromitacji) opisuje postępowanie dla instancji MPX, SDX i VPX, ale nie wspomina o parach HA. Zaleca m.in. odtworzenie konfiguracji z backupu sprzed kompromitacji, rotację KEK i wymianę certyfikatów. Rapid7 dopisuje brakujący element wprost: „Inspect both nodes of every HA pair”.

Dla VE oznacza to zmianę jednostki oceny. Finding dotyczy pary, a nie pojedynczego urządzenia, i nie zamyka się, dopóki oba węzły nie mają oceny kompromitacji:

asset: netscaler-ha-pair-01 (node A + node B) vulnerability: fixed: true # 14.1-73.41 on A and B compromise: node_A: assessed, rebuilt node_B: not assessed # finding stays open secrets_rotated: false # /nsconfig was exfiltrated, so rotation is required

To rozszerzenie modelu z wpisu o dowodach przed patchem („fixed” i „clean” to dwa różne stany) i z Ivanti Connect Secure: przy klastrach i parach HA pole „compromise” trzeba prowadzić osobno dla każdego węzła.

Wskaźniki według Rapid7

Poniżej wybór wskaźników dokładnie w postaci z raportu. Pełna lista, w tym wszystkie ścieżki, sześć hashy SHA-256 i dodatkowe adresy dostarczania payloadu, jest w źródle. Rapid7 informuje też, że reguły YARA i dalsze IoC udostępnia klientom.

paths /nsconfig/.slap/ /nsconfig/.relay/ /flash/.nsvm/ /var/tmp/.s2loot/ /var/tmp/.ux/slapshot.py /var/tmp/.ux/whipd.py /tmp/.uxdlock /tmp/.uxdport /var/netscaler/logon/LogonPoint/custom/.slap.receiver /var/netscaler/logon/LogonPoint/custom/.ctxs.receiver /var/netscaler/logon/LogonPoint/custom/receiver.deb domains v5v.in (nsvmd C2) c.v5v.in (SNI) IPs 209.74.64.192 nsvmd C2 192.159.99.139 .slap C2, relay, reverse-agent, loot upload 213.209.159.55 stage server, staged-data collection 179.60.146.241 serves 1.sh 45.92.1.17 stage/loot, port 30444 SHA-256 ffe052fc50271e7739d458b155df790438776032bfd125b974735e1dd9c0b138 nsvmd 6774bfed99da38cec82e721de4bd64a67db7840efadcc71e7df02eb6f0a03c44 1.sh a0ba4e1ad622d9c3d950b4156d4430812d05bee216ab22c3804a9f7a80535556 17447d.sh 56a892d80096a9db4ca473a9c3109729c60a5ba901d6ba65948bdb1f4a6fb186 2.sh / r.sh

Poza samymi IoC Rapid7 zaleca polowanie na ustawiony setuid na /bin/sh, nieautoryzowane handlery PHP w Apache i aliasy udające pliki CSS, a także przegląd skanowania sieci wewnętrznej z adresów źródłowych NetScalera.

Co powinien zrobić VE

(1) Wersja: na każdym węźle każdej pary build co najmniej 14.1-73.41, 13.1-64.28, 14.1-73.41 FIPS lub 13.1-37.282 (FIPS/NDcPP). To spełnia jednocześnie CTX697174 i CTX697096; Rapid7 zaleca dodatkowo zweryfikować wcześniejsze poprawki z CTX697096. (2) Założenie kompromitacji: Rapid7 zaleca traktować urządzenia internetowe, które były podatne w oknie kampanii, jako potencjalnie przejęte, i pisze wprost, że „patching alone is insufficient”. (3) Dowody przed restartem na obu węzłach, zanim ktokolwiek wykona failover, upgrade albo rebuild. (4) Polowanie na obu węzłach: ścieżki .slap, .relay, .nsvm, setuid /bin/sh, handlery PHP, aliasy CSS, crashe nsaaad, restarty Pitboss, wykonania ns_monuploadd_err.pl, ruch do infrastruktury z raportu. (5) Odbudowa pary jako całości, a nie węzeł po węźle z synchronizacją z partnera, którego stanu nie znasz (moja ocena; Citrix w CTX694799 każe odtwarzać konfigurację z backupu sprzed kompromitacji). (6) Rotacja wszystkich poświadczeń i kluczy, które były w /nsconfig: LDAP/RADIUS, klucze SSL, materiał szyfrowania kluczy. (7) Polityka: pozycja w znanym łańcuchu podnosi priorytet i zakres analizy niezależnie od tego, że CVSS, SSVC i KEV opisują błąd jako „tylko DoS”.

Powiązane na blogu

Źródła

  • Rapid7 — NetScaler Intrusions Chaining CVE-2026-88771 and CVE-2026-88779 (19.10.2026) — rapid7.com
  • Citrix / Cloud Software Group — CTX697096, Security Bulletin for CVE-2026-88771 (27.09.2026) — support.citrix.com
  • Citrix / Cloud Software Group — CTX697174, Security Bulletin for CVE-2026-88779 (03.10.2026) — support.citrix.com
  • Citrix — CTX694799, Steps to Take if NetScaler ADC is Suspected to be Compromised — support.citrix.com
  • NVD — CVE-2026-88771 (CVSS 3.1 9.8, SSVC CISA: technical impact total) — nvd.nist.gov
  • NVD — CVE-2026-88779 (CVSS 3.1 7.5, SSVC CISA: technical impact partial) — nvd.nist.gov
  • CISA Known Exploited Vulnerabilities Catalog (88771 od 27.09.2026, 88779 od 04.10.2026; wersja 2026.10.16) — cisa.gov

Nota redakcyjna: stan informacji 19 października 2026, ok. 23:55 CEST, na podstawie raportu Rapid7 z 19.10.2026 (wskaźniki porównane z kodem źródłowym strony), biuletynów Citrix CTX697096 i CTX697174, strony CTX694799, rekordów NVD obu CVE (status „Analyzed”, SSVC CISA) i katalogu CISA KEV w wersji 2026.10.16. Raport Rapid7 dotyczy jednego zbadanego urządzenia i nie podaje numeru buildu, liczby ofiar ani okna czasowego kampanii. Nie weryfikowałem i źródła nie podają: czy w badanym przypadku implant faktycznie trafił na węzeł partnerski HA i czy failover został wymuszony; czy restart podczas aktualizacji do buildu naprawionego może ponownie uruchomić zachowany w logach payload; jak przebiega atak bez CVE-2026-88779 (interpretacja zdania o „24h” jest moja); czy samo usunięcie 88771 przerywa łańcuch (logicznie usuwa źródło komendy, ale Rapid7 tego nie testuje). Biuletyn CTX697174 nie wspomina o 88771 ani o łączeniu podatności i nie zawiera wytycznych dla HA. W CTX697096 build 13.1 FIPS/NDcPP zapisano raz jako „13.1-37.279”, raz jako „13.1.37.279”. Opis odbudowy pary HA i model findingu na poziomie pary to ocena autora, nie zalecenia Citrix ani Rapid7.

Zapamiętaj jedno

W ataku opisanym przez Rapid7 CVE-2026-88779, oceniany wszędzie jako DoS, był wyzwalaczem: crash SAML i restart sprawiły, że crash handler uruchomił jako root komendę wstrzykniętą przez CVE-2026-88771. Implant umiał skopiować się na drugi węzeł HA i wymusić failover. Zaktualizuj oba węzły do 14.1-73.41, 13.1-64.28 lub 13.1-37.282, zbierz dowody przed restartem, oceń kompromitację każdego węzła osobno, zrotuj sekrety z /nsconfig i zamykaj finding na poziomie pary, nie urządzenia.