Támadás a Node.js ellen JavaScript objektum prototípusok manipulálásával

A Helmholtz Center for Information Security (CISPA) és a Royal Institute of Technology (Svédország) kutatói elemezték a JavaScript prototípus szennyezési technika alkalmazhatóságát a Node.js platform és az arra épülő népszerű alkalmazások elleni támadások létrehozására, amelyek kódvégrehajtáshoz vezettek.

A prototípus-szennyezési módszer a JavaScript nyelv egy olyan funkcióját használja, amely lehetővé teszi új tulajdonságok hozzáadását bármely objektum gyökérprototípusához. Az alkalmazások tartalmazhatnak kódblokkokat (gadgeteket), amelyek működését egy helyettesített tulajdonság befolyásolja; például a kód tartalmazhat egy olyan konstrukciót, mint például: 'const cmd = options.cmd || "/bin/sh"', amelynek logikája megváltozik, ha a támadónak sikerül lecserélnie a „cmd” tulajdonságot a gyökérprototípusban.

A sikeres támadás megköveteli, hogy az alkalmazás külső adatok segítségével új tulajdonságot tudjon létrehozni az objektum gyökérprototípusában, és a végrehajtás során találkozzon egy modullal, amely a módosított tulajdonságtól függ. A prototípus módosítása a Node.js „__proto__” és „constructor” szolgáltatástulajdonságainak feldolgozásával valósítható meg. A "__proto__" tulajdonság az objektum osztályának prototípusát adja vissza, a "constructor" tulajdonság pedig az objektum létrehozásához használt függvényt.

Ha az alkalmazáskód az „obj[a][b] = érték” hozzárendelést tartalmazza, és az értékek külső adatokból vannak beállítva, a támadó „a”-t állíthat be a „__proto__” értékre, és elérheti saját tulajdonának telepítését. a „b” névvel és az „érték” értékkel az objektum gyökérprototípusában (obj.__proto__.b = érték;), és a prototípusban beállított tulajdonság minden objektumban látható lesz. Hasonlóképpen, ha a kód olyan kifejezéseket tartalmaz, mint „obj[a][b][c] = érték”, ha az „a”-t a „konstruktor” értékre, a „b”-t pedig a „prototípusra” állítja be minden létező objektumban, akkor definiáljon egy új tulajdonságot "c" névvel és "érték" értékkel.

Példa a prototípus megváltoztatására: const o1 = {}; const o2 = new Object(); o1.__proto__.x = 42; // az „x” tulajdonság létrehozása a gyökérprototípusban console.log (o2.x); // az „x” tulajdonság elérése egy másik objektumból // a kimenet 42 lesz, mivel a gyökér prototípust az o1 objektumon keresztül változtatták meg, ami az o2 objektumban is használatos

Példa a sebezhető kódra: function entryPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; return p; }

Ha az entryPoint függvény argumentumai bemeneti adatokból vannak kialakítva, akkor a támadó átadhatja a „__proto__” értéket az arg1-nek, és létrehozhat egy tulajdonságot tetszőleges névvel a gyökérprototípusban. Ha az arg2-nek a "toString" értéket, az arg3-nak pedig az 1-es értéket adja meg, megadhatja a "toString" tulajdonságot (Object.prototype.toString=1), és összeomolhatja az alkalmazást a toString() hívása során.

Példák azokra a helyzetekre, amelyek támadókód végrehajtásához vezethetnek, többek között a „main”, „shell”, „exports”, „contextExtensions” és „env” tulajdonságok létrehozása. Például egy támadó létrehozhat egy „fő” tulajdonságot egy objektum gyökérprototípusában, és beleírhatja a szkriptje elérési útját (Object.prototype.main = „./../../pwned.js”), és ez a tulajdonság a végrehajtáskor meghívásra kerül a követelmény("my-package") konstrukció kódjában, ha a benne foglalt csomag nem határozza meg kifejezetten a "main" tulajdonságot a package.json fájlban (ha a tulajdonság nincs megadva, a gyökér prototípusból lesz beszerezve). A „shell”, „exports” és „env” tulajdonságok hasonlóképpen helyettesíthetők: legyen rootProto = Object.prototype; rootProto["exportál"] = {".":"./changelog.js"}; rootProto["1"] = "/útvonal/hoz/npm/scripts/"; // trigger call request("./target.js"); Object.prototype.main = "/útvonal/útvonal/npm/scripts/changelog.js"; Object.prototype.shell = "csomópont"; Object.prototype.env = {}; Object.prototype.env.NODE_OPTIONS = "—inspect-brk=0.0.0.0:1337"; // hívás triggerelése request("bytes");

A kutatók 10 1958, a legtöbb függőséggel rendelkező NPM-csomagot elemeztek, és azt találták, hogy közülük 4420-nak nincs fő tulajdonsága a package.json fájlban, 355 relatív elérési utat használ a követelmény utasításaiban, XNUMX pedig közvetlenül a parancshelyettesítő API-t használja.

Működő példa erre a Parse Server backend támadására szolgáló kihasználás, amely felülbírálja az evalFunctions tulajdonságot. Az ilyen sérülékenységek azonosításának egyszerűsítésére olyan eszköztárat fejlesztettek ki, amely egyesíti a statikus és dinamikus elemzési módszereket. A Node.js tesztelése során 11 modult azonosítottak, amelyek segítségével olyan támadásokat lehet szervezni, amelyek a támadó kódjának végrehajtásához vezetnek. A Parse Server mellett két kihasználható biztonsági rést is azonosítottak az NPM CLI-ben.

Forrás: opennet.ru

Hozzászólás