Unsachgemäße Initialisierung

Beschreibung

Unsachgemäße Initialisierung tritt auf, wenn eine Anwendung kritische Variablen, Datenstrukturen oder Ressourcen vor der Verwendung nicht ordnungsgemäß initialisiert. Dies umfasst das Versäumnis, Speicherallokationen zu initialisieren, keine Standardwerte für sicherheitskritische Variablen zu setzen, Datenstrukturen nur teilweise zu initialisieren oder sich auf undefinierte Anfangswerte zu verlassen. Die resultierenden undefinierten oder angreiferkontrollierten Werte können zu Sicherheitslücken führen.

Risiko

Sicherheitskritische Flags können standardmäßig auf "erlaubt" stehen. Nicht initialisierte Pointer verursachen Abstürze oder beliebigen Speicherzugriff. Sensible Daten aus vorherigen Operationen werden im Speicher exponiert. Authentifizierungsvariablen können Prüfungen umgehen, wenn sie nicht ordnungsgemäß initialisiert werden. Kryptographische Schlüssel können schwach oder vorhersehbar sein. Pufferinhalte können Informationen an Angreifer preisgeben.

Lösung

Initialisieren Sie alle Variablen immer explizit. Verwenden Sie Sprachfunktionen, die Initialisierung erzwingen. Initialisieren Sie sicherheitskritische Variablen auf sichere Standardwerte (standardmäßig verweigern). Verwenden Sie Konstruktoren und Initialisierungslisten. Leeren Sie Speicherallokationen vor der Verwendung. Implementieren Sie statische Analyse zur Erkennung nicht initialisierter Variablen.

Häufige Konsequenzen

AuswirkungDetails
VertraulichkeitBereich: Informationsoffenlegung

Nicht initialisierter Speicher kann sensible Daten enthalten.
AutorisierungBereich: Zugriffskontrollumgehung

Nicht initialisierte Flags können standardmäßig "erlauben" sein.
VerfügbarkeitBereich: Abstürze

Nicht initialisierte Pointer verursachen Abstürze.

Beispielcode + Lösungscode

Verwundbarer Code

// VERWUNDBAR: Nicht initialisierte Variablen in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// VERWUNDBAR: Nicht initialisiertes Sicherheits-Flag
int check_access_vulnerable(int user_id) {
    int is_admin;  // VERWUNDBAR: Nicht initialisiert

    if (user_id == ADMIN_USER_ID) {
        is_admin = 1;
    }
    // VERWUNDBAR: is_admin nicht initialisiert wenn nicht Admin
    // Stack-Müll könnte ungleich Null sein!

    return is_admin;  // Könnte Müllwert zurückgeben und Zugriff erlauben
}

// VERWUNDBAR: Nicht initialisierter Puffer
void send_response_vulnerable(int socket) {
    char buffer[1024];  // VERWUNDBAR: Enthält Stack-Müll

    // Nur teilweise gefüllt
    strcpy(buffer, "Response: OK");

    // VERWUNDBAR: Sendet alle 1024 Bytes inklusive nicht initialisierter Daten
    send(socket, buffer, sizeof(buffer), 0);
}

// VERWUNDBAR: Nicht initialisierte Struktur
typedef struct {
    char* username;
    char* password;
    int permissions;
    int is_authenticated;
} UserSession;

UserSession* create_session_vulnerable() {
    // VERWUNDBAR: malloc initialisiert Speicher nicht
    UserSession* session = malloc(sizeof(UserSession));

    // Vergessen alle Felder zu initialisieren
    session->username = "guest";
    // VERWUNDBAR: password, permissions, is_authenticated nicht initialisiert!

    return session;
}

// VERWUNDBAR: Teilweise initialisiertes Array
void process_data_vulnerable() {
    int data[100];  // VERWUNDBAR: Nicht initialisiert

    // Nur einige Elemente gesetzt
    for (int i = 0; i < 50; i++) {
        data[i] = i;
    }

    // VERWUNDBAR: Verwendung nicht initialisierter Elemente
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        sum += data[i];  // data[50-99] sind Müll
    }
}

// VERWUNDBAR: Nicht initialisierter Pointer
void use_pointer_vulnerable() {
    char* ptr;  // VERWUNDBAR: Nicht initialisiert

    if (some_condition) {
        ptr = get_data();
    }

    // VERWUNDBAR: ptr könnte nicht initialisiert sein
    printf("%s\n", ptr);  // Absturz oder beliebiges Lesen
}
# VERWUNDBAR: Python-Initialisierungsprobleme
class VulnerableUser:
    # VERWUNDBAR: Instanzvariablen nicht in __init__ initialisiert

    def authenticate(self, username, password):
        if check_credentials(username, password):
            self.is_authenticated = True
            self.username = username

    def check_permission(self, resource):
        # VERWUNDBAR: is_authenticated existiert möglicherweise nicht
        if self.is_authenticated:  # AttributeError wenn authenticate nicht aufgerufen
            return True
        return False

# VERWUNDBAR: Bedingte Initialisierung
def process_request_vulnerable(request):
    result = None  # Teilweise Initialisierung

    if request.type == 'A':
        result = handle_type_a(request)
    elif request.type == 'B':
        result = handle_type_b(request)
    # VERWUNDBAR: Wenn Typ 'C' ist, ist result None

    # VERWUNDBAR: Nimmt an, dass result immer gültig ist
    return result.data  # AttributeError wenn result None ist

# VERWUNDBAR: Dictionary ohne Standardwerte
def get_config_vulnerable():
    config = {}

    if os.path.exists('config.json'):
        config = json.load(open('config.json'))

    # VERWUNDBAR: Nimmt an, dass Schlüssel existieren
    db_host = config['database']['host']  # KeyError wenn nicht in Datei
    return db_host

# VERWUNDBAR: Klasse ohne ordnungsgemäße Standardwerte
class VulnerableSession:
    def __init__(self):
        # VERWUNDBAR: Sicherheitskritische Felder nicht initialisiert
        pass

    def set_user(self, user):
        self.user = user
        self.permissions = user.permissions

    def can_access(self, resource):
        # VERWUNDBAR: permissions existiert möglicherweise nicht
        return resource in self.permissions
// VERWUNDBAR: Java-Initialisierungsprobleme
public class VulnerableInitialization {

    // VERWUNDBAR: Instanzfeld nicht initialisiert
    private Boolean isAdmin;  // null standardmäßig

    public boolean checkAccess() {
        // VERWUNDBAR: NPE wenn isAdmin nie gesetzt
        return isAdmin;  // Auto-Unboxing von null wirft NPE
    }

    // VERWUNDBAR: Array nicht ordnungsgemäß initialisiert
    private int[] permissions;

    public void setPermission(int index, int value) {
        // VERWUNDBAR: permissions-Array könnte null sein
        permissions[index] = value;  // NPE
    }

    // VERWUNDBAR: Teilweise Initialisierung im Konstruktor
    private String username;
    private String password;
    private int accessLevel;

    public VulnerableInitialization(String user) {
        this.username = user;
        // VERWUNDBAR: password und accessLevel nicht initialisiert
        // accessLevel ist standardmäßig 0, was Zugriff gewähren könnte!
    }

    // VERWUNDBAR: Bedingte Initialisierung
    private Connection dbConnection;

    public void connect(boolean useSSL) {
        if (useSSL) {
            dbConnection = createSSLConnection();
        }
        // VERWUNDBAR: dbConnection null wenn useSSL false
    }

    public void query(String sql) {
        // VERWUNDBAR: NPE wenn connect mit false aufgerufen wurde
        dbConnection.execute(sql);
    }
}

// VERWUNDBAR: Builder ohne Prüfung erforderlicher Felder
public class VulnerableBuilder {
    private String apiKey;
    private String endpoint;
    private Integer timeout;

    public VulnerableBuilder apiKey(String key) {
        this.apiKey = key;
        return this;
    }

    public APIClient build() {
        // VERWUNDBAR: Prüft nicht, ob erforderliche Felder gesetzt sind
        return new APIClient(apiKey, endpoint, timeout);
    }
}
// VERWUNDBAR: JavaScript-Initialisierungsprobleme
class VulnerableService {
    constructor() {
        // VERWUNDBAR: Keine Initialisierung kritischer Felder
    }

    // VERWUNDBAR: Feld möglicherweise nicht initialisiert
    async processRequest(req) {
        // VERWUNDBAR: this.config könnte undefined sein
        const endpoint = this.config.apiEndpoint;
        return fetch(endpoint);
    }

    // VERWUNDBAR: Bedingte Initialisierung
    initialize(options) {
        if (options.debug) {
            this.logger = new Logger();
        }
        // VERWUNDBAR: logger undefined wenn nicht Debug-Modus
    }

    log(message) {
        // VERWUNDBAR: TypeError wenn logger nicht initialisiert
        this.logger.write(message);
    }
}

// VERWUNDBAR: Objekt ohne Standardwerte
function createUser(data) {
    const user = {
        name: data.name
        // VERWUNDBAR: Fehlende role, permissions, etc.
    };

    // VERWUNDBAR: Nimmt an, alle Eigenschaften existieren
    if (user.role === 'admin') {  // undefined, nie wahr
        // Aber auch nie ordnungsgemäß verweigert
    }

    return user;
}

// VERWUNDBAR: Array-Element-Zugriff ohne Initialisierung
function processItems(count) {
    const items = new Array(count);  // Erstellt sparse Array

    // VERWUNDBAR: Elemente sind undefined
    for (let i = 0; i < count; i++) {
        // items[i] ist undefined!
        console.log(items[i].value);  // TypeError
    }
}

Lösungscode

// SICHER: Ordnungsgemäße Initialisierung in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// SICHER: Auf sicheren Standardwert initialisieren
int check_access_safe(int user_id) {
    int is_admin = 0;  // SICHER: Standard auf Verweigern

    if (user_id == ADMIN_USER_ID) {
        is_admin = 1;
    }

    return is_admin;
}

// SICHER: Puffer mit Null initialisieren
void send_response_safe(int socket) {
    char buffer[1024] = {0};  // SICHER: Null-initialisiert

    // Oder memset verwenden
    // char buffer[1024];
    // memset(buffer, 0, sizeof(buffer));

    strcpy(buffer, "Response: OK");

    // SICHER: Nur tatsächliche Datenlänge senden
    send(socket, buffer, strlen(buffer), 0);
}

// SICHER: Vollständig initialisierte Struktur
UserSession* create_session_safe() {
    // SICHER: calloc initialisiert Speicher mit Null
    UserSession* session = calloc(1, sizeof(UserSession));
    if (!session) return NULL;

    // SICHER: Explizite Initialisierung aller Felder
    session->username = NULL;
    session->password = NULL;
    session->permissions = 0;
    session->is_authenticated = 0;  // Standard auf nicht authentifiziert

    return session;
}

// SICHER: Initialisierungsfunktion verwenden
void init_session(UserSession* session) {
    memset(session, 0, sizeof(UserSession));
    session->permissions = DEFAULT_PERMISSIONS;
}

// SICHER: Vollständig initialisiertes Array
void process_data_safe() {
    int data[100] = {0};  // SICHER: Alle Elemente Null

    for (int i = 0; i < 50; i++) {
        data[i] = i;
    }

    // SICHER: Alle Elemente haben bekannte Werte
    int sum = 0;
    for (int i = 0; i < 100; i++) {
        sum += data[i];
    }
}

// SICHER: Pointer auf NULL initialisieren
void use_pointer_safe() {
    char* ptr = NULL;  // SICHER: Auf NULL initialisiert

    if (some_condition) {
        ptr = get_data();
    }

    // SICHER: NULL-Prüfung vor Verwendung
    if (ptr != NULL) {
        printf("%s\n", ptr);
    }
}
# SICHER: Python mit ordnungsgemäßer Initialisierung
class SafeUser:
    def __init__(self):
        # SICHER: Alle Attribute mit sicheren Standardwerten initialisieren
        self.is_authenticated = False
        self.username = None
        self.permissions = []

    def authenticate(self, username, password):
        if check_credentials(username, password):
            self.is_authenticated = True
            self.username = username
            self.permissions = get_user_permissions(username)

    def check_permission(self, resource):
        # SICHER: is_authenticated existiert immer
        if self.is_authenticated:
            return resource in self.permissions
        return False

# SICHER: Dataclasses für garantierte Initialisierung verwenden
from dataclasses import dataclass, field
from typing import List, Optional

@dataclass
class SafeSession:
    username: str
    is_authenticated: bool = False
    permissions: List[str] = field(default_factory=list)
    access_level: int = 0

# SICHER: Dictionary mit Standardwerten
def get_config_safe():
    default_config = {
        'database': {
            'host': 'localhost',
            'port': 5432
        },
        'debug': False
    }

    config = default_config.copy()

    if os.path.exists('config.json'):
        with open('config.json') as f:
            loaded = json.load(f)
            # SICHER: Mit Standardwerten zusammenführen
            deep_merge(config, loaded)

    return config

# SICHER: get() mit Standardwerten verwenden
def process_request_safe(request):
    handlers = {
        'A': handle_type_a,
        'B': handle_type_b,
    }

    # SICHER: Standard-Handler wenn Typ nicht gefunden
    handler = handlers.get(request.type, handle_unknown)
    result = handler(request)

    # SICHER: Ergebnis vor Verwendung prüfen
    if result and hasattr(result, 'data'):
        return result.data
    return None
// SICHER: Java mit ordnungsgemäßer Initialisierung
public class SafeInitialization {

    // SICHER: Mit sicherem Standardwert initialisieren
    private boolean isAdmin = false;

    public boolean checkAccess() {
        return isAdmin;  // Keine NPE, standardmäßig immer false
    }

    // SICHER: Array initialisieren
    private int[] permissions = new int[10];  // Mit Nullen initialisiert

    public void setPermission(int index, int value) {
        if (index >= 0 && index < permissions.length) {
            permissions[index] = value;
        }
    }

    // SICHER: Vollständige Initialisierung im Konstruktor
    private final String username;
    private final String password;
    private final int accessLevel;

    public SafeInitialization(String user, String pass, int level) {
        this.username = Objects.requireNonNull(user, "Username erforderlich");
        this.password = pass != null ? pass : "";
        this.accessLevel = level;
    }

    // SICHER: Optional für nullable Felder verwenden
    private Optional<Connection> dbConnection = Optional.empty();

    public void connect(boolean useSSL) {
        if (useSSL) {
            dbConnection = Optional.of(createSSLConnection());
        } else {
            dbConnection = Optional.of(createConnection());
        }
    }

    public void query(String sql) {
        // SICHER: Explizite Behandlung des nicht initialisierten Zustands
        dbConnection.orElseThrow(() ->
            new IllegalStateException("Nicht verbunden")
        ).execute(sql);
    }
}

// SICHER: Builder mit Validierung
public class SafeBuilder {
    private String apiKey;
    private String endpoint;
    private Integer timeout = 30000;  // Standardwert

    public SafeBuilder apiKey(String key) {
        this.apiKey = key;
        return this;
    }

    public SafeBuilder endpoint(String url) {
        this.endpoint = url;
        return this;
    }

    public APIClient build() {
        // SICHER: Erforderliche Felder validieren
        Objects.requireNonNull(apiKey, "API-Schlüssel erforderlich");
        Objects.requireNonNull(endpoint, "Endpoint erforderlich");

        return new APIClient(apiKey, endpoint, timeout);
    }
}
// SICHER: JavaScript mit ordnungsgemäßer Initialisierung
class SafeService {
    constructor(config = {}) {
        // SICHER: Mit Standardwerten initialisieren
        this.config = {
            apiEndpoint: 'https://api.default.com',
            timeout: 5000,
            retries: 3,
            ...config  // Mit bereitgestellter Konfiguration überschreiben
        };

        this.logger = config.debug ? new Logger() : new NullLogger();
        this.initialized = true;
    }

    async processRequest(req) {
        // SICHER: config ist immer initialisiert
        const endpoint = this.config.apiEndpoint;
        return fetch(endpoint);
    }

    log(message) {
        // SICHER: logger ist immer initialisiert (möglicherweise NullLogger)
        this.logger.write(message);
    }
}

// SICHER: Objekt mit allen erforderlichen Standardwerten
function createUser(data) {
    const user = {
        name: data.name || 'Unbekannt',
        email: data.email || null,
        role: data.role || 'guest',
        permissions: data.permissions || [],
        isActive: data.isActive ?? true,
        createdAt: new Date()
    };

    // SICHER: role ist immer definiert
    if (user.role === 'admin') {
        user.permissions.push('admin:*');
    }

    return user;
}

// SICHER: Array ordnungsgemäß initialisiert
function processItems(count) {
    // SICHER: Array.from erstellt ordnungsgemäß initialisiertes Array
    const items = Array.from({ length: count }, (_, i) => ({
        id: i,
        value: 0,
        processed: false
    }));

    for (const item of items) {
        console.log(item.value);  // Sicherer Zugriff
    }

    return items;
}

// SICHER: Nullish Coalescing und Optional Chaining verwenden
function getConfig(options) {
    return {
        host: options?.database?.host ?? 'localhost',
        port: options?.database?.port ?? 5432,
        ssl: options?.database?.ssl ?? false
    };
}

Ausgenutzt in der Praxis

Privilegieneskalation

Nicht initialisierte isAdmin-Flags, die standardmäßig auf true stehen.

Informationsoffenlegung

Nicht initialisierte Puffer, die Speicherinhalte preisgeben.

Denial of Service

Null Pointer-Dereferenzierungen durch nicht initialisierte Pointer.


Werkzeuge zum Testen/Ausnutzen

  • Speicher-Sanitizer (MSan für nicht initialisierte Lesevorgänge).

  • Statische Analysatoren (Coverity, PVS-Studio).

  • Compiler-Warnungen (-Wuninitialized).


CVE-Beispiele

  • CVE-2019-14899: Nicht initialisierte Speicheroffenlegung im Linux-Kernel.

  • CVE-2020-14386: Ausnutzung nicht initialisierter Stack-Variable.


Referenzen

  1. MITRE. "CWE-665: Improper Initialization." https://cwe.mitre.org/data/definitions/665.html

  2. CERT C: Variablen vor Verwendung initialisieren.