Атака на Node.js праз маніпуляцыі з прататыпамі аб'ектаў JavaScript

Даследнікі Цэнтра Гельмгольца па інфармацыйнай бяспецы (CISPA) і Каралеўскага тэхналагічнага інстытута (Швецыя) прааналізавалі дастасавальнасць тэхнікі засмечвання прататыпа аб'ектаў JavaScript ("prototype pollution") для стварэння нападаў на платформу Node.js і папулярныя прыкладанні на яе аснове, якія прыводзяць да выканання кода.

Метад засмечвання прататыпа выкарыстоўвае асаблівасць мовы JavaScript, якая дазваляе дадаць новыя ўласцівасці ў каранёвы прататып любога аб'екта. У дадатках могуць сустракацца блокі кода (гаджэты), на працу якіх уплывае падстаўленая ўласцівасць, напрыклад, у кодзе можа быць канструкцыя выгляду 'const cmd = options.cmd || "/bin/sh"', логіка працы якой будзе зменена, калі атакавалы здолее падставіць уласцівасць "cmd" у каранёвай прататып.

Для паспяховага здзяйснення нападу патрабуецца, каб у прыкладанні якія паступаюць звонку дадзеныя маглі выкарыстоўвацца для стварэння новай уласцівасці ў каранёвым прататыпе аб'екта, а таксама каб падчас выкананні сустракаўся гаджэт, які залежыць ад змененай уласцівасці. Змена прататыпа ажыццяўляецца дзякуючы апрацоўцы ў Node.js службовых уласцівасцяў "__proto__" і "constructor". Уласцівасць "__proto__" вяртае прататып класа аб'екта, а ўласцівасць "constructor" вяртае функцыю, выкарыстоўваную для стварэння аб'екта.

Калі ў кодзе прыкладання сустракаецца прысваенне «obj[a][b] = value» і значэнні выстаўляюцца з вонкавых дадзеных, атакавалы можа выставіць «a» у значэнне «__proto__» і дамагчыся ўсталёўкі сваёй уласцівасці з імем «b» і значэннем «value» у каранёвым прататыпе аб'екта (obj.__proto__.b = value;), пры гэтым выстаўленая ў прататыпе ўласцівасць будзе відаць ва ўсіх аб'ектах. Аналагічна калі ў кодзе сустракаюцца выразы выгляду "obj[a][b][c] = value", выставіўшы "a" у значэнне "constructor", а "b" у "prototype" ва ўсіх існуючых аб'ектах можна вызначыць новую ўласцівасць з імем "c" і значэннем "value".

Прыклад змены прататыпа: const o1 = {}; const o2 = new Object(); o1.__proto__.x = 42; // ствараем у каранёвым прататыпе ўласцівасць "x" console.log (o2.x); // звяртаемся да ўласцівасці «x» з іншага аб'екта // на выхадзе атрымаем 42, бо праз аб'ект o1 быў зменены каранёвы прататып, які выкарыстоўваецца ў тым ліку і ў аб'екце o2

Прыклад уразлівага кода: function entryPoint (arg1, arg2, arg3) { const obj = {}; const p = obj[arg1]; p[arg2] = arg3; return p; }

Калі аргументы функцыі entryPoint фармуюцца з уваходных дадзеных, то атакавалы можа перадаць у arg1 значэнне "__proto__" і стварыць у каранёвым прататыпе ўласцівасць з любым імем. Калі перадаць у arg2 значэнне "toString", а ў arg3 - 1, можна вызначыць уласцівасць "toString" (Object.prototype.toString=1) і дамагчыся краху прыкладання падчас выкліку функцыі toString().

У якасці прыкладу сітуацый, якія могуць прывесці да выканання кода атакавалага, прыводзіцца стварэнне ўласцівасцяў "main", "shell", "exports", "contextExtensions" і "env". Напрыклад, атакавалы можа стварыць у каранёвым прататыпе аб'екта ўласцівасць "main", запісаўшы ў яго шлях да свайго скрыпту (Object.prototype.main = "./../../pwned.js") і дадзеная ўласцівасць будзе выклікана ў момант выканання у кодзе канструкцыі require(«my-package»), калі які падключаецца пакет відавочна не вызначае ў package.json уласцівасць «main» (калі ўласцівасць не вызначана, яно будзе атрымана з каранёвага прататыпа). Аналагічна могуць быць падстаўлены ўласцівасці "shell", "exports" і "env": 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");

Даследнікі прааналізавалі 10 тысяч NPM-пакетаў, мелых найвялікі лік залежнасцяў, і выявілі, што 1958 з іх не маюць уласцівасці main у package.json, 4420 выкарыстаюць адносныя шляхі ў выразе require, а 355 напроста выкарыстоўваюць API для падстаноўкі каманд.

У якасці працавальнага прыкладу можна прывесці эксплоит для нападу на бэкэнд Parse Server, які перавызначае ўласцівасць evalFunctions. Для спрашчэння выяўлення падобных уразлівасцяў распрацаваны інструментар, які камбінуе метады статычнага і дынамічнага аналізу. Падчас тэставанняў Node.js было выяўлена 11 гаджэтаў, якія можна выкарыстоўваць для арганізацыі нападаў, якія прыводзяць да выканання кода атакавалага. Апроч Parse Server, дзве эксплуатаваныя ўразлівасці таксама былі выяўлены ў NPM CLI.

Крыніца: opennet.ru

Дадаць каментар