LE BLOG DE RICK Chasseurs de succès Linux Random WU

Par Rick dans WU le 21/04/2021.


Ben & Harry

Cet article est le numéro 4 de la série WU PhackCTF 2021.

  1. WU PHACKCTF 2021
  2. Alien
  3. Alter Egg-o
  4. Ben & Harry
  5. Git de France
  6. Quick Response Code
  7. Tendu comme un slip & No strings

Ce chall de programmation nous donne un lien vers un site web ainsi qu’un port. Celui-ci enverrait des informations aléations sous la forme :

{
    "b": 10,
    "code": "12 31 124 54 36 76…"
}

À chaque fois qu’on interroge ce site, les chiffres changent. Mais est-ce réellement des informations aléatoires ? Non bien sur, ce sera pas drôle sinon.

Les tests

Pour récupérer les informations, j’ai d’abord utilisé la commande telnet pour me connecter et recevoir les informations du serveur. À chaque JSON reçu, il me demandait d’écrire la réponse. Si je tape n’importe quoi, il m’envoie bouler. À force de recevoir les informations, j’ai fini par me rendre compte de quelque chose. On ne reçoit aucun chiffre se trouvant au-dessus de b dans code. Par exemple, si b=4, code ne contient aucun 4.

Peut-etre que b représente alors la base tandis que code contient une suite de caractères ascii codée dans cette dernière. Je récupère alors à nouveau la suite et la décode dans la base. Bingo, j’obtiens une phrase à la con. Je la rentre dans mon terminal pour répondre au serveur… et il m’en redemande un. Bon, on va faire un script pour pas se casser la tête !

Réception et envoi des messages

Je refais ce que je faisais à la main : j’ouvre une connexion avec telnet. J’importe la bibliothèque Python et créé une nouvelle connexion avec le site et le port.

import telnetlib
tn = telnetlib.Telnet('ben-and-harry.phack.fr', 1664)

Pour la réception, j’aurais aimé utiliser read_all() de la bibliothèque mais cette fonction ne lit que jusqu’à EOF. On va devoir utiliser autre chose. Je sais que ce qui nous intéresse est juste la partie JSON, on va donc utiliser la fonction read_until() pour lire jusqu’au caractère }, symbolisant la fin des données JSON.

Pour l’envoi, il suffit d’utiliser la fonction write(), sans oublier de rajouter un caractère de retour à la ligne pour confirmer notre message.

On finit par une sorte de flush pour vider le retour inutile qui nous demande juste de refaire une autre conversion : read_some()

Bien sur, on convertit la reception en JSON.

Convertissement (wololo)

La fonction int() est très pratique en Python, ça permet de convertir en entier un string et on peut meme préciser la base ! Je vais faire ça pour tous les caractères du code et je les reconvertis ensuite avec la fonction chr() en caractères. Je concatène le tout dans une belle variable qui sera retourné après.

message = ""
for char in data['code'].split(' '):
    message += chr(int(char, base))

Code final

J’assemble mes deux bouts de programmes et je le lance une première fois. Ça me retourne une erreur après plusieurs réussites. Le flag peut-etre ? Je modifie alors un poil le programme, en gardant dans une variable la réponse du serveur. J’entoure le tout de try pour récupérer l’erreur. Une fois l’erreur attrapée, j’affiche juste le dernier message du serveur. Et oui, le flag était bien là et venait embeter la bibliothèque JSON de Python ! Elle essayait de transformer en JSON le flag, alors que s’en est pas.

import telnetlib 
import json

tn = telnetlib.Telnet('ben-and-harry.phack.fr', 1664)
findFlag = False

while not findFlag:
    try:
        newdata = tn.read_until(b'}').decode("utf-8")
        data = json.loads(newdata)
        base = data['b']
        message = ""
        for char in data['code'].split(' '):
            message += chr(int(char, base))
        tn.write(message.encode('utf-8') + b"\n")
        tn.read_some()
    except:
        findFlag = True

print(newdata)