
У декодері Brotli від Google виявлено вразливість, що призводить до пошкодження пам’яті. За шкалою CVSS v4.0 вона має критичний рівень 9.2 і впливає на всі версії від 1.0.3 до 1.2.0. Node.js оприлюднила її 22 жовтня під назвою Node2Shell. Наступного дня Python опублікувала попередження про ту саму вразливість, оскільки пакети Brotli та brotlicffi на PyPI компілюють той самий декодер. Якщо ваш стек працює з HTTP і розпаковує відповіді, ця вразливість, імовірно, вже є у вашому дереві залежностей.
Вона працює в обидва боки
Віддалений атакуючий без автентифікації надсилає спеціально сформований потік, стиснутий Brotli, і декодер продовжує приймати байти, які він мав відхилити. Ці байти переповнюють невеликий робочий буфер. Після цього атакуючий може витікати дані з пам’яті, зупиняти процес або отримувати контроль над виконуваним кодом. Неприємна частина полягає в тому, що це працює в обидва боки: зловмисний клієнт може захопити незаславлений сервер, який приймає стиснуті тіла запитів, а зловмисний сервер може захопити незаславлений клієнт, який приймає стиснуті відповіді.
OpenAI виявила цю вразливість у лютому та повідомила про неї як про віддалене виконання коду без автентифікації. Ця дата має значення, і причина, чому вона має значення, не є лестивою для нікого.
Причиною є булевий тип
Вразливість знаходиться в функції DecodeBlockTypeAndLength, яка обробляє перемикання блоків — точки, де потік Brotli змінює дерево Хаффмана, яке використовує. У вразливих версіях вона повертає звичайний булевий тип, і значення false може означати дві дуже різні речі. Або потік сформовано неправильно, або декодеру потрібно більше вхідних даних. Виклики не можуть визначити, що саме сталося. На швидкому шляху декодер повністю ігнорує повернуте значення.
Спеціально сформований потік може оголосити один тип блоку, а потім вичерпати його довжину. Це примушує перемикання, яке не може завершитися успішно. Тоді декодер або повідомляє, що йому потрібно більше вхідних даних для потоку, який уже завершено, або продовжує декодування зі станом блоку, який був до цього. Другий шлях призводить до запису за межами буфера.
Виправлення в основному репозиторії, коміт 0ed4268 у google/brotli, змушує функцію повертати код помилки та додає новий код, BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH, який дорівнює мінус сімнадцять. Тепер декодування зупиняється при помилці формату як на безпечному, так і на швидкому шляху. Порівняння джерельного коду версій 1.2.0 та 1.2.1 показує, що єдині суттєві зміни — це цей коміт та оновлення номера версії.
Отже, виправлення існує в джерельному коді з лютого. Чого не існувало, так це релізу. Brotli 1.2.1 — перша випущена версія, яка містить це виправлення, що означає, що кожен проєкт, який використовує Brotli, мав чекати, і тепер кожен такий проєкт має випустити власне оновлення.
Ваш сканер сліпий до цієї вразливості
Вам не потрібно імпортувати Brotli, щоб ця вразливість вас торкнулася. HTTP-клієнти, такі як requests, httpx та aiohttp, автоматично завантажують пакет, якщо він присутній. Аналітика Aikido відверто говорить про практичні наслідки: станом на 23 жовтня бази даних попереджень не пов’язують цей CVE з жодним із пакетів PyPI, тому pip-audit, Dependabot та Safety не позначать вразливі версії. Ви можете отримати чистий звіт сканування, але все одно використовувати версію 1.2.0.
Ще дві деталі, які варто запам’ятати. Модуль mod_brotli від Apache не декодує Brotli, тому цей шлях не постраждав. І зміна заголовка Accept-Encoding не є виправленням, оскільки зловмисний сервер може надіслати відповідь у форматі Brotli незалежно від того, що оголошує клієнт, а urllib3 обирає декодер на основі заголовка Content-Encoding у відповіді, а не на основі того, що ви просили.
Що робити насправді
Оновіть до Brotli 1.2.1 або brotlicffi 1.2.1.0 у всіх середовищах, де вони присутні. Потім перескомпілюйте образи контейнерів, які містять Brotli, оскільки файл блокування залежностей на хості не впливає на шар, який уже знаходиться у вашому реєстрі. Знову розгорніть, перезапустіть сервіси та переконайтеся, що активні робочі навантаження працюють на виправленій збірці, а не припускайте, що конвеєр зробив те, що ви йому наказали.
На що я постійно повертаюся, так це на розрив між виправленням та релізом, а не на саму вразливість. Вразливість пошкодження пам’яті в одній із найбільш завантажуваних бібліотек стиснення в інтернеті була правильно діагностована у лютому, виправлена в джерельному коді, але все одно стала відомою світові як критичне попередження в жовтні, тому що ніхто не вважав це виправленням безпеки. Цей розрив буде повторюватися. Саме тому ніхто не може надати вам звіт сканера, який свідчить, що все гаразд.