Numerischer Trunkierungsfehler
Beschreibung
Numerischer Trunkierungsfehler tritt auf, wenn ein numerischer Wert in einen kleineren Datentyp konvertiert wird, der nicht den vollen Bereich des ursprünglichen Werts darstellen kann, was zu Verlust signifikanter Bits und einem falschen Wert führt. Zum Beispiel produziert das Casten eines 32-bit Integers, der 0x12345678 enthält, zu einem 16-bit Integer den Wert 0x5678, wobei die oberen Bits verloren gehen. Wenn trunkierte Werte für sicherheitskritische Operationen wie Pufferallokation, Schleifeniteration oder Zugriffskontrollentscheidungen verwendet werden, kann der resultierende kleinere Wert Buffer-Overflows, Endlosschleifen oder Sicherheitsumgehungen ermöglichen.
Risiko
Numerische Trunkierungsfehler können schwerwiegende Sicherheitsimplikationen haben. Wenn ein größer Größenwert zu einem kleineren Typ trunkiert wird, wird ein kleiner Puffer allokiert, während nachfolgende Operationen die ursprüngliche große Größe annehmen – was Buffer-Overflow verursacht. Trunkierung kann Sicherheitsprüfungen umgehen, die den größeren Wert verwenden, während Operationen den trunkierten Wert verwenden. Angreifer erstellen Eingaben mit spezifischen Bitmustern, die gefährliche trunkierte Werte produzieren. Diese Schwachstelle wurde historisch untererfasst, betrifft aber kritische Software auf allen Plattformen. Aktuelle Forschung hat zahlreiche Trunkierungsschwachstellen in Open-Source-Projekten entdeckt.
Lösung
Vermeiden Sie implizite einengende Konvertierungen zwischen Integer-Typen. Wenn eine Konvertierung notwendig ist, verifizieren Sie, dass der Wert im Bereich des Zieltyps liegt, bevor Sie konvertieren. Verwenden Sie Compiler-Warnungen für implizites Einengen (-Wconversion, -Wnarrowing). Wenden Sie statische Analyse an, um Trunkierungspunkte zu identifizieren. Verwenden Sie Typen, die groß genug für die zu verarbeitenden Daten sind. In sicherheitskritischem Code verwenden Sie explizite Bereichsvalidierung vor jedem einengenden Cast. Erwägen Sie die Verwendung von SafeInt oder ähnlichen Bibliotheken, die Trunkierung erkennen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Speicherbeschädigung Trunkierte Größenwerte führen zu unterdimensionierten Allokationen und nachfolgenden Buffer-Overflows. |
| Zugriffskontrolle | Bereich: Sicherheitsumgehung Trunkierung kann dazu führen, dass große Werte Prüfungen passieren, die sie in ihrer ursprünglichen Form ablehnen würden. |
| Verfügbarkeit | Bereich: Denial-of-Service Trunkierung in Schleifenzählern kann Endlosschleifen verursachen; in Allokationen kann Ressourcenerschöpfung verursachen. |
Beispielcode + Lösungscode
Anfälliger Code
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// ANFÄLLIG: 32-bit zu 16-bit Trunkierung
void allocate_buffer(uint32_t requested_size) {
uint16_t size = requested_size; // Trunkiert auf 16 Bits
// Wenn requested_size = 0x10100, size = 0x0100 (256)
char *buffer = malloc(size); // Kleine Allokation
// Operationen verwenden ursprüngliche Größe
read_data(buffer, requested_size); // Massiver Overflow!
}
// ANFÄLLIG: Trunkierung umgeht Längenprüfung
void copy_with_limit(char *dest, char *src, size_t len) {
unsigned short limit = len; // Trunkiert große len-Werte
// len = 65537 wird zu limit = 1
if (limit > MAX_SIZE) {
return; // Kleines limit passiert Prüfung
}
memcpy(dest, src, len); // Verwendet ursprüngliches großes len!
}
// ANFÄLLIG: Schleifenzähler-Trunkierung
void process_elements(uint32_t count) {
uint8_t i;
// count = 260 trunkiert, i geht nur 0-255 dann wickelt um
for (i = 0; i < count; i++) {
process_element(i); // Endlosschleife wenn count > 255
}
}
// ANFÄLLIG: Rückgabewert-Trunkierung
int16_t get_file_size(const char *filename) {
struct stat st;
stat(filename, &st);
// st.st_size ist 64-bit, trunkiert zu 16-bit Rückgabe
return st.st_size; // Große Dateien geben falsche Größe zurück
}
Korrigierter Code
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
// SICHER: Vor Trunkierung validieren
int allocate_buffer_safe(size_t requested_size) {
// Validieren, dass Größe vernünftig ist
if (requested_size > MAX_BUFFER_SIZE) {
return -1;
}
// Passenden Typ verwenden (keine Trunkierung nötig)
char *buffer = malloc(requested_size);
if (!buffer) return -1;
read_data(buffer, requested_size);
return 0;
}
// SICHER: Konsistente Typen verwenden
void copy_with_limit_safe(char *dest, size_t dest_size,
const char *src, size_t len) {
// size_t durchgehend verwenden - keine Trunkierung
if (len > MAX_SIZE || len > dest_size) {
return;
}
memcpy(dest, src, len);
}
// SICHER: Bereich vor Einengung validieren
int process_elements_safe(uint32_t count) {
// Prüfen, ob count in Schleifenvariablentyp passt
if (count > UINT8_MAX) {
// Entweder ablehnen oder passenden Typ verwenden
return -1;
}
uint8_t limit = (uint8_t)count; // Sicher nach Validierung
for (uint8_t i = 0; i < limit; i++) {
process_element(i);
}
return 0;
}
// Alternative: Größere Schleifenvariable verwenden
void process_elements_large(size_t count) {
for (size_t i = 0; i < count; i++) {
process_element(i);
}
}
// SICHER: Passenden Typ zurückgeben
int64_t get_file_size_safe(const char *filename) {
struct stat st;
if (stat(filename, &st) != 0) {
return -1;
}
// Volle Größe ohne Trunkierung zurückgeben
return (int64_t)st.st_size;
}
// Hilfsfunktion: Sicheres Einengen mit Validierung
bool safe_narrow_to_u16(size_t value, uint16_t *result) {
if (value > UINT16_MAX) {
return false; // Würde trunkieren
}
*result = (uint16_t)value;
return true;
}
Ausgenutzt in der Praxis
Windows Shell Privilegieneskalation (Microsoft, 2025)
CVE-2025-49679 ist ein numerischer Trunkierungsfehler in der Windows-Shell-Komponente, der lokalen Angreifern ermöglicht, Privilegien zu eskalieren. CVSS 7.8 mit hoher Auswirkung auf Vertraulichkeit, Integrität und Verfügbarkeit.
Mehrere Open-Source-Projekte (OSS-Fuzz, 2023-2024)
Forschung mit OSS-Sydr-Fuzz entdeckte 12 neue numerische Trunkierungsfehler in 5 Open-Source-Projekten und demonstrierte die Verbreitung dieser untererforschten Schwachstellenklasse.
Historisch: Integer-Trunkierung in Protokoll-Handlern (Verschiedene)
Mehrere historische Schwachstellen in Netzwerkprotokoll-Handlern (HTTP, DNS, SMB) stammten von der Trunkierung von 32-bit-Längenfeldern zu 16-bit-Typen.
Tools zum Testen/Ausnutzen
-
UBSan — erkennt implizite Trunkierung mit -fsanitize=implicit-conversion.
-
Coverity — statische Analyse zur Identifikation einengender Konvertierungen.
-
Sydr — Fuzzer mit symbolischer Ausführung zur Findung von Trunkierungsfehlern.
CVE-Beispiele
-
CVE-2025-49679 — Windows Shell numerische Trunkierung Privilegieneskalation.
-
CVE-2016-2324 — Git Integer-Trunkierung in Pfadbehandlung.
-
CVE-2019-11477 — Linux-Kernel SACK Integer-Overflow mit Trunkierung.
Referenzen
-
MITRE. "CWE-197: Numeric Truncation Error." https://cwe.mitre.org/data/definitions/197.html
-
CERT. "INT31-C. Ensure that integer conversions do not result in löst or misinterpreted data." https://wiki.sei.cmu.edu/confluence/display/c/INT31-C
-
OpenSSF. "Secure Coding Guide for Python: CWE-197." https://best.openssf.org/Secure-Coding-Guide-for-Python/CWE-664/CWE-197/