DNS Rebinding: kaip naršyklė tampa įrankiu atakuoti jūsų vidinį tinklą.
Įsivaizduokite: darbuotojas paspaudžia nuorodą — atrodo paprastas svetainė, jokių įspėjimų, jokių virusų. Tačiau tuo metu jo naršyklė jau skaituoja biuro vidinį tinklą ir siunčia duomenis užpuolikui. Maršrutizatorius, vidinės paslaugos, administravimo panelės — viskas, ko naršyklė gali pasiekti.
Tai DNS rebinding. Ataka žinoma nuo 1996 metų, vis dar veikia, ir dauguma administratorių apie ją negalvoja.
KAIP NARŠYKLĖ SAUGO VIDINIUS IŠTEKLIUS — IR KODĖL TAI SUBYRA
Naršyklės laikosi same-origin policy (vienodos kilmės taisyklės): JavaScript iš evil.com negali skaityti atsakymų iš bank.com. Tai bazinė apsauga nuo cross-site atakų.
Tačiau ši taisyklė turi aklą tašką. Same-origin policy remiasi domeno vardu, o ne IP adresu. Naršyklė neseka, koks IP adresas slepiasi už domeno — svarbiausia, kad užklausa eina į tą patį hostname.
DNS rebinding išnaudoja būtent tai. Užpuolikas kontroliuoja domeną evil.com ir jo DNS serverį. Viskas prasideda, kai auka atidaro puslapį evil.com.
ATAKOS ANATOMIJA ŽINGSNIS PO ŽINGSNIO
1 žingsnis. Auka atidaro http://evil.com. Naršyklė daro DNS užklausą — gauna tikrą užpuoliko IP, tarkime 1.2.3.4. Puslapis užsikrauna. Jame yra JavaScript.
2 žingsnis. DNS įrašas evil.com nustatytas su TTL = 1 sekundė. TTL (Time To Live) — tai laikas, kurį naršyklė saugo DNS atsakymą talpykloje. Paprastai tai minutės ar valandos. Čia — viena sekundė. Naršyklė beveik iš karto pamiršta seną IP ir kitoje užklausoje vėl kreipiasi į DNS.
3 žingsnis. JavaScript puslapyje palaukia kelias sekundes, tada daro naują užklausą į evil.com — pavyzdžiui, fetch('http://evil.com/api/data').
4 žingsnis. Naršyklė vėl daro DNS užklausą evil.com. Bet dabar užpuoliko DNS serveris atsako kitu IP — tarkime 192.168.1.1. Tai aukos maršrutizatoriaus IP vietiniame tinkle.
5 žingsnis. Naršyklė samprotauja: domenas tas pats — evil.com, same-origin nepažeistas. Užklausa eina į 192.168.1.1 — tiesiai į aukos maršrutizatorių. JavaScript nuskaito atsakymą ir siunčia jį užpuolikui.
Auka apie tai nieko nežino.
KĄ UŽPUOLIKAS GALI DARYTI
Po sėkmingo rebinding aukos naršyklė — tai proxy į jos tinklą. Per JavaScript užpuolikas gali:
Skaityti vidinį tinklą — tikrinti adresus nuo 192.168.1.1 iki 192.168.1.254, patikrinti atvirus portus, nustatyti kokios paslaugos veikia.
Atakuoti maršrutizatorių — dauguma namų ir biuro maršrutizatorių turi web sąsają ant porto 80 ar 8080. Be slaptažodžio arba su gamykliniu — pilna prieiga.
Atakuoti vidines paslaugas — serverių valdymo panelės, Grafana, Jenkins, Kubernetes dashboard, Elasticsearch be autentifikacijos, vidiniai API. Viskas, kas pasiekiama iš aukos kompiuterio — pasiekiama užpuolikui.
Atakuoti localhost — jei aukos kompiuteryje veikia kažkas ant 127.0.0.1 (dev serveris, vietinė duomenų bazė, REST API), rebinding veikia ir ten. Užpuolikas tiesiog keičia IP į 127.0.0.1, o ne į privatų diapazoną.
REALŪS ATVEJAI
2018 metais tyrėjas Brannon Dorsey pademonstruojo DNS rebinding prieš Google Home ir Chromecast — prietaisai nutekino geolokacijos duomenis ir leido valdyti save per bet kurio vartotojo naršyklę, atidariusią kenksmingą puslapį. Tuo pačiu metu Tavis Ormandy iš Google Project Zero demonstravo tą pačią ataką prieš BitTorrent klientus uTorrent ir Transmission, bei Blizzard žaidimus. Google pataisė po kelių mėnesių nuo publikacijos.
Taip pat 2018 metais NCC Group išleido Singularity — atvirą atakų automatizavimo framework. Demonstracinė versija pasiekiama rebind.it. Ataka nebereikalauja specialių žinių.
Pažeidžiamos beveik visos naršyklės. 2025 m. spalį Chrome 142 pridėjo Local Network Access (LNA) — svetainės dabar turi paprašyti vartotojo leidimo prieš bet kokią užklausą į vidinį tinklą ar loopback. Tylus rebinding be vartotojo sąveikos Chrome 142+ nebevaikia. Firefox diegia LNA palaipsniui — įjungta pagal nutylėjimą Nightly, nuo Firefox 147 plečiama vartotojams su Enhanced Tracking Protection Strict. Safari LNA neįdiegė.
KAIP APSISAUGOTI
Chrome 142 LNA iš dalies uždaro problemą naršyklės pusėje, tačiau pasikliauti vien tuo nepakanka: Firefox ir Safari atsilieka, vartotojas gali paspausti „Leisti” prompt lange, o serveris nežino su kokia naršykle ateis užklausa. Trumpas TTL yra teisėta DNS konfigūracija, kurios negalima uždrausti. Patikima apsauga kuriama infrastruktūros lygmenyje, nepriklausomai nuo naršyklės.
1 lygmuo — DNS resolver su apsauga nuo rebinding
Šis lygmuo saugo klientines mašinas ir biuro tinklus — kur naršyklė realiai naudojama ir gali tapti proxy užpuolikui. Serveris neturi naršyklės, todėl šis lygmuo serverio paties neliečia. Bet jūsų darbo stočiai ar įmonės tinklui — svarbus.
Pačiam serveriui gera praktika — sukonfigūruoti šifruotą DNS per systemd-resolved. Tai neapsaugo nuo rebinding, bet šifruoja serverio DNS srautą — tiekėjas nemato kokius domenus rezoliuoja mašina, ir apsaugo nuo DNS atsakymų klastojimo tranzite:
[Resolve]
DNS=9.9.9.9#dns.quad9.net
DNSOverTLS=yes
Čia 9.9.9.9 — Quad9 IP adresas, #dns.quad9.net — hostname TLS sertifikato tikrinimui. DNSOverTLS=yes įjungia DNS užklausų šifravimą. Po pakeitimo:
sudo systemctl restart systemd-resolved
Prieš rebinding konkrečiai padeda dnsmasq su opcija stop-dns-rebind. Tai konfigūruojama maršrutizatoriuje (jei palaiko dnsmasq, pvz. OpenWRT) — ir apsaugo visus tinklo įrenginius iš karto:
# /etc/dnsmasq.conf
stop-dns-rebind
rebind-localhost-ok
stop-dns-rebind verčia dnsmasq atmesti atsakymus, kur viešas domenas rezoliuojasi į RFC1918 adresą (192.168.x.x, 10.x.x.x, 172.16-31.x.x) arba 127.x.x.x. rebind-localhost-ok — išimtis 127.0.0.1: kai kurios teisėtos maršrutizatoriaus paslaugos naudoja loopback vidiniams poreikiams ir be šios eilutės sugriūtų.
2 lygmuo — Host antraštės tikrinimas nginx
Tai esminė apsauga bet kuriai paslaugai. Jei nginx priima užklausas tik iš žinomų hostname — rebinding neveiks, nes užklausa ateis su antrašte Host: evil.com, o ne su laukiamu vardu.
server {
listen 80 default_server;
# Numatytasis blokas — atmeta viską nežinoma
return 444;
}
server {
listen 80;
server_name myserver.example.com;
# Tik šis host apdorojamas
}
return 444 — nginx specifinis kodas: serveris uždaro ryšį nesiųsdamas nė vieno baito atsakymo. Užpuolikas negauna net klaidos statuso — ryšys tiesiog nutraukiamas.
Vidinėms paslaugoms kur reikia priimti užklausas ir pagal hostname ir pagal IP — galima eksplicitiškai išvardinti leidžiamas reikšmes:
server {
listen 8080;
server_name internal.company.local 192.168.1.50;
if ($host !~* ^(internal\.company\.local|192\.168\.1\.50)$) {
return 444;
}
}
$host — nginx kintamasis su įeinančios užklausos Host antraštės reikšme. Sąlyga !~* reiškia „nesutampa be didžiųjų/mažųjų raidžių skirtumo”. Jei Host nėra nei internal.company.local nei 192.168.1.50 — ryšys uždaromas. Bet koks rebinding su svetimu domenu gauna 444.
3 lygmuo — autentifikacija visose vidinėse paslaugose
Rebinding veikia tik jei paslauga atsako į užklausas be patikrinimo. Grafana be slaptažodžio, Jenkins be autorizacijos, Elasticsearch ant 0.0.0.0 — tai visi taikiniai.
Taisyklė paprasta: kiekviena paslauga su web sąsaja turi reikalauti autentifikacijos, net jei ji yra „vidinė” ir „nepasiekiama iš išorės.”
4 lygmuo — tinklo segmentacija
Paslaugos, kurios neturėtų būti pasiekiamos iš naršyklės — neturėtų būti pasiekiamos iš darbo stočių apskritai. VLAN, nftables, ugniasienės taisyklės tinklo lygmenyje.
nft add rule inet filter forward \
ip saddr 192.168.10.0/24 \
ip daddr 192.168.20.0/24 \
tcp dport { 8080, 9090, 5601 } drop
Taisyklė skaitoma taip: bet koks srautas iš darbo stočių (192.168.10.0/24) į serverius (192.168.20.0/24) portais 8080 (valdymo panelės), 9090 (Prometheus) ir 5601 (Kibana) — atmesti. Net jei darbo stoties naršyklė bus naudojama kaip proxy per rebinding — ji fiziškai negalės pasiekti šių paslaugų. IP diapazonus pakeiskite savais.
PATIKRINKITE SAVO INFRASTRUKTŪRĄ
1 žingsnis. Patikrinkite kas klauso visuose sąsajose — tai paslaugos pasiekiamos iš tinklo, o ne tik iš localhost:
ss -tlnp | grep -v 127.0.0.1
Kiekviena eilutė išvestyje — tai portas atidarytas tinklo ryšiams. Patikrinkite rankiniu būdu kad kiekvienas reikalauja autentifikacijos:
curl http://localhost:3000 # Grafana — turi prašyti prisijungimo
curl http://localhost:9200 # Elasticsearch — neturi atsakyti be auth
curl http://localhost:8080 # Jenkins ir kitos panelės
2 žingsnis. Patikrinkite nginx ar nėra bloko kuris priima užklausas su bet kokia Host antrašte:
grep -r "default_server\|server_name _" /etc/nginx/
Komanda ieško dviejų šablonų. default_server — blokas kurį nginx naudoja kai nė vienas server_name nesutapo su užklausos Host antrašte. server_name _ — eksplicitinis catch-all, priimantis bet kokį hostname.
Jei komanda ką nors rado — tai dar ne problema. Svarbu ką failas daro su užklausa. Patikrinkite ar jis aktyvus:
ls /etc/nginx/sites-enabled/
Jei rastas failas yra sites-enabled — atidarykite jį ir pažiūrėkite į location / bloką. Pavojinga: ten yra try_files arba proxy_pass — serveris teikia turinį bet kuriam Host. Saugu: ten yra return 444 — serveris uždaro ryšį be atsakymo.
Jei eksplicitinio default_server nėra — nginx siunčia užklausas su nežinomu Host į pirmą rastą aktyvų bloką. Tai taip pat reikia uždaryti. Sukurkite naują failą ir įklijuokite į jį šią konfigūraciją:
sudo nano /etc/nginx/sites-available/default-catch-all.conf
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
Išsaugokite failą (Ctrl+O, tada Ctrl+X nano redaktoriuje), aktyvuokite jį simboline nuoroda ir perkraukite nginx:
sudo ln -s /etc/nginx/sites-available/default-catch-all.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Patikrinkite kad apsauga veikia — užklausa su svetimu Host turi grąžinti tuščią atsakymą:
curl -v -H "Host: evil.com" http://localhost/
# Laukiamas rezultatas: Empty reply from server
Internetinis tikrinimo įrankis: rebind.it — Singularity demonstracinė svetainė, parodo ar jūsų naršyklė dabar yra pažeidžiama rebinding.
IŠVADA
DNS rebinding — ataka, žinoma nuo 1996 metų ir niekur nedingsianti, nes jos pagrinde yra architektūrinis apribojimas, o ne klaida. Naršyklės kaltinti negalima — ji dirba pagal specifikaciją.
Apsauga nesudėtinga: dnsmasq su stop-dns-rebind maršrutizatoriuje, Host antraštės tikrinimas nginx, privaloma autentifikacija visose vidinėse paslaugose. Trys žingsniai, kiekvienas užtrunka minutes.
„Grafana be slaptažodžio, nes ji vidinė” — tai ne argumentas. Jūsų kolegos naršyklė jau gali būti proxy užpuolikui.
