
Défi CTF exploitant un débordement de tas dans png_image_finish_read de libpng pour écraser un pointeur de fonction et lancer un shell, avec des scripts de construction et un générateur d'exploit.
Ce défi est basé sur une vulnérabilité réelle de débordement de tampon dans libpng (concernant plus précisément l'API simplifiée png_image_finish_read lors du traitement d'images entrelacées 16 bits).
Vous disposez d'un binaire vulnérable victim qui utilise une version statiquement liée et vulnérable de libpng. L'application lit un fichier PNG nommé exploit.png dans un tampon.
Votre objectif est de créer un fichier PNG malveillant qui déclenche un débordement de tas afin d'écraser un pointeur de fonction dans la structure Logger (située immédiatement après le tampon d'image), redirigeant l'exécution vers la fonction win() pour lancer un shell.
Prérequis : gcc, make, python3, git, autoconf, automake, libtool.
Clonez le dépôt :
git clone --recursive https://github.com/bohemian-miser/CVE-2025-65018_Exploit_Challenge.git
cd CVE-2025-65018_Exploit_Challenge
Compilez le défi (avec le libpng vulnérable) :
./build.sh
Ce script va :
libpng inclus pour activer la vulnérabilité.libpng.victim.La vulnérabilité réside dans la façon dont libpng gère les images entrelacées lors de la conversion d'une entrée 16 bits vers une sortie 8 bits.
PNG_FORMAT_RGBA). libpng alloue un tampon d'une taille suffisante pour des données 8 bits.png_combine_row écrit incorrectement des données dans le tampon de sortie en utilisant la profondeur de bits 16 bits de l'entrée.Le binaire contient une fonction auxiliaire win() qui appelle execl("/bin/sh", ...). Nous avons besoin de son adresse. Comme le binaire est compilé avec -no-pie, les adresses sont statiques.
nm victim | grep win
# Output: 00000000004013e0 T win
Adresse cible : 0x4013e0
solve.py)Nous devons créer un PNG valide qui :
IHDR) spécifiant une profondeur de 16 bits.win).Le script solve.py fait ceci :
Logger (située à 4096 octets du début du tampon).win dans les données de pixels de la dernière ligne.IDAT.Disposition de la charge utile :
L'adresse de win 0x4013e0 (Little Endian : E0 13 40 00 ...) doit être encodée dans des pixels RVB 16 bits.
Générez le PNG malveillant :
python3 solve.py 4013e0
Ceci crée exploit.png.
Exécutez le binaire victime :
./victim
Sortie attendue :
[*] Win function is at: 0x4013e0
[*] Buffer at: 0x7ffd51353530
[*] Logger at: 0x7ffd51354530
[*] Offset from buffer start to logger: 4096 bytes
[*] Processing image...
[+] png_image_finish_read success
[*] Calling logger...
[*] Hacked! Spawning shell...
$
Pour voir le débordement en action, vous pouvez utiliser GDB.
1. Placez un point d'arrêt avant l'appel vulnérable :
break 62
run
2. Surveillez l'écrasement :
La structure Logger se trouve à un décalage de 4096 octets. Surveillons le pointeur de fonction cible.
print &ctx.logger.log_func
# $1 = (void (**)(const char *)) 0x7fffffffc8f0
watch *0x7fffffffc8f0
continue
3. Déclenchement :
GDB s'arrêtera lorsque png_combine_row écrira dans le pointeur de fonction.
Hardware watchpoint 2: *0x7fffffffc8f0
Old value = 4199366 (0x4013c6 <normal_log>)
New value = 4199392 (0x4013e0 <win>)
0x00007ffff7e024d9 in __memcpy_avx_unaligned_erms ()
Cela confirme que libpng a écrasé notre pointeur avec l'adresse de win !
victim.c : Code source vulnérable.solve.py : Générateur d'exploit.libpng-src/ : Code source de libpng (v1.6.37).build.sh : Script de compilation de l'ensemble.Makefile : Système de construction du binaire victime.