Esse é um desafio de engenharia reversa criada para o ctf Blue Water CTF 2024. Para esse desafio, foi apenas disponibilizado o arquivo binário maybe_checker.
Entendendo o Programa
┌──(ata㉿vBoxKali)-[~/Videos]
└─$ ./maybe_checker
Enter the flag: abcdef
Wrong flag
Ao rodar o programa, ele apenas pede a flag do usuário e diz se o input está correto ou não. Então, teremos que fazer o processo de engenharia reversa para descobrir a flag a partir das verificações feitas pelo programa.
image
Utilizando o Ghidra para realizar a análise do programa, conseguimos achar a função FUN_00401180 que é onde é impresso se a flag está correta ou errada.
Analisando o Código
A linha de código 16 não é muito clara a princípio, porém se olharmos no código assembly podemos notar que é feita uma chamada de função nessa linha e está passando um argumento dela em RDI.
Se analisarmos de novo essa parte do código, podemos perceber que é primeiro gerado um valor aleatório e colocado em iVar2 e então é utilizado esse valor para realizar uma operação e então deslocar DAT_00402041 (possível endereço que guarda os endereços das funções) um valor aleatório, que será sempre múltiplo 9. Além disso, é passado como argumento para essa função a variável auStack_78, que se olharmos na linha 14 podemos ver que é a variável que guarda o valor dado como entrada pelo usuário, com um deslocamento que será o valor em DAT_00402040[ ( iVar2 % 0x3c ) * 9 ], que é o valor onde se encontra os endereços das funções ( DAT_00402041 ) menos 1.
Se olharmos no lugar da memória aonde está DAT_00402040, conseguimos ver que a cada 9 espaços de memória, há um endereço de uma função e antes desse endereço um valor, que é o valor de deslocamento do input do usuário na variável auStack_78. Então, agora precisamos analisar essas funções que são chamadas aleatoriamente.
Essas funções, parecem realizar verificações sobre o param_1, que sabemos que é o que o usuário digitou de entrada no programa, e retorna verdadeiro ou falso. Então, essas funções é a onde programa realiza as verificações para decidir se a flag está correta ou não, então podemos anotar todas essas vericações e tentar conseguir chegar a flag original a partir dessas funções.
Porém, ao anotar essas verificações, é necessário levar em conta o deslocamento que houve sobre a string de parâmetro da função. Então, por exemplo, se olharmos na imagem que mostra os endereços dessas funções, podemos ver que a função FUN_00401270 é chamada com 05h de deslocamento sobre o seu parâmetro. Com isso, se formos anotar essa verificação, temos que levar em conta esse deslocamento, fazendo com que a FUN_00401270 fique como s[18] < s[19], sendo s o param_1.
Com isso, podemos agora anotar todas essas verificações que são realizadas. Todas as equações estão abaixo:
Com essas equações temos certeza que a flag tem 48 caracteres, pois s[47] é o último digito, e temos certeza de alguns digitos, fazendo a flag que temos até agora ser:
bwctf{_____-_____-_____-_____-_____-_____-_____}
Como nenhum desses valores que sabemos é usado nas outras equações, teremos que descobrir um outro valor qualquer para então calcular os valores restantes.
Para descobrir o primeiro valor, podemos usar essas duas equações:
s[30] * s[13] == 3570
s[27] * s[13] == 3417
Como s[13] aparece nas duas equações, podemos olhar os divisores dos números 3570 e 3417 e tentar achar algum valor que seja divisor dos dois números.
Os números 1, 3, 17 e 51 são divisores dos dois números, porém, como 1, 3 e 17 são números nulos na tabela ASCII que com certeza não fazem parte da flag, apenas nos resta o número 51, então s[13] = 51. Agora, apenas nos resta encontar os outros valores a partir de s[13].
A seguir, há todas as contas feitas para encontrar a flag: