DarkReplica (CVE-2026-23631): kaip Redis atidavė RCE per replikacijos mechanizmą
DarkReplica (CVE-2026-23631): kaip Redis atidavė RCE per replikacijos mechanizmą
Redis veikia už pusės šiuolaikinio interneto — sesijų talpykla, užduočių eilės, greičio ribojimas, pub/sub. Būtent dėl to pažeidžiamumas jame retai lieka tik teorinis. CVE-2026-23631, pavadintas DarkReplica, yra use-after-free klaida replikacijos posistemėje, kuri tam tikromis sąlygomis atveria kelią į savavališko kodo vykdymą serveryje. Tyrėjas Yoni Sherez ją rado ZeroDay.Cloud 2025 varžybose Londone praėjusių metų gruodį ir gavo $30 000. Pataisymas išleistas 2026 m. gegužės 5 d. Jei dar neatnaujinote — skaitykite toliau.
KAS NUTIKO
CVE-2026-23631 — use-after-free pažeidžiamumas Redis replikacijos mechanizme. CVSS 6.1 (Medium pagal CVSSv4.0), CWE-416. Oficialus Redis aprašymas: autentifikuotas vartotojas gali išnaudoti master-replica sinchronizacijos mechanizmą ir sukelti use-after-free Lua funkcijų variklyje, o tai gali lemti nuotolinį kodo vykdymą. Pažeidžiamumas paveikia visas Redis versijas su Lua scripting palaikymu — tai praktiškai visos realiai naudojamos versijos. Vienintelis apribojimas: reikalinga autentifikacija Redis serveryje. Koncepcijos įrodymas paskelbtas tyrėjo writeup.
Svarbi pastaba dėl CVSS: kai kurie šaltiniai nurodo 8.5 High — tai senesnis CVSS v2 balas iš antrinio šaltinio. Oficialus Redis ir NVD įvertinimas pagal CVSSv4.0 yra 6.1 Medium, su aukštu atakos sudėtingumu (AC:H). Tai nereiškia, kad pažeidžiamumas nepavojingas. Tai reiškia, kad sėkmingai išnaudoti jį reikia kelių sąlygų sutapimo — tačiau Yoni Sherez parodė, kad tai įmanoma.
KAS YRA REDIS REPLIKACIJA IR LUA VARIKLIS
Redis palaiko master-replica replikaciją: vienas serveris skiriamas pagrindiniu, kiti — replikomis. Replika prisijungia prie master serverio, gauna pilną sinchronizaciją paleidžiant, o tada priima nuolatinę komandų srautą realiuoju laiku. Komanda SLAVEOF naudojama master serveriui priskirti. Tai standartinis mechanizmas aukštam pasiekiamumui ir skaitymo masteliavimui.
Redis taip pat turi integruotą Lua variklį — tiksliau, du. Pirmasis yra scripting engine (EVAL, EVALSHA, SCRIPT LOAD) — senesnis modelis savavališkiems Lua skriptams vykdyti. Antrasis — functions engine (FUNCTION LOAD, FCALL) — naujesnis dizainas, leidžiantis registruoti pavadintas funkcijų bibliotekas, kurios saugomos RDB/AOF ir sinchronizuojamos tarp klasterio mazgų. Būtent functions engine tapo DarkReplica įėjimo tašku.
KAIP VEIKIA KLAIDA
Redis yra vienos gijos serveris. Kai Lua funkcija vykdoma per ilgai — pagal numatytuosius nustatymus ilgiau nei 5 sekundes — serveris nebegali įprastu būdu apdoroti naujų užklausų. Kad visiškai neužšaltų, Redis prieš vykdant Lua kodą įdiegia kabliuką per lua_sethook. Šis kabliukas suveikia kas 100 000 Lua instrukcijų ir iškviečia processEventsWhileBlocked(), kuri apdoroja laukiančius įvykius iš event loop ir palaiko serverio atsakomumą net lėtos funkcijos vykdymo metu.
Kritinė detalė: processEventsWhileBlocked() apdoroja ne tik paprastų klientų užklausas — ji tvarko visus I/O įvykius, įskaitant komandas, ateinančias iš master serverio per replikacijos kanalą. Ir niekas tame kelyje netikrina, ar šiuo metu vykdoma Lua funkcija. Paprasti klientai, bandantys vykdyti neleistiną komandą skripto metu, gauna klaidą BUSY Redis is busy running a script. Tačiau ta pati komanda FUNCTION FLUSH, ateinanti iš master serverio per replikacijos kanalą — praeis.
Rezultatas: Lua variklis ištrinamas iš atminties master komanda tuo pačiu metu, kai funkcija vis dar jį naudoja. Lua aplinka atlaisvinta — tačiau vykdymas toliau kreipiasi į jau atlaisvintą atmintį. Tai klasikinis use-after-free: atlaisvintas Lua variklis, kuris vis dar naudojamas. CWE-416 gryniausia forma.
KAIP TAI IŠNAUDOJAMA
Užpuolikas, turintis autentifikuotą prieigą prie Redis serverio, vykdo tokią seką. Pirmiausia jis paleidžia lėtą Lua funkciją per FCALL — tokią, kuri veiks pakankamai ilgai, kad Redis pasiektų timeout ribą ir pradėtų kviesti processEventsWhileBlocked(). Tada per replikacijos kanalą — sukonfigūravęs kontroliuojamą „master” serverį — siunčia komandą FUNCTION FLUSH. Redis ją priima ir sunaikina Lua variklį funkcijos vykdymo metu.
Gavęs use-after-free, Yoni Sherez sukūrė technikų rinkinį savavališkam proceso atminties skaitymui ir rašymui. Jo žodžiais, išnaudojimui reikėjo gilaus Redis vidinės struktūros ir Lua 5.1 virtualios mašinos išmanymo — tai ne paprastas vieno paspaudimo eksploitas. Tačiau rezultatas pasiektas: savalinių sisteminių komandų vykdymas tiksliniame serveryje Redis proceso tapatybės vardu. Pilnas techninis writeup paskelbtas ZeroDay.Cloud platformoje.
KAS NUTINKA TOLIAU — PRIKLAUSO NUO KONFIGŪRACIJOS
Pažeidžiamumas suveikia tik esant kelioms sąlygoms vienu metu: autentifikuota prieiga prie Redis, galimybė sukonfigūruoti replikacijos kanalą, įjungtas Lua scripting (pagal numatytuosius nustatymus aktyvus) ir replika su išjungtu replica-read-only. Jei Redis visai nenaudoja replikacijos — master kanalo atakos vektorius neprieinamas. Jei Redis pasiekiamas tik iš localhost arba griežtai kontroliuojamo privataus tinklo — rizika ženkliai sumažėja.
Labiausiai pažeidžiamos konfigūracijos, kuriose Redis pasiekiamas keliems klientams, naudojama replikacija ir autentifikacija silpna arba jos nėra. Tokios nuostatos dažnai pasitaiko kūrimo aplinkose ir serveriuose, kurie buvo „greitai paleisti” nesilaikant jokių apsaugos gairių. Redis Cloud instancijos apsaugotos — tiekėjas jau įdiegė pataisymus.
REALI ATAKOS GRANDINĖ
Realus scenarijus atrodo taip. Žiniatinklio programa naudoja Redis talpyklai ir sesijoms. Redis turi slaptažodį, tačiau jis silpnas arba nutekėjęs. Užpuolikas jungiasi tiesiogiai — per atvirą 6379 prievadą arba per programos pažeidžiamumą, leidžiantį siųsti savalingas Redis komandas. Serveris veikia su Redis 7.4.8, nepakeitu nuo įdiegimo. Užpuolikas paleidžia lėtą Lua funkciją per FCALL, tuo pačiu metu paleidžia kontroliuojamą Redis instanciją ir per SLAVEOF paskiria ją master serveriu tiksliniui serveriui. Kai Lua timeout suveikia ir Redis įeina į processEventsWhileBlocked(), FUNCTION FLUSH komanda iš fiktyvaus master sunaikina Lua variklį. Use-after-free atveria kelią į RCE. Redis veikia redis vartotojo vardu — užpuolikas gauna shell su tomis teisėmis, nuskaito duomenis iš atminties ir gauna prieigą prie sesijų duomenų bei programos talpyklos.
CHRONOLOGIJA
2025 m. gruodis. ZeroDay.Cloud 2025 varžybos Londone. Yoni Sherez renkasi Redis kaip taikinį — „dėl jo sudėtingumo ir didelės bei įdomios atakos paviršiaus”, kaip jis rašė writeup. Randa DarkReplica. Gauna $30 000. 2026 m. sausis — CVE rezervuotas. 2026 m. gegužės 5 d. — Redis išleidžia pataisymą visoms penkioms palaikomoms šakoms vieną dieną. 2026 m. birželio 2 d. — Yoni Sherez paskelbia pilną techninį writeup ZeroDay.Cloud platformoje. Šeši mėnesiai nuo radimo iki viešo atskleidimo. Pataisymas pasirodė mėnesį anksčiau nei techninės detalės tapo viešos. Taip ir turėtų veikti responsible disclosure.
KODĖL TAI SVARBU
Redis nėra nišinis įrankis. Tai talpykla už jūsų nginx, sesijų saugykla jūsų WordPress, užduočių eilė jūsų programai. Jis veikia beveik kiekviename production serveryje, kuris daro ką nors sudėtingesnio nei statinių failų tiekimas. DarkReplica paveikia visas Redis versijas su Lua scripting — tai visos versijos, kurios realiai naudojamos serveriuose. Todėl CVSS 6.1 neturėtų sukelti nerūpestingumo: „Medium” yra atakos sudėtingumo, o ne jos pasekmių įvertinimas. RCE yra RCE, nesvarbu, kiek sąlygų reikia tam pasiekti.
Atskira istorija — Redis be autentifikacijos arba su silpnu slaptažodžiu, tiesiogiai prieinamas iš interneto. Tokioms instancijoms sąlyga „reikalinga autentifikacija” tiesiog išnyksta iš lygties. DarkReplica su replikacija virsta tiesioginiu keliu į RCE. Tokių serverių yra daugiau, nei norėtųsi pripažinti — Redis istoriškai buvo suprojektuotas veikti patikimame tinkle, ir daugelis administratorių vis dar elgiasi taip, lyg taip ir būtų.
ATNAUJINIMAS
Pataisymas išleistas 2026 m. gegužės 5 d. visoms palaikomoms šakoms. Patikrinkite dabartinę Redis versiją — pirmoji komanda parodys kliento versiją, antroji paklaus veikiančio serverio. Jei Redis apsaugotas slaptažodžiu, perduokite jį per žymą -a; jei ne — praleiskite ją:
redis-cli --version
redis-cli INFO server | grep redis_version
# jei Redis reikalauja slaptažodžio:
redis-cli -a JŪSŲ_SLAPTAŽODIS INFO server | grep redis_version
Tada palyginkite su pataisytų versijų lentele. Jei jūsų versija patenka į paveiktą diapazoną — atnaujinkite nedelsiant.
Paveiktos šakos ir pataisytos versijos pagal oficialų Redis advisory:
- Redis 7.2.x: paveiktos 7.2.0 – 7.2.13, pataisyta 7.2.14
- Redis 7.4.x: paveiktos 7.4.0 – 7.4.8, pataisyta 7.4.9
- Redis 8.2.x: paveiktos 8.2.0 – 8.2.5, pataisyta 8.2.6
- Redis 8.4.x: paveiktos 8.4.0 – 8.4.2, pataisyta 8.4.3
- Redis 8.6.x: paveiktos 8.6.0 – 8.6.2, pataisyta 8.6.3
Atnaujinimas Ubuntu/Debian sistemose priklauso nuo to, iš kur Redis buvo įdiegtas. Jei iš oficialios redis.io saugyklos — įsitikinkite, kad saugykla prijungta, tada atnaujinkite. Jei saugykla dar nepridėta, oficiali redis.io instrukcija:
sudo apt-get install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis
Jei saugykla jau sukonfigūruota — pakanka atnaujinti paketą:
sudo apt-get update
sudo apt-get install redis
redis-cli --version
Svarbu: Ubuntu ir Debian iš savo standartinių saugyklų teikia pasenusią Redis versiją — dažniausiai 6.x arba 7.0. Komanda sudo apt install redis-server be oficialios redis.io saugyklos nesuteiks reikiamos versijos — tik packages.redis.io turi aktualias 7.2, 7.4 ir 8.x šakas. Po atnaujinimo paleiskite paslaugą iš naujo:
sudo systemctl restart redis-server
sudo systemctl status redis-server
Jei atnaujinti šiuo metu neįmanoma, Redis oficialiai aprašo du laikinuosius sprendimus. Pirmasis — blokuoti Lua skriptų vykdymą: apribokite komandas EVAL, EVALSHA, FCALL ir FCALL_RO per ACL mechanizmą visiems vartotojams, kuriems ši funkcija nereikalinga. Tikslus sintaksas priklauso nuo Redis versijos ir ACL konfigūracijos — žr. oficialią Redis ACL dokumentaciją. Antrasis laikinasis sprendimas — įsitikinti, kad visos replikos veikia su replica-read-only yes. Tai numatytoji reikšmė, tačiau verta patikrinti tiesiogiai. Kiekvienoje replikoje vykdykite:
redis-cli CONFIG GET replica-read-only
Jei išvestis rodo no — replika pažeidžiama. Įjunkite atgal:
redis-cli CONFIG SET replica-read-only yes
Kad pakeitimas išliktų po paleidimo iš naujo, pridėkite į /etc/redis/redis.conf:
replica-read-only yes
Abu laikinieji sprendimai sumažina riziką, tačiau nepašalina pažeidžiamumo — atnaujinimas išlieka vieninteliu išsamiu sprendimu.
Nepriklausomai nuo atnaujinimo būsenos, įsitikinkite, kad Redis nėra tiesiogiai pasiekiamas iš interneto. Prievadas 6379 turi būti uždarytas ugniasienėje visiems, išskyrus patikimus IP adresus. Patikrinkite per nftables:
sudo nft list ruleset | grep 6379
Jei išvestis tuščia — nėra aiškios taisyklės tam prievadui, ir Redis arba apsaugotas bind-address konfigūracijoje, arba prieinamas visiems. Patikrinkite:
grep -E "^bind|^protected-mode" /etc/redis/redis.conf
Reikšmė bind 127.0.0.1 reiškia, kad Redis klauso tik localhost. protected-mode yes — papildoma apsauga, blokuojanti išorines jungtis be slaptažodžio. Abi turi būti teisingai sukonfigūruotos.
IŠVADOS
DarkReplica primena, kad post-authentication nereiškia mažos rizikos. Autentifikacija Redis dažnai reiškia vieną slaptažodį programos ryšio eilutėje, o ne realią izoliaciją. Replikacijos mechanizmas — Redis dalis, kuri retai laikoma atakos paviršiumi. Būtent ten Yoni Sherez rado use-after-free, kurio niekas nesitikėjo. Atnaujinkite Redis iki pataisytos savo šakos versijos: 7.2.14, 7.4.9, 8.2.6, 8.4.3 arba 8.6.3. Uždarykite prievadą 6379 nuo interneto, patikrinkite replikacijos nustatymus — ir šis atakos vektorius jums bus uždarytas.
