[CTF GEMA] Free Flag
CTF GEMA Groupe 2025
Niveau de Difficulté : Hard
Catégorie du Challenge : Forensic
Description :
I think it’s too sensitive so they hide it so much like that First we install the file and we got a picture of a red flag as the following
Steps to Solve

La première étape dans tout défi de forensique consiste à vérifier s'il y a des éléments suspects en utilisant la commande strings, ainsi que des fichiers cachés avec la commande binwalk, comme suit :

Booyah, nous avons trouvé un mot encodé en BASE64... nous allons maintenant le décoder.

Nous avons ce message (1000x570 S)... Je pense que c’est la taille de quelque chose, mais continuons à chercher... EDIT (((LE NOM DU FICHIER EST FREEFLAG.jpg))).

Ici, nous avons utilisé la commande binwalk, et nous avons découvert qu'il y avait des fichiers cachés dedans. Extrayons-les avec cette commande :
binwalk -e --dd=.* FREEFLAG.jpg
Maintenant, nous avons ces fichiers à l'intérieur.


Et un fichier zip contient (flag.txt), mais il est protégé par un mot de passe et aucun mot de passe dans les listes de mots ne fonctionne pour ce fichier, donc nous devons trouver un mot de passe.

Après une recherche approfondie sans indice et sans rien de vraiment utile, nous devons penser aux 7 images qui portent la mention (___ false). Pourquoi existent-elles en premier lieu ?
Nous avons découvert que les images représentent un séparateur entre les différentes parties du mot de passe comme suit... Nous savons tous que les fichiers PNG commencent par (IHDR) et se terminent par (IEND)...
Donc, lorsque nous regardons la fin de la première image en utilisant la commande strings
et que nous observons ce qui se trouve entre la première et la deuxième image, nous découvrons qu'il y a un mot entre chaque image et la suivante.

Lorsque nous les rassemblons, nous obtenons le mot de passe. Le mot de passe est : WTBVTjQxTDNEVEgzUDRTUW==, et il est évidemment encodé en BASE64. Nous l'avons donc décodé en utilisant CyberChef.

Maintenant, nous avons le mot de passe original qui est : Y0UN4IL3DTH3P4SS, et maintenant, enfin, nous pouvons extraire le (flag.txt)...

Après l'extraction, nous avons trouvé beaucoup et beaucoup de zéros et de uns, chaque chiffre étant sur une nouvelle ligne...
Nous pouvons connaître le nombre de zéros et de uns en observant la taille du fichier, car comme nous le savons tous, le zéro représente un bit et le un aussi.

Nous avons obtenu la taille du fichier, qui est de 1 139 999 bits.
Mais nous ne pouvons pas dire qu'il y a un million et 140 000 zéros et uns dans ce fichier, car chaque chiffre est sur une nouvelle ligne et nous savons que le caractère ( ) est considéré comme un bit. Nous divisons donc la taille du fichier par 2, ce qui nous donne 570 001 bits (570 000 zéros et uns).
Mais c'est le nombre que nous avons trouvé au début, 1000x570 bits. Maintenant, nous savons ce que cela signifie, c'est la taille des zéros et des uns sur chaque ligne.
Donc, en utilisant Python, nous allons organiser le fichier de manière à ce qu'il y ait 570 colonnes par ligne {570 zéros et uns sur chaque ligne pour 1000 lignes}. Et maintenant, nous obtenons cela.
width, height = 1000, 570
file_path = "flag.txt"
with open(file_path, "r") as f:
data = f.read().split()
assert len(data) == width * height, "La taille des données ne correspond pas à la résolution indiquée."
pbm_path = "flag.pbm"
with open(pbm_path, "w") as f:
f.write(f"P1\n{width} {height}\n")
for i in range(height):
f.write(" ".join(data[i * width:(i + 1) * width]) + "\n")
pbm_path
from PIL import Image
import numpy as np
pbm_path = "flag.pbm"
with open(pbm_path, "r") as f:
lines = f.readlines()
assert lines[0].strip() == "P1", "Format PBM non reconnu."
width, height = map(int, lines[1].split())
data = np.array([int(pixel) for line in lines[2:] for pixel in line.split()]).reshape((height, width))
png_path = "flag.png"
img = Image.fromarray((data * 255).astype(np.uint8))
img.save(png_path)
png_path

Le flag est : FLAG{Y0UG0TMY1DEA}.
Flag
FLAG{Y0UG0TMY1DEA}