Unsachgemäße Eigentumsverwaltung

Beschreibung

Unsachgemäße Eigentumsverwaltung ist eine Schwachstellenklasse, die auftritt, wenn ein Produkt falsches Eigentum zuweist oder die ordnungsgemäße Eigentümerschaft von Objekten oder Ressourcen nicht verifiziert. Dies stellt einen grundlegenden Fehler der Zugangskontrolle dar, bei dem das System nicht zuverlässig feststellen kann, wer eine bestimmte Ressource legitimerweise kontrolliert. Die Schwäche kann sich manifestieren als Zuweisung von Dateien an falsche Benutzer, Versäumnis der Eigentümerschaftsverifikation vor destruktiven Operationen oder Akzeptanz von Konfigurationen aus Quellen, die nicht ordnungsgemäß als Eigentümer validiert wurden. Eigentumsverwaltung unterscheidet sich von Berechtigungsverwaltung - sie betrifft, wer eine Ressource kontrolliert, nicht welche Operationen erlaubt sind.

Risiko

Unsachgemäße Eigentumsverwaltung erzeugt erhebliche Privilegieneskalationsrisiken. Wenn Anwendungen die Eigentümerschaft nicht verifizieren, können Benutzer Operationen auf Ressourcen durchführen, die ihnen nicht gehören, und potenziell Daten anderer Benutzer zerstoren oder modifizieren. Setuid-Programme, die Konfigurationsdateien verwenden, die Nicht-Root-Benutzern gehören, erlauben diesen Benutzern, das Verhalten privilegierter Programme zu beeinflussen. Prozesse, die Prozesse anderer Benutzer ohne Eigentümerschaftsverifikation beenden, ermöglichen Denial-of-Service-Angriffe. Ressourcen-Eigentumskonfusion kann dazu führen, dass ein Benutzer Zugang zu den Privilegien, Daten oder Fähigkeiten eines anderen erhält. Das Risiko erstreckt sich auf Privilegieneskalation, wenn Angreifer die Eigentümerschaft manipulieren können, um Kontrolle über Systemressourcen zu erlangen.

Lösung

Verwalten Sie sorgfältig die Einstellung, Verwaltung und Handhabung der Ressourceneigentümerschaft während des gesamten Lebenszyklus. Verifizieren Sie immer die Eigentümerschaft, bevor Sie destruktive oder privilegierte Operationen auf Ressourcen erlauben. Setuid-Programme sollten nur Konfigurationsdateien verwenden, die Root gehören und restriktive Berechtigungen haben. Implementieren Sie Eigentümerschaftsprüfungen vor Prozesssignalen, Dateimodifikationen oder Ressourcenfreigaben. Etablieren und pflegen Sie explizit Vertrauenszonengrenzen basierend auf Eigentümerschaft. Beim Erstellen von Ressourcen weisen Sie die Eigentümerschaft sofort und atomar dem entsprechenden Prinzipal zu. Protokollieren Sie Eigentümeränderungen für Sicherheitsaudits. Verwenden Sie plattformbereitgestellte Eigentümerschaftsverifikations-APIs anstatt benutzerdefinierte Prüfungen zu implementieren. Erwägen Sie die Verwendung von fähigkeitsbasierter Sicherheit, bei der Eigentümerschaft kryptografisch verifiziert wird.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Ein Angreifer kann erhöhte Privilegien erlangen oder die Identität eines anderen Benutzers annehmen, indem er unsachgemäße Eigentumszuweisung ausnutzt. Operationen, die ohne Eigentümerschaftsverifikation durchgeführt werden, können Ressourcen anderer Benutzer betreffen, was zu unbefugter Datenmodifikation, -löschung oder Privilegieneskalation führt.

Beispielcode

Anfälliger Code (Python)

Die folgenden Beispiele demonstrieren unsachgemäße Eigentumsverwaltung:

# Anfällig: Prozessbeendigung ohne Eigentümerschaftsverifikation
import os
import signal

def vulnerable_kill_process(process_id):
    # Anfällig: Keine Verifikation, dass Benutzer den Prozess besitzt
    os.kill(process_id, signal.SIGKILL)
    # Jeder Benutzer kann jeden Prozess beenden!

def vulnerable_delete_user_file(file_path):
    # Anfällig: Keine Eigentümerschaftsprüfung
    os.remove(file_path)
    # Benutzer kann Dateien löschen, die ihm nicht gehören

class VulnerableResourceManager:

    def deallocate_resource(self, resource_id):
        # Anfällig: Keine Eigentümerschaftsverifikation
        resource = self.get_resource(resource_id)
        resource.deallocate()
        # Jeder Benutzer kann jede Ressource freigeben

    def modify_resource(self, resource_id, new_data):
        # Anfällig: Modifiziert ohne Eigentümerschaftsprüfung
        resource = self.get_resource(resource_id)
        resource.update(new_data)
// Anfällig: Setuid-Programm verwendet Nicht-Root-Konfigurationsdatei
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// Dies ist ein setuid root Programm
int vulnerable_setuid_program(void) {
    char config_path[256];
    char *home = getenv("HOME");

    // Anfällig: Verwendet Konfigurationsdatei aus Benutzer-Heimverzeichnis
    snprintf(config_path, sizeof(config_path), "%s/.myapp.conf", home);

    FILE *config = fopen(config_path, "r");
    if (config) {
        // Anfällig: Konfigurationsdatei gehört Nicht-Root-Benutzer
        // Benutzer kann privilegiertes Programmverhalten kontrollieren!
        parse_config(config);
        fclose(config);
    }

    // Führt privilegierte Operationen basierend auf benutzerkontrollierter Konfiguration aus
    do_privileged_operations();

    return 0;
}

// Anfällig: Keine Eigentümerschaftsprüfung vor Dateioperationen
int vulnerable_file_operation(const char *filepath, uid_t requesting_user) {
    // Anfällig: Verifiziert nicht, dass requesting_user die Datei besitzt
    int fd = open(filepath, O_RDWR);
    if (fd >= 0) {
        write(fd, "modified", 8);  // Modifiziert Datei, die Benutzer möglicherweise nicht besitzt
        close(fd);
    }
    return 0;
}
// Anfällig: Java-Ressourcenverwaltung ohne Eigentümerschaft
public class VulnerableResourceManager {

    public void deleteUserData(String userId, String dataId) {
        // Anfällig: Keine Verifikation, dass aktueller Benutzer der Eigentümer ist
        UserData data = userDataRepository.findById(dataId);
        userDataRepository.delete(data);
        // Jeder authentifizierte Benutzer kann Daten jedes Benutzers löschen
    }

    public void updateUserProfile(String targetUserId, ProfileData newData) {
        // Anfällig: Keine Eigentümerschaftsprüfung
        UserProfile profile = profileRepository.findByUserId(targetUserId);
        profile.update(newData);
        profileRepository.save(profile);
        // Benutzer kann Profile anderer Benutzer modifizieren
    }

    public void terminateUserSession(String sessionId) {
        // Anfällig: Kann Sitzungen beenden, die ihm nicht gehören
        Session session = sessionRepository.findById(sessionId);
        session.terminate();
        // Benutzer kann Sitzungen anderer Benutzer beenden
    }
}

Korrigierter Code (Python)

# Korrigiert: Prozessbeendigung mit Eigentümerschaftsverifikation
import os
import signal
import pwd

def get_process_owner(process_id):
    """Ermittelt die UID des Prozesseigentümers"""
    try:
        with open(f'/proc/{process_id}/status', 'r') as f:
            for line in f:
                if line.startswith('Uid:'):
                    # Reale UID ist der erste Wert
                    return int(line.split()[1])
    except (FileNotFoundError, PermissionError):
        return None
    return None

def secure_kill_process(process_id):
    """Beendet Prozess nur wenn im Besitz des aktuellen Benutzers"""
    current_user = os.getuid()
    process_owner = get_process_owner(process_id)

    if process_owner is None:
        raise ProcessNotFoundError(f"Prozess {process_id} nicht gefunden")

    if process_owner != current_user:
        raise PermissionError(
            f"Kann Prozess {process_id} nicht beenden: gehört UID {process_owner}"
        )

    os.kill(process_id, signal.SIGKILL)

def secure_delete_user_file(file_path, requesting_user):
    """Löscht Datei nur wenn im Besitz des anfragenden Benutzers"""
    try:
        file_stat = os.stat(file_path)
    except FileNotFoundError:
        raise FileNotFoundError(f"Datei nicht gefunden: {file_path}")

    if file_stat.st_uid != requesting_user:
        raise PermissionError(
            f"Kann {file_path} nicht löschen: nicht im Besitz des anfragenden Benutzers"
        )

    os.remove(file_path)

class SecureResourceManager:

    def deallocate_resource(self, resource_id, requesting_user):
        """Gibt Ressource nur frei wenn im Besitz des anfragenden Benutzers"""
        resource = self.get_resource(resource_id)

        if resource.owner_id != requesting_user.id:
            raise PermissionError(
                f"Benutzer {requesting_user.id} besitzt Ressource {resource_id} nicht"
            )

        resource.deallocate()
        self.audit_log.record('resource_deallocated', resource_id, requesting_user.id)

    def modify_resource(self, resource_id, new_data, requesting_user):
        """Modifiziert Ressource nur nach Eigentümerschaftsverifikation"""
        resource = self.get_resource(resource_id)

        if resource.owner_id != requesting_user.id:
            raise PermissionError(
                f"Benutzer {requesting_user.id} kann Ressource {resource_id} nicht modifizieren"
            )

        resource.update(new_data)
        self.audit_log.record('resource_modified', resource_id, requesting_user.id)
// Korrigiert: Setuid-Programm mit ordnungsgemäßer Konfigurationseigentümerschaft
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>

// Korrigiert: Verwendet nur Root-eigene Konfiguration
int secure_setuid_program(void) {
    const char *config_path = "/etc/myapp/config.conf";

    // Verifiziert Konfigurationsdatei-Eigentümerschaft vor Verwendung
    struct stat config_stat;
    if (stat(config_path, &config_stat) != 0) {
        fprintf(stderr, "Kann Konfigurationsdatei nicht abrufen\n");
        return -1;
    }

    // Korrigiert: Konfiguration muss Root gehören
    if (config_stat.st_uid != 0) {
        fprintf(stderr, "SICHERHEIT: Konfigurationsdatei gehört nicht Root\n");
        return -1;
    }

    // Korrigiert: Konfiguration darf nicht von anderen schreibbar sein
    if (config_stat.st_mode & (S_IWGRP | S_IWOTH)) {
        fprintf(stderr, "SICHERHEIT: Konfigurationsdatei hat unsichere Berechtigungen\n");
        return -1;
    }

    FILE *config = fopen(config_path, "r");
    if (config) {
        parse_config(config);
        fclose(config);
    }

    do_privileged_operations();
    return 0;
}

// Korrigiert: Verifiziert Eigentümerschaft vor Dateioperationen
int secure_file_operation(const char *filepath, uid_t requesting_user) {
    struct stat file_stat;

    if (stat(filepath, &file_stat) != 0) {
        return -1;
    }

    // Eigentümerschaft verifizieren
    if (file_stat.st_uid != requesting_user) {
        fprintf(stderr, "Benutzer %d besitzt Datei %s nicht (gehört %d)\n",
                requesting_user, filepath, file_stat.st_uid);
        return -1;
    }

    int fd = open(filepath, O_RDWR);
    if (fd >= 0) {
        write(fd, "modified", 8);
        close(fd);
    }

    return 0;
}
// Korrigiert: Java-Ressourcenverwaltung mit Eigentümerschaftsverifikation
public class SecureResourceManager {

    public void deleteUserData(User currentUser, String dataId) {
        UserData data = userDataRepository.findById(dataId)
            .orElseThrow(() -> new ResourceNotFoundException(dataId));

        // Korrigiert: Eigentümerschaft vor Löschung verifizieren
        if (!data.getOwnerId().equals(currentUser.getId())) {
            auditLog.logUnauthorizedAccess(currentUser, "delete", dataId);
            throw new UnauthorizedAccessException(
                "Benutzer besitzt diese Daten nicht"
            );
        }

        userDataRepository.delete(data);
        auditLog.logResourceDeleted(currentUser, dataId);
    }

    public void updateUserProfile(User currentUser, String targetUserId, ProfileData newData) {
        // Korrigiert: Kann nur eigenes Profil aktualisieren
        if (!currentUser.getId().equals(targetUserId)) {
            auditLog.logUnauthorizedAccess(currentUser, "update_profile", targetUserId);
            throw new UnauthorizedAccessException(
                "Kann Profil eines anderen Benutzers nicht modifizieren"
            );
        }

        UserProfile profile = profileRepository.findByUserId(targetUserId)
            .orElseThrow(() -> new ProfileNotFoundException(targetUserId));

        profile.update(newData);
        profileRepository.save(profile);
        auditLog.logProfileUpdated(currentUser);
    }

    public void terminateUserSession(User currentUser, String sessionId) {
        Session session = sessionRepository.findById(sessionId)
            .orElseThrow(() -> new SessionNotFoundException(sessionId));

        // Korrigiert: Sitzungseigentümerschaft verifizieren
        if (!session.getUserId().equals(currentUser.getId())) {
            // Admin-Überschreibungsprüfung
            if (!currentUser.hasRole(Role.ADMIN)) {
                auditLog.logUnauthorizedAccess(currentUser, "terminate_session", sessionId);
                throw new UnauthorizedAccessException(
                    "Kann Sitzung eines anderen Benutzers nicht beenden"
                );
            }
            auditLog.logAdminSessionTermination(currentUser, session.getUserId(), sessionId);
        }

        session.terminate();
    }
}

Die Korrektur verifiziert die Eigentümerschaft, bevor destruktive oder modifizierende Operationen auf Ressourcen erlaubt werden.


Ausgenutzt in der Praxis

Setuid-Konfigurationsausnutzung (Unix-Systeme, Historisch)

CVE-1999-1125 dokumentierte ein setuid root Programm, das auf Konfigurationsdateien angewiesen war, die Nicht-Root-Benutzern gehörten, was Privilegieneskalation durch Modifikation der Konfiguration ermöglichte, um das Verhalten privilegierter Programme zu beeinflussen.

Prozessbeendigungsschwachstellen (Verschiedene Systeme, Fortlaufend)

Anwendungen, die Prozesse ohne Eigentümerschaftsverifikation beenden, haben Denial-of-Service-Angriffe ermöglicht, bei denen Benutzer Prozesse anderer Benutzer oder kritische Systemdienste beenden.

Multi-Tenant-Ressourcenzugriff (Cloud-Anwendungen, Fortlaufend)

Cloud-Anwendungen, die die Ressourceneigentümerschaft nicht verifizierten, haben Cross-Tenant-Angriffe ermöglicht, bei denen ein Kunde auf Ressourcen eines anderen Kunden zugreifen, diese modifizieren oder löschen könnte.


Tools zum Testen/Ausnutzen

  • ps/top — Prozesslistentools zur Identifikation der Prozesseigentümerschaft.

  • stat — Dateistatustool zur Prüfung der Dateieigentümerschaft.

  • Application security scanners — Tools zur Identifikation von Eigentümerschaftsverifikationslücken.


CVE-Beispiele

  • CVE-1999-1125 — Setuid root Programm verließ sich auf Konfigurationsdateien, die Nicht-Root-Benutzern gehörten, was Privilegieneskalation ermöglichte.

Referenzen

  1. MITRE Corporation. "CWE-282: Improper Ownership Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/282.html

  2. OWASP Foundation. "Broken Access Control." OWASP Top 10. https://owasp.org/Top10/A01_2021-Broken_Access_Control/

  3. CERT C Secure Coding Standard. "FIO15-C. Ensure that file operations are performed in a secure directory." https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C