flawopen.com/Teardowns/cve-2023-6246-glibc-syslog-heap-buffer-overflow
CVE-2023-6246: Heap-Überlauf in glibc-syslog
CVE-2023-6246 ist ein glibc-syslog-Heap-Überlauf durch einen langen Header. Installieren Sie das korrigierte glibc-Paket Ihrer Distribution.
Stellen Sie sich einen Mitarbeiter vor, der ein Paket und sein Etikett mit einem kurzen Lineal misst. Das Etikett passt nicht, deshalb erfasst die Berechnung den benötigten Platz nicht. Er bestellt eine winzige Schachtel und versucht, das vollständige Etikett samt Inhalt hineinzudrucken. In glibc konnte ein langer syslog-Header die erforderliche Größe unbestimmt lassen, sodass der Logger zu wenig Heap-Speicher reservierte.
Kernkonzepte & Begriffe
glibc- Die GNU C Library stellt zentrale C-Runtime-Funktionen für die meisten Linux-Programme bereit.
__vsyslog_internal()- Interne glibc-Implementierung, die
syslog()undvsyslog()zum Formatieren der Nachricht und desSYSLOG_HEADERvor der Übergabe an den Systemlogger verwenden. SYSLOG_HEADER- Prioritäts- und Identifikationspräfix vor der syslog-Nachricht. Es kann den Programmnamen oder eine über
openlog()gesetzte Kennung enthalten. Heap-based buffer overflow (CWE-122)- Ein Schreibvorgang überschreitet die Grenzen eines Heap-Puffers. Hier scheiterte die Größenberechnung, wenn der Header mit langem Namen nicht in den festen Anfangspuffer passte.
Framework-Zuordnungen
- CWE-Referenz für die in diesem Leitfaden beschriebene Schwachstelle: CWE-122
Ursachenanalyse
Laut glibc-Hinweis aktualisierte __vsyslog_internal() die erforderliche Puffergröße nicht, wenn ein SYSLOG_HEADER mit langem Programmnamen formatiert wurde. Im verwundbaren Code konnte die Headerlänge l mindestens so groß wie der 1.024-Byte-Stackpuffer sein; dadurch wurde der Zweig übersprungen, der den Nachrichtenkörper formatierte und bufsize setzte. Der spätere Heap-Pfad verwendete dann eine undefinierte oder nullgroße Größe und schrieb Header und Nachricht in einen zu kleinen Bereich. Qualys zufolge kann der lange Name aus dem vom Aufrufer kontrollierten Basename von argv[0] oder einer mehr als 1.024 Byte langen openlog()-Kennung stammen. Ein verwundbares setuid-Programm, das diesen Protokollpfad nutzt, kann den Fehler sicherheitsrelevant machen. Qualys demonstrierte eine lokale Rechteausweitung über su auf Fedora 38. Das Risiko hängt von lokalem Zugriff, Konfiguration und Aufrufpfad ab; es ist kein allgemeiner entfernter syslog-Exploit.
Schritt-für-Schritt Angriffsablauf
Lokale Voraussetzung
Ein lokaler Prozess muss über ein Programm mit betroffener glibc syslog() oder vsyslog() erreichen. Für Sicherheitsauswirkungen braucht es einen privilegierten Aufrufer und einen Pfad, der den Programmnamen-Präfix nicht durch eine sichere, begrenzte Kennung ersetzt.
Langer Header
Der Header überschreitet den Anfangspuffer|Der SYSLOG_HEADER enthält einen langen Programmnamen (__progname, abgeleitet vom Basename von argv[0]) oder eine lange openlog()-Kennung. Qualys zufolge muss der auslösende Wert länger als 1.024 Byte sein.
Fehlende Berechnung
Zweig für Größenberechnung wird übersprungen|Passt der Header nicht in den 1.024-Byte-Stackpuffer, überspringt der verwundbare Code den Zweig, der bufsize berechnet. Dem Heap-Pfad fehlt dann Platz für Header und formatierte Nachricht.
Speicherauswirkung
Schreibvorgang überschreitet die Zuweisung|Der Logger schreibt Header und Nachricht in einen zu kleinen Puffer und beschädigt den Heap. Qualys zeigte lokale Rechteausweitung über su auf Fedora 38; leiten Sie daraus keine gleiche Erreichbarkeit für alle Anwendungen oder Distributionen ab.
Quellcode: Verwundbar vs. Sicher
Der alte Zweig ließ bufsize auf null, wenn der Header nicht in den Stackpuffer passte; dadurch konnte der Heap-Fallback zu wenig Speicher reservieren. Der Fix markiert den Stackpuffer in diesem Fall als unbrauchbar, misst den Nachrichtenkörper darin, setzt l + vl und verwendet anschließend den bestehenden Allokationspfad mit der erforderlichen Größe. Dies sind gezielte Upstream-Auszüge, keine vollständigen eigenständigen Funktionen.
Quelltextauszug: misc/syslog.c
/* Gezielter Auszug aus misc/syslog.c vor 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);
}
/* Ein langer Header überspringt den obigen Zweig zur Größenfestlegung. */
/* Gezielter Auszug aus misc/syslog.c nach 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;
Checkliste für Engineering & Systemsicherheit
- ✓Aktualisieren Sie glibc mit dem korrigierten Paket für Ihre Distribution und Version; leiten Sie den Paketstatus nicht allein aus der Upstream-Version ab.
- ✓Prüfen Sie den Sicherheitshinweis Ihrer Distribution: Upstream-Fixes sind glibc 2.39, 2.38-42, 2.37-57 und 2.36-126.
- ✓Ermitteln Sie privilegierte Programme mit Aufrufen von
syslog()odervsyslog()und prüfen Sie, ob kontrollierte Programmnamen oderopenlog()-Kennungen in den Header gelangen. - ✓Berechnen Sie bei formatiertem Logging die vollständige Header- und Nachrichtenlänge auch dann, wenn der feste Anfangspuffer nicht reicht; testen Sie lange Programmnamen und die Größenarithmetik.