Skip to content
KitploitKITPLOIT
도구블로그
Log in
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-18963 — CVE-2026-18963에 대한 Docker 기반 실습 환경 및 Python 익스플로잇으로, 이메일 인증 우회를 통해 계정 탈취를 가능하게 하는 Keycloak 비밀번호 재설정 흐름 우회 취약점입니다. | Kitploit
도구/GitHubGitHub/ivanesk315/cve-2026-18963
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingIdentity & Access Management (IAM)AuthenticationLearning & EducationLabs & Practice
GitHubivanesk315/cve-2026-18963

CVE-2026-18963

CVE-2026-18963에 대한 Docker 기반 실습 환경 및 Python 익스플로잇으로, 이메일 인증 우회를 통해 계정 탈취를 가능하게 하는 Keycloak 비밀번호 재설정 흐름 우회 취약점입니다.

1621일 전아직 검토되지 않음
저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-18963 — Keycloak Reset-Credentials Flow Bypass Lab

개요

Keycloak의 CVE-2026-18963 (CVSS 9.1) 취약점을 시뮬레이션하는 Lab으로, 공격자가 비밀번호 재설정 흐름에서 이메일 검증을 우회하여 임의의 계정을 탈취할 수 있게 합니다.

보안 연구 및 교육 목적으로만 사용하십시오.

요구 사항

  • Docker & Docker Compose
  • Python 3.8+
  • pip

사용 안내

1. 취약한 Keycloak 실행

docker-compose up -d

Keycloak이 시작될 때까지 기다립니다 (~30-60초).

2. Lab 설정

pip install -r requirements.txt
python setup-lab.py

스크립트가 생성하는 항목:

  • reset-password가 활성화된 Realm vuln-lab
  • 이메일 발송을 위한 SMTP (MailHog) 구성
  • 사용자 victim ([email protected] / VictimPass123!)

3. Exploit 실행

python exploit.py -u http://127.0.0.1:8080 -r vuln-lab -t victim -p Pwned123!

옵션:

  • -u / --url: Keycloak URL (기본값: http://127.0.0.1:8080)
  • -r / --realm: Realm 이름 (기본값: vuln-lab)
  • -t / --target: 대상 사용자 이름 (기본값: victim)
  • -p / --password: 새 비밀번호 (기본값: Pwned123!)
  • -v / --verbose: 디버그 출력 활성화

4. 이메일 확인 (선택 사항)

MailHog UI: http://127.0.0.1:8025 — exploit 과정에서 발송된 reset-password 이메일을 확인합니다.

5. 정리

docker-compose down -v

기술 세부 사항

근본 원인

Keycloak의 두 가지 결함이 결합되어 공격 체인을 형성합니다:

결함 1 — Selector 상태 손상 (DefaultAuthenticationFlow.java): 사용자가 "Try Another Way"를 클릭하면, auth note AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED가 execution model ID 대신 "true" (불리언 문자열)로 저장됩니다. "true" 값은 특정 execution에 바인딩되지 않으므로 flow 내 단계 전반에 걸쳐 지속되어, selector가 잘못된 컨텍스트를 표시하게 만듭니다.

결함 2 — 무조건적 action 성공 (ResetCredentialEmail.java): ResetCredentialEmail의 action() 메서드는 action token을 확인하지 않고 무조건 context.success()를 호출합니다. 정상적으로 action()은 사용자가 이메일의 링크를 클릭할 때(action token 보유)만 호출됩니다. 그러나 selector가 손상되면 공격자는 flow processing을 통해 action()을 직접 트리거할 수 있습니다.

상세 공격 흐름

Attacker                              Keycloak
   │                                     │
   │─── GET /auth (OIDC + PKCE) ────────>│  1. auth session 초기화
   │<── Login page + cookies ────────────│
   │                                     │
   │─── GET /reset-credentials ─────────>│  2. reset flow로 이동
   │<── Username form ──────────────────│
   │                                     │
   │─── POST tryAnotherWay=on ─────────>│  3. selector 상태 손상
   │<── Authenticator selector ─────────│     SELECTOR_DISPLAYED = "true"
   │                                     │
   │─── POST username=victim ──────────>│  4. selector를 통해 username 전송
   │<── "Check your email" page ────────│     이메일 발송, CURRENT_EXEC = email_id
   │                                     │
   │─── GET /reset-credentials ────────>│  5. reset flow 재진입
   │<── Corrupted selector (!!!) ───────│     processFlow()가 SELECTOR="true" 확인
   │                                     │     → email 단계에 selector 표시
   │                                     │
   │─── POST {} (empty body) ──────────>│  6. BYPASS: action() 트리거
   │<── 302 → UPDATE_PASSWORD ─────────│     processAction()이 form에서
   │                                     │     authenticationExecution을 찾지 못함
   │─── GET /required-action ──────────>│     → action() 분기로 진입
   │<── Password update form ──────────│     ResetCredentialEmail.action()
   │                                     │     → context.success() (무조건적!)
   │                                     │     → flow가 ResetPassword로 전환
   │                                     │
   │─── POST password-new=Pwned! ──────>│  7. 새 비밀번호 설정
   │<── 302 → /account/ ──────────────│     Account takeover 완료
   │                                     │
   └── 새 비밀번호로 로그인 ─────────────┘

step 6이 작동하는 이유

DefaultAuthenticationFlow.processAction()에서 POST를 수신할 때:

  1. form에서 tryAnotherWay 확인 → 없음 (빈 form)
  2. form에서 authenticationExecution 확인 → 없음 (빈 form)
  3. 마지막 분기로 진입: URL의 model에 대해 authenticator.action(result) 호출

URL에 execution=<email_exec_id> (selector form action에서 유래)가 포함되어 있으므로, ResetCredentialEmail.action()이 호출됨 → context.success() 반환 → flow가 ResetPassword로 전환 → 비밀번호 설정 form 표시.

영향받는 버전

제품영향받음패치됨
Keycloak (upstream)< 26.7.226.7.2+
RHBK 26.4.x< 26.4.1526.4.15+
RHBK 26.6.x< 26.6.626.6.6+

패치 (PR #51844)

DefaultAuthenticationFlow.java:

  • setAuthNote(SELECTOR_DISPLAYED, "true") → setAuthNote(SELECTOR_DISPLAYED, model.getId())
  • processFlow()가 Boolean.parseBoolean() 대신 selector.equals(lastExecutionId) 확인
  • 일치하지 않으면 → removeAuthNote(SELECTOR_DISPLAYED)

ResetCredentialEmail.java:

  • action()이 context.success() 호출 전에 ACTION_TOKEN_USER_ID 확인
  • 유효한 action token이 없으면 → context.failure(INVALID_USER)

참고 자료

  • NVD - CVE-2026-18963
  • Red Hat CVE Page
  • Keycloak Issue #51833
  • Fix PR #51844
  • Kudelski Security Research
  • The Hacker News
도구 다운로드