githubEditar

FlagCasino

CTF Try Out - Reversing

HTB Casino Challenge - Writeup Completo de Engenharia Reversa

Visão Geral do Challenge

Nome do Challenge: Casino Categoria: Engenharia Reversa Dificuldade: very easy Flag: HTB{r4*******************bl3}

Análise Inicial

Informações do Arquivo

Arquivo: casino
Tamanho: 16.936 bytes (0x42a8)
Tipo: ELF 64-bit LSB executable
MD5: 0478c3a259655afcd1cc67e808c20861
SHA256: b93bef52fd4178d7914752d87bf0b5ca2b93fcbd9d76a668cd68c8f873169257

Execução Básica

Quando executado, o binário apresenta uma interface temática de casino e solicita entrada de caracteres em um loop. Entrada incorreta resulta em terminação com uma mensagem de segurança.

Análise Estática com IDA Pro

Identificação de Funções

O binário contém várias funções, com a lógica principal residindo em:

  • Função main no endereço 0x1185

  • Função placeholder stub em 0x1020

Análise da Função Main

A função main decompilada revela o algoritmo principal:

Análise do Algoritmo

O algoritmo opera da seguinte forma:

  1. O loop executa 29 vezes (0 até 0x1C = 28)

  2. Para cada iteração:

    • Lê um único caractere da entrada do usuário

    • Usa o valor ASCII do caractere como seed para srand()

    • Gera um número aleatório usando rand()

    • Compara o resultado com check[i]

    • Termina a execução se houver divergência

Variável Global Crítica

O array check no endereço 0x4080 contém 116 bytes de valores esperados. Como há 29 iterações e cada chamada rand() retorna um inteiro de 32 bits, isso se traduz em 29 valores esperados de 4 bytes cada.

Extração de Dados Brutos

Os bytes brutos do array check:

Análise de Vulnerabilidade

A vulnerabilidade crítica reside na natureza previsível da função rand() da biblioteca padrão C:

  1. Saída Determinística: Dado o mesmo seed, rand() sempre produz a mesma sequência

  2. Chamada Única: Apenas uma chamada rand() por seed significa que cada caractere mapeia para exatamente um valor esperado

  3. Espaço de Chaves Limitado: Apenas caracteres ASCII imprimíveis (32-126) precisam ser testados

Desenvolvimento da Solução

Abordagem

A solução usa uma abordagem de força bruta que aproveita a natureza determinística de rand():

  1. Converter o array de bytes brutos para inteiros de 32 bits (little-endian)

  2. Para cada valor esperado, testar todos os caracteres ASCII imprimíveis

  3. Usar cada caractere como seed para srand()

  4. Comparar a saída de rand() com o valor esperado

  5. Armazenar caracteres correspondentes para construir a flag

Implementação

Execução da Solução

Executar o solver produz a seguinte saída:

Verificação

A solução pode ser verificada executando o binário original e inserindo cada caractere da flag sequencialmente. O programa aceitará todos os caracteres e exibirá a mensagem de sucesso.

Insights Principais e Lições Aprendidas

Insights Técnicos

  1. Fraqueza de PRNG Determinístico: A função rand() da biblioteca padrão C é determinística quando semeada, tornando-a inadequada para propósitos criptográficos

  2. Vulnerabilidade de Seed de Uso Único: Usar cada caractere como um seed fresco cria um mapeamento direto entre entrada e saída

  3. Espaço de Busca Limitado: Apenas 95 caracteres ASCII imprimíveis reduzem significativamente a complexidade da força bruta

Implicações para Red Team

  1. Análise de PRNG: Sempre analise como geradores de números aleatórios são semeados e usados em aplicações

  2. Exploração de Determinismo: Procure por padrões onde entrada do usuário influencia diretamente saídas supostamente aleatórias

  3. Predição de Seed: Em cenários do mundo real, seeds previsíveis podem comprometer sistemas criptográficos inteiros

Recomendações Defensivas

  1. PRNGs Criptograficamente Seguros: Use /dev/urandom, CryptGenRandom, ou fontes similares para aleatoriedade crítica de segurança

  2. Semeadura Adequada: Use fontes de alta entropia como tempo do sistema, IDs de processo e geradores de números aleatórios de hardware

  3. Evitar Entrada Direta do Usuário: Nunca use entrada direta do usuário como seeds para geração de números aleatórios sensíveis à segurança

Conclusão

Este challenge demonstra uma vulnerabilidade clássica no uso de geradores de números pseudo-aleatórios. A natureza determinística de rand() combinada com semeadura previsível cria uma fraqueza trivialmente explorável. A solução exigiu entender o algoritmo através de engenharia reversa, identificar a vulnerabilidade e implementar um ataque de força bruta eficiente que aproveita as propriedades matemáticas do PRNG.

A flag resume perfeitamente a lição central: geradores de números aleatórios são apenas tão imprevisíveis quanto seus padrões de implementação e uso permitem.

Atualizado