Výzkumníci z Helmholtzova centra pro informační bezpečnost (CISPA) a Královského technologického institutu (Švédsko) analyzovali použitelnost techniky znečištění prototypu objektů JavaScriptu ("prototype pollution") k vytváření útoků na platformu Node.js a populární aplikace na jejím základě, které vedou k provedení kódu.
Metoda znečištění prototypu využívá vlastnosti jazyka JavaScript, která umožňuje přidat nové vlastnosti do kořenového prototypu jakéhokoli objektu. V aplikacích se mohou objevovat bloky kódu (widgety), na jejichž funkčnost má vliv vložená vlastnost; například v kódu může být konstrukce ve formátu ‘const cmd = options.cmd || "/bin/sh"‘, jejíž logika bude změněna, pokud útočník dokáže vložit vlastnost „cmd“ do kořenového prototypu.
Pro úspěšné provedení útoku je třeba, aby se v aplikaci externí data dala použít pro vytvoření nové vlastnosti v kořenovém prototypu objektu, a také aby během provádění existoval widget, který závisí na změněné vlastnosti. Změna prototypu se provádí díky zpracování v Node.js pomocí speciálních vlastností „__proto__“ a „constructor“. Vlastnost „__proto__“ vrací prototyp třídy objektu, zatímco vlastnost „constructor“ vrací funkci použitou k vytvoření objektu.
Pokud se v kódu aplikace vyskytuje přiřazení „obj[a][b] = value“ a hodnoty jsou nastaveny z externích dat, útočník může nastavit „a“ na hodnotu „__proto__“ a dosáhnout tak nastavení své vlastnosti s názvem „b“ a hodnotou „value“ v kořenovém prototypu objektu (obj.__proto__.b = value;), přičemž nastavená vlastnost v prototypu bude viditelná ve všech objektech. Podobně, pokud se v kódu vyskytují výrazy ve formátu „obj[a][b][c] = value“, může útočník při nastavování „a“ na hodnotu „constructor“ a „b“ na „prototype“ v všech existujících objektech definovat novou vlastnost s názvem „c“ a hodnotou „value“.
Příklad změny prototypu: const o1 = {}; const o2 = new Object(); o1.__proto__.x = 42; // vytváříme v kořenovém prototypu vlastnost „x“ console.log(o2.x); // přistupujeme k vlastnosti „x“ z jiného objektu // na výstupu dostaneme 42, protože přes objekt o1 byl změněn kořenový prototyp, který se používá i v objektu o2.
Příklad zranitelného kódu: function entryPoint(arg1, arg2, arg3){ const obj = {}; const p = obj[arg1]; p[arg2] = arg3; return p; }
Pokud jsou argumenty funkce entryPoint vytvářeny z vstupních dat, může útočník předat do arg1 hodnotu „__proto__“ a vytvořit v kořenovém prototypu jakoukoli vlastnost. Pokud se do arg2 předá hodnota „toString“ a do arg3 — 1, lze definovat vlastnost „toString“ (Object.prototype.toString=1) a způsobit havárii aplikace při volání funkce toString().
Jako příklad situací, které mohou vést ke spuštění kódu útočníka, se uvádí vytváření vlastností „main“, „shell“, „exports“, „contextExtensions“ a „env“. Například útočník může vytvořit v kořenovém prototypu objektu vlastnost „main“, do které zapíše cestu k vlastnímu skriptu (Object.prototype.main = „./../..//pwned.js“) a tato vlastnost bude volána během vykonávání kódu v konstrukci require(„my-package“), pokud připojený balíček výslovně nedefinuje v package.json vlastnost „main“ (pokud vlastnost není definována, bude získána z kořenového prototypu). Podobně mohou být podstrčeny vlastnosti „shell“, „exports“ a „env“: let rootProto = Object.prototype; rootProto[„exports“] = {„.“: „./changelog.js“}; rootProto[„1“] = „/path/to/npm/scripts/“; // vyvolání volání 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“; // vyvolání volání require („bytes“);
Výzkumníci analyzovali 10 tisíc NPM balíčků s největším počtem závislostí a zjistili, že 1958 z nich nemá vlastnost main v package.json, 4420 používá relativní cesty ve výrazu require a 355 přímo používá API pro podstrčení příkazů.
Jako funkční příklad lze uvést exploit pro útok na backend Parse Server, který přepisuje vlastnost evalFunctions. Pro usnadnění identifikace takových zranitelností byl vyvinut nástroj kombinující metody statické a dynamické analýzy. Během testování Node.js bylo odhaleno 11 gadgetů, které lze použít k organizaci útoků vedoucích k provedení kódu útočníka. Kromě Parse Server byly v NPM CLI také identifikovány dvě zranitelnosti, které lze zneužít.
Zdroj: opennet.ru
