Zeecka zeecka

CrazyLooper

BreizhCTF 2019 - Prog (150 pts)

BreizhCTF 2019: CrazyLooper

Détails du challenge

EventChallengeCategoryPointsSolves
BreizhCTF 2019CrazyLooperProgrammation1502

Challenge : chall md5sum : 339457087fe3c986e45937eaf26cbfea

TL;DR

Nous avions un fichier encodé récursivement avec plusieurs algorithmes. Chaque algorithme était indiqué au début du fichier décodé. Nous avons écrit un programme qui décode récursivement le premier fichier jusqu’à obtenir le dernier texte en clair.

Méthodologie

Premier coup d’œil au fichier

La commande file ne nous a renvoyé que « data », mais un examen plus approfondi du début du fichier nous a apporté davantage d’informations :

xxd chall | head -n 1
00000000: 786f 725f 4a3a 3225 3815 0170 637b 335e  xor_J:2%8..pc{3^

Nous avons constaté que le fichier commence par « xor_J: », ce qui signifie qu’il faut décoder le fichier en effectuant un xor avec la lettre « J ».

with open("chall","rb") as f:
    c = f.read()

algo,content = c.split(":",1)

out = ""
for l in content:
    out += chr(ord(l)^ord("J"))  # Xor content with "J"

with open("challoutput","wb") as f2:
    f2.write(out)
xxd challoutput | head -n 1
00000000: 786f 725f 4b3a 2931 7914 2824 2f2e 2871  xor_K:)1y.($/.(q

Nous obtenons un second xor avec une autre lettre.

Passons au script

Voici mon script final. À noter que nous avons plusieurs algorithmes (pas seulement xor mais aussi base32, base64, uuencode, bzip2, …). Vous pouvez également remarquer que, parfois, la clé xor est donnée sous forme d’entier.

cp chall chall0
import bz2
import base64
import zlib

def isInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

n = 0
while 1:
    with open("chall"+str(n),"rb") as f:
        l = f.read()
    algo,content = l.split(":",1)
    if "xor" in algo:
        key = algo.replace("xor_","")
        if not isInt(key):
            key = ord(key)
        else:
            key = int(key)
        out = ""
        for l in content:
            out += chr(ord(l)^key)
        with open("chall"+str(n+1),"wb") as f:
            f.write(out)
    elif "base16" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(base64.b16decode(content))
    elif "base32" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(base64.b32decode(content))
    elif "base64" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(base64.b64decode(content))
    elif "uu_codec" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(content.decode("uu"))
    elif "bz2_codec" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(bz2.decompress(content))
    elif "zlib_codec" in algo:
        with open("chall"+str(n+1),"wb") as f:
            f.write(zlib.decompress(content))
    else:
        print(algo)
    n += 1

Le programme plante pour le fichier chall149.

cat chall149
breizhctf{crazy_encodings_looperz}

Flag

breizhctf{crazy_encodings_looperz}

Zeecka