Node.js:n hyökkääminen JavaScript-objektien prototyyppejä manipuloimalla

Helmholtzin tietoturvakeskuksen (CISPA) ja Royal Institute of Technologyn (Ruotsi) tutkijat analysoivat JavaScript-prototyypin saastetekniikan soveltuvuutta Node.js-alustalle ja siihen perustuville suosituille sovelluksille, jotka johtavat koodin suorittamiseen.

Prototyyppi saastuttava menetelmä käyttää JavaScript-kielen ominaisuutta, jonka avulla voit lisätä uusia ominaisuuksia minkä tahansa objektin juuriprototyyppiin. Sovellukset voivat sisältää koodilohkoja (gadgeteja), joiden toimintaan korvattu ominaisuus vaikuttaa; koodi voi esimerkiksi sisältää rakenteen, kuten 'const cmd = options.cmd || "/bin/sh"', jonka logiikka muuttuu, jos hyökkääjä onnistuu korvaamaan "cmd"-ominaisuuden juuriprototyypissä.

Onnistunut hyökkäys edellyttää, että sovellus voi käyttää ulkoisia tietoja luodakseen uuden ominaisuuden objektin juuriprototyyppiin ja että suoritus kohtaa gadgetin, joka riippuu muokatusta ominaisuudesta. Prototyypin muuttaminen tapahtuu käsittelemällä Node.js:n palveluominaisuudet "__proto__" ja "constructor". Ominaisuus "__proto__" palauttaa objektin luokan prototyypin ja "constructor" -ominaisuus palauttaa objektin luomiseen käytetyn funktion.

Jos sovelluskoodi sisältää määrityksen "obj[a][b] = arvo" ja arvot on asetettu ulkoisista tiedoista, hyökkääjä voi asettaa "a" arvoon "__proto__" ja saavuttaa oman omaisuutensa asennuksen nimellä "b" ja arvolla "value" kohteen juuriprototyypissä (obj.__proto__.b = arvo;), ja prototyypissä asetettu ominaisuus näkyy kaikissa objekteissa. Vastaavasti, jos koodi sisältää lausekkeita, kuten "obj[a][b][c] = arvo", asettamalla "a" "konstruktori"-arvoksi ja "b" "prototyyppi" kaikissa olemassa olevissa objekteissa, voit määritä uusi ominaisuus nimellä "c" ja arvolla "arvo".

Esimerkki prototyypin vaihtamisesta: const o1 = {}; const o2 = new Object(); o1.__proto__.x = 42; // luo ominaisuus "x" juuriprototyyppiin console.log (o2.x); // pääsy ominaisuus "x" toisesta objektista // lähtö on 42, koska juuriprototyyppiä muutettiin objektin o1 kautta, jota käytetään myös objektissa o2

Esimerkki haavoittuvasta koodista: function entryPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; paluu p; }

Jos entryPoint-funktion argumentit muodostetaan syötetiedoista, hyökkääjä voi välittää arvon "__proto__" arvolle arg1 ja luoda ominaisuuden millä tahansa nimellä juuriprototyyppiin. Jos annat arg2:lle arvon "toString" ja arg3:lle arvon 1, voit määrittää "toString"-ominaisuuden (Object.prototype.toString=1) ja kaataa sovelluksen kutsun toString() aikana.

Esimerkkejä tilanteista, jotka voivat johtaa hyökkääjäkoodin suorittamiseen, ovat "main", "shell", "exports", "contextExtensions" ja "env" ominaisuuksien luominen. Hyökkääjä voi esimerkiksi luoda "main"-ominaisuuden objektin juuriprototyyppiin ja kirjoittaa siihen polun komentosarjaansa (Object.prototype.main = "./../../pwned.js") ja tätä ominaisuutta kutsutaan suoritushetkellä konstruktion request("my-package") koodissa, jos mukana oleva paketti ei nimenomaisesti määritä "main"-ominaisuutta paketissa package.json (jos ominaisuutta ei ole määritetty, se saadaan juuriprototyypistä). Ominaisuudet "shell", "exports" ja "env" voidaan korvata samalla tavalla: let rootProto = Object.prototype; rootProto["vienti"] = {".":"./changelog.js"}; rootProto["1"] = "/polku/npm/skriptit/"; // laukaista kutsu vaatia("./target.js"); Object.prototype.main = "/polku/npm/scripts/changelog.js"; Object.prototype.shell = "solmu"; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = "—inspect-brk=0.0.0.0:1337"; // trigger call request("tavuja");

Tutkijat analysoivat 10 1958 NPM-pakettia, joissa oli eniten riippuvuuksia ja havaitsivat, että 4420 355:lla niistä ei ole pääomaisuutta package.jsonissa, XNUMX XNUMX käyttää suhteellisia polkuja vaativissa lausekkeissaan ja XNUMX käyttää suoraan komentojen korvaussovellusliittymää.

Toimiva esimerkki on hyväksikäyttö Parse Server -taustajärjestelmään hyökkäämiseksi, joka ohittaa evalFunctions-ominaisuuden. Tällaisten haavoittuvuuksien tunnistamisen yksinkertaistamiseksi on kehitetty työkalupakki, joka yhdistää staattiset ja dynaamiset analyysimenetelmät. Node.js:n testauksen aikana tunnistettiin 11 gadgetia, joiden avulla voidaan järjestää hyökkäyksiä, jotka johtavat hyökkääjän koodin suorittamiseen. Parse Serverin lisäksi NPM CLI:ssä tunnistettiin myös kaksi hyödynnettävissä olevaa haavoittuvuutta.

Lähde: opennet.ru

Lisää kommentti