Funktionsaufruf mit falschem Argumenttyp

Beschreibung

Funktionsaufruf mit falschem Argumenttyp ist ein Programmierfehler, bei dem Code eine Funktion, Prozedur oder Routine mit einem Argument aufruft, das einen anderen Datentyp hat als von der Funktion erwartet. Diese Schwachstelle tritt am häufigsten in locker typisierten Sprachen auf, in stark typisierten Sprachen, in denen variable Argumenttypen zur Kompilierzeit nicht erzwungen werden können, oder wenn implizite Typumwandlungen stattfinden. Wenn Funktionen Argumente unerwarteter Typen erhalten, können sie die Daten falsch interpretieren, fehlerhafte Operationen ausführen oder undefiniertes Verhalten zeigen, das zu Sicherheitslücken führen kann.

Risiko

Falsche Argumenttypen erzeugen je nach Kontext erhebliche Sicherheitsrisiken. Das Übergeben eines Pointers, wo ein Integer erwartet wird (oder umgekehrt), kann zu Speicherkorruption führen. Zeichenbehandlungsfunktionen, die Werte außerhalb des gültigen Bereichs erhalten, können Speicher falsch zugreifen. Typverwechslungen in sicherheitskritischen Funktionen können Authentifizierungs- oder Autorisierungsprüfungen umgehen. In Sprachen mit impliziter Typumwandlung können subtile Typunterschiede erfolgreich kompilieren, aber zur Laufzeit gefährlich falsche Ergebnisse produzieren. Format-String-Funktionen sind besonders anfällig - das Übergeben eines Integers, wo ein String-Pointer erwartet wird, kann Abstürze oder Informationslecks verursachen.

Lösung

Verwenden Sie wenn möglich stark typisierte Sprachen. Aktivieren Sie Compiler-Warnungen für Typunterschiede und behandeln Sie Warnungen als Fehler. In C verwenden Sie immer Funktionsprototypen und aktivieren Sie die Warnungen -Wformat und -Wconversion. Für Funktionen mit variablen Argumenten verwenden Sie Format-Attribute, um Compiler-Prüfungen zu ermöglichen. Vermeiden Sie implizite Umwandlungen - verwenden Sie explizite Casts nur wenn nötig und nach sorgfältiger Überprüfung. Befolgen Sie CERT-Richtlinien für Zeichenbehandlungsfunktionen. Verwenden Sie statische Analysetools, die Typunterschiede erkennen. In dynamisch typisierten Sprachen fügen Sie explizite Typüberprüfungen an Funktionseinstiegspunkten hinzu.

Häufige Auswirkungen

AuswirkungDetails
SonstigesBereich: Sonstiges

Qualitätsverschlechterung - Funktionen produzieren falsches oder undefiniertes Verhalten, wenn sie mit falschen Argumenttypen aufgerufen werden.
IntegritätBereich: Integrität

Speicher ändern - Typverwechslung kann dazu führen, dass Funktionen an falsche Speicherstellen schreiben.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz, Beenden oder Neustart - Typunterschiede können Abstürze verursachen, besonders bei Pointer/Integer-Verwechslung.

Beispielcode

Anfälliger Code

// Anfällig: Int übergeben wo Pointer in printf erwartet
#include <stdio.h>

void vulnerable_printf_type(int value) {
    // Anfällig: %s erwartet char*, aber int wird übergeben
    printf("Wert: %s\n", value);  // FALSCHER TYP!
    // Behandelt Integer als Speicheradresse - stürzt ab oder leckt Speicher
}

// Anfällig: Zeichenfunktion mit Wert außerhalb des Bereichs
#include <ctype.h>

int vulnerable_char_check(int input) {
    // Anfällig: isalpha erwartet unsigned char Bereich (0-255) oder EOF
    // Übergabe eines beliebigen int kann undefiniertes Verhalten verursachen
    char c = (char)input;  // Kann auf manchen Plattformen negativ sein

    if (isalpha(c)) {  // Undefiniert wenn c negativ und nicht EOF
        return 1;
    }
    return 0;
}

// Anfällig: Signed/Unsigned Unterschied
void vulnerable_memset(char* buffer, int value, int size) {
    // Wenn size negativ ist, interpretiert memset es als riesige positive Zahl
    memset(buffer, value, size);  // size_t erwartet, int übergeben
}

// Anfällig: Float wo int erwartet
void process_count(int count) {
    for (int i = 0; i < count; i++) {
        // Element verarbeiten
    }
}

void vulnerable_float() {
    float f = 10.7f;
    // Anfällig: Float wird stillschweigend zu int abgeschnitten
    process_count(f);  // Implizite Konvertierung, erwartet evtl. 11 Iterationen
}
// Anfällig: Java Typverwechslung mit Generics
import java.util.*;

public class VulnerableTypes {

    // Anfällig: Raw Type erlaubt falsche Typen
    @SuppressWarnings("unchecked")
    public void vulnerableGeneric() {
        List list = new ArrayList();  // Raw Type
        list.add("string");
        list.add(123);  // Typen mischen!

        for (Object item : list) {
            // Anfällig: ClassCastException zur Laufzeit
            String s = (String) item;  // Stürzt bei Integer ab
            process(s);
        }
    }

    // Anfällig: Varargs Typverwechslung
    public void logMessage(String format, Object... args) {
        System.out.printf(format, args);
    }

    public void vulnerableVarargs() {
        int[] numbers = {1, 2, 3};
        // Anfällig: int[] übergeben wo mehrere Objects erwartet
        logMessage("Werte: %d, %d, %d", numbers);  // Falsch!
        // numbers wird als einzelnes Object behandelt, nicht 3 separate Argumente
    }
}
# Anfällig: Python Typfehler
def process_items(items: list) -> int:
    """Verarbeitet eine Liste von Elementen und gibt Anzahl zurück."""
    total = 0
    for item in items:
        total += len(item)  # Erwartet Elemente mit len()
    return total

# Anfällig: String übergeben wo Liste erwartet
result = process_items("hallo")  # String ist iterierbar, aber len("h") etc.
# Funktioniert aber produziert unerwartetes Ergebnis (zählt Zeichen)

# Anfällig: Falschen Typ an Sicherheitsfunktion übergeben
def verify_hash(data: bytes, expected_hash: str) -> bool:
    """Verifiziert dass Daten-Hash mit erwartetem übereinstimmt."""
    import hashlib
    actual = hashlib.sha256(data).hexdigest()
    return actual == expected_hash

# Anfällig: str statt bytes übergeben
user_data = request.form['data']  # str Typ
# verify_hash(user_data, expected)  # TypeError oder Encoding-Probleme
// Anfällig: Variadische Funktion Typverwechslung
#include <stdarg.h>
#include <stdio.h>

void vulnerable_variadic(int count, ...) {
    va_list args;
    va_start(args, count);

    for (int i = 0; i < count; i++) {
        // Nimmt an alle Argumente sind char*
        char* str = va_arg(args, char*);  // Typ muss übereinstimmen!
        printf("%s\n", str);
    }

    va_end(args);
}

void call_vulnerable() {
    // Anfällig: int übergeben wo char* erwartet
    vulnerable_variadic(3, "hallo", 12345, "welt");
    // 12345 als Pointer interpretiert - Absturz oder Müll
}

Lösung

// Korrigiert: Korrekte Typen für printf
#include <stdio.h>

void secure_printf_type(int value) {
    // Korrigiert: %d für int, nicht %s
    printf("Wert: %d\n", value);
}

void secure_printf_string(const char* str) {
    // Korrigiert: %s mit tatsächlichem String-Pointer
    printf("Wert: %s\n", str);
}

// Korrigiert: Sichere Zeichenbehandlung
#include <ctype.h>

int secure_char_check(int input) {
    // Korrigiert: Cast zu unsigned char für Zeichenfunktionen
    unsigned char c = (unsigned char)input;

    // Oder zuerst Bereich validieren
    if (input < 0 || input > 255) {
        return 0;  // Ungültiger Zeichenwert
    }

    if (isalpha(c)) {
        return 1;
    }
    return 0;
}

// Korrigiert: Richtiger Typ für Größe
#include <string.h>
#include <stddef.h>

void secure_memset(char* buffer, int value, size_t size) {
    // Korrigiert: size_t für Größen verwenden
    memset(buffer, value, size);
}

int secure_memset_checked(char* buffer, int value, int size) {
    // Korrigiert: Vor impliziter Konvertierung validieren
    if (size < 0) {
        return -1;  // Fehler: ungültige Größe
    }
    memset(buffer, value, (size_t)size);
    return 0;
}

// Korrigiert: Explizite Typkonvertierung mit Bewusstsein
void secure_float_handling() {
    float f = 10.7f;

    // Korrigiert: Explizite Konvertierung mit Rundungsentscheidung
    int count_floor = (int)f;           // 10 - abschneiden
    int count_round = (int)(f + 0.5f);  // 11 - runden

    // Passenden wählen basierend auf Anforderungen
    process_count(count_round);
}
// Korrigiert: Java mit korrekten Generics
import java.util.*;

public class SecureTypes {

    // Korrigiert: Parametrisierte Typen verwenden
    public void secureGeneric() {
        List<String> list = new ArrayList<>();
        list.add("string");
        // list.add(123);  // Kompilierfehler!

        for (String s : list) {
            // Typsichere Iteration
            process(s);
        }
    }

    // Korrigiert: Korrekte Varargs-Behandlung
    public void logMessage(String format, Object... args) {
        System.out.printf(format, args);
    }

    public void secureVarargs() {
        int[] numbers = {1, 2, 3};

        // Korrigiert: Zu Wrapper-Objekten konvertieren
        logMessage("Werte: %d, %d, %d", numbers[0], numbers[1], numbers[2]);

        // Oder Integer-Array verwenden
        Integer[] boxedNumbers = {1, 2, 3};
        logMessage("Werte: %d, %d, %d", (Object[]) boxedNumbers);
    }

    // Korrigiert: Typsicheres Logging
    public void secureLog(String message, int... values) {
        StringBuilder sb = new StringBuilder(message);
        for (int v : values) {
            sb.append(" ").append(v);
        }
        System.out.println(sb);
    }
}
# Korrigiert: Python mit Typvalidierung
from typing import List, Union

def process_items_secure(items: List[str]) -> int:
    """Verarbeitet eine Liste von String-Elementen und gibt Gesamtlänge zurück."""
    if not isinstance(items, list):
        raise TypeError(f"Liste erwartet, {type(items).__name__} erhalten")

    total = 0
    for item in items:
        if not isinstance(item, str):
            raise TypeError(f"str-Elemente erwartet, {type(item).__name__} erhalten")
        total += len(item)
    return total

# Korrigiert: Typsichere Hash-Verifizierung
def verify_hash_secure(data: Union[bytes, str], expected_hash: str) -> bool:
    """Verifiziert dass Daten-Hash mit erwartetem übereinstimmt."""
    import hashlib

    # Korrigiert: Sowohl bytes als auch str behandeln
    if isinstance(data, str):
        data = data.encode('utf-8')
    elif not isinstance(data, bytes):
        raise TypeError(f"bytes oder str erwartet, {type(data).__name__} erhalten")

    actual = hashlib.sha256(data).hexdigest()
    return actual == expected_hash

# Laufzeit-Typüberprüfung verwenden
from typing import get_type_hints
import functools

def type_checked(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)
        # Argumenttypen gegen Hints validieren
        # (vereinfacht - Produktion wäre gründlicher)
        return func(*args, **kwargs)
    return wrapper
// Korrigiert: Typsichere Alternativen zu Variadic
#include <stdio.h>

// Korrigiert: Typisiertes Array statt Variadic verwenden
void secure_print_strings(const char** strings, int count) {
    for (int i = 0; i < count; i++) {
        if (strings[i] != NULL) {
            printf("%s\n", strings[i]);
        }
    }
}

void call_secure() {
    const char* strings[] = {"hallo", "welt", "test"};
    secure_print_strings(strings, 3);
}

// Korrigiert: Typsichere Union für gemischte Typen
typedef enum { TYPE_INT, TYPE_STRING, TYPE_FLOAT } ArgType;

typedef struct {
    ArgType type;
    union {
        int i;
        const char* s;
        float f;
    } value;
} TypedArg;

void secure_mixed_print(TypedArg* args, int count) {
    for (int i = 0; i < count; i++) {
        switch (args[i].type) {
            case TYPE_INT:
                printf("%d\n", args[i].value.i);
                break;
            case TYPE_STRING:
                printf("%s\n", args[i].value.s);
                break;
            case TYPE_FLOAT:
                printf("%f\n", args[i].value.f);
                break;
        }
    }
}

CVE-Beispiele

  • CVE-2006-1174: Argumenttyp-Unterschied im Funktionsaufruf führte zur Sicherheitsumgehung.
  • CVE-2007-1420: Typverwechslung verursachte Absturz in String-Behandlungsfunktion.

Referenzen

  1. MITRE Corporation. "CWE-686: Function Call With Incorrect Argument Type." https://cwe.mitre.org/data/definitions/686.html
  2. CERT C Coding Standard. "EXP37-C. Call functions with the correct number and type of arguments."
  3. CERT C Coding Standard. "STR37-C. Arguments to character handling functions must be representable as an unsigned char."