Prever um gerador pseudoaleatório
Um gerador comum, como o random do Python, tem estado interno; quem descobre o estado prevê todos os próximos números.
Um computador não sorteia nada de verdade. Um gerador pseudoaleatório guarda um estado interno e, a cada pedido, aplica uma fórmula fixa: devolve um número calculado a partir do estado e atualiza o estado. Os números parecem aleatórios, mas quem conhece o estado sabe exatamente quais virão.
O módulo random do Python usa o Mersenne Twister (MT19937). O estado dele são 624 números de 32 bits. Cada saída de random.getrandbits(32) é um desses números passado por uma etapa chamada tempering, feita de deslocamentos e XORs. Essa etapa se desfaz exatamente. Então:
- junte 624 saídas seguidas de 32 bits;
- desfaça o tempering em cada uma e obtenha as 624 palavras do estado;
- carregue o estado num gerador novo, com
random.setstate((3, tuple(estado) + (624,), None)); - peça os próximos números: são os mesmos que a vítima vai receber.
Por isso a documentação do Python avisa que o random não deve ser usado para segurança. Senhas, tokens, sais e chaves precisam de um gerador criptográfico, como o módulo secrets ou os.urandom, que não deixa reconstruir o estado a partir das saídas.
Num CTF, desconfie de qualquer lista com exatamente 624 números de 32 bits: é o estado inteiro de um Mersenne Twister.