
Исправление уязвимости загрязнения прототипа (CVE-2023-26136) для пакета tough-cookie
Прототипное загрязнение — это уязвимость JavaScript, которая позволяет атакующему добавлять произвольные свойства к прототипам глобальных объектов, которые затем могут наследоваться пользовательскими объектами. Источник прототипного загрязнения — это любые управляемые пользователем данные, которые позволяют добавлять произвольные свойства к объектам-прототипам. Наиболее распространённые источники: URL JSON Web Messages
Для пакета tough-cookies (v2.5.0) наиболее актуален первый — через URL Это происходит следующим образом:
Вот пример запроса:
https://vulnerable-website.com/?__proto__[badProperty]=payload
При разборе строки запроса на пары ключ:значение URL-парсер может интерпретировать __proto__ как произвольную строку.
В какой-то момент рекурсивная операция слияния может присвоить значение evilProperty с помощью выражения, эквивалентного следующему:
targetObject.__proto__.badProperty = 'payload';
__proto__ имеет особое назначение в JavaScript. Как мы знаем, если для некоторого объекта свойство P1 не найдено, оно будет искаться в прототипе этого объекта
Пример
function myClass() {
this.P1 = 'value';
}
let mc = new myClass();
console.log(mc.P1); //Value
console.log(mc.P2); //Undefined
mc.__proto__.P2 = 'value2';
let mc2 = new myClass();
console.log(mc.P2); //value2
После изменения __proto__ все созданные экземпляры myClass будут иметь свойство P2
Для пакета tough-cookies ( v2.5.0 ) эту уязвимость прототипного загрязнения можно увидеть в следующем фрагменте кода:
await new Promise((resolve, reject) => {
cookiejar.setCookie(
"Slonser=polluted; Domain=__proto__; Path=/notauth",
"https://__proto__/admin",
{ loose: true },
(err, cookie) => {
if (err) {
reject(err);
} else {
resolve(cookie);
}
}
);
});
Было обнаружено, что класс CookieJar по умолчанию использует MemoryCookieStore в качестве хранилища. И в нескольких методах MemoryCookieStore объекты инициализируются следующим образом
this.idx = {};
Это означает, что в прототип this.idx могут быть добавлены свойства со значениями (которые могут быть проблематичными) через __proto__. Чтобы предотвратить это, в нескольких местах инициализация была изменена следующим образом:
this.idx = Object.create(null);
Это создаёт пустой объект без прототипа. Был добавлен тест memstore_vulnerability_fix_test.js, проверяющий исправление.