Falsche Konvertierung zwischen numerischen Typen
Beschreibung
Falsche Konvertierung zwischen numerischen Typen ist eine Schwachstelle, bei der ein Programm Werte zwischen verschiedenen numerischen Typen auf eine Weise konvertiert, die unerwartete oder falsche Ergebnisse erzeugt. Dies umfasst Konvertierungen zwischen vorzeichenbehafteten und vorzeichenlosen Ganzzahlen, Konvertierungen, die Werte abschneiden (z.B. long zu int), Fließkomma-zu-Ganzzahl-Konvertierungen, die Präzision verlieren, und implizite Konvertierungen, die die Wertsemantik ändern. Wenn der konvertierte Wert in sensiblen Operationen wie Speicherallokation, Array-Indizierung oder Sicherheitsentscheidungen verwendet wird, kann der falsche Wert zu ernsthaften Sicherheitslücken führen.
Risiko
Falsche numerische Konvertierungen schaffen verschiedene Sicherheitsrisiken je nach Kontext. Die Konvertierung von signed zu unsigned bei negativen Werten erzeugt große positive Werte, was möglicherweise Pufferüberläufe verursacht, wenn sie als Größen verwendet werden. Die Abschneidung größer Werte auf kleinere Typen verliert höherwertige Bits, was zu unerwartet kleinen Werten führt. Fließkomma-zu-Ganzzahl-Konvertierung verliert Nachkommastellen und kann präzisionsabhängige Sicherheitsprüfungen zum Scheitern bringen. Plattformabhängige Typgrößen schaffen Portabilitätsfehler, die sich als Sicherheitslücken auf verschiedenen Architekturen manifestieren.
Lösung
Vermeiden Sie Typkonvertierungen, wenn möglich, indem Sie konsistente Typen in Berechnungen verwenden. Wenn eine Konvertierung notwendig ist, validieren Sie explizit, dass der Wert in den Bereich des Zieltyps passt, bevor Sie konvertieren. Verwenden Sie sichere Konvertierungsfunktionen oder Makros, die auf Überlauf und Unterlauf prüfen. Seien Sie sich impliziter Konvertierungen in Ausdrücken bewusst und verwenden Sie explizite Casts, um die Absicht klar zu machen. Testen Sie auf mehreren Plattformen mit unterschiedlichen Typgrößen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Integrität | Bereich: Integrität Datenmodifikation - Falsche Werte aus schlechten Konvertierungen können Daten korrumpieren oder falsche Berechnungen erzeugen. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Absturz - Unerwartete Werte können Abstürze verursachen, besonders bei Speicheroperationen. |
| Sonstiges | Bereich: Sonstige Qualitätsverschlechterung - Programme erzeugen falsche Ergebnisse, wenn Konvertierungen Werte unerwartet ändern. |
Beispielcode und Lösung
Verwundbarer Code
// Verwundbar: Signed zu Unsigned Konvertierung
#include <stdlib.h>
#include <string.h>
void verwundbar_kopieren(char* dest, char* src, int length) {
// VERWUNDBAR: Wenn length negativ ist, macht unsigned Konvertierung es riesig
// memcpy wird massive Speichermengen lesen/schreiben
memcpy(dest, src, (size_t)length); // -1 wird SIZE_MAX!
}
unsigned int verwundbar_lese_große() {
int size = read_from_network();
if (size == -1) {
// Fehlerbedingung gibt -1 zurück
return size; // Konvertiert -1 zu 4.294.967.295 (UINT_MAX)!
}
return size;
}
// Verwundbar: Abschneidung von größerem zu kleinerem Typ
void verwundbar_abschneidung(size_t large_size) {
// Auf 64-Bit-System: size_t ist 64-Bit, int ist 32-Bit
int small_size = (int)large_size; // Schneidet auf 32 Bits ab
// Wenn large_size 0x100000010 (4GB + 16 Bytes) war
// wird small_size nur 16!
char* buffer = malloc(small_size);
// Allokiert 16 Bytes statt 4GB
// Späterer Code verwendet large_size zum Schreiben - Buffer Overflow!
fill_buffer(buffer, large_size);
}
// Verwundbar: Java Fließkomma zu Ganzzahl
public class VerwundbareKonvertierung {
// Verwundbar: Präzisionsverlust
public int berechneRabatt(float preis, float rabattProzent) {
float rabattBetrag = preis * rabattProzent / 100;
// Verwundbar: Abschneidung Richtung Null
int cents = (int)(rabattBetrag * 100);
// 1,999€ werden 199 Cents, nicht 200
// Wiederholte Berechnungen akkumulieren Fehler
return cents;
}
// Verwundbar: Überlauf bei Konvertierung
public int verwundbarerArrayIndex(long userIndex) {
// Verwundbar: Long zu Int Abschneidung
int index = (int)userIndex;
// Wenn userIndex = 0x100000000L (4GB), wird index 0
// Umgeht Grenzenprüfung, wenn basierend auf Original-Long
return array[index];
}
}
Sichere Lösung
// Sicher: Sichere Signed zu Unsigned Konvertierung
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
int sichere_kopie(char* dest, size_t dest_size, char* src, int length) {
// Sicher: Länge vor Konvertierung validieren
if (length < 0) {
return -1; // Fehler: negative Länge
}
if ((size_t)length > dest_size) {
return -1; // Fehler: würde Ziel überlaufen
}
memcpy(dest, src, (size_t)length);
return 0;
}
// Sicher: Vor Abschneidung prüfen
int sichere_abschneidung(size_t large_size) {
// Sicher: Verifizieren, dass Wert in Zieltyp passt
if (large_size > INT_MAX) {
return -1; // Fehler: Wert zu groß
}
int small_size = (int)large_size; // Sicher nach Prüfung
char* buffer = malloc(small_size);
if (buffer == NULL) return -1;
fill_buffer(buffer, small_size); // Gleiche Variable verwenden
free(buffer);
return 0;
}
// Sicher: Sichere Konvertierungs-Hilfsfunktionen
// size_t sicher zu int konvertieren
int size_zu_int(size_t value, int* result) {
if (value > INT_MAX) {
return -1; // Würde überlaufen
}
*result = (int)value;
return 0;
}
// int64_t sicher zu int32_t konvertieren
int i64_zu_i32(int64_t value, int32_t* result) {
if (value < INT32_MIN || value > INT32_MAX) {
return -1; // Außerhalb des Bereichs
}
*result = (int32_t)value;
return 0;
}
// Signed sicher zu Unsigned konvertieren
int signed_zu_unsigned(int value, unsigned int* result) {
if (value < 0) {
return -1; // Negative Werte ungültig für unsigned
}
*result = (unsigned int)value;
return 0;
}
// Sicher: Java sichere Konvertierungen
public class SichereKonvertierung {
// Sicher: Ordnungsgemäße Rundung für Währung
public int berechneRabattSicher(double preis, double rabattProzent) {
double rabattBetrag = preis * rabattProzent / 100;
// Sicher: Ordnungsgemäße Rundung verwenden
int cents = (int)Math.round(rabattBetrag * 100);
return cents;
}
// Sicher: Grenzenprüfung vor Konvertierung
public int sichererArrayIndex(long userIndex) {
// Sicher: Bereich vor Konvertierung validieren
if (userIndex < 0 || userIndex >= array.length) {
throw new IndexOutOfBoundsException("Ungültiger Index: " + userIndex);
}
// Sicher: wir haben verifiziert, dass es passt
int index = (int)userIndex;
return array[index];
}
// Sicher: Math.toIntExact verwenden (Java 8+)
public int sicherZuInt(long value) {
// Wirft ArithmeticException wenn Wert nicht in int passt
return Math.toIntExact(value);
}
}
Ausgenutzt in der Praxis
OpenSSL Signed-to-Unsigned Schwachstelle (2014)
Eine fehlerhafte Typkonvertierung in OpenSSL bei der Verarbeitung von TLS-Heartbeat-Erweiterungen führte zur Heartbleed-Schwachstelle, die es Angreifern ermöglichte, Speicher vom Server zu lesen.
Firefox Integer-Abschneidung (2016)
Eine Integer-Abschneidung in Firefox bei der Verarbeitung von WebGL-Inhalten ermöglichte Remote-Code-Ausführung durch speziell gestaltete Webseiten.
Linux Kernel Signed/Unsigned Verwechslung (diverse)
Mehrere Linux-Kernel-Schwachstellen resultierten aus Verwechslungen zwischen signed und unsigned Typen, die zu Privilegieneskalation führten.
Tools zum Testen und Ausnutzen
-
UndefinedBehaviorSanitizer — Erkennt Integer-Überlauf und Konvertierungsprobleme.
-
PVS-Studio — Statischer Analysator zur Erkennung von Typkonvertierungsfehlern.
-
Cppcheck — Open-Source-Tool zur statischen Analyse für C/C++.
CVE-Beispiele
-
CVE-2022-2639 — Integer-Coercion-Fehler verhindert ordnungsgemäße Fehleranzeige und führt zu Out-of-Bounds-Write.
-
CVE-2021-43537 — 64-Bit zu 32-Bit Integer-Abschneidung verursacht Heap-Buffer Overflow.
-
CVE-2007-4268 — Vorzeichenerweiterungsfehler löst Heap-Überlauf aus.
Referenzen
-
MITRE Corporation. "CWE-681: Incorrect Conversion between Numeric Types." https://cwe.mitre.org/data/definitions/681.html
-
CERT C Coding Standard. "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.+Ensure+that+integer+conversions+do+not+result+in+löst+or+misinterpreted+data
-
CERT C Coding Standard. "INT02-C: Understand integer conversion rules." https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules