
Простой скрипт на Python для проверки на гипотетическую уязвимость JWT.
Простой скрипт на Python для проверки гипотетической уязвимости JWT.
Допустим, есть приложение, которое использует JWT-токены, подписанные алгоритмом HS256. Пример токена выглядит следующим образом:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.zbgd5BNF1cqQ_prCEqIvBTjSxMS8bDLnJAE_wE-0Cxg
Вышеуказанный токен можно декодировать в следующие данные:
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Для вычисления подписи используется следующий секрет:
supersecret
Для вычисления подписи используется следующий псевдокод:
$alg = "sha256";
$data = "...";
$key = "supersecret";
hmac($alg, $data, $key);
Но что, если неожиданное поле "kid":0 будет внедрено в заголовок?
{
"alg": "HS256",
"typ": "JWT",
"kid": 0
}
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Поле kid — это стандартный способ выбора ключа. Мое предположение: если поле kid не ожидается, возможна уязвимая реализация, которая будет обрабатывать строковое значение $key как массив:
hmac($alg, $data, $key[kid]);
В результате значение "s" ($key[0]) будет использоваться как секрет HMAC.
Скрипт injector.py принимает исходный JWT-токен, внедряет поле "kid":0 в заголовок и генерирует токены, подписанные односимвольными секретами (коды ASCII: 32–126 [{пробел}, !, ", #, ..., x, y, z, {, |, }, ~]):
python3 injector.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.zbgd5BNF1cqQ_prCEqIvBTjSxMS8bDLnJAE_wE-0Cxg
В результате создаются два файла: tokens.txt и tokens_meta.txt. tokens.txt содержит сгенерированные токены и может использоваться как список полезных нагрузок для Burp Intruder. Если какой-либо токен действителен (что означает, что приложение уязвимо), файл tokens_meta.txt можно использовать для проверки того, какой алгоритм и секрет использовались для генерации данного токена. Файл tokens_meta.txt содержит следующие данные:
token1:algorithm:secret
...
token{n}:algorithm:secret
См. CHANGELOG