Fetch the Flag CTF 2022: solução de Juggalo Central
Alexander Kraev
10 de novembro de 2022
0 minutos de leituraObrigado por participar do Fetch com a gente! Parabéns aos milhares de participantes que se juntaram a nós noFetch the Flag CTF. E um agradecimento especial aos Snykers que criaram, testaram e documentaram os desafios!
Se você participou do Fetch the Flag de 2022 da Snyk e não conseguiu concluir o desafio Juggalo Central, veio ao lugar certo. Vamos analisar a solução juntos!
Passo a passo
Para começar, há um link para um site com o formulário de login de sempre, com dois campos: username e password. Também há um arquivo com extensão .php. Vamos dar uma olhada primeiro no site.
O site
Como mencionei, a página tem dois campos de entrada (e uma imagem de um palhaço). Primeiro, verifiquei o código-fonte da página, o arquivo .css e até a imagem. Não encontrei nada que pudesse aproveitar. Notei uma coisa: havia duas mensagens de erro diferentes — uma quando eu usava um nome de usuário comum, como “admin”, e outra quando usava uma sequência aleatória, como “qweasdzxc”.
O código
Dentro de index.php, encontrei três funções: getFlag, searchUserByName e validateCredentails.
A primeira função, getFlag, consulta uma tabela do banco de dados chamada flag e retorna a primeira linha encontrada. Depois de analisar o código, concluí que a chave que procuro está armazenada nessa tabela.
A segunda função, searchUserByName, tenta encontrar um usuário com base na variável de entrada chamada $username. Se houver resultados, a função os retorna. Notei uma coisa nesta linha:
Isso significa que a função não retornaria apenas uma linha (já que espero que os usuários tenham nomes de usuário únicos): se mais de um usuário tiver o mesmo nome, retornará todos eles. Mais tarde, descobri que isso não nos ajuda, por causa do que acontece na próxima função. Às vezes, é assim que funciona um CTF.
A terceira função, validateCredentails, lê o nome de usuário e a senha enviados no corpo da requisição POST e chama searchUserByName para verificar se existe um usuário com esse nome. Também entendi por que a mensagem de erro era diferente para um nome de usuário com caracteres aleatórios. Se o usuário informado não existir, a função retorna: "Juggalo not found!". Já para qualquer nome de usuário existente com uma senha incorreta, a mensagem de erro era: "Invalid credalo".
Encontrando um nome de usuário válido
Agora vamos encontrar credenciais válidas. Quando tentei algo comum, como “admin”, apareceu a mensagem de erro "Invalid credalo". Com a análise do código da etapa anterior, posso concluir que existe um usuário com o valor “admin” no campo de nome de usuário.
A primeira tentativa
Agora que temos um nome de usuário válido, vamos ver como descobrir a senha. A mensagem de erro indicando que não temos acesso a esse usuário é exibida por causa da seguinte linha de código:
No lado esquerdo da condição, a senha do usuário é recuperada do banco de dados. No lado direito, estão os primeiros 20 caracteres do hash md5 que contém duas variáveis fornecidas pelo usuário: username e password.
A princípio, pensei que, por causa dessa condição, qualquer senha válida teria 20 caracteres. Resumindo: eu estava errado.
A segunda tentativa
Depois de pensar um pouco no desafio, tive outra ideia. Esta linha usa o operador de comparação !=. Então consultei a documentação oficial do PHP para entender como funcionam os operadores de comparação no PHP. Uma frase da documentação que não entendi estava logo ao lado do operador !=:
Espera. O que é “type juggling”? Depois de ler isso, abri de novo a página do desafio. O palhaço continuava lá, me observando.
O ataque
Acontece que o PHP tem algo chamado “type juggling”. Depois de ler sobre o assunto e executar alguns testes de PHP online, cheguei à seguinte condição
Surpreendentemente, isso retornou “true”. Isso acontece porque o PHP converte os dois operandos em valores numéricos. Agora, para encontrar a senha certa do usuário “admin”, basta gerar um hash md5 que atenda a duas condições: começar com “0e” e conter apenas números depois disso (ou pelo menos 18 caracteres depois, por causa do uso de substr).
O script
Este é um script em Python que encontra o hash certo:
Depois de um minuto, consegui entrar na página Juggalo Central usando as credenciais geradas por este script.
Mais soluções do Fetch the Flag
Quer saber como encontramos as outras flags? Confira a página de soluções do Fetch the Flag para ver como fizemos isso.
