
CVE-2023-4911 (Looney Tunables) rapport d'analyse et laboratoire de reproduction Docker
| Champ | Valeur |
|---|---|
| CVE ID | CVE-2023-4911 |
| Type d'attaque | Dépassement de tampon tas → Élévation de privilèges locale (Local Privilege Escalation) |
| CVSS 3.1 | 7.8 (High) |
| Date de divulgation | 2023-10-03 |
| Point vulnérable | Analyseur GLIBC_TUNABLES du chargeur dynamique glibc (ld.so) |
| Version vulnérable | glibc 2.34~2.38 |
CVE-2023-4911 est une vulnérabilité de dépassement de tampon tas dans le chargeur dynamique de la bibliothèque C GNU (glibc) lors de l'analyse de la variable d'environnement GLIBC_TUNABLES. Un attaquant peut exploiter ce dépassement pour manipuler le chemin de recherche de bibliothèques (RPATH) du chargeur dynamique, ce qui permet, lorsqu'un binaire SUID root (su, sudo, etc.) est exécuté, de charger à la place une bibliothèque partagée malveillante préparée par l'attaquant et d'exécuter du code arbitraire avec les privilèges root. Comme glibc est un composant essentiel de pratiquement toutes les distributions Linux majeures, cette vulnérabilité a affecté la plupart des distributions basées sur glibc publiées après avril 2021.
while (true)
{
char *name = p;
size_t len = 0;
/* 이름(name) 길이 찾기 */
while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
len++;
/* '=' 없이 끝나면 종료 */
if (p[len] == '\0')
{
if (__libc_enable_secure)
tunestr[off] = '\0';
return;
}
/* ':'를 먼저 만나면 잘못된 항목 */
if (p[len] == ':')
{
p += len + 1;
continue;
}
/* '='를 만났으므로 value 시작으로 이동 */
p += len + 1;
/* 원본 문자열에서 value 계산 */
char *value = &valstring[p - tunestr];
len = 0;
/* value 길이 찾기 */
while (p[len] != ':' && p[len] != '\0')
len++;
...
/* tunestr에 복사 */
...
if (p[len] != '\0')
p += len + 1;
}
__tunables_init() cherche GLIBC_TUNABLES dans la liste des variables d'environnement.tunables_strdup() alloue un tampon avec __minimal_malloc() et copie la chaîne originale (à ce stade, malloc est une implémentation très précoce, pas encore complètement initialisée).parse_tunables() parcourt ce tampon en utilisant le délimiteur : (deux-points) et, pour chaque paire key=value, attribue la valeur au tunable correspondant.parse_tunables() traite un tunable dans l'ordre suivant : analyse du nom → déplacement de p → analyse de la valeur → déplacement de p. Avec une entrée normale, après avoir traité la valeur, p est déplacé au début du tunable suivant pour l'analyser.
Cependant, si une entrée de la forme name=name=value est fournie, par exemple :
GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=AAAA...(longue chaîne)
lors de la première analyse, la totalité de glibc.malloc.mxfast=AAAA... est reconnue comme une seule valeur et copiée dans le tampon tunestr. Ensuite, comme il n'y a pas de deux-points (:) séparateur après la valeur pour indiquer le tunable suivant, le pointeur d'analyse (p) ne se déplace pas vers l'élément suivant et pointe à nouveau vers le début de la valeur déjà copiée.
Le problème est que cette valeur elle-même a la forme name=value. Lors de l'itération suivante, l'analyseur la reconnaît à tort comme un nouveau tunable et écrit des données redondantes dans le tampon. Comme tunestr est alloué uniquement pour la taille de la chaîne originale, ces écritures redondantes provoquent un dépassement de tampon tas.
Le dépassement de tampon tas écrase les zones tas adjacentes allouées de manière contiguë par __minimal_malloc(). L'attaquant peut ainsi modifier le pointeur l_info[DT_RPATH] de la structure interne link_map du chargeur dynamique (ld.so) pour le rediriger vers une adresse de pile contrôlée par l'attaquant.
Dans cette zone de pile, une structure Elf64_Dyn préfabriquée est placée, indiquant un répertoire choisi par l'attaquant comme nouveau chemin de recherche de bibliothèques (RPATH). En conséquence, ld.so charge en priorité la bibliothèque partagée malveillante préparée par l'attaquant au lieu des bibliothèques système normales.
GLIBC_TUNABLES de la forme name=name=value.su).ld.so).parse_tunables() de ld.so.l_info[DT_RPATH] de link_map est modifié pour pointer vers une adresse de pile où se trouve une fausse structure Elf64_Dyn préparée par l'attaquant.ld.so utilise ces informations RPATH manipulées pour charger un libc.so.6 malveillant préparé par l'attaquant.libc.so.6 malveillant s'exécute avec les privilèges root, effectuant setuid(0), setgid(0) et l'exécution de /bin/sh.su ne soit exécutée, permettant ainsi d'obtenir un shell root sans vérification du mot de passe.Le PoC utilise une méthode de force brute, répétant execve() jusqu'à ce que la disposition mémoire souhaitée (influencée par l'ASLR) soit obtenue. Par conséquent, le succès et le temps nécessaire de l'attaque dépendent de l'environnement, nécessitant généralement plusieurs centaines à plusieurs milliers de tentatives.
Clonez d'abord le dépôt git dans votre répertoire :
git clone https://github.com/baeseungwon1010/CVE-2023-4911

Construisez l'image Docker avec la commande suivante :
cd C* && docker compose run --rm cve-2023-4911-lab

Une fois à l'intérieur du conteneur, exécutez le code d'exploitation :
cd /home/student/exploit && ./exp
Après exécution, attendez ; vous verrez que l'utilisateur normal est passé à sudo(0).

Mettez à jour glibc vers une version postérieure à la version vulnérable. Après la mise à jour, redémarrez/relancez si possible pour garantir qu'aucune version précédente de glibc ne reste en mémoire. Si la mise à jour immédiate n'est pas possible, une mesure temporaire consiste à supprimer les processus SUID, SGID superflus.