Bug Bounty 03 - Deleting User's Account via Reflected XSS chained with CSRF
Salve rapaziada, no post de hoje irei falar sobre uma vulnerabilidade que encontrei no programa de bug bounty do Skyscanner na plataforma Bugcrowd.
Enquanto navegava pela aplicação, notei que ao fazer uma busca, haviam vários parâmetros sendo passados pelo método GET, similar a este resultado:
Dei uma no código fonte e vi que o a URL não era refletida no código fonte da aplicação.
Depois de pesquisar um pouco mais, notei que ao realizar uma busca por locais que não haviam viagens a URL era refletida no código. Utilizei o seguinte link para encontrar essa funcionalidade:
(O link refletido na imagem abaixo é um pouco diferente pois esqueci de tirar print no momento em que encontrei a vulnerabilidade :/ )
Com isso, fui injetando algumas tags nos parâmetros e vendo se eles eram refletidos sem algum tipo de sanitização. Notei que ao inserir algo no parâmetro ref ele era refletido no código fonte e adivinhem... sem nenhum tipo de sanitização.
Ao inserir determinados payloads, eu recebia um código 500 e a aplicação era redirecionada para uma página de erro.
Depois de algumas tentativas, decidi inserir uma tag que já havia utilizado em outros programas de bug bounty:
"><marquee>rapt00r</marquee>
Esta tag cria uma espécie de painel (tipo aqueles painéis de LED que as letras ficam indo de uma ponta a outra do painel)
E bingo!!! O nosso marquee foi adicionado com sucesso no código. Infelizmente não tirei print dessa parte e nem do código fonte pois fiquei muito animado ao ver que realmente funcionou :)
Pesquisando um pouco mais sobre como utilizar a tag marquee, notei que ela suporta um evento JS chamado onfinish.
Então, quando o marquee era finalizado, podíamos executar códigos Javascript. Infelizmente também esqueci de tirar print dessa parte :(
Dependendo do tamanho do painel criado pelo marquee, demoraria muito para o banner finalizar. Então adicionei outros 2 atributos ao nosso marquee: width e loop, que servem para você definir o tamanho e o número de vezes que você quer que o banner apareça.
Bom, nesse ponto nosso payload estava da seguinte forma:
"><marquee width=0 loop=1 onfinish="alert(1)">rapt00r</marquee>
Agora, o link junto com o payload ficaria da seguinte forma:
E quando o usuário acessava, ele veria o alerta em sua tela :)
Decidi então encadear com um CSRF para realizar o account takeover, mas infelizmente não havia a opção de troca de email (e para trocar a senha era necessário saber a senha antiga :/ )
Sem perder as esperanças, notei que havia a opção de deletar a conta. Hmm, interessante...
Para realizar a exclusão da conta era necessário enviar uma request (necessário que o usuário esteja autenticado) do tipo DELETE para o endpoint /profile/user/delete-account e a conta seria deletada.
Para finalizar, irei deixar o código da requisição que utilizei no evento JS para realizar a exclusão da conta do usuário que visitasse o link:
var request = new XMLHttpRequest();
request.open('DELETE', 'https://www.skyscanner.com.br/profile/user/delete-account', false);
request.send();
E o link final para explorar a vulnerabilidade ficou da seguinte forma:
Como PoC desta vulnerabilidade, deixo um vídeo e vocẽs podem acessar pelo link:
É isso aí galera, recomendo utilizar outras tags além do iframe, img, script, pode ser que vocês consigam dar esse "bypass" da mesma forma que eu acabei de mostrar :)
Valeuuu !!!