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

Автор Сообщение
news_bot ®

Стаж: 6 лет 2 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
27-Июл-2022 18:32

Исследователи Центра Гельмгольца по информационной безопасности (CISPA) и Королевского технологического института (Швеция) проанализировали применимость техники засорения прототипа объектов JavaScript ("prototype pollution") для создания атак на платформу Node.js и популярные приложения на её основе, приводящих к выполнению кода.
Метод засорения прототипа использует особенность языка JavaScript, позволяющую добавить новые свойства в корневой прототип любого объекта. В приложениях могут встречаться блоки кода (гаджеты), на работу которых влияет подставленное свойство, например, в коде может быть конструкция вида 'const cmd = options.cmd || "/bin/sh"', логика работы которой будет изменена, если атакующий сумеет подставить свойство "cmd" в корневой прототип.
Для успешного совершения атаки требуется, чтобы в приложении поступающие извне данные могли использоваться для создания нового свойства в корневом прототипе объекта, а также чтобы в ходе выполнения встречался гаджет, зависящий от изменённого свойства. Изменение прототипа осуществляется благодаря обработке в Node.js служебных свойств "__proto__" и "constructor". Свойство "__proto__" возвращает прототип класса объекта, а свойство "constructor" возвращает функцию, используемую для создания объекта.
Если в коде приложения встречается
присвоение "obj[a] = value" и значения выставляются из внешних данных, атакующий может выставить "a" в значение "__proto__" и добиться установки своего свойства с именем "b" и значением "value" в корневом прототипе объекта (obj.__proto__.b = value;), при этом выставленное в прототипе свойство будет видно во всех объектах. Аналогично если в коде встречаются выражения вида "obj[a][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
===========

Похожие новости: Теги для поиска: #_javascript, #_node.js, #_prototype, #_pollution
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 27-Апр 09:35
Часовой пояс: UTC + 5