Funktionsaufruf mit falscher Argumentreihenfolge

Beschreibung

Funktionsaufruf mit falscher Argumentreihenfolge ist ein Programmierfehler, bei dem ein Produkt eine Funktion mit Argumenten aufruft, die in der falschen Sequenz angegeben sind. Dies tritt häufig auf, wenn Funktionen mehrere Parameter desselben oder kompatiblen Typs haben, was es leicht macht, sie versehentlich zu vertauschen. Während streng typisierte Compiler Typunterschiede abfangen können, tritt diese Schwachstelle häufig bei variadischen Funktionen, Format-Strings oder wenn Parameter denselben Typ haben (wie zwei Strings oder zwei Integer) auf. Der Fehler führt dazu, dass die Funktion mit den falschen Daten arbeitet.

Risiko

Falsche Argumentreihenfolge schafft erhebliche Risiken je nach Zweck der Funktion. Authentifizierungsfunktionen mit vertauschten Benutzername/Passwort-Parametern können mit falschen Anmeldedaten authentifizieren oder unangemessen fehlschlagen. Speicherfunktionen wie memcpy() mit vertauschter Quelle/Ziel können kritische Daten überschreiben. Sicherheitssensitive Funktionen mit umgekehrten Parametern können unbefugten Zugriff gewähren oder falsche Berechtigungen anwenden.

Lösung

Verwenden Sie Funktionen mit benannten Parametern, wenn die Sprache sie unterstützt. Ordnen Sie Funktionsparameter nach Wichtigkeit oder verwenden Sie Muster, die die Reihenfolge offensichtlich machen (Ziel vor Quelle oder alphabetisch). Dokumentieren Sie die Parameterreihenfolge klar und verwenden Sie aussagekräftige Parameternamen. Aktivieren Sie Compiler-Warnungen für Typunterschiede und implizite Konvertierungen. Verwenden Sie statische Analysetools, die Argumentreihenfolgeprobleme erkennen können. Erwägen Sie die Erstellung von Wrapper-Funktionen mit klareren Schnittstellen.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Authentifizierungs- oder Autorisierungsfunktionen mit vertauschten Parametern können unbefugten Zugriff gewähren.
IntegritätBereich: Integrität

Datenmodifikation - Operationen wie Kopieren oder Verschieben mit vertauschter Quelle/Ziel korrumpieren Daten.
SonstigesBereich: Sonstige

Qualitätsverschlechterung - Funktionen erzeugen falsche Ergebnisse, wenn sie mit falschen Parametern arbeiten.

Beispielcode und Lösung

Verwundbarer Code

<?php
// Verwundbar: Authentifizierungsfunktion mit umgekehrten Argumenten aufgerufen
function authenticate($username, $password) {
    $query = "SELECT * FROM users WHERE username = ? AND password = ?";
    $stmt = $db->prepare($query);
    $stmt->execute([$username, hash_password($password)]);
    return $stmt->fetch() !== false;
}

// VERWUNDBAR: Argumente umgekehrt - Benutzername und Passwort vertauscht!
$username = $_POST['username'];
$password = $_POST['password'];

if (authenticate($password, $username)) {  // FALSCHE REIHENFOLGE!
    // Versucht Benutzer nach Passwort zu finden, mit gehashem Benutzernamen
    login_user($username);
}
// Verwundbar: memcpy mit umgekehrter Quelle und Ziel
#include <string.h>

void verwundbar_kopieren(char* dest, const char* src, size_t len) {
    // VERWUNDBAR: Quelle und Ziel umgekehrt!
    memcpy(src, dest, len);  // Schreibt in Quelle (const), liest aus Ziel
    // Dies kann abstürzen oder Speicher korrumpieren
}

// Verwundbar: Berechtigungsprüfung mit vertauschtem Benutzer und Ressource
int prüfe_berechtigung(int user_id, int resource_id, int permission) {
    // Implementierung prüft alle drei Parameter
    return database_check(user_id, resource_id, permission);
}

void verwundbare_zugriffsprüfung() {
    int user = get_current_user();
    int resource = get_requested_resource();

    // VERWUNDBAR: user_id und resource_id vertauscht!
    if (prüfe_berechtigung(resource, user, PERM_READ)) {  // FALSCHE REIHENFOLGE!
        // Prüft ob 'resource' (als Benutzer) Berechtigung auf 'user' (als Ressource) hat
        // Völlig falsche Sicherheitsprüfung!
        grant_access();
    }
}
# Verwundbar: Funktion mit gleichtypigen Parametern
def erstelle_benutzer(username, email, role):
    """Erstellt Benutzer mit gegebenem Benutzernamen, E-Mail und Rolle."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [username, email, role]
    )

# Verwundbar: Mit Argumenten in falscher Reihenfolge aufgerufen
def registriere_neuen_benutzer():
    email = request.form['email']
    username = request.form['username']
    role = 'user'

    # VERWUNDBAR: E-Mail und Benutzername vertauscht!
    erstelle_benutzer(email, username, role)  # FALSCHE REIHENFOLGE!
    # Speichert E-Mail als Benutzername und Benutzername als E-Mail

Sichere Lösung

<?php
// Sicher: Benannte Parameter oder Wrapper mit Validierung verwenden
function authenticate(string $username, string $password): bool {
    // Validierung hinzufügen, um offensichtliche Vertauschungen zu erkennen
    if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            "Benutzername sieht aus wie E-Mail - Argumentreihenfolge prüfen");
    }

    $query = "SELECT * FROM users WHERE username = ? AND password = ?";
    $stmt = $db->prepare($query);
    $stmt->execute([$username, hash_password($password)]);
    return $stmt->fetch() !== false;
}

// Sicher: Benannte Parameter verwenden (PHP 8+)
$username = $_POST['username'];
$password = $_POST['password'];

if (authenticate(username: $username, password: $password)) {
    // Benannte Parameter machen Reihenfolge explizit
    login_user($username);
}
// Sicher: Klare Parameterbenennung und Dokumentation
#include <string.h>

/**
 * Daten sicher von Quelle zu Ziel kopieren.
 * @param dest Zielpuffer (muss mindestens len Bytes haben)
 * @param src Quelldaten zum Kopieren
 * @param len Anzahl der zu kopierenden Bytes
 */
void sichere_kopie(void* dest, const void* src, size_t len) {
    // Parameterreihenfolge entspricht Standardkonvention: dest, src, len
    if (dest == NULL || src == NULL) return;
    memcpy(dest, src, len);
}

// Sicher: Berechtigungsprüfung mit klaren Parametertypen
typedef struct {
    int id;
} UserId;

typedef struct {
    int id;
} ResourceId;

int prüfe_berechtigung(UserId user, ResourceId resource, int permission) {
    // Verschiedene Typen verhindern versehentliches Vertauschen
    return database_check(user.id, resource.id, permission);
}

void sichere_zugriffsprüfung() {
    UserId user = { .id = get_current_user() };
    ResourceId resource = { .id = get_requested_resource() };

    // Compiler würde bei Vertauschung wegen Typunstimmigkeit warnen
    if (prüfe_berechtigung(user, resource, PERM_READ)) {
        grant_access();
    }
}
# Sicher: Keyword-Argumente oder Dataclasses verwenden
from dataclasses import dataclass

@dataclass
class NeuerBenutzer:
    username: str
    email: str
    role: str = 'user'

def erstelle_benutzer_sicher(user: NeuerBenutzer):
    """Erstellt Benutzer aus strukturierten Daten."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [user.username, user.email, user.role]
    )

# Sicher: Kann Argumente mit Dataclass nicht vertauschen
def registriere_neuen_benutzer():
    user = NeuerBenutzer(
        username=request.form['username'],
        email=request.form['email'],
        role='user'
    )
    erstelle_benutzer_sicher(user)  # Einzelnes Argument - kein Reihenfolgeproblem

# Alternative: Immer Keyword-Argumente verwenden
def erstelle_benutzer_kwargs(*, username: str, email: str, role: str = 'user'):
    """Erstellt Benutzer. Nur-Keyword-Argumente verhindern Positionsfehler."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [username, email, role]
    )

# Verwendung - muss Keyword-Argumente verwenden
erstelle_benutzer_kwargs(username="hans", email="[email protected]", role="user")
# erstelle_benutzer_kwargs("hans", "[email protected]")  # Fehler! Keywords erforderlich

Ausgenutzt in der Praxis

OpenSSL Parameter-Vertauschung (2015)

Eine Schwachstelle in OpenSSL, bei der Parameter in einer Verschlüsselungsfunktion vertauscht wurden, führte zu unsicherer Verschlüsselung bei bestimmten Konfigurationen.

Microsoft Windows GDI Schwachstelle (2007)

Eine Windows-GDI-Schwachstelle entstand durch vertauschte Parameter in einer Bildverarbeitungsfunktion, was zu Speicherkorruption und potenzieller Code-Ausführung führte.


Tools zum Testen und Ausnutzen

  • Clang Static Analyzer — Erkennt Argumentreihenfolgeprobleme in C/C++.

  • SonarQube — Statisches Analysetool mit Argumentvalidierungsregeln.

  • Pylint — Python-Linter, der Argumentprobleme erkennt.


CVE-Beispiele

  • CVE-2006-7049 — Anwendung ruft Funktionen mit falscher Argumentreihenfolge auf, ermöglicht Umgehung von Zugriffsbeschränkungen.

Referenzen

  1. MITRE Corporation. "CWE-683: Function Call With Incorrect Order of Arguments." https://cwe.mitre.org/data/definitions/683.html

  2. CERT C Coding Standard. "EXP37-C: Call functions with the correct number and type of arguments." https://wiki.sei.cmu.edu/confluence/display/c/EXP37-C.+Call+functions+with+the+correct+number+and+type+of+arguments