Atacando um "Recuperar Senha" Mal Concebido

O formulário de "nome de usuário e senha" de muitos sites hoje em dia costuma ter um recurso de "recuperar a senha" para dar conta daquelas inevitáveis vezes em que a esquecemos. Mas, se esse recurso não for muito bem implementado, pode acabar se tornando uma maneira de burlar todo o esquema, permitindo que nos identifiquemos como qualquer usuário sem sabermos sua senha. Neste post, vou descrever um caso como esse com o qual me deparei há algum tempo atrás.

Descrição do Recurso de Recuperação da Senha

No site que eu estava analisando, a funcionalidade de "recuperar senha" funcionava da seguinte forma: quando o usuário acessava a função de recuperação da senha, aparecia um formulário onde a aplicação solicitava que o usuário digitasse o nome do usuário. A aplicação então mandava uma mensagem para o endereçõ de email que estava cadastrado, informando um endereço parecido com a abaixo:

http://www.site.com.br/recuperarsenha.asp?auth=BUKt6uSsfjdool17z5TM2w==

Quando o usuário recebia o email (supondo que não fosse engolido por algum filtro de spam), ele clicava nesse endereço e era enviado para uma outra página. Nela, a aplicação solicitava novamente o nome do usuário. Ao digitá-lo, o usuário era redirecionado para uma outra tela onde podia cadastrar uma nova senha para aquele usuário.

Observações e Suspeitas Iniciais

Notei, contudo, que a aplicação toda vez gerava exatamente o mesmo endereço para o mesmo usuário. Em outras palavras: aparentemente, o token de autenticação dessa URL (o trecho BUKt6uSsfjdool17z5TM2w== após o parâmetro auth) era função apenas do nome do usuário. Por si só, isso já não era uma idéia muito boa: se alguém mais pegasse esse endereço (digamos, de um backup da máquina do usuário), ele poderia trocar a senha.

Isso me levou à seguinte suspeita: será que existe alguma maneira de entender o significado oculto desse token e quem sabe prever qual seria o token correto para outros usuários?

Analisando a Composição do Token

Tinha-nos sido dado um usuário válido na aplicação, que, a título de exemplo, vou chamar aqui de TEMPESTSECURITY. Após requerer a recuperação da senha pela primeira vez, recebi por email o endereço que já citei acima. Resolvi, entretanto, fazer a seguinte experiência: a aplicação tinha um recurso que me permitia alterar meus dados cadastrais, inclusive meu próprio nome de login – desde que esse nome não estivesse sendo usado por algum outro usuário. Alterei-o, então, de "TEMPESTSECURITY" para 12345678, pedi novamente a recuperação da senha e recebi por email o seguinte endereço para clicar:

http://www.site.com.br/recuperarsenha.asp?auth=OBtJB7Mmzod55ElTpxv04Q==

Após isso alterei mais uma vez o login do usuário de 12345678 para 1234567812345678 e reenviei uma nova solicitação de recuperar senha. Ao executar a funcionalidade mais uma vez, a seguinte URL foi gerada:

http://www.site.com.br/recuperarsenha.asp?auth=OBtJB7Mmzoc4G0kHsybOh3nkSVOnG/Th

Os tokens parecem codificados pelo clássico algoritmo Base64. Então, a próxima tarefa é decodificá-los e convertê-los para hexadecimal, na esperança que isso torne mais fácil discernirmos algum padrão na sua composição:

 Login: 12345678
 Token: OBtJB7Mmzod55ElTpxv04Q== 
 Hexdump: 381b4907b326ce87 79e44953a71bf4e1
------------------------------------------------------------------------------
 Login: 1234567812345678
 Token: OBtJB7Mmzoc4G0kHsybOh3nkSVOnG/Th             
 Hexdump: 381b4907b326ce87 381b4907b326ce87 79e44953a71bf4e1

Note que, no exemplo com o login "1234567812345678", o trecho "381b4907b326ce87" se repete. Assim, podemos afirmar que o algoritmo de codificação trabalha em blocos de oito bytes e que cada bloco é cifrado de forma independente, sem lembrança dos blocos anteriores. O trecho "79e44953a71bf4e1" também se repete e parece ser algum tipo de preenchimento (padding): ele não aparece se o nome do login tiver menos de oito caracteres.

Baseado-se nessas informações, foi possível realizar um ataque contra a funcionalidade de recuperar senha de tal forma que é possivel predizer qualquer token gerado pela aplicação para qualquer usuário. Como prova de conceito realizei um ataque contra o usuário cujo login é ADMINISTRADOR para predizer o token que a aplicação geraria para o mesmo.

O primeiro passo foi alterar o login do usuário TEMPESTSECURITY para ADMINISTXXXXX, pois como já foi explicado, o algoritmo utilizado pela funcionalidade recuperar senha criptografa o conteúdo de 8 em 8 bytes de forma independe, então o primeiro passo é descobrir os 8 primeiros bytes referente ao token do login ADMINISTRADOR. Após alterar o login submeti uma solicitação de recuperar senha para aplicação e o resultado foi a seguinte URL:

http://www.site.com.br/recuperarsenha.asp?auth=fB8vtmxTKPXUAO9/J5yHEw==

Analisando o token gerado, foi possível descobrir os 8 bytes do token referente aos 8 primeiros caracteres do Login ADMINISTRADOR, no caso, referente aos caracteres ADMINIST.

O segundo passo foi alterar o login do usuário TEMPESTSECURITY para RADOR que são exatamente os 5 caracteres restantes do login ADMINISTRADOR. Após isso foi submetido novamente uma solicitação de recuperar senha para aplicação e o resultado foi a seguinte URL:

http://www.site.com.br/recuperarsenha.asp?auth=R1891kecNBo=

Analisando o token gerado, foi possível descobrir os 8 bytes do token referente aos 5 últimos caracteres do login ADMINISTRADOR, no caso, referente aos caracteres RADOR.

Por que fazer em duas partes ao invés de criar um único usuário "12345678ADMINISTRADOR"? Porque havia um tamanho máximo para o nome do usuário.

Por fim, bastou concatenar os resultados do usuário ADMINIST com os 8 bytes referentes aos caracteres RADOR e codificar o resultado com o algoritmo BASE-64. Por fim, obtive como resultado o token que seria gerado pela aplicação para o usuário cujo login é ADMINISTRADOR.

O token gerado para o usuário ADMINISTRADOR foi:

fB8vtmxTKPVHXz3WR5w0Gg==

Assim, simplesmente acessando a seguinte URL:

http://www.site.com.br/recuperarsenha.asp?auth=fB8vtmxTKPVHXz3WR5w0Gg==

Eu fui capaz de trocar a senha de administrador e acessar sua conta, obtendo domínio total da aplicação web.

Existem várias maneiras de implementar um recurso de "recuperar senha" que não tenha esse tipo de vulnerabilidade, mas isso é assunto pra um outro post.

Agradecimentos a: João Paulo "Jopa" Campello e Marco "Kiko" Carnut pelas dicas e dúvidas tiradas durante a análise.

Comentários
Aceita-se formatação à la TWiki. HTML e scripts são filtrados. Máximo 15KiB.

 
Enviando... por favor aguarde...
Comentário enviado com suceso -- obrigado.
Ele aparecerá quando os moderadores o aprovarem.
Houve uma falha no envio do formulário!
Deixei uma nota para os admins verificarem o problema.
Perdoe-nos o transtorno. Por favor tente novamente mais tarde.
Marco Carnut | 2010-09-14 08:10:18 | permalink | topo

G,

Ou, talvez, eles não tenham trilha de auditoria em absoluto. ;)

-K.

Geraldo Fonseca | 2010-09-13 17:19:06 | permalink | topo

Muito bom, parabéns.

Não é muito comum uma aplicação permitir que o usuário altere sua própria ID (a única que conheço é o Twitter), e isso me deixou intrigado. Suponho que os caras devem ter um trabalho enorme prá manter as trilhas de auditoria coerentes...

Diogo Pontual | 2010-09-02 21:28:06 | permalink | topo

Muito bom! Uma estrategia bem inteligente, aprendi muito com isso.

Marco Carnut | 2010-09-02 10:33:20 | permalink | topo

Pimpão,

Ficou muito legal o seu post. Simples, direto e mortal. :) Parabéns.

-K.