LE BLOG DE RICK Chasseurs de succès Linux Random wu Flux Atom

Par Rick dans WU le 21/04/2021.


Des oeufs et du code

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

  1. WU PHACKCTF 2021
  2. Git de France
  3. Des oeufs et du code
  4. Rétroingénierie à Phack
  5. La Stégano au Phack

Cet article est une compilation de 2 anciens articles du WU du Phack 2021. Ces articles n'ont pas été altérés.

Quick Response Code

Pour ce chall, on a une grosse archive ZIP. À l’intérieur se trouve plus de 1000 images de QRCodes, le flag est donc caché dedans.

J’en scanne un au hasard et j’y lis Nothing here suivi d’un long id. J’ai alors développé rapidement un programme Python pour lire tout ça, avec un print dès que le fichier ne commnce pas par Nothing here. Pleins de flags s’affichent. Il est donc découpé en pleins de petits morceaux. Bon, je réécris le script en utilisant un dictionnaire afin d’afficher dans l’ordre le flag.

J’ai perdu la phrase indiquant que le flag est en petit morceaux mais elle ressemblait à ça : Flag part X is "Y" ! Bla bla….

Il suffit d’installer pyzbar pour lire les QR Codes :

pip install pyzbar # pour python3, peut changer selon votre OS

Voici ensuite le code pour analyser l’ensemble des fichier :

from PIL import Image
from pyzbar.pyzbar import decode
import os

flagPart = {} 

for qrfile in os.listdir('.'):
    if qrfile.endswith(".png"):
        result = decode(Image.open(qrfile))[0].data.decode("utf-8")
        if not result.startswith("Nothing here"):
            tmp = result.split(' ')
            flagPart[int(tmp[2])] = tmp[4].split('\"')[1]

for key in sorted(flagPart):
    print(flagPart[key], end='')
print()

Ben & Harry

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 ne serait 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)