Віддалене виконання коду в JsonWebToken

Автор: Данило Діденко, Security Support Engineer

Open source пакет JsonWebToken відіграє важливу роль при автентифікації та авторизації для багатьох сучасних програм. JWT був розроблений і наразі підтримується платформою Auth0. Кількість щотижневих завантажень цього пакету станом на сьогодні досягла відмітки в цілих 10 мільйонів, це означає, що JWT є дуже популярним у сучасних IT інфраструктурах.

Нещодавно, у JWT було виявлено вразливість високого рівня – CVE-2022-23529, яка може використовуватися кіберзлочинцями для віддаленого виконання коду (RCE) на цільовому сервері шифрування. Вразливості було призначено ступінь серйозності CVSS 7.6.
На щастя, зараз причин для паніки немає. Вразливість вже виправили у патчі до нової версії JsonWebToken 9.0.0. Однак, якщо ви все ще використовуєте пакет JWT 8.5.1 або ще більш ранньої версії, то наполегливо рекомендуємо вам якнайшвидше оновитись.

Тепер давайте детальніше розглянемо цю вразливість та яким чином зловмисники могли її реалізувати.

Для цього почнемо з технічного визначення JWT та його структури:

JsonWebToken (JWT) — це компактний, безпечний для URL-адрес, відкритий стандарт, який визначає метод безпечної передачі інформації шляхом кодування та підпису даних JSON. JWT використовуються для передачі різних типів інформації, але в основному його використовують для доставки «вимог», які є фрагментами інформації. На практиці вимоги, швидше за все, міститимуть корисну інформацію про користувача, що найчастіше використовується для авторизації та автентифікації.

JWT має рядкову структуру, яка складається з 3 частин, розділених крапкою (.): заголовка, корисного навантаження та підпису.

Header.Payload.Signature

jwt_token

Структурна схема JWT

JWT Header – це заголовок, він складається здебільшого з двох параметрів, які вказують на тип токена та алгоритм підпису.

JWT Payload – це корисне навантаження, що є другою частиною токена, яка саме і міститиме вимоги. Як ми вже зазначили раніше, найчастіше це дані користувача.

JWT Signature – це третя частина, вона являє собою підпис, який потім обчислюється за формулою з використанням секретного ключа. Підпис використовується для підтвердження того, що токен не було підроблено або скомпрометовано.

А ось такий вигляд має повна форма JWT після шифрування:

jwt_example

Роль JWT у процесі автентифікації

Щоб краще зрозуміти суть вразливості, також важливо дізнатися про роль токенів JWT у процесі автентифікації. Давайте розглянемо як працює процес автентифікації по пунктах.

jwt process
  1. Користувач намагається автентифікуватись, надаючи свої облікові дані.
  2. Сервер автентифікації отримує запит користувача і звіряє надані облікові дані з базою даних.
  3. Якщо облікові дані дійсні, сервер автентифікації генерує JWT, який містить вимоги до користувача, і підписує його секретним ключем.
  4. JWT повертається до користувача та зазвичай зберігається у його браузері як файл cookie або в локальному сховищі браузера.
  5. Коли користувач запитує доступ до захищеного ресурсу, запит, що містить JWT, буде згенеровано програмою та відправлено до сервера автентифікації JWT. Саме на цьому кроці зловмисник і може провести атаку з «отруєнням» секретного ключа маючи доступ до менеджера ключів.
  6. Перш ніж користувач отримає доступ, надісланий JWT буде перевірено за допомогою секретного ключа. Це робиться для того, щоб переконатися, що його не було підроблено, і що користувач має необхідні дозволи для перегляду інформації. У пакеті node.js JsonWebToken це робиться за допомогою функції verify.
  7. Якщо JWT успішно підтверджено, користувачу надається доступ до захищеного ресурсу. Якщо ж токен підтвердити не вдалось, доступ користувачу блокується і повертається повідомлення у вигляді «error 401», або якщо термін дії JWT минув, користувач повинен увійти знову та отримати новий токен.

Отже, якщо секретні ключі зберігаються недостатньо надійно, кіберзлочинець зможе виконати свій шкідливий код на самому хості, тим самим отримати або змінити конфіденційні дані, що містяться на сервері.

Про вразливість

Як правило, атаки на JWT включають різні методи підробки з використанням помилок в реалізації пакета. Такі атаки мають серйозні наслідки, оскільки в більшості випадків успішна атака дозволяє зловмиснику обійти механізми автентифікації та авторизації, щоб отримати доступ до конфіденційної інформації, викрасти та/або змінити дані.

Одним із методів, що входять до пакета JsonWebToken, є verify.

Метод verify отримує три параметри: token, secretOrPublicKey та options. Ця функція підтверджує дійсність JWT і повертає декодовану частину корисного навантаження.

Відповідно до документації secretOrPublicKey — це рядок або буфер. Як виглядає функція verify.js. в JsonWebToken – показано на скриншоті.

snippet from verify

Проте, якщо в бібліотеці не задано список дозволених алгоритмів, тоді замість них для передачі ключа буде використовуватись пошта з підвищеною конфіденційністю (PEM), що надається параметром secretOrPublicKey.

Це створює наступну проблему: відсутність перевірки на підтвердження того, що secretOrPublicKey насправді є дійсним вмістом PEM файлу. І це, своєю чергою, призводить до того, що метод toString() застосовується для цього не перевіреного об’єкта, можна сказати, «наосліп». І це означає, що зловмисники, які контролюють secretOrPublicKey, можуть застосувати свій власний метод toString, який потім буде підтверджено JsonWebToken та відправлено на сервер. Цей тип атаки було названо «poisoned secret key», тобто отруєний секретний ключ.

Використовуючи знайдену вразливість, кіберзлочинець матиме змогу додати зловмисний об’єкт до функції verify через параметр secretOrPublicKey і замінити її метод toString(), таким чином у нього буде можливість здійснити віддалене виконання зловмисного коду на сервері, що вважається однією із найруйнівніших кібератак.

На щастя, розробники JWT оперативно виправили недолік коду, видаливши його вразливу частину та замінивши її перевіркою дійсності параметрів secretOrPublicKey.

Умови реалізації вразливості

Збереження та обслуговування секретних ключів зазвичай охоплює передові практики для забезпечення їх безпеки, такі як використання менеджерів ключів, ротації секретних ключів, шифрування ключів та інші.

Зважаючи на це, щоб скористатися вразливістю, описаній в цій публікації, зловмиснику необхідно отримати контроль над секретними ключами, і тільки за таких умов у нього буде можливість контролювати значення secretOrPublicKey та змога провести атаку RCE. Тому спосіб реалізації даної вразливості є досить складним, але через руйнівні властивості їй і було присвоєно високу оцінку серйозності CVSS 7.6.

Висновок

Під час використання програмного забезпечення з відкритим вихідним кодом, безпека має вирішальне значення для уникнення та зменшення вірогідності руйнівних кібератак.

Для запобігання таким типам вразливостей необхідно регулярно проводити аудит безпеки, забезпечувати безпечні трансфери секретних ключів, та приділяти особливу увагу їх зберіганню.

Не менш важливими є заходи, що дозволяють зменшити ризик виникнення таких вразливостей в майбутньому. Необхідно виконувати регулярні сканування продукту, що дозволить вам виявляти вразливості безпеки в проєкті ще на ранніх стадіях написання коду та впродовж подальшого життєвого циклу програми.

Зокрема, для досягнення найвищого рівня безпеки публічних користувацьких інтерфейсів вашого периметра, ми рекомендуємо вам використовувати новітні методи сканування такі як DAST, IAST та їх поєднання.

Підписатися на новини