Tinklaraštis

Web Cache Poisoning: viena užklausa — tūkstančiai užkrėstų vartotojų.

Poisoning_2
Linux

Web Cache Poisoning: viena užklausa — tūkstančiai užkrėstų vartotojų.

Ankstesniuose straipsniuose nagrinėjome atakas kurioms reikia kad auka ką nors padarytų — paspaustų nuorodą, atidarytų laišką. Web Cache Poisoning veikia kitaip. Užpuolikas išsiunčia vieną HTTP užklausą ir eina gerti kavos. Kitas kelias valandas — ar dienas — visi svetainės lankytojai iš talpyklos gauna užkrėstą puslapį. Automatiškai, be jokios sąveikos.

2018 metais tyrėjas James Kettle iš PortSwigger Black Hat USA parodė kaip perėmė RedHat.com pagrindinį puslapį viena užklausa. „Mes tiesiog gavome visišką kontrolę virš RedHat.com pagrindinio puslapio, ir tai nebuvo labai sudėtinga,” — pasakė jis.

KAIP VEIKIA CDN TALPYKLA

CDN stovi tarp vartotojo ir serverio. Kai ateina pirmoji užklausa — CDN kreipiasi į kilmės serverį, gauna atsakymą ir išsaugo jį talpykloje. Visos vėlesnės užklausos tam pačiam URL gauna talpykloje esantį atsakymą nekreipiantis į serverį. Tai pagreitina svetainę ir sumažina serverio apkrovą.

Norėdamas nuspręsti kurį talpyklos atsakymą grąžinti, CDN naudoja talpyklos raktą — užklausos parametrų rinkinį kuris identifikuoja puslapį. Standartinis raktas: užklausos metodas + URL + antraštė Host.

GET /index.html HTTP/1.1
Host: target.com
# Talpyklos raktas: GET | target.com | /index.html

Viskas kas nepatenka į talpyklos raktą vadinama unkeyed input — nekeliamu įvedimu. CDN jį ignoruoja ieškant talpykloje, tačiau perduoda kilmės serveriui. Serveris gali naudoti šiuos duomenis atsakymui formuoti. Ir čia prasideda problema.

UNKEYED ANTRAŠTĖS — TALPYKLOS AKLAS TAŠKAS

Egzistuoja antraštės kurias CDN perduoda serveriui bet neįtraukia į talpyklos raktą. Dažniausios:

X-Forwarded-Host — alternatyvus Host serveriams už proxy
X-Host — X-Forwarded-Host analogas
X-Forwarded-Scheme — protokolas (http arba https)
X-Forwarded-Port — portas

Daugelis framework’ų ir programų naudoja šias antraštes absoliutiems URL konstruoti atsakyme — nuorodose, skriptuose, redirect adresuose. Tai patogu dirbant už reverse proxy.

Tačiau CDN jų neįtraukia į talpyklos raktą. Tai reiškia kad dvi užklausos su skirtingomis X-Forwarded-Host reikšmėmis gaus tą patį talpykloje esantį atsakymą — tą kuris atėjo pirmas.

ATAKOS ANATOMIJA ŽINGSNIS PO ŽINGSNIO

1 žingsnis. Užpuolikas siunčia užklausą į pagrindinį puslapį su pakeista antrašte X-Forwarded-Host:

GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: evil.com

2 žingsnis. CDN gauna užklausą, ieško talpykloje pagal raktą GET | target.com | / — talpykla tuščia arba pasenusi. Užklausa eina į kilmės serverį.

3 žingsnis. Serveris gauna abi antraštes. Jis naudoja X-Forwarded-Host absoliutiems URL konstruoti atsakyme. Vietoj https://target.com/static/app.js HTML atsiranda:

<script src="https://evil.com/static/app.js"></script>

4 žingsnis. CDN gauna atsakymą su nuodingu skriptu ir jį talpina pagal raktą GET | target.com | /. Jokių perspėjimų — atsakymas atrodo kaip bet kuris kitas.

5 žingsnis. Kiti tūkstančiai vartotojų atidaro pagrindinį puslapį ir iš talpyklos gauna HTML su skriptu evil.com/static/app.js. Jų naršyklės jį įkelia ir vykdo. Užpuolikas jau seniai išėjo.

REALŪS ATVEJAI

2018 m. rugpjūtį James Kettle pristatė „Practical Web Cache Poisoning” Black Hat USA. Jis parodė atakas prieš realias svetaines:

RedHat.com — antraštė X-Forwarded-Host buvo naudojama Open Graph žymų URL generavimui HTML. Kettle pakeitė ją savo domenu, CDN užkešavo atsakymą. RedHat.com pagrindinis puslapis pradėjo įkelti resursus iš užpuoliko serverio visiems lankytojams.

Mozilla Firefox Shield — Firefox atnaujinimų ir plėtinių pristatymo mechanizmas. Kettle apnuodijo atsakymo talpyklą kurį Firefox gauna paleisdamas naršyklę. Ataka leido paveikti naršyklės elgesį visiems vartotojams gavusiems apnuodytą talpykloje esantį atsakymą.

Cloudflare pagal nutylėjimą ignoruoja antraštę Vary — tai užfiksuota jo oficialioje dokumentacijoje: „Cloudflare does not consider vary values in caching decisions.” Dvi išimtys: Vary: Accept-Encoding palaikoma visuose planuose; Vary vaizdams — tik mokamose Pro ir aukštesnėse planų versijose. Talpyklos apnuodijimui per X-Forwarded-Host nei vienas nepadeda.

KAIP PATIKRINTI SAVO SVETAINĘ

1 žingsnis. Raskite unkeyed antraštes — tas kurios veikia atsakymą bet nėra talpyklos rakte. Naudokite cache buster kad netyčia nieko neužkešuotumėte. Cache buster — tai unikalus parametras URL (?cb=test123) kuris padaro užklausą unikalia ir verčia CDN eiti į serverį, o ne grąžinti kešą. Be jo testas gali patekti į kešą ir apnuodyti realius vartotojus:

# Pridedame unikalų parametrą kad nepatektume į realią talpyklą
curl -s "https://target.com/?cb=test123" \
  -H "X-Forwarded-Host: canary.example.com" | grep "canary"

Jei atsakyme pasirodė canary.example.com — serveris naudoja tą antraštę atsakyme. Tai unkeyed input.

2 žingsnis. Patikrinkite ar atsakymas kešuojamas — žiūrime į antraštę X-Cache:

curl -sI "https://target.com/" | grep -i "x-cache\|cf-cache\|age"

X-Cache: HIT reiškia atsakymas atėjo iš talpyklos. X-Cache: MISS — iš serverio. Age: 120 — atsakymas talpykloje jau 120 sekundžių.

Jei antraštė naudojama atsakyme IR atsakymas kešuojamas — svetainė potencialiai pažeidžiama.

APSAUGA

Nenaudoti unkeyed antraščių URL konstruoti

Patikimiausia apsauga — nepasitikėti antraštėmis X-Forwarded-Host, X-Host ir panašiomis generuojant nuorodas. Svetainės bazinis URL turi būti nurodytas aiškiai konfigūracijoje:

# Blogai — imame host iš antraštės
base_url = request.headers.get('X-Forwarded-Host', request.host)

# Gerai — imame iš konfigūracijos
base_url = settings.BASE_URL  # https://mysite.com

Pašalinti pavojingas antraštes nginx prieš programą

Jei programa neturėtų matyti šių antraščių — pašaliname jas nginx lygmenyje:

server {
    listen 80;
    server_name mysite.com;

    # Pakeičiame potencialiai pavojingas antraštes tikra host reikšme
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Host $host;

    location / {
        proxy_pass http://backend;
    }
}

Čia mes ne tiesiog ištrinsime antraštę — mes eksplicitiškai nustatome jos reikšmę lygia $host (tikrai nginx host). Programa gaus teisingą reikšmę nepriklausomai nuo to ką atsiuntė klientas.

Pridėti unkeyed antraštes į talpyklos raktą per Vary

Atsakymo antraštė Vary nurodo CDN kurios užklausos antraštės turi įeiti į talpyklos raktą. Pridėjus ten X-Forwarded-Host — CDN kešuos atskirus atsakymus kiekvienai tos antraštės reikšmei:

Vary: X-Forwarded-Host

Svarbus apribojimas: ne visi CDN gerbia Vary. Cloudflare jį pagal nutylėjimą ignoruoja. Todėl Vary yra papildoma priemonė, ne pagrindinė.

Sukonfigūruoti talpyklos taisykles Cloudflare

Cloudflare Cache Rules leidžia konfigūruoti talpyklos raktą. Pagrindinės opcijos (talpykla pagal įrenginio tipą, query string rūšiavimas) prieinamos visuose planuose. HTTP antraščių pridėjimas į talpyklos raktą yra Enterprise plano funkcija. Žemesniems nei Enterprise planams — tą patį galima padaryti per Cloudflare Workers (Cache API) be Enterprise prenumeratos.

Dashboard → Rules → Cache Rules → Create Rule → Cache key → Add setting.

TIPINĖS KLAIDOS

Manoma kad HTTPS apsaugo nuo talpyklos apnuodijimo. Neapsaugo — ataka veikia HTTP antraščių lygmenyje, TLS čia nesvarbu.

Tikrinamas tik pagrindinis puslapis. Ataka veikia bet kuriame kešuojamame puslapyje — statiniuose failuose, API atsakymuose, kategorijų puslapiuose. Kettle rado pažeidžiamumų būtent pagrindiniuose puslapiuose nes jie kešuojami agresyviau.

Pasikliaunama tik antrašte Vary. Cloudflare ir kai kurie kiti CDN ją ignoruoja. Pagrindinė apsauga yra programos ir nginx lygmenyje.

Neišvalomi X antraštės iš API endpoint manant kad API nekešuojamas. Jei CDN sukonfigūruotas agresyviai arba programuotojas pridėjo Cache-Control: public — kešuojamas.

IŠVADA

Web Cache Poisoning išplečia Host antraštės ataką iki lygio kuris nereikalauja sąveikos su auka. Viena užklausa, kelios sekundės — ir tūkstančiai vartotojų gauna apnuodytą puslapį kol talpykla neatsinaujina.

Susirūpinti turėtų visi pas kuriuos stovi CDN ir kurių programa naudoja X-Forwarded-Host ar panašias antraštes URL konstruoti. Patikrinti paprasta — curl su žymės parametru ir grep rezultate.

Apsauga kuriama ne CDN, o programos ir nginx lygmenyje: aiškus BASE_URL konfigūracijoje, pavojingų antraščių pašalinimas reverse proxy lygyje, ir jokio pasitikėjimo tuo ką klientas siunčia X antraštėse.

Leave your thought here

El. pašto adresas nebus skelbiamas. Būtini laukeliai pažymėti *