Forskere fra Helmholtz-senteret for informasjonssikkerhet (CISPA) og Kungliga Tekniska Högskolan (Sverige) har analysert anvendbarheten av teknikken prototypeforurensning for å skape angrep mot Node.js-plattformen og populære applikasjoner basert på den, som fører til kodeutførelse.
Prototypeforurensning bruker en egenskap i JavaScript-språket som lar deg legge til nye egenskaper i rotprototypen til et hvilket som helst objekt. Applikasjoner kan inneholde kodeblokker (widgets) der fungerende egenskaper påvirkes av en utsatt egenskap, for eksempel i koden kan det være en konstruksjon som ‘const cmd = options.cmd || "/bin/sh"’, hvis logikk vil endres hvis en angriper klarer å sette egenskapen «cmd» i rotprototypen.
For å gjennomføre et vellykket angrep må data fra eksterne kilder kunne brukes til å opprette en ny egenskap i rotprototypen til objektet, samt at det under kjøring finnes en widget som er avhengig av den endrede egenskapen. Endringen av prototypen skjer gjennom behandling av Node.js' spesialegenskaper «__proto__» og «constructor». Egenskapen «__proto__» returnerer prototypen til objektklassen, mens egenskapen «constructor» returnerer funksjonen som brukes til å opprette objektet.
Hvis koden i applikasjonen inneholder en tildeling «obj[a][b] = value» og verdiene kommer fra eksterne data, kan angriperen sette «a» til verdien «__proto__» og oppnå at sin egen egenskap med navnet «b» og verdien «value» settes i rotprototypen til objektet (obj.__proto__.b = value;), og egenskapen som er satt i prototypen vil være synlig i alle objekter. På lignende måte, hvis koden inneholder uttrykk som «obj[a][b][c] = value», kan man sette «a» til verdien «constructor», og «b» til «prototype», og dermed definere en ny egenskap med navnet «c» og verdien «value» i alle eksisterende objekter.
Eksempel på endring av prototypen: const o1 = {}; const o2 = new Object(); o1.__proto__.x = 42; // oppretter i rotprototypen egenskapen «x» console.log(o2.x); // får tilgang til egenskapen «x» fra et annet objekt // resultatet vil være 42, siden rootprototypen ble endret gjennom o1, som også brukes i o2
Eksempel på sårbar kode: function entryPoint(arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; return p; }
Når argumentene til funksjonen entryPoint dannes fra inngangsdata, kan en angriper sende verdien «__proto__» i arg1 og opprette en egenskap med et vilkårlig navn i rotprototypen. Hvis arg2 settes til «toString» og arg3 til 1, kan egenskapen «toString» bli definert (Object.prototype.toString=1) og forårsake en krasj i applikasjonen under kall til funksjonen toString().
Som et eksempel på situasjoner som kan føre til at angripers kode blir utført, nevnes opprettelse av egenskapene «main», «shell», «exports», «contextExtensions» og «env». For eksempel kan en angriper opprette en egenskap «main» i rotprototypen av objektet og skrive inn stien til skriptet sitt (Object.prototype.main = «.\/..\/..\/pwned.js»), og denne egenskapen vil bli kalt under kjøring i koden til konstruksjonen require(«my-package»), hvis den tilkoblede pakken ikke eksplisitt definerer egenskapen «main» i package.json (hvis egenskapen ikke er definert, vil den bli hentet fra rotprototypen). Tilsvarende kan egenskapene «shell», «exports» og «env» bli substituert: let rootProto = Object.prototype; rootProto[«exports»] = {«.»:«.\/changelog.js»}; rootProto[«1»] = «\/path\/to\/npm\/scripts\/»; \/\/ trigger call require («.\/target.js»); Object.prototype.main = «\/path\/to\/npm\/scripts\/changelog.js»; Object.prototype.shell = «node»; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = «—inspect-brk=0.0.0.0:1337»; \/\/ trigger call require («bytes»);
Forskere har analysert 10 000 NPM-pakker med flest avhengigheter, og funnet ut at 1958 av dem ikke har eiendommen main i package.json, 4420 bruker relative stier i require-uttrykket, og 355 bruker direkte API for å substituere kommandoer.
Som et fungerende eksempel kan man nevne en utnyttelse for å angripe backend av Parse Server, som omdefinerer egenskapen evalFunctions. For å forenkle identifiseringen av slike sårbarheter har et verktøy blitt utviklet som kombinerer metoder for statisk og dynamisk analyse. Under testing av Node.js ble 11 gadgets identifisert, som kan brukes til å utføre angrep som fører til kjøring av angripers kode. I tillegg til Parse Server, ble to utnyttbare sårbarheter også oppdaget i NPM CLI.
Kilde: opennet.ru
