Pag-atake sa Node.js sa pamamagitan ng pagmamanipula ng mga prototype ng object ng JavaScript

Sinuri ng mga mananaliksik mula sa Helmholtz Center for Information Security (CISPA) at Royal Institute of Technology (Sweden) ang applicability ng JavaScript prototype pollution technique para gumawa ng mga pag-atake sa Node.js platform at mga sikat na application batay dito, na humahantong sa code execution.

Ang prototype polluting method ay gumagamit ng feature ng JavaScript language na nagbibigay-daan sa iyong magdagdag ng mga bagong property sa root prototype ng anumang object. Ang mga application ay maaaring maglaman ng mga bloke ng code (mga gadget) na ang operasyon ay apektado ng isang pinalit na property; halimbawa, ang code ay maaaring maglaman ng isang construct tulad ng 'const cmd = options.cmd || "/bin/sh"', ang lohika nito ay mababago kung mapapalitan ng attacker ang property na β€œcmd” sa root prototype.

Ang isang matagumpay na pag-atake ay nangangailangan na ang application ay maaaring gumamit ng panlabas na data upang lumikha ng isang bagong property sa root prototype ng object, at ang pagpapatupad na iyon ay makakatagpo ng isang gadget na nakadepende sa binagong property. Ang pagpapalit ng prototype ay nagagawa sa pamamagitan ng pagproseso ng "__proto__" at "constructor" na mga katangian ng serbisyo sa Node.js. Ibinabalik ng property na "__proto__" ang prototype ng klase ng object, at ibinabalik ng property na "constructor" ang function na ginamit para likhain ang object.

Kung ang application code ay naglalaman ng assignment na "obj[a][b] = value" at ang mga value ay itinakda mula sa external na data, maaaring itakda ng attacker ang "a" sa value na "__proto__" at makamit ang pag-install ng kanilang sariling property. na may pangalang "b" at ang value na "value" sa root prototype ng object (obj.__proto__.b = value;), at ang property na nakatakda sa prototype ay makikita sa lahat ng object. Katulad nito, kung ang code ay naglalaman ng mga expression tulad ng "obj[a][b][c] = value", sa pamamagitan ng pagtatakda ng "a" sa value ng "constructor", at "b" sa "prototype" sa lahat ng umiiral na object, maaari mong tukuyin ang isang bagong pag-aari na may pangalang "c" at ang halaga na "halaga".

Halimbawa ng pagpapalit ng prototype: const o1 = {}; const o2 = bagong Bagay(); o1.__proto__.x = 42; // gumawa ng property na β€œx” sa root prototype console.log (o2.x); // access property "x" mula sa isa pang object // ang output ay magiging 42, dahil ang root prototype ay binago sa pamamagitan ng object o1, na ginagamit din sa object o2

Halimbawa ng vulnerable code: function entryPoint (arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; bumalik p; }

Kung ang mga argumento ng entryPoint function ay nabuo mula sa data ng pag-input, maaaring ipasa ng isang attacker ang value na "__proto__" sa arg1 at lumikha ng isang property na may anumang pangalan sa root prototype. Kung ipapasa mo sa arg2 ang value na "toString" at arg3 ang value 1, maaari mong tukuyin ang property na "toString" (Object.prototype.toString=1) at i-crash ang application habang tumatawag sa toString().

Kasama sa mga halimbawa ng mga sitwasyon na maaaring humantong sa pagpapatupad ng code ng attacker ang paggawa ng "pangunahing", "shell", "exports", "contextExtensions" at "env" na mga katangian. Halimbawa, ang isang attacker ay maaaring lumikha ng isang "pangunahing" property sa root prototype ng isang object, isulat dito ang path sa kanyang script (Object.prototype.main = "./../../pwned.js") at tatawagin ang property na ito sa oras ng execution sa code ng construct require("my-package"), kung hindi tahasang tinukoy ng kasamang package ang "pangunahing" property sa package.json (kung hindi tinukoy ang property, ito ay makukuha mula sa root prototype). Ang mga katangian ng "shell", "exports" at "env" ay maaaring palitan nang katulad: hayaan ang 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");

Sinuri ng mga mananaliksik ang 10 NPM package na may pinakamalaking bilang ng mga dependency at nalaman na 1958 sa mga ito ay walang pangunahing property sa package.json, 4420 ang gumagamit ng mga relatibong path sa kanilang mga requirement na pahayag, at 355 ang direktang gumagamit ng command substitution API.

Ang isang gumaganang halimbawa ay isang pagsasamantala para sa pag-atake sa backend ng Parse Server na nag-o-override sa property ng evalFunctions. Upang gawing simple ang pagkilala sa mga naturang kahinaan, binuo ang isang toolkit na pinagsasama ang mga static at dynamic na pamamaraan ng pagsusuri. Sa panahon ng pagsubok sa Node.js, natukoy ang 11 gadget na maaaring magamit upang ayusin ang mga pag-atake na humahantong sa pagpapatupad ng code ng umaatake. Bilang karagdagan sa Parse Server, dalawang mapagsamantalang kahinaan ang natukoy din sa NPM CLI.

Pinagmulan: opennet.ru

Magdagdag ng komento