Le programme C++ fourni implémente un système d’instructions. On a donc une liste d’instructions qui sont passées au programme pour être exécutées
Puis une vérification sur l’état des registres final est faite pour savoir si nous avions le bon input
On va pas s’amuser à comprendre ce qui se passe en détail dans le programme mais à voir ce qu’il en ressort en fonction de notre input. Pour ce faire, vu que mon c++ est bancal je vais réimplémenter le code en python à l’aide de ChatGPT pour gagner du temps. On mettra tout dans le fichier chall.py
On peut faire plusieurs essais en python et en c++ avec le même input pour voir que l’état final des registres est le même donc à priori pas d’erreur d’implémentation, merci ChatGPT
Etude des registres
Pour voir un peu le comportement des registres, j’ai fait une fonction discover qui permet de tester des flags différents avec la possibilité de définir un début commun entre les flags et d’afficher les différences entre l’état des registres avec la fonction highlight_diff
En faisant ça, on peut soumettre des flags différents et voir si certaines parties des registres réagissent à des changements minimes, exemple avec des flags dont seul le premier caractère est commun :
On voit que le byte 4 du premier registre, autrement dit c’est le premier byte si on lit le registre en little endian, est toujours le même avec la valeur bc,
En essayant avec des flag qui commencent par les 3 mêmes caractères :
On voit 2 choses intéressante :
Maintenant les 3 derniers bytes du registre n°1 sont fixes
Le byte de l’essai d’avant n’a pas changé, c’est toujours bc
On peut donc émettre l’hypothèse qu’en faisant un brute force caractère par caractère on peut vérifier l’état des registres final et en déduire d’abord le premier caractère, puis le second etc…
import random
from colorama import Fore, Style
from chall import Program, CHARSET, INSTRUCTIONS, REGISTERS
def solve():
flag = ''
expected_state = b''.join([register.to_bytes(4, byteorder='little') for register in REGISTERS])
for i in range(35):
missing_n = 35 - len(flag) - 1
for c in CHARSET:
attempt_flag = "HTB{" + flag + c + ('_' * missing_n) + "}"
program = Program(attempt_flag.encode())
program.execute(INSTRUCTIONS)
current_state = b''.join([int(register).to_bytes(4, byteorder='little') for register in program.registers])
if expected_state[:i+1] == current_state[:i+1]:
flag += c
break
print(f"Flag: HTB{{{flag}}}")
if __name__ == '__main__':
solve()