
Joomla! com_users의 인증 우회를 악용해 인증 없이 계정을 생성할 수 있는 CVE-2026-90907을 탐지하고 익스플로잇하는 Python CLI로, 비파괴 검사 모드와 PoC를 제공합니다.
승인된 보안 테스트 전용입니다. 소유하지 않았거나 명시적인 서면 허가를 받지 않은 시스템에 대해 익스플로잇 모드를 실행하는 것은 불법입니다. 기본 모드(
CHECK)는 비파괴적이며 아무것도 생성하지 않습니다.
Joomla! CMS 코어의 중간 심각도 권한 부여 우회(CVSS 6.9)인
CVE-2026-90907을
탐지하고 (선택적으로 -U를 사용하여) 익스플로잇하는 CLI 도구입니다.
이 취약점은 인증되지 않은 원격 공격자가 com_users → profile.save
컨트롤러를 통해 무단 사용자 계정 생성을 유발할 수 있게 하며,
전역 구성에서 공개 등록이 비활성화된 경우에도 가능합니다.
| 필드 | 값 |
|---|---|
| CVE ID | CVE-2026-90907 |
| 심각도 | 중간 — CVSS 6.9 |
| 유형 | 권한 부여 우회 / 부적절한 접근 제어 (CWE-862) |
| 구성 요소 | com_users 컴포넌트, profile.save 작업 |
| 공격 벡터 | 원격, 인증되지 않음, 동일 세션 2단계 POST |
| 수정 버전 | Joomla! 5.4.9 및 6.1.4 (보안 릴리스, 2026-09-29) |
Joomla! 보안 공지(2026-09-29) 및 공개 권고 자료에 따르면:
Joomla! 3.x도 영향을 받지만 수명 종료(EOL) 상태입니다. 공식 패치를 받지 못할 것이므로 마이그레이션을 계획하십시오. 도구의 버전 배너 검사는 정보 제공용이며, 판정은 동작 기반입니다(아래 참조).
공격자가 제어하는 계정은 관리자 또는 백엔드 접근 권한이 없는 낮은 권한의 프런트엔드 계정입니다. 그럼에도 불구하고 공격자는 다음과 같은 작업을 할 수 있습니다:
ProfileModel::save()는 사용자 이름이 규정 준수로 간주될 때만
$data['username']을 unset()합니다. isUsernameCompliant는 사용자
상태 com_users.edit.profile.data에서 파생되며, 컨트롤러는 양식 유효성
검사가 실패할 때 이 상태를 전체 요청으로 채웁니다. 또한 컨트롤러는
들어오는 요청의 로그인 상태를 확인하지 않습니다. 따라서 하나의 게스트
세션 내에서:
privacyconsent 없이
POST → 유효성 검사 실패 → 오염된 사용자 이름이 세션 사용자 상태에
저장됨 (아직 아무것도 생성되지 않음).jform[privacyconsent][privacy]=1을 함께 재제출 → unset() 가드가
건너뛰어짐 → INSERT INTO #__users → user_id > 0과 함께 303
리다이렉트.user.login(필드 이름은 passwd가 아닌 password)을 POST하고
플래시 메시지를 읽음: 올바름 → "you cannot access the private section"
(인증 OK, ACL 차단) / 잘못됨 → "do not match". 이 차등이 증거입니다.git clone https://github.com/aorozco-sys/CVE-2026-90907.git
cd CVE-2026-90907
pip install -r requirements.txt # only dependency: requests
# CHECK mode (default) — non-destructive: never sends consent, never creates an account
python3 joomla_cve_2026_90907.py https://ejemplo.com
# Verbose CHECK (full request/response log on stderr)
python3 joomla_cve_2026_90907.py https://ejemplo.com --no-color -v
# EXPLOIT mode (-U) — creates a real account in #__users (authorized targets only!)
python3 joomla_cve_2026_90907.py https://ejemplo.com \
-U audit.user -E [email protected] -N "CVE Audit"
# Through a proxy (e.g. Burp Suite) with a custom timeout
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--proxy http://127.0.0.1:8080 --timeout 30
# Exploit without the differential login verification
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--no-verify-login
| 플래그 | 설명 |
|---|---|
TARGET | 기본 URL (정규화됨, 후행 슬래시 없음) |
-U/--username | EXPLOIT 모드를 활성화합니다. -U가 없으면 → 비파괴적 CHECK |
-P/--password | 기본값: secrets로 생성, 영숫자+기호 16자, 항상 출력됨 |
-E/--email | 기본값: <username>@example.invalid |
-N/--name | 기본값: CVE Audit |
-o/--output | 증거 디렉터리 (기본값: cwd 아래 evidence_cve90907_<ts>) |
--proxy URL | 요청용 프록시 (Burp: http://127.0.0.1:8080) |
--timeout | 기본값 20초 |
--ua | User-Agent (기본값 cve-2026-90907-audit/1.0) |
--no-verify-login | 로그인 차등 검사를 건너뜀 (exploit 모드) |
--verify-ssl | TLS 검증 (기본값: 검증하지 않음) |
--no-color | ANSI 색상 없음 |
-v/--verbose | stderr에 전체 요청/응답 로그 출력 |
| 코드 | 의미 |
|---|---|
0 | 정상 / 취약하지 않음 / 알 수 없음 |
1 | 취약함 (check에서는 LIKELY, exploit에서는 CONFIRMED) |
2 | 운영 오류 (네트워크, 의존성 등) |
Location에 profile이 포함된 303, 로그인으로 리다이렉트되지 않음) + 검증 오류
플래시 (예: 개인정보 처리방침 필수 메시지). 확정적 확인 =
exploit 모드.summary.json에 나열됩니다.user_id > 0인 Location.각 실행은 타임스탬프가 붙은 -o 디렉터리를 생성하며, 여기에는 00_token.txt,
01_version.txt, 02_w1_seed.txt, 03_w2_exploit.txt,
04_login_correct.txt, 05_login_wrong.txt 및 summary.json이 포함됩니다. 모든 파일은
전체 REQUEST (메서드/URL/주요 헤더/본문), RESPONSE (상태,
Location, Server, 추출된 플래시, 본문 첫 500바이트) 및 ISO
타임스탬프를 기록합니다 — 침투 테스트 보고서에 첨부할 준비가 되어 있습니다.
privacyconsent를 전송하지 않으며, 규칙을 준수하지 않는
사용자 이름(probe())을 사용합니다: 저장은 폼 규칙에서 실패하고 아무것도 저장되지 않습니다.user_id > 0을 반환한 경우(반환해서는 안 됨), exploit
모드는 W2 전에 중단됩니다.user_usergroup_map 행도 제거합니다).MIT — LICENSE 참조.