Атака на Node.js чрез манипулации с прототипите на обектите JavaScript.

Изследователи от Центъра за информационна сигурност на Хелмхолц (CISPA) и от Королевския технологичен институт (Швеция) проучиха приложимостта на техниката за замърсяване на прототипи на обекти JavaScript („prototype pollution“) за извършване на атаки върху платформата Node.js и популярни приложения, базирани на нея, което води до изпълнение на код.

Методът за замърсяване на прототипа използва особеност на JavaScript, която позволява добавянето на нови свойства в коренния прототип на всеки обект. В приложенията могат да срещнете блокове код (гаджети), на които работата им зависи от вмъкнатото свойство, например в кода може да има конструкция от вида ‘const cmd = options.cmd || „/bin/sh“‘, логиката на която ще бъде променена, ако атакуващият успее да вмъкне свойство „cmd“ в коренния прототип.

За успешното извършване на атака е необходимо в приложението входящите данни от външни източници да могат да бъдат използвани за създаване на ново свойство в коренния прототип на обекта, както и да присъства гаджет, зависещ от промененото свойство. Промяната на прототипа се извършва чрез обработка на служебните свойства „__proto__“ и „constructor“ в Node.js. Свойството „__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/»; // предизвикване на извикване 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»; // предизвикване на извикване require («bytes»);

Изследователите анализирали 10 хиляди NPM пакета с най-много зависимости и установили, че 1958 от тях нямат свойството main в package.json, 4420 използват относителни пътища в израза require, а 355 директно използват API за подмяна на команди.

Пример на работещ експлойт за атака на бекенда на Parse Server, който пренаписва свойството evalFunctions. За улеснение на откритията на подобни уязвимости е разработен инструмент, комбиниращ методи на статичен и динамичен анализ. В хода на тестовете на Node.js бяха открити 11 джаджи, които могат да се използват за организиране на атаки, водещи до изпълнение на кода на нападателя. Освен Parse Server, две експлоатирани уязвимости също бяха установени в NPM CLI.

Източник: opennet.ru

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster