flawopen.com/Teardowns/cve-2023-6246-glibc-syslog-heap-buffer-overflow
CVE-2023-6246 : overflow heap de glibc syslog
CVE-2023-6246 est un débordement de heap dans syslog de glibc, déclenché par un en-tête long. Installez le paquet glibc corrigé de votre distribution.
Imaginez un employé qui mesure un colis et son étiquette avec une petite règle. L’étiquette ne tient pas, donc le calcul n’enregistre pas l’espace nécessaire. Il commande alors une boîte minuscule et tente d’y imprimer toute l’étiquette et le contenu. Dans glibc, un en-tête syslog long pouvait laisser la taille requise indéterminée et faire allouer trop peu de mémoire heap par le journaliseur.
Concepts Clés et Termes
glibc- La GNU C Library fournit des fonctions centrales du runtime C utilisées par la plupart des programmes Linux.
__vsyslog_internal()- Implémentation interne de glibc utilisée par
syslog()etvsyslog()pour formater le message et sonSYSLOG_HEADERavant son envoi au journaliseur système. SYSLOG_HEADER- Préfixe de priorité et d’identification formaté avant le message syslog. Il peut inclure le nom du programme ou un identifiant fourni à
openlog(). Heap-based buffer overflow (CWE-122)- Une écriture dépasse les limites d’un tampon alloué sur le heap. Ici, le calcul échouait quand l’en-tête avec un nom long ne tenait pas dans le tampon fixe initial.
Correspondances de référentiels
- Référence CWE pour la faiblesse décrite dans ce guide : CWE-122
Analyse de Cause Racine
L’avis glibc indique que __vsyslog_internal() ne mettait pas à jour la taille requise lors du formatage d’un SYSLOG_HEADER contenant un nom de programme long. Dans le code vulnérable, la longueur l de l’en-tête pouvait atteindre ou dépasser le tampon de pile de 1 024 octets ; la branche qui formatait le corps du message et définissait bufsize était alors ignorée. L’allocation heap suivante utilisait une taille non définie ou nulle, puis écrivait l’en-tête et le message dans un espace trop petit. Qualys précise que le nom long peut provenir du basename d’un argv[0] contrôlé par l’appelant ou d’un identifiant openlog() de plus de 1 024 octets ; un programme setuid vulnérable qui journalise par ce chemin peut rendre le défaut sensible. Qualys a démontré une élévation locale de privilèges via su sur Fedora 38. Le risque dépend de l’accès local, de la configuration et du chemin d’appel ; ce n’est pas un exploit syslog distant générique.
Déroulement de l'Attaque Étape par Étape
Précondition locale
Un processus local doit atteindre syslog() ou vsyslog() par un programme utilisant la glibc affectée. L’impact de sécurité suppose un appelant privilégié et un chemin qui ne remplace pas le préfixe du nom du programme par un identifiant sûr et borné.
En-tête long
L’en-tête dépasse le tampon initial|Le SYSLOG_HEADER inclut un nom de programme long (__progname, dérivé du basename de argv[0]) ou un identifiant openlog() long. Qualys indique que la valeur déclenchante doit dépasser 1 024 octets.
Calcul incomplet
La branche de calcul de taille est ignorée|Lorsque l’en-tête ne tient pas dans le tampon de pile de 1 024 octets, le code vulnérable ignore la branche qui calcule bufsize. L’allocation heap n’a alors pas assez d’espace pour l’en-tête et le message formaté.
Impact mémoire
L’écriture dépasse l’allocation|Le journaliseur écrit l’en-tête et le message dans un tampon trop petit et corrompt le heap. Qualys a démontré une élévation locale via su sur Fedora 38 ; ne généralisez pas cette exposition à toutes les applications ou distributions.
Code Source : Vulnérable vs Sécurisé
L’ancienne branche laissait bufsize à zéro lorsque l’en-tête ne tenait pas dans le tampon de pile ; l’allocation heap pouvait donc être trop petite. Le correctif marque ce tampon comme inutilisable, l’emploie pour mesurer le corps, enregistre l + vl, puis reprend le chemin d’allocation existant avec la taille nécessaire. Ce sont des extraits ciblés upstream, pas des fonctions complètes autonomes.
Extrait source: misc/syslog.c
/* Extrait ciblé de misc/syslog.c avant le commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = NULL;
size_t bufsize = 0;
...
if (0 <= l && l < sizeof bufs)
{
va_list apc;
va_copy (apc, ap);
int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc,
mode_flags);
if (0 <= vl && vl < sizeof bufs - l)
buf = bufs;
bufsize = l + vl;
va_end (apc);
}
/* Un en-tête long contourne la branche précédente qui définit la taille. */
/* Extrait ciblé de misc/syslog.c après le commit 6bd0e4efcc78. */
char bufs[1024];
char *buf = bufs;
size_t bufsize;
...
if (0 <= l && l < sizeof bufs)
{
pos = bufs + l;
len = sizeof (bufs) - l;
}
else
{
buf = NULL;
pos = bufs;
len = sizeof (bufs);
}
vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags);
if (!(0 <= vl && vl < len))
buf = NULL;
bufsize = l + vl;
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Mettez glibc à niveau avec le paquet corrigé de votre distribution et de votre version ; ne déduisez pas son état depuis la seule version upstream.
- ✓Vérifiez l’avis de votre distribution : les corrections upstream sont glibc 2.39, 2.38-42, 2.37-57 et 2.36-126.
- ✓Inventoriez les programmes privilégiés qui appellent
syslog()ouvsyslog()et vérifiez si un nom contrôlé par l’appelant ou un identifiantopenlog()atteint l’en-tête. - ✓Pour le journalisme formaté, comptabilisez la taille totale de l’en-tête et du corps même si le tampon fixe initial est insuffisant ; ajoutez un test avec un nom de programme long et vérifiez l’arithmétique d’allocation.