ey...... (Вступление)
Я и снова другая статья. Для тех, кто не понял, "ey" - это то, как начинаются все JWT токены. Я всегда стараюсь делать креативные вступления. Эта статья предназначена для всех, кто заинтересован в изучении и "совершенствовании" знаний о JWT.Предварительные требования: Желательно, немного разбираться в Linux и web
Уровень: Легкий
- Паутина
- Дневник белой шляпы [Часть 1]: не DDoS
- Дневник белой шляпы [Часть 2]: Интервью [GraphQL]
- Дневник белой шляпы [Часть 3]: Cтажировкa [File Inclusion (Remote / Local)]
- Дневник белой шляпы [Часть 5]: Удачная догадка [RCE - Проверка простейших CVE, найденных в PHP-приложениях]
- Дневник белой шляпы [Часть 6]: Сообщение [Websockets + Tool]
- ОС
- Дневник белой шляпы [Часть 4]: Знания [PrivEsc - Linux Capabilities] [Повышение привилегий - Возможности Linux]
Содержание
- История
- Что такое
шифрованиекодирование? - Что такое BASE64? Как это работает? Зачем нам это нужно?
- Что такое JWT? Как это работает? Зачем нам это нужно?
- ВЕБ-аббревиатуры JSON (JWT/JWK...)
- Атаки на JWT
- Некоторые случаи
История
Я не силен в шифровании и прочем. Все началось с одного из выступлений в blackhat (https://www.youtube.com/watch?v=9gKMoCH0tms), где Брюс Шна́йер сказал, "Я пришел в компьютерную безопасность из криптографии, а криптография - это математика. И одна из вещей, которые я сказал, когда писал 'Прикладную криптографию', заключается в том, что нам нужно защищать себя не законами, а математикой. Что в некотором роде интересно, но на самом деле невероятно наивно. Потому что то, что я узнал за последние несколько лет, изучая уязвимости, заключается в том, что криптография, математика, не могут нас спасти. Большинство хороших атак, которые мы наблюдаем, не являются проблемами, которые могла бы устранить криптография, даже если бы она была применена.". Я не собираюсь высказывать свое собственное мнение по этому поводу, в основном потому, что у меня нет знаний в математике, поэтому я решил поинтересоваться, как криптография используется в кибербезопасности. Как мы знаем oн используется для обеспечения конфиденциальности и целостности данных.Что такое шифрование кодирование?
Кодирование - это процесс перевода символов в специализированный формат для нужд обработки информации. Это просто процесс преобразования данных в другой формат. Почему мы хотим кодировать данные?
Мы хотим закодировать данные, чтобы сделать их пригодными для хранения, обработки или передачи в другое приложение. Самым простым примером кодирования может быть кодировка URL.
URL (Uniform Resource Locator) - это адрес, который используется для доступа к ресурсам в Интернете. URL-адрес может содержать буквенно-цифровые символы (AZ, az, 0-9), дефис (-), подчеркивание (_), точку (.), тильду (~) без необходимости кодирования данных. Также есть некоторые зарезервированные символы, которые можно использовать в URL, нет необходимости кодировать их, если они используются по назначению, в противном случае они должны быть закодированы. Этими символами являются двоеточие ( : ), косая черта (/), вопросительный знак (?), aмперсанд (&), знак равенства (=), знак плюса (+), знак доллара ($), запятая (,), точка с запятой ( ; ).
Давайте представим, что у нас есть URL-адрес
https://xss.pro/?user=andy&desc=animeNerd. В этом случае "&" показывает нам, что у нас есть 2 параметра, desc и user. Desc показывает описание пользователя. Теперь давайте предположим, что наше описание - "Аниме&Nerd", но мы знаем, что "&" используется между двумя разными параметрами, а "Nerd" - это не параметр, это значение. В этом случае нам придется закодировать его по URL-адресу. Подумайте, что наш URL-адрес выглядел бы следующим образом https://xss.pro/?user=andy&desc=Anime&Nerd. В данном случае мы относимся к "Nerd" как к параметру, а не к значению. Если мы хотим, чтобы это было значение, оно должно быть urlencoded, и наш url-адрес будет выглядеть следующим образом https://xss.pro/?user=andy&desc=Anime%26Nerd.Зачем нам нужна кодировка URL?
По той же причине, по которой нам вообще нужна кодировка, для обработки данных. URL-адрес может содержать только определенный набор символов, поэтому нам нужно закодировать некоторые символы перед их передачей.
Что такое шифрование?
Существует множество определений по этому поводу. Для меня, в наиболее точном варианте, шифрование - это процесс преобразования необработанного текста в зашифрованный текст
Зачем нам нужно шифрование?
В основном это нужно нам для защиты информации. Простым примером может служить HTTPS-соединение, которое шифрует данные, которые мы отправляем и получаем. HTTPS использует (TLS)/SSL для шифрования связи.
В чем разница между шифрованием и кодированием?
На самом деле они служат разным целям. Шифрование используется для сокрытия "секретной" информации, a кодированиe для того чтобы сделать данные пригодными для обработки и тп.
Что такое BASE64? Как это работает? Зачем нам это нужно?
BASE64 - это алгоритм, который используется для кодирования двоичного кода в удобочитаемый текст. Самый простой пример можно привести при передаче изображений. BASE64 используется для кодирования необработанных изображений. Вы можете спросить, зачем нам это нужно. Это устраняет необходимость отдельных файлов для изображений. Данные изображения могут быть включены непосредственно в HTML-код в виде строки в кодировке BASE64. Вы можете увидеть пример на изображении ниже. Я использовал тег "img" с закодированным изображением.
Изображение [1]: Закодированное изображение
Я объясняю эту часть только потому, что полезно понять, как это работает. Мы делаем это для себя, ради наших знаний. Я могу допускать ошибки, я говорю об этом в каждой своей статье, вы вольны их исправлять. Предположим, что мы должны в BASE64 закодировать слово "XSS". Мы должны преобразовать слово "XSS" в ASCII.
ASCII (American Standard Code for Information Interchange) - это система, которая присваивает символу уникальный номер.
Изображение [2]: Таблица ASCII [
https://wikimedia.org]
Код:
X:88
S:83
S:83
Двоичная система счисления - это система счисления, которая использует только две цифры, 0 и 1. В этом случае мы будем использовать 8-битный двоичный код, который представляет собой последовательность из 8 двоичных цифр (тоесть в 0 и 1). Наша работа на этом этапе заключается в преобразовании каждого значения ASCII в его 8-битное двоичное представление. У нас есть ASCII-значения букв "X" и "S". Мы будем использовать их для преобразования слова в двоичный код.
Давайте попробуем получить двоичное значение буквы X, разделив ее ASCII-значение на 2.
Код:
(88)/2 44 0 0
(44)/2 22 0 1
(22)/2 11 0 2
(11)/2 5 1 3
(5)/2 2 1 4
(2)/2 1 0 5
(1)/2 0 1 6
Ответ здесь
1011000Давайте попробуем получить двоичное значение буквы S, разделив ее ASCII-значение на 2.
Код:
(83)/2 41 1 0
(41)/2 20 1 1
(20)/2 10 0 2
(10)/2 5 0 3
(5)/2 2 1 4
(2)/2 1 0 5
(1)/2 0 1 6
Ответ здесь
1010011Эти значения являются 7-битными двоичными, мы должны сделать их 8-битными (чтобы равномерно делилась на 6, типо 8*3=24, а 24 делится на 6), просто добавьте 0 в начале
X: 01011000 S: 01010011 .Давайте объединим все двоичные значения вместе, чтобы сформировать единую двоичную строку 010110000101001101010011. Поскольку BASE64 кодирует данные группами по 6 бит, нам может потребоваться дополнить двоичную строку нулями справа, чтобы она равномерно делилась на 6 (мы уже сделали это). Теперь мы должны разделить двоичную строку на 6-битные группы: 010110 000101 001101 010011. Время для преобразования каждого 6-разрядного двоичного кода в десятичный и нахождения соответствующих значений в соответствии с таблицей набора символов BASE64.Вычисление:
Код:
(010110)₂ = (0 × 2⁵) + (1 × 2⁴) + (0 × 2³) + (1 × 2²) + (1 × 2¹) + (0 × 2⁰) = (22)₁₀
(000101)₂ = (0 × 2⁵) + (0 × 2⁴) + (0 × 2³) + (1 × 2²) + (0 × 2¹) + (1 × 2⁰) = (5)₁₀
(001101)₂ = (0 × 2⁵) + (0 × 2⁴) + (1 × 2³) + (1 × 2²) + (0 × 2¹) + (1 × 2⁰) = (13)₁₀
(010011)₂ = (0 × 2⁵) + (1 × 2⁴) + (0 × 2³) + (0 × 2²) + (1 × 2¹) + (1 × 2⁰) = (19)₁₀
Изображение [3]: Таблица BASE64 [
https://www.woolha.com]
Код:
22:W
5:F
13:N
19:T
Очевидно, что это всего лишь простое объяснение. Этого должно быть достаточно только для того, чтобы у вас появилось понимание, или, как говoрил один из моих русскоязычных наставников, "vision".
Что такое JWT? Как это работает? Зачем нам это нужно?
Для этого мы должны сначала понять, что такое объект JSON. Для тех, кто работает с веб-сайтами, вы, вероятно, видели данные, отправляемые с типом содержимого application/json, где данные имеют вид {"key":"value"}. Объект JSON - это набор пар "key-value".JWT (JSON Web Token) - это стандарт, который определяет способ передачи информации в виде объекта JSON. Он широко используется в системах аутентификации. Возможно, вы увидели заголовок "Authorization" (в основном
Authorization: Bearer <token>), содержащий закодированный токен JWT в качестве значения.Как это работает?
Чем меньше вы думаете об этом, тем легче это работает =)
Токены JWT состоят из 3 частей: заголовка, полезной нагрузки (payload) и подписи (signature).
Заголовок показывает нам используемый алгоритм подписи и токен (которым является JWT). Существует множество алгоритмов подписи, и для их понимания необходимы знания в области криптографии. В нашем случае мы решим лабораторные работы и разберемся в основах.
Пример:
Код:
{
"alg": "HS256",
"typ": "JWT"
}
Полезная нагрузка - это данные. Эти данные называются "заявлениями". Обычно в нем содержится информация о пользователе, дата истечения срока действия "exp", дата создания "iat" и т.д. Я расскажу подробнее об этом заголовке по мере того, как мы будем решать лабораторные задачи. На данный момент все, что вам нужно знать, это то, что он содержит информацию о пользователе и что "exp" показывает дату истечения срока действия JWT. После этой даты JWT недействителен и не должен функционировать.
Пример:
Код:
{
"name": "Grozdniy Andy",
"exp": "1693948820",
"iat": 1693887608
}
Подпись - это зашифрованный заголовок+полезная нагрузка+секрет. Шифрование происходит с помощью алгоритма, используемого в заголовке.
Честно говоря, алгоритмов существует очень много. Чтобы глубоко понять весь этот процесс, вы должны очень хорошо разбираться в криптографии, что я не умею, криптография - сложная штука. Несмотря на то, что это не сильно повлияет на поиск уязвимостей, тем не менее понимание криптографии поможет в поиске новых возможных векторов атак. Так зачем же я написал всю эту чушь? Это мой способ пожелать вам "удачи".
Зачем нам это нужно?
Вы можете найти много информации по этому поводу. По моему собственному опыту, JWT используются в основном для аутентификации, и они хранят информацию пользователя в себе. Почему мы должны использовать его, когда у нас есть cookie? По самой простой причине JWT снижают нагрузку на сервер, поскольку данные хранятся в самом JWT, а не на сервере. Несмотря на то, что это правда, лично я считаю, что JWT был создан для того, чтобы мы могли находить уязвимости)
Помните, что если бы разработчики выполняли свою работу так, как от них требуется, не было бы такого понятия, как "пентест приложений". © GrozdniyAndy (слова друга. кредит мне)
ВЕБ-аббревиатуры JSON (JWT/JWK...)
Вы можете рассердиться, что, черт возьми, он не объяснил JWT на примерах, и бежит объяснять аббревиатуры. Это потому, что лучше ознакомиться с теоретической частью, прежде чем переходить к технической.Что такое JOSE?
Мужское имя в переводе с испанского, эквивалентное.... Просто шучу. JOSE - JSON Object Signing and Encryption - это набор стандартов, которые определяют, как безопасно передавать данные JSON и манипулировать ими с использованием различных криптографических методов. JWT использует JOSE для шифрования.
Что такое JWS?
JWS - JSON Web Signature - является частью JOSE, которая занимается обеспечением целостности и подлинности данных JSON с помощью цифровых подписей (algorithm). Он также используется в заголовке JWT как "alg", что указывает на используемый алгоритм.
Что такое JWE?
JWE (JSON Web Encryption) - это способ надежно скрыть содержимое объекта JSON, чтобы только авторизованные стороны могли его прочитать. Итак, в чем разница между JWS и JWE. JWS использует подпись (signature), в то время как JWE использует электронное шифрование (encryotion). Если JWT зашифрован с помощью JWE, мы не сможем прочитать полезную нагрузку (payload), просто расшифровав JWT с помощью BASE64. Также стоит упомянуть, что JWT сначала подписывается (JWS) для обеспечения его целостности и происхождения, а затем весь JWT (включая подпись JWS) шифруется (JWE) для обеспечения конфиденциальности.
Что такое JWA?
JWA - JSON Web Algorithms - определяет набор криптографических алгоритмов, которые могут использоваться для таких задач, как подписание (алгоритмы - JWS) и шифрование данных (JWE) в формате JSON
Что такое JWK?
JWK - JSON Web Key - содержит информацию о типе ключа, его значении и дополнительных метаданных в формате JSON. Насколько я понимаю, он используется для подписи данных и проверки цифровых подписей. Они HE предназначены для шифрования и дешифрования данных.
Что такое JKU?
JKU - JSON Key URL -используется в веб-токенах JSON для указания URL-адреса, по которому можно найти набор веб-ключей JSON (JWK). Так что просто это URL-адрес, который содержит JWK.
Я в хорошем настроении, так что давайте сперва поставим Дуа Липу, а потом Ивана (Я не знаю почему, но мне нравится эта песня *с музыкой, да?*) и продолжим наши атаки.
Атаки на JWT
Непроверенная подписьМы знаем, что токены JWT подписываются с помощью подписи. Чтобы отредактировать полезную нагрузку, мы должны знать "секрет". В некоторых случаях мы можем редактировать полезную нагрузку (payload), не зная секрета, и это будет работать.
ПОЖАЛУЙСТА, всегда создавайте шпаргалку при решении лабораторных работ. Поверьте мне, это очень поможет вам при поиске конкретных уязвимостей в системах.
Лаборатория №1:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-unverified-signatureУ нас есть данные для входа (wiener:peter), пришло время запустить Burp Suite и взломать : )- (тире это типо борода)
Мы вошли в систему и получили JWT в качестве session cookie. Первое, что пришло мне в голову, это "Почему они используют это как сессию? Хранят ли они эти данные?". Ребята, я не знаю об этом, это пришло к нам от умов, которые создали PUT и вместо этого используют POST.
Изображение [4]: Вход
jwt.io чтобы проанализировать наш токен JWT. Первая часть - это заголовок, вторая часть - полезная нагрузка, а третья - подпись. Если мы попытаемся отредактировать нашу полезную нагрузку в jwt.io само по себе это не сработает, потому что у нас нет секретного ключа. В любом случае полезная нагрузка - это просто данные, закодированные в BASE64, мы можем их просто декодировать.
Изображение [5]: Проверка токена JWT
Изображение [6]: Декодирование полезной нагрузки (payload)
"iss" означает "issuer", это "название" системы, которая выдала нам токен JWT. "Exp" показывает дату истечения срока действия, как вы знаете, "sub" означает "subject", он может содержать идентификатор пользователя. В нашем случае он содержит имя пользователя. Что ж, мы можем просто отредактировать это и написать "administrator". Обычно редактирование и замена исходной полезной нагрузкой не сработают, потому что должна быть проверка подписи. В нашем случае это сработает, потому что нет проверки подписи. Я имею в виду, что обычно на веб-сайте, если у нас есть токен JWT. Мы можем декодировать полезную нагрузку с помощью BASE64, отредактировать ее так, как мы хотим, и заменить текущей полезной нагрузкой "BASE64". Но это не сработает.
Изображение [7]: Редактирование полезной нагрузки (payload)
Мы заменили наше имя пользователя на administrator.
Изображение [8]: Редактирование полезной нагрузки (payload)
Мы заменили текущую полезную нагрузку на отредактированную и изменили
id=wiener на id=administrator. Теперь мы успешно вошли в систему как администратор. Я уверен, что вы сможете решить дальше удалив пользователя "carlos".Алгоритм "none"
Представьте, что к полезной нагрузке JWT не была применена цифровая подпись или криптографическая защита. В этом случае мы можем отправить JWT без какой-либо подписи, он будет содержать просто заголовок и полезную нагрузку.
Почему это вообще должно сработать?
Первый случай - это когда JWT не имеет подписи и алгоритма, и система может принять его как действительный (valid). Во втором случае системы могут принять его, но по-прежнему обрабатывать так, будто оно имеет подпись. В первом случае они просто принимают его как есть, во втором случае они принимают это так, как будто оно имеет подпись.
Я собираюсь сделать это вручную, я предпочитаю, чтобы вы тоже делали, как я. Поскольку мы снова (возможно) будем писать простой инструмент, полезно понять, как он работает. Другие атаки более запутанны, чем эта.
Лаборатория №2:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-flawed-signature-verificationВ этом случае мы должны вручную декодировать первую и вторую части токена JWT.
Изображение [9]: Вход
Изображение [10]: Проверка токена JWT
Изображение [11]: Декодирование первой и второй части (header+payload)
Давайте отредактируем первую часть нашего JWT и заменим название алгоритма на "none".
Изображение [12]: Редактирование заголовка
Как вы видите, в конце закодированных данных есть символ = . Мы должны просто удалить его. Почему мы не можем использовать "="? Потому что JWT разработан для обеспечения безопасности URL-адресов и часто используется в контекстах, где символы типа "=" могут вызывать проблемы с URL-адресами или передачей данных. Как вы знаете из приведенного выше, когда я писал о кодировке URL, знак равенства находится между параметром и значением, поэтому это может вызвать путаницу.
Изображение [13]: Редактирование полезной нагрузки
Я отредактировал полезную нагрузку, как делал это в предыдущей лаборатории.
Изображение [14]: Ввод нового JWT.
Я объединил закодированную версию заголовка и полезную нагрузку. Добавил точку после каждого из них и отправил запрос. В качестве ответа мы теперь являемся администраторами.
BruteForce ключа
Кое-что я узнаю, пока пишу статью, кое-что я уже знаю и сохранил в своей шпаргалке. Я предпочитаю, чтобы вы сделали то же самое. Я протестировал инструменты JWT, и лучшим из них для bruteforce является JWT Cracker и JWTCat.
Если вы используете Linux, вы можете сделать следующее:
Bash:
git clone https://github.com/brendan-rius/c-jwt-cracker.git
sudo apt update
sudo apt install libssl-dev
sudo make
sudo cp jwtcrack /usr/bin/jwtcrack
Bash:
sudo apt update
sudo apt install python3.11-venv
git clone https://github.com/AresS31/jwtcat
cd jwtcat
python -m venv env
python -m pip install -r requirements.txt
Разница между ними в том, что JWT Cracker хорош для брутфорса X символов, предоставляя алфавит и длину, в то время как JWTCat делает брутфорс с готовым списком слов.
Я буду использовать
https://raw.githubusercontent.com/wallarm/jwt-secrets/master/jwt.secrets.list этот список для брутфорса.
Bash:
python3 jwtcat.py wordlist -w jwt.secrets.list <тут токен>
Лаборатория №3:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-weak-signing-keyВ этой лаборатории мы должны брутфорсить и попытаться получить секретный ключ. Сначала мы входим в систему как обычно и получаем наш JWT.
Изображение [15]: Вход
Вы уже должны были установить инструменты и список для брутфорса. Пришло время получить секретный ключ при помощи брутфорса.
Изображение [16]: JWTCat
Мы получили секретный ключ, теперь мы можем отредактировать полезную нагрузку и заменить имя пользователя на administrator.
Изображение [17]: Редактирование JWT
Мы можем использовать новый токен JWT и быть администраторами.
Изображение [18]: Становление администратором
Инъекция заголовка JWK (JWK Header Injection)
Цель этой лабораторной работы - отредактировать JWT, добавить заголовок JWK и подписать нашей собственной подписью. На самом деле мы можем сами сгенерировать заголовок JWK, если захотим. Давайте сначала войдем в систему
Лаборатория №4:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-weak-signing-keyЯ решу эту задачу по-своему. Зачем я нужен, если мы собираемся копировать-вставлять ответы из portswigger, верно?
Изображение [19]: Вход
Изображение [20]: Анализ JWT
Когда мы анализируем наш токен JWT, мы видим, что он зашифрован с помощью открытого и закрытого ключей. Также обратите внимание на наш "kid". Наша работа здесь заключается в создании JWK, мы можем сделать это с помощью
https://mkjwk.org. Мы хотим использовать подпись как RS256 и использовать "kid" в качестве ключа, а также поставить "yes" в "Show X.509".
Изображение [21]: Генерирование JWK
После создания нашего собственного JWK мы должны заменить значения в редакторе JWT и сгенерировать новый JWT. Замените открытый и закрытый ключи на те, которые мы сгенерировали, замените имя пользователя на "administrator" и замените заголовок таким образом, как я это сделал.
Изображение [22]: Обновление JWT
Изображение [23]: Решение лаборатории
На самом деле это похоже на предыдущую атаку. Единственное отличие заключается в том, что теперь ключи будут храниться по определенному URL-адресу.
Лаборатория №5:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-jku-header-injectionМы входим в систему как обычно и получаем наш JWT. Уже похоже на рутинную работу whitehat

Изображение [24]: Вход
Изображение [25]: Анализ JWT
Изображение [26]: Генерирование JWK
Изображение [27]: Добавление ключей на наш сервер
Изображение [28]: Обновление JWT
Изображение [29]: Гыотово родня
Я чувствую, что скоро стану учителем литературы, преподающим новую infosec лексику. Я знаю, что уязвимости звучат странно по-русски, возможно, это потому, что я не являюсь носителем языка.
Что такое заголовок "kid"?
kid - Key ID - нужен для того чтобы помочь в выборе ключа, когда доступно несколько ключей для проверки JWT. Думайте об этом как об идентификаторе, который показывает, какой ключ используется для подписи.
Лаборатория №6:
https://portswigger.net/web-security/jwt/lab-jwt-authentication-bypass-via-kid-header-path-traversalЯ решу эту лабораторную работу с помощью расширения BurpSuite, до сих пор мы им не пользовались, в этой лаборатории я не смог найти альтернативного способа.
Изображение [30]: Загрузка расширения
Изображение [31]: Вход
Изображение [32]: Перехват трафика
Ладно, нам лучше подождать здесь. Давайте перейдем к нашему расширению и сгенерируем новый симметричный ключ.
Изображение [33]: Генерируем новый симметричный ключ
Здесь возникает вопрос, что такое AA= и почему мы его использовали? AA= - это нулевой байт закодированный в base64, что означает, что это ничто. Мы просто ничего не используем в качестве ключа. Мы делаем это, потому что мы не можем оставить ключ пустым, поэтому вместо него мы используем нулевой байт.
Изображение [33]: Генерируем новый JWT
Изображение [34]: Хакнули
Это все лаборатории, которые могут "подтолкнуть" вас вперед. Домашнее задание:
Код:
https://portswigger.net/web-security/jwt/algorithm-confusion/lab-jwt-authentication-bypass-via-algorithm-confusion
https://portswigger.net/web-security/jwt/algorithm-confusion/lab-jwt-authentication-bypass-via-algorithm-confusion-with-no-exposed-key
Вы можете подумать, что я решил простые задачи и оставил вам сложные. Вы правы, ученик должен превзойти учителя.
Последнее редактирование: