Débordement de tampon (stack-based buffer overflow) classique dans Savant Web Server 3.1 démontrant une corruption de mémoire à distance du début des années 2000 via une requête HTTP forgée.
Débordement de tampon classique basé sur la pile dans Savant Web Server 3.1 démontrant une corruption mémoire distante du début des années 2000 via une requête HTTP malveillante (une vulnérabilité de 2002 qui exige plus d'un débutant que la plupart des CVEs de débordement de tampon de 2025).
Ce dépôt fait partie du matériel que j'utilise lorsque j'enseigne l'exploitation des corruptions mémoire (en plus de mon travail habituel, j'enseigne également dans différents cours de cybersécurité où j'aide à former la prochaine génération de rétro-ingénieurs). Quand j'aborde les débordements de tampon basés sur la pile en classe, je travaille sur des cas réels plutôt que sur des exemples jouets, et ce CVE est l'un de ceux auxquels je reviens spécifiquement lorsque je veux challenger des étudiants qui ont déjà une certaine expérience avec les écrasements de base d'EIP.
La raison en est que l'année dans un identifiant CVE ne vous dit rien sur la difficulté de l'exploitation. La plupart des étudiants supposent que les CVEs plus anciens doivent être plus simples : un débordement direct, un JMP ESP, terminé. Celui-ci prouve le contraire. Certains CVEs que j'enseigne de 2025 sont fondamentalement plus basiques que celui-ci, parce que la classe de vulnérabilité est plus simple ou les contraintes sont moindres. CVE-2002-1120 nécessite de comprendre des choses que certaines exploits modernes n'exigent pas : pourquoi certains opcodes ne peuvent pas être utilisés dans certaines parties de la requête, comment fabriquer un saut conditionnel qui se déclenche toujours quand le saut inconditionnel est bloqué, comment livrer du shellcode quand il ne tient pas là où on le mettrait normalement, et comment un egghunter résout un problème d'espace qui rendrait l'exploit impossible autrement.
C'est le CVE que j'assigne quand je veux voir si quelqu'un comprend réellement ce qu'il fait.
Cette vulnérabilité affecte Savant 3.1, un serveur HTTP Windows freeware de 2002. Ce qui la rend digne d'étude en 2025, ce n'est pas l'âge mais la combinaison de contraintes qu'elle introduit et les techniques nécessaires pour les contourner :
Chacune de ces contraintes est une leçon en soi.
Savant est un serveur HTTP Windows open-source freeware initialement conçu pour transformer n'importe quel ordinateur de bureau en serveur web. Il écoute sur le port TCP 80 et traite les requêtes HTTP GET standard. Le débordement se produit dans le gestionnaire qui copie le chemin de l'URI dans un tampon de pile de taille fixe sans valider sa longueur.
Détails techniques clés :
Savant traite les requêtes HTTP GET entrantes et copie le chemin de l'URI dans un tampon de pile de taille fixe sans vérifier sa longueur. Une version simplifiée de la logique vulnérable ressemble à ceci :
char uri_buffer[270];
strcpy(uri_buffer, uri_path);
Envoyer une requête GET avec un URI d'environ 271 octets écrase l'adresse de retour sauvegardée sur la pile. Le débordement est contraint ; en envoyer significativement plus provoque un plantage tel que EIP n'est plus contrôlé, donc la fenêtre utile est étroite.
L'exploitation est plus complexe qu'un simple écrasement d'EIP à cause de deux propriétés supplémentaires du serveur : le champ de la méthode HTTP est également copié en mémoire et exécuté, et le corps de la requête HTTP est stocké dans une région de tas séparée plutôt que sur la pile (ces deux propriétés deviennent des parties essentielles de la chaîne d'exploitation).
Le plantage peut être reproduit en envoyant une requête GET avec un URI suffisamment long. Aucune authentification n'est requise. Exemple avec Python :
import socket
HOST = '127.0.0.1'
PORT = 80
payload = b"A" * 271
request = (
b"GET /" + payload + b" HTTP/1.1\r\n"
b"Host: 127.0.0.1\r\n"
b"Connection: close\r\n"
b"\r\n"
)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send(request)
s.close()
Lorsqu'il est exécuté sous un débogueur, le plantage montre EIP écrasé avec des données contrôlées par l'utilisateur :
EIP = 41414141
confirmant que l'adresse de retour sauvegardée a été corrompue par le débordement.
Le but de ce dépôt n'est pas seulement de démontrer le plantage, mais de parcourir le processus d'exploitation complet étape par étape, y compris chaque contrainte qui rend ce cas plus difficile qu'un écrasement standard d'EIP et chaque décision prise pour les contourner.
Pour garder le README principal propre, les notes d'exploitation détaillées, les scripts et les étapes du débogueur sont placés dans le dossier Vulnerability 📂 de ce dépôt.
Vous y trouverez le flux de travail complet utilisé pour exploiter ce CVE, notamment :