NGINX Rift: 18 metų senumo klaida rewrite modulyje ir kodėl jūsų serveris šiuo metu yra pavojuje.
NGINX Rift: 18 metų senumo klaida rewrite modulyje ir kodėl jūsų serveris šiuo metu yra pavojuje.
Įsivaizduok: tavo nginx veikia jau kelerius metus. HTTPS sukonfigūruotas, saugumo antraštės nustatytos, fail2ban blokuoja botus. Uždarytos visos akivaizdžios spragos. Ir staiga kažkas siunčia vieną HTTP užklausą — tokią pat kaip tūkstančiai kitų — ir tavo darbuotojo procesas sugriūna. Jei ASLR išjungtas, jie jau vykdo savo kodą nginx vardu.
Išoriškai nieko nesugedo. Nginx paleido naują darbuotoją ir toliau dirba. Jokio įspėjimo. Tik žurnale mirktelėjo eilutė: „worker process exited on signal 11.”
Sveiki atvykę į CVE-2026-42945, žinomą kaip NGINX Rift.
JIS BUVO VISUR — IR NIEKAS NEPASTEBĖJO
2026 m. gegužės 13 d. F5 kartu su tyrimų platforma depthfirst atskleidė kritinę pažeidžiamumą ngx_http_rewrite_module modulyje — modulyje, atsakingame už rewrite, if ir set direktyvų apdorojimą, tai yra už URL perrašymą. Beveik kiekviena netriviali nginx konfigūracija jį naudoja.
Pažeidžiamumas egzistuoja nuo 2008 metų. Nuo nginx 0.6.27 versijos. Jis sėdėjo šaltinio kode per visas versijas, per visus saugumo auditus, per visus atnaujinimus. 18 metų.
Paveikta: NGINX Open Source 0.6.27 — 1.30.0, NGINX Plus R32 — R36, ir viskas, kas sukompiliuota iš to paties ngx_http_script.c — įskaitant Ingress NGINX Kubernetes klasteriuose.
CVSS v4.0: 9.2 Critical. CVSS v3.1: 8.1 High.
Įdomi detalė apie tai, kaip ji buvo rasta: depthfirst įkėlė nginx šaltinio kodą į savo AI kodo analizės sistemą ir gavo rezultatą maždaug per šešias valandas. Šešios valandos prieš aštuoniolika metų. Tai ne kaltinimas nginx — tai signalas, kad rankinis kodo peržiūrėjimas nebespėja su tokia klaidų klase.
KAS YRA HEAP BUFFER OVERFLOW IR KODĖL TAI PAVOJINGA
Prieš nagrinėjant konkretią klaidą — sekundė kontekstui, nes šis terminas svarbus.
Kai nginx apdoroja užklausą, jis paskiria atminties gabalą (heap) darbui su duomenimis. Buffer overflow atsitinka tada, kai programa įrašo daugiau duomenų nei telpa į paskirtą gabalą ir pradeda užrašyti gretimą atmintį. Toje gretimoje atmintyje gali būti funkcijų rodyklės, valdymo struktūros — kas tik nori.
Kodėl tai kritiškai svarbu: jei užpuolikas gali kontroliuoti, kas tiksliai įrašoma už buferio ribos, jis gali perrašyti funkcijos rodyklę savo adresu. Kai nginx iškviečia tą funkciją — vykdomas užpuoliko kodas. Tai ir yra Remote Code Execution.
KAip veikia klaida
nginx apdoroja rewrite taisykles dviem perėjimais per kodą.
Pirmasis perėjimas — žvalgas. Jis eina per taisyklę ir skaičiuoja: kiek baitų reikia paskirti rezultatinei eilutei? Žiūri į šabloną, į replacement eilutę, į captures — ir formuoja reikiamą buferio dydį.
Antrasis perėjimas — vykdytojas. Gauna jau paskirtą buferį reikiamo dydžio ir kopijuoja į jį duomenis.
Problema slepiasi viename vėliavėlėje vardu is_args. Ji nustatoma pirmojo perėjimo metu, kai replacement eilutėje aptinkamas klaustukas — tai signalas, kad toliau eina query string, tai yra parametrai kaip ?id=123. Logika teisinga: vėliavėlė reikalinga, kad pirmasis perėjimas tiksliai apskaičiuotų ilgį.
Tačiau vėliavėlė nėra atstatoma tarp perėjimų. Ji prasismelkia į antrąjį — ir ten verčia funkciją ngx_escape_uri veikti kitu režimu, su kita ekranavimo logika ir kitais ilgio skaičiavimais. Rezultatas: antrasis perėjimas įrašo daugiau baitų nei paskyrė pirmasis. Buferis perpildomas.
Suveikia tik esant dviem sąlygoms vienu metu:
— unnamed PCRE captures taisyklėje: $1, $2, $3 (regex grupė be pavadinimo — tiesiog laužtiniai skliaustai)
— klaustukas replacement eilutėje
Pavyzdys — tipinis API proxy:
location /api/ {
rewrite ^/api/(.*)$ /internal?id=$1 last;
}
Čia yra ir unnamed capture (.*) — tai $1 — ir klaustukas prieš id=$1. Abi sąlygos įvykdytos. Ši konfigūracija yra pažeidžiama.
Ir tai nėra egzotika. Tai standartinis šablonas, randamas pusėje nginx pamokų internete. Žmonės rašė jį teisingai — jie tiesiog nežinojo, kad viduje slypi vėliavėlė, kuri neteisingai neatstatoma.
KAIP KONKREČIAI IŠNAUDOJAMA
Užpuolikas siunčia HTTP užklausą į pažeidžiamą endpoint. URI — ilga eilutė iš pasikartojančių simbolių, pavyzdžiui, šimtai pliuso ženklų.
Pirmasis perėjimas skaičiuoja buferio dydį pagal normalią logiką — neatsižvelgdamas į prasismelkusią vėliavėlę. Buferis paskiriamas.
Antrasis perėjimas pradeda kopijuoti — ir dėl neteisingos vėliavėlės ngx_escape_uri pradeda pridėti escape sekas (%2B vietoj +, pavyzdžiui). Eilutė auga. Peržengia buferio ribą. Užrašo gretimą atmintį.
Kritiškai svarbi detalė: duomenys, rašomi už buferio ribos, ateina tiesiai iš užpuoliko URI. Jis kontroliuoja, kas tiksliai ten patenka. Tai ne atsitiktinis atminties sugadinimas — tai valdomas įrašas.
KAS NUTINKA TOLIAU — PRIKLAUSO NUO SISTEMOS NUSTATYMŲ
Su įjungtu ASLR (Address Space Layout Randomization, parametras kernel.randomize_va_space = 2):
Kiekvieną kartą paleidžiant procesą atminties adresai yra atsitiktiniai. Užpuolikas nežino, kur tiksliai atmintyje yra tai, ką jis nori perrašyti. Perpildymas įvyksta, bet patenka į atsitiktinę vietą — nginx sugriūna su signal 11 (segfault) ir paleidžiamas iš naujo. Tai Denial of Service: nemalonu, svetainė mirkteli, bet ne katastrofa.
Be ASLR arba su išjungtu ASLR:
Adresai nuspėjami. Užpuolikas žino, kur rašyti. Rezultatas — deterministinis RCE: viena užklausa, bet koks kodas nginx vardu.
Tačiau yra niuansas su ASLR: depthfirst savo PoC dokumentavo techniką pavadinimu progressive heap shaping. Tai eilė specialiai parinktų užklausų, kurios palaipsniui „sudėlioja” heap reikiama forma — taip, kad reikiamos struktūros atsidurtų nuspėjamose vietose net su įjungtu ASLR. Tai sudėtingiau nei viena užklausa, reikalauja laiko, bet veikia. ASLR nėra absoliuti apsauga — jis pakelia kartelę, bet neužsandarina spragos.
Gegužės 16 d. — praėjus trims dienoms po PoC paskelbimo — VulnCheck užfiksavo pirmąsias realias išnaudojimo bandymus internete.
ATAKOS GRANDINĖ REALIAME PASAULYJE
NGINX Rift ypač pavojingas ne pats savaime, o kartu su kitomis gegužės 2026 pažeidžiamumomis.
NGINX Rift suteikia užpuolikui kodo vykdymą nginx darbuotojo proceso kontekste — vartotojas www-data arba nginx, be privilegijų. Pats savaime nemalonu, bet ne root.
Dirty Frag (CVE-2026-43284 / CVE-2026-43500) — Linux branduolio pažeidžiamumas, atskleistas 2026 m. gegužės pradžioje. Leidžia bet kuriam neprivilegijuotam vartotojui gauti root per page cache perpildymą esp4, esp6 ir rxrpc branduolio moduliuose.
Grandinė: viena HTTP užklausa → atrama nginx darbuotojo procese → Dirty Frag → root serveryje. Be autentifikacijos. Be paskyrų. Be pėdsakų programų žurnaluose.
Tai ne teorinė ataka. Abu pažeidžiamumai turi būti pataisyti dabar.
PATIKRINK SAVE — TRYS KOMANDOS
Pirma — nginx versija. Reikia 1.30.1 arba naujesnės:
nginx -v
Jei matai kažką panašaus į nginx/1.24.0 arba nginx/1.18.0 — esi pažeidžiamas.
Antra — ar konfigūracijoje yra pažeidžiamų rewrite taisyklių. Ieškome rewrite direktyvų su $1/$2 ir klaustuku:
grep -rn "rewrite" /etc/nginx/ | grep -E '\$[0-9].*\?'
Tuščias išvestis — gerai. Netuščias — turi pažeidžiamą konfigūraciją, atnaujink nedelsiant nepriklausomai nuo nginx versijos.
Trečia — ASLR. Kol neatnaujinai, įsitikink, kad įjungtas:
cat /proc/sys/kernel/randomize_va_space
Turi būti 2. Jei 0 arba 1 — tai reiškia RCE viena užklausa. Įjunk nedelsiant:
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
echo "kernel.randomize_va_space = 2" | sudo tee /etc/sysctl.d/99-aslr.conf
sudo sysctl -p /etc/sysctl.d/99-aslr.conf
Tai neužsandarina pažeidžiamumo — bet perkelia scenarijų nuo RCE prie DoS. Žymiai geriau.
ATNAUJINIMAS
Atnaujinimas — vienintelis pilnas sprendimas. Konfigūraciniai sprendimų būdai nepakankantys production aplinkoje.
Debian/Ubuntu:
sudo apt update && sudo apt install nginx
nginx -v
Svarbu: oficialios Ubuntu ir Debian saugyklos kartais atsilieka kelias dienas nuo upstream. Jei apt pateikia versiją žemiau 1.30.1 — prijunk oficialią nginx.org saugyklą tiesiogiai. Tai saugu: GPG raktai patikrinti.
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update && sudo apt install nginx
RHEL/AlmaLinux/Rocky Linux:
sudo dnf update nginx
nginx -v
Po atnaujinimo — būtinai patikrink konfigūraciją ir perkrauk. Kartais po didelio atnaujinimo nginx keičia direktyvų elgesį ir konfigūracija nustoja tikrinantis:
sudo nginx -t && sudo systemctl reload nginx
nginx -t tikrina konfigūracijos sintaksę. Jei klaidų nėra — reload pritaiko naują versiją be prastovų. Jei yra — ištaiso prieš taikant.
JEI DABAR NEGALIMA ATNAUJINTI
Kartais production negalima liesti dabar pat: leidimas, pakeitimų sustabdymas, derinimas. Tokiu atveju — konfigūracinė mitigacija.
Pažeidžiamumas reikalauja dviejų sąlygų vienu metu: unnamed capture ($1, $2) ir klaustukas replacement eilutėje. Pašalink vieną — klaida nesuveiks.
Pirmas būdas — pakeisti unnamed captures į named. Named captures eina kitu kodo keliu ir neaktyvina pažeidžiamo kelio:
# Buvo — pažeidžiama (unnamed capture, klaustukas):
rewrite ^/api/(.*)$ /internal?id=$1 last;
# Tapo — saugu (named capture):
rewrite ^/api/(?P.*)$ /internal?id=${id} last;
(?P.*) — tai named capture su pavadinimu id. ${id} — kreipimasis į jį pagal pavadinimą. Funkciškai tas pats, bet kitas kodo kelias.
Antras būdas — pašalinti rewrite su klaustuku ir perrašyti per proxy_pass:
# Vietoj rewrite:
location ~ ^/api/(.+)$ {
proxy_pass http://backend/internal?id=$1;
}
proxy_pass neeina per ngx_http_rewrite_module — pažeidžiamumas netaikomas.
Tai laikina priemonė. Atnaujinimas vis tiek būtinas.
KUBERNETES IR INGRESS NGINX — YPATINGAS ATVEJIS
Jei naudoji Ingress NGINX Controller Kubernetes klasteryje — situacija sudėtingesnė.
2026 m. kovo mėnesį Kubernetes projektas nutraukė Ingress NGINX palaikymą. Paskutinė versija — v1.15.1. Ji turi tą patį ngx_http_script.c su tuo pačiu pažeidžiamumu. Ir upstream pataisymo nebus — projektas uždarytas.
Ingress controller ypatybė: jis paprastai pasiekiamas iš viešojo interneto tiesiai prie klasterio krašto. NGINX Rift čia — pažeidžiamumas be autentifikacijos, pasiekiamas tiesiai iš interneto, be pataisymo.
Migracija: nginx-gateway-fabric (oficialus F5 įpėdinis), Traefik arba Envoy. Tai ne greita užduotis, bet ji jau nebebėra neprivaloma.
KODĖL TAI NE „DAR VIENAS CVE”
nginx veikia maždaug 34% visų pasaulio interneto serverių. Jis stovi prieš backend, prieš duomenų bazes, prieš API — pirmas gauna kiekvieną įeinančią HTTP užklausą, anksčiau už bet kurį kitą apsaugos lygmenį. Cloudflare viršuje? WAF taisyklės? Puiku. Tačiau užklausos iš tikrų vartotojų vis tiek pasiekia nginx — ir viena iš jų gali būti specialiai suformuota.
Kuo šis CVE skiriasi nuo daugumos kitų:
— klaida kode, kuris vykdomas apdorojant kiekvieną rewrite užklausą
— nereikalauja autentifikacijos
— nereikalauja jokių privilegijų
— veikia per paprastą HTTP
— PoC viešas nuo pirmos dienos
Nginx atnaujinimas — tai ne „padarysiu savaitgalį”. Išnaudojimas jau vyksta.
