Sulmi në Node.js përmes manipulimit të prototipeve të objekteve JavaScript

Studiuesit nga Qendra Helmholtz për Sigurinë e Informacionit (CISPA) dhe Instituti Mbretëror i Teknologjisë (Suedi) analizuan zbatueshmërinë e teknikës së ndotjes së prototipit JavaScript për të krijuar sulme në platformën Node.js dhe aplikacione të njohura të bazuara në të, duke çuar në ekzekutimin e kodit.

Metoda e prototipit të ndotjes përdor një veçori të gjuhës JavaScript që ju lejon të shtoni veti të reja në prototipin rrënjë të çdo objekti. Aplikacionet mund të përmbajnë blloqe kodi (gadgets) funksionimi i të cilave ndikohet nga një veti e zëvendësuar; për shembull, kodi mund të përmbajë një konstrukt si 'const cmd = options.cmd || "/bin/sh"', logjika e së cilës do të ndryshohet nëse sulmuesi arrin të zëvendësojë vetinë "cmd" në prototipin rrënjë.

Një sulm i suksesshëm kërkon që aplikacioni të mund të përdorë të dhëna të jashtme për të krijuar një pronë të re në prototipin rrënjë të objektit dhe që ekzekutimi të hasë një vegël që varet nga vetia e modifikuar. Ndryshimi i prototipit realizohet duke përpunuar veçoritë e shërbimit "__proto__" dhe "konstruktor" në Node.js. Vetia "__proto__" kthen prototipin e klasës së objektit dhe vetia "konstruktor" kthen funksionin e përdorur për të krijuar objektin.

Nëse kodi i aplikacionit përmban caktimin "obj[a][b] = vlerë" dhe vlerat janë vendosur nga të dhënat e jashtme, një sulmues mund të vendosë "a" në vlerën "__proto__" dhe të arrijë instalimin e pronës së tij me emrin “b” dhe vlerën “vlera” në prototipin rrënjësor të objektit (obj.__proto__.b = vlerë;), dhe vetia e vendosur në prototip do të jetë e dukshme në të gjitha objektet. Në mënyrë të ngjashme, nëse kodi përmban shprehje si "obj[a][b][c] = vlerë", duke vendosur "a" në vlerën "konstruktor" dhe "b" në "prototip" në të gjitha objektet ekzistuese, mund të Përcaktoni një pronë të re me emrin "c" dhe vlerën "vlera".

Shembull i ndryshimit të prototipit: const o1 = {}; const o2 = objekt i ri(); o1.__proto__.x = 42; // krijoni pronësinë “x” në konsolën e prototipit rrënjë.log (o2.x); // aksesoni vetinë "x" nga një objekt tjetër // dalja do të jetë 42, pasi prototipi rrënjë u ndryshua përmes objektit o1, i cili përdoret gjithashtu në objektin o2

Shembull i kodit të cenueshëm: funksioni entryPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; kthimi p; }

Nëse argumentet e funksionit entryPoint formohen nga të dhënat hyrëse, atëherë një sulmues mund të kalojë vlerën “__proto__” në arg1 dhe të krijojë një pronë me çdo emër në prototipin rrënjë. Nëse kaloni arg2 vlerën "toString" dhe arg3 vlerën 1, mund të përcaktoni veçorinë "toString" (Object.prototype.toString=1) dhe të prishni aplikacionin gjatë thirrjes në toString().

Shembuj të situatave që mund të çojnë në ekzekutimin e kodit të sulmuesit përfshijnë krijimin e vetive "main", "shell", "exports", "contextExtensions" dhe "env". Për shembull, një sulmues mund të krijojë një pronë "kryesore" në prototipin rrënjë të një objekti, duke shkruar në të shtegun drejt skriptit të tij (Object.prototype.main = "./../../pwned.js") dhe kjo veti do të thirret në momentin e ekzekutimit në kodin e konstruktit Kërko ("my-package"), nëse paketa e përfshirë nuk e përcakton në mënyrë eksplicite veçorinë "kryesore" në package.json (nëse vetia nuk është e përcaktuar, do të merret nga prototipi rrënjë). Vetitë "shell", "exports" dhe "env" mund të zëvendësohen në mënyrë të ngjashme: le rootProto = Object.prototype; rootProto["eksportet"] = {".":"./changelog.js"}; rootProto["1"] = "/rruga/në/npm/skriptet/"; // thirrja e nxitjes kërkohet ("./target.js"); Object.prototype.main = "/path/to/npm/scripts/changelog.js"; Object.prototype.shell = "nyje"; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = "—inspect-brk=0.0.0.0:1337"; // Kërkohet thirrja e aktivizimit ("bytes");

Studiuesit analizuan 10 paketa NPM me numrin më të madh të varësive dhe zbuluan se 1958 prej tyre nuk kanë një pronë kryesore në package.json, 4420 përdorin shtigje relative në deklaratat e tyre të kërkuara dhe 355 përdorin drejtpërdrejt API-në e zëvendësimit të komandës.

Një shembull i punës është një shfrytëzim për të sulmuar prapavijën e serverit Parse që anashkalon veçorinë evalFunctions. Për të thjeshtuar identifikimin e dobësive të tilla, është zhvilluar një paketë mjetesh që kombinon metodat e analizës statike dhe dinamike. Gjatë testimit të Node.js, u identifikuan 11 pajisje që mund të përdoren për të organizuar sulme që çojnë në ekzekutimin e kodit të sulmuesit. Përveç serverit Parse, dy dobësi të shfrytëzueshme u identifikuan gjithashtu në NPM CLI.

Burimi: opennet.ru

Shto një koment