HackademINT

Club de cybersécurité de Telecom SudParis


Serial Keyler

Auteur : Bdenneu

----------------------------------

L’énoncé

On vous demande d’écrire un générateur d’entrées valides pour ce binaire, puis de le valider sur les entrées fournies par le service distant afin d’obtenir le flag.

SerialKeyler

Service : nc challenges2.france-cybersecurity-challenge.fr 3001

On reverse!

Ce challenge est un keygenme en 64bits. Voici la fonction main :

Le programme récupere un username (scanf), puis un Serial (scanf). Enfin, il lance une fonction (surement de vérification (0x55cde3d7483a) puis, selon le resultat, affiche “[>] Valid serial!” (si eax=1) et “[!] Incorrect serial.” sinon. Les arguments de la fonction de vérification seront username (rbp-0x90 mis dans rdi) et serial (rbp-0x50 mis dans rsi). Voyons cette fonction de vérification:

Cette fois ci, pour être plus didactique, je vais expliquer ce qui se passe en statique.

Le username est stocké dans rbp-0x78, et le serial est stocké dans rbp-0x80. Les instructions qui suivent sont les vérifications de canary.

Ensuite, un strlen est effectué (récupère la longueur de l’entrée utilisateur), la valeur est stockée dans rbp-0x58.

Le memset(rbp-0x58, 0, 0x40) alloue une zone mémoire.

On rentre ensuite dans une boucle. Le compteur est rbp-0x60. Sa valeur est comparée à rbp-0x58 (longueur de l’entrée utilisateur). Tant que sa valeur est inférieure (jb = jump below), on continue la boucle.

Dans la première partie, on récupere le username rbp - 0x78 (mov rdx …) , que l’on additionne au compteur rbp-0x60 (mov rax …, add rax, rdx), et on en récupére le premier byte (movzx eax…). Cette valeur est mise dans rbp-0x61.

On peut résumer l’opération par mov byte rbp-0x61, username[rbp-0x60].

Dans la seconde partie, on récupère la longueur du username rbp-0x58 (mov rax …), auquelle on soustrait le compteur rbp-0x60 et 1, et on le met dans rax.

On peut résumer l’opération par mov rax, len(username)-compteur-1.

On remet ensuite rbp-0x61 dans rdx, on le xor avec 0x1f, et on le place dans rbp+rax-0x50. On itére le compteur, et on continue.

Au final, voila une traduction de la boucle en python:


calculated = [b'' for i in range(0x40)]
for i in range(len(username)):
	calculated[len(username)-i-1] = username[i]^0x1f

Enfin, on compare juste cette chaine avec le serial. Essayons donc de créer un sérial valide:

Parfait! Maintenant, il faut juste scripter pour récupérer les usernames du serveur, et renvoyer un serial correct:


from pwn import *
import re
r = remote('challenges2.france-cybersecurity-challenge.fr', 3001)
while 1:
    data = b''
    while data == b'':
	data = r.recvrepeat(0.1)
    print(data)
    x = re.findall(b"username: (.*?)\n>>>", data)[0]
    x = b''.join([bytes([i^0x1f]) for i in x[::-1]])
    r.sendline(x)

Flag