
Демонстрирует критическую уязвимость предсказуемости ключа подписи JWT в PowerJob Server, позволяющую офлайн-вывод ключа и подделку токена для захвата администратора и обхода аутентификации OpenAPI.
Ключ подписи JWT (HS256) сервера PowerJob формируется путем BASE64-декодирования жестко заданной константы, объединенной с MD5-хешем URL JDBC по умолчанию (DefaultSecretProvider / JwtServiceImpl). URL JDBC является общедоступным в конфигурации развертывания по умолчанию (docker-compose / application-daily.properties), поэтому злоумышленник может полностью автономно вычислить ключ и подделать действительный JWT для любого пользователя (включая администратора); токен приложения OpenAPI также может быть подделан для обхода аутентификации OpenAPI.
application-daily.properties раскрывает в открытом видеjdbc:mysql://powerjob-mysql:3306/powerjob-daily?...powerjob-server-auth/.../jwt/impl/DefaultSecretProvider.java:31-45: return md5(environment.getProperty("spring.datasource.core.jdbc-url"));powerjob-server-auth/.../jwt/impl/JwtServiceImpl.java:44-102: жестко заданная константа BASE_SECURITY; genSecretKey(secret) = Decoders.BASE64.decode(BASE_SECURITY.concat(secret)) → Keys.hmacShaKeyForusername/encryptedToken) имеет вторичную проверку для учетных записей PWJB (DigestUtils.rePassword(password, username)), но:
appId/password/encryptType) может быть подделан напрямую для обхода аутентификации (OpenApiSecurityServiceImpl:87-105);Окружение: локальный сервер PowerJob (127.0.0.1:7700, URL JDBC jdbc:mysql://127.0.0.1:3307/powerjob_daily?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true). Злоумышленник вычисляет все автономно, только на основе общедоступной информации:
# ① Вычисление encryptedToken (= rePassword(password, username)); вычислимо при пароле по умолчанию
rePassword("powerjob_admin", "ADMIN")
= ADMIN_b82a450701f6a71723fb99931fe35e18_b # побайтово совпадает с DB user_info.token_login_verify_info ✅
# ② Вычисление ключа подписи HS256 = BASE64(BASE_SECURITY + MD5(JDBC_URL))
secret = BASE_SECURITY + md5(jdbc_url) # 101-байтовый ключ
# ③ Подделка веб-JWT администратора (claims: username=PWJB_ADMIN, encryptedToken=результат ①, sub=PowerJob)
Фактический результат (подделанный токен проходит аутентификацию):
[*] /namespace/list без токена :
{"success":false,"data":null,"message":"PowerJobAuthException: UserNotLoggedIn","code":"-100"}
[*] /namespace/list с подделанным JWT :
{"success":true,"data":{"index":0,"pageSize":10,"totalPages":1,"totalItems":1,"data":[{"id":1,"code":"default_namespace","name":"default_namespace","dept":null,"tags":null,"extra":null,"status":1,"statusStr":"ENABLE","gmtCreate":"2026-08-07T13:07:32.000+00:00","gmtCreateStr":"2026-08-07 21:07:32","gmtModified":"2026-08-07T13:07:32.000+00:00","gmtModifiedStr":"2026-08-07 21:07:32","showName":"default_namespace(default_namespace)","token":"14e4ebff-9a79-4845-ac66-8b20c4dff2ee","componentUserRoleInfo":{"observer":[],"qa":[],"developer":[],"admin":[]},"creatorShowName":null,"modifierShowName":null}]},"message":null}
→ подделанный токен аутентифицируется как администратор и возвращает реальные данные (базовый сценарий отклоняется с UserNotLoggedIn).
Ключевые моменты:
encryptedToken совпадает со значением, хранящимся в БД, побайтово (ADMIN_b82a450701f6a71723fb99931fe35e18_b).BASE_SECURITY + MD5-хешем публичного URL JDBC по умолчанию → вычислим автономно без каких-либо учетных данных.encryptedToken можно пересчитать автономно при пароле по умолчанию (powerjob_admin, находка PJ-02) → полный захват учетной записи администратора.encryptedToken, но путь токена приложения OpenAPI (claims appId/password/encryptType, OpenApiSecurityServiceImpl:87-105) все равно может быть подделан независимо для обхода аутентификации OpenAPI.Даже если пароль по умолчанию изменен, уязвимость сохраняется через другие векторы атаки:
encryptedToken любого действительного пользователя другими способами (например, SQL-инъекция, раскрытие резервной копии БД, утечка журналов или раскрытие информации через другие конечные точки), может объединить этот токен с предсказуемым ключом подписи для подделки JWT для этого конкретного пользователя.encryptedToken, поскольку подделанный токен теперь содержит легитимный encryptedToken, полученный из фактической записи базы данных.PoC: powerjob_jwt_key.py 192.168.49.128:7700


encryptedToken для всех учетных записей.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1 Критический (в сочетании с паролем по умолчанию / OpenAPI)