Fehlerhafte Benutzerverwaltung

Beschreibung

Fehlerhafte Benutzerverwaltung ist eine Schwachstellenklasse, die auftritt, wenn ein Produkt Benutzer innerhalb seiner Umgebung nicht ordnungsgemäß verwaltet. Diese Schwäche manifestiert sich, wenn Benutzer falschen Berechtigungsgruppen zugewiesen werden, falsche Rollen erhalten oder ihre Gruppenmitgliedschaften falsch aufgezeichnet oder gewartet werden. Das Ergebnis ist, dass Benutzer unbeabsichtigte Zugriffsrechte auf sensible Objekte und Funktionalität erhalten. Anders als Autorisierungsumgehungsschwachstellen, die Zugriffskontrollen umgehen, betrifft diese Schwäche die fehlerhafte Zuweisung oder Verfolgung legitimer Benutzerattribute, die den Zugriff bestimmen.

Risiko

Fehlerhafte Benutzerverwaltung erzeugt Privilegieneskalationsrisiken, indem Benutzern Zugang über ihren beabsichtigten Umfang hinaus gewährt wird. Wenn Benutzer falschen Gruppen zugewiesen werden, können sie möglicherweise auf administrative Funktionen, sensible Daten oder privilegierte Operationen zugreifen. Container- und Virtualisierungsumgebungen, die ergänzende Gruppen-IDs nicht ordnungsgemäß aufzeichnen, können Benutzern ermöglichen, gruppenbasierte Beschränkungen zu umgehen. Betriebssysteme, die Benutzer fälschlicherweise privilegierten Gruppen wie wheel oder admin zuweisen, ermöglichen unbefugte Privilegienerhöhung. Das Risiko erstreckt sich auf Multi-Tenant-Umgebungen, wo fehlerhafte Benutzer-Tenant-Zuordnung Cross-Tenant-Daten offenlegen könnte. Automatisierte Benutzerbereitstellungssysteme, die Gruppenmitgliedschaften falsch konfigurieren, können weit verbreitete Zugangskontrollfehler erzeugen, die viele Benutzer gleichzeitig betreffen.

Lösung

Implementieren Sie robuste Benutzerverwaltungsprozesse mit Validierung aller Benutzerattributzuweisungen. Verifizieren Sie Gruppenmitgliedschaften und Rollenzuweisungen bevor Zugriff gewährt wird. Prüfen Sie Benutzer-Gruppen-Beziehungen regelmäßig, um Fehlkonfigurationen zu erkennen. Zeichnen Sie alle Benutzerattribute einschließlich ergänzender Gruppen-IDs auf und verfolgen Sie sie, um sicherzustellen, dass sie über Operationen hinweg ordnungsgemäß gewartet werden. Verwenden Sie rollenbasierte Zugriffskontrolle (RBAC) mit klar definierten Rollen und validieren Sie, dass Benutzer nur geeigneten Rollen zugewiesen werden. Implementieren Sie Genehmigungsworkflows für privilegierte Gruppenmitgliedschaften. Testen Sie Benutzerbereitstellungs- und Verwaltungsoperationen, um korrekte Gruppenzuweisungen sicherzustellen. Protokollieren Sie alle Benutzerattributänderungen für Sicherheitsüberwachung. Erwägen Sie die Implementierung von attributbasierter Zugriffskontrolle (ABAC) für granularere Benutzerverwaltung.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Benutzer, die falschen Gruppen zugewiesen werden oder falsch verwaltete Attribute haben, erlangen unbeabsichtigten Zugang zu sensiblen Ressourcen. Dies kann zu unbefugtem Datenzugriff, Privilegieneskalation und der Fähigkeit führen, Operationen durchzuführen, die anderen Benutzerklassen vorbehalten sind.

Beispielcode

Anfälliger Code (Python)

Die folgenden Beispiele demonstrieren fehlerhafte Benutzerverwaltung:

# Anfällig: Benutzerbereitstellung mit fehlerhafter Gruppenzuweisung
class VulnerableUserProvisioning:

    def create_user(self, username, department):
        user = User(username=username)

        # Anfällig: Logikfehler weist falsche Gruppe zu
        if department == "engineering":
            # Bug: Sollte "developers" sein, weist aber "admins" zu
            user.groups.add("admins")  # Falsche Gruppe!
        elif department == "finance":
            user.groups.add("finance")
        else:
            user.groups.add("users")

        user.save()
        return user

    def sync_user_from_ldap(self, ldap_entry):
        user = User(username=ldap_entry['cn'])

        # Anfällig: Synchronisiert keine ergänzenden Gruppen
        user.primary_group = ldap_entry['gidNumber']
        # Fehlend: Synchronisation ergänzender Gruppen
        # Benutzer verliert Gruppenmitgliedschaften während der Synchronisation

        user.save()

class VulnerableContainerRuntime:

    def start_container(self, user_config):
        # Anfällig: Erfasst ergänzende Gruppen-IDs nicht
        process = ContainerProcess()
        process.uid = user_config.uid
        process.gid = user_config.gid
        # Fehlend: process.supplementary_gids = user_config.groups
        # Container kann gruppenbasierte Beschränkungen umgehen

        process.start()
// Anfällig: Betriebssystem-Benutzerverwaltung
#include <grp.h>
#include <pwd.h>
#include <unistd.h>

int vulnerable_add_user_to_system(const char *username) {
    struct passwd *pw;

    // Benutzer erstellen
    pw = create_user(username);

    // Anfällig: Logikfehler fügt Benutzer zu privilegierter Gruppe hinzu
    // wenn er in regulärer Benutzergruppe sein sollte
    if (is_staff_member(username)) {
        // Bug: Sollte auf Admin-Rolle prüfen, nicht auf Mitarbeiter
        add_to_group(username, "wheel");  // Gewährt fälschlicherweise sudo-Zugriff
    }

    return 0;
}

int vulnerable_setgroups(uid_t uid) {
    // Anfällig: Setzt nur primäre Gruppe, verliert ergänzende Gruppen
    struct passwd *pw = getpwuid(uid);
    if (pw) {
        setgid(pw->pw_gid);
        // Fehlend: initgroups() oder setgroups() Aufruf
        // Benutzer verliert alle ergänzenden Gruppenmitgliedschaften
    }
    return 0;
}
// Anfällig: Java-Benutzerverwaltungsdienst
public class VulnerableUserService {

    public void provisionUser(UserRequest request) {
        User user = new User();
        user.setUsername(request.getUsername());

        // Anfällig: Rollenzuordnungsfehler
        if (request.getAccessLevel().equals("standard")) {
            // Bug: Tippfehler weist Standardbenutzern Admin-Rolle zu
            user.addRole(Role.ADMINISTRATOR);  // Sollte Role.STANDARD sein
        }

        userRepository.save(user);
    }

    public void importUsersFromCSV(List<String[]> userData) {
        for (String[] row : userData) {
            User user = new User();
            user.setUsername(row[0]);

            // Anfällig: Spaltenindexfehler
            // Nimmt an, row[1] ist Rolle, aber CSV hat Abteilung in row[1]
            user.addRole(Role.valueOf(row[1]));  // Falsche Spalte!

            userRepository.save(user);
        }
    }

    public void copyUserPermissions(User source, User target) {
        // Anfällig: Kopiert alle Gruppen einschließlich privilegierter
        target.setGroups(new HashSet<>(source.getGroups()));
        // Sollte admin/privilegierte Gruppen herausfiltern
        userRepository.save(target);
    }
}

Korrigierter Code (Python)

# Korrigiert: Benutzerbereitstellung mit validierter Gruppenzuweisung
class SecureUserProvisioning:

    # Definiert gültige Abteilung-zu-Gruppe-Zuordnungen
    DEPARTMENT_GROUPS = {
        "engineering": "developers",
        "finance": "finance",
        "hr": "hr",
        "it": "it_staff",
    }

    PRIVILEGED_GROUPS = {"admins", "wheel", "sudo", "root"}

    def create_user(self, username, department, created_by):
        user = User(username=username)

        # Korrigiert: Validierte Zuordnung verwenden
        if department not in self.DEPARTMENT_GROUPS:
            raise ValueError(f"Unbekannte Abteilung: {department}")

        target_group = self.DEPARTMENT_GROUPS[department]

        # Korrigiert: Versehentliche privilegierte Gruppenzuweisung verhindern
        if target_group in self.PRIVILEGED_GROUPS:
            raise SecurityError(
                f"Kann privilegierte Gruppe nicht automatisch zuweisen: {target_group}"
            )

        user.groups.add(target_group)
        user.save()

        # Audit-Protokoll
        self.audit_log.record(
            action='user_created',
            username=username,
            groups=list(user.groups),
            created_by=created_by.username
        )

        return user

    def sync_user_from_ldap(self, ldap_entry):
        user = User(username=ldap_entry['cn'])
        user.primary_group = ldap_entry['gidNumber']

        # Korrigiert: Ergänzende Gruppen synchronisieren
        if 'memberOf' in ldap_entry:
            for group_dn in ldap_entry['memberOf']:
                group_name = self.extract_group_name(group_dn)
                if self.is_allowed_group(group_name):
                    user.supplementary_groups.add(group_name)

        user.save()
        return user

class SecureContainerRuntime:

    def start_container(self, user_config):
        process = ContainerProcess()
        process.uid = user_config.uid
        process.gid = user_config.gid

        # Korrigiert: Alle ergänzenden Gruppen-IDs aufzeichnen
        process.supplementary_gids = list(user_config.groups)

        # Gruppenberechtigungen vor Start validieren
        self.validate_group_permissions(process)

        process.start()

        # Container-Start mit vollständigen Gruppeninformationen protokollieren
        self.audit_log.record(
            action='container_started',
            uid=process.uid,
            gid=process.gid,
            supplementary_gids=process.supplementary_gids
        )
// Korrigiert: Betriebssystem-Benutzerverwaltung
#include <grp.h>
#include <pwd.h>
#include <unistd.h>
#include <syslog.h>

// Definiert privilegierte Gruppen
const char *PRIVILEGED_GROUPS[] = {"wheel", "sudo", "admin", "root"};
const int NUM_PRIVILEGED = 4;

int is_privileged_group(const char *group) {
    for (int i = 0; i < NUM_PRIVILEGED; i++) {
        if (strcmp(group, PRIVILEGED_GROUPS[i]) == 0) {
            return 1;
        }
    }
    return 0;
}

int secure_add_user_to_system(const char *username, const char *role) {
    struct passwd *pw;

    pw = create_user(username);

    // Korrigiert: Explizite Rolle-zu-Gruppe-Zuordnung mit Validierung
    const char *target_group;

    if (strcmp(role, "admin") == 0) {
        // Nur explizite Admin-Rolle erhält wheel-Zugriff
        if (!is_authorized_to_create_admin(get_current_user())) {
            syslog(LOG_WARNING, "Unbefugter Admin-Erstellungsversuch: %s", username);
            return -1;
        }
        target_group = "wheel";
    } else if (strcmp(role, "developer") == 0) {
        target_group = "developers";
    } else {
        target_group = "users";
    }

    add_to_group(username, target_group);

    syslog(LOG_INFO, "Benutzer %s mit Gruppe %s erstellt", username, target_group);
    return 0;
}

int secure_setgroups_for_user(uid_t uid) {
    struct passwd *pw = getpwuid(uid);
    if (!pw) return -1;

    // Korrigiert: Alle Gruppen einschließlich ergänzender initialisieren
    if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
        return -1;
    }

    // Verifizieren, dass Gruppen gesetzt wurden
    gid_t groups[NGROUPS_MAX];
    int ngroups = getgroups(NGROUPS_MAX, groups);
    if (ngroups < 0) {
        return -1;
    }

    syslog(LOG_DEBUG, "%d Gruppen für Benutzer %s gesetzt", ngroups, pw->pw_name);
    return 0;
}
// Korrigiert: Java-Benutzerverwaltungsdienst
public class SecureUserService {

    private static final Set<Role> PRIVILEGED_ROLES =
        Set.of(Role.ADMINISTRATOR, Role.SUPER_ADMIN, Role.SECURITY_ADMIN);

    private static final Map<String, Role> ACCESS_LEVEL_MAPPING = Map.of(
        "standard", Role.STANDARD,
        "power_user", Role.POWER_USER,
        "analyst", Role.ANALYST
    );

    public void provisionUser(UserRequest request, User createdBy) {
        User user = new User();
        user.setUsername(request.getUsername());

        // Korrigiert: Validierte Zuordnung verwenden
        String accessLevel = request.getAccessLevel().toLowerCase();
        if (!ACCESS_LEVEL_MAPPING.containsKey(accessLevel)) {
            throw new IllegalArgumentException(
                "Unbekannte Zugangsstufe: " + accessLevel
            );
        }

        Role role = ACCESS_LEVEL_MAPPING.get(accessLevel);

        // Korrigiert: Privilegierte Rollenzuweisung über diesen Pfad blockieren
        if (PRIVILEGED_ROLES.contains(role)) {
            throw new SecurityException(
                "Privilegierte Rollen können nicht über Standardbereitstellung zugewiesen werden"
            );
        }

        user.addRole(role);
        userRepository.save(user);

        auditLog.record("user_provisioned", user, createdBy);
    }

    public void importUsersFromCSV(List<String[]> userData, User importedBy) {
        // Korrigiert: CSV-Struktur validieren
        String[] header = userData.get(0);
        int usernameCol = findColumn(header, "username");
        int roleCol = findColumn(header, "role");

        if (usernameCol < 0 || roleCol < 0) {
            throw new IllegalArgumentException(
                "CSV muss 'username' und 'role' Spalten haben"
            );
        }

        for (int i = 1; i < userData.size(); i++) {
            String[] row = userData.get(i);
            User user = new User();
            user.setUsername(row[usernameCol]);

            // Korrigiert: Rollenwert validieren
            String roleName = row[roleCol].toUpperCase();
            try {
                Role role = Role.valueOf(roleName);

                // Privilegierte Rollen im Massenimport blockieren
                if (PRIVILEGED_ROLES.contains(role)) {
                    logger.warn("Überspringe privilegierte Rolle im Import: " + roleName);
                    continue;
                }

                user.addRole(role);
            } catch (IllegalArgumentException e) {
                logger.error("Ungültige Rolle in CSV-Zeile " + i + ": " + roleName);
                continue;
            }

            userRepository.save(user);
        }
    }

    public void copyUserPermissions(User source, User target, User copiedBy) {
        // Korrigiert: Privilegierte Gruppen herausfiltern
        Set<String> safeGroups = source.getGroups().stream()
            .filter(g -> !isPrivilegedGroup(g))
            .collect(Collectors.toSet());

        target.setGroups(safeGroups);
        userRepository.save(target);

        auditLog.record("permissions_copied", source, target, safeGroups, copiedBy);
    }
}

Die Korrektur implementiert validierte Zuordnungen, verhindert versehentliche privilegierte Gruppenzuweisungen und wartet alle Benutzerattribute einschließlich ergänzender Gruppen ordnungsgemäß.


Ausgenutzt in der Praxis

Container-Gruppen-ID-Umgehung (Container-Plattformen, 2022)

CVE-2022-36109 dokumentierte ein Containerisierungsprodukt, das es versäumte, die ergänzende Gruppen-ID eines Benutzers aufzuzeichnen, was Benutzern ermöglichte, gruppenbasierte Beschränkungen innerhalb von Containern zu umgehen.

Unix Wheel-Gruppen-Fehlkonfiguration (Unix-Systeme, 1999)

CVE-1999-1193 dokumentierte ein Betriebssystem, das Benutzer fälschlicherweise der privilegierten wheel-Gruppe zuwies, was unbefugte Root-Privilegieneskalation durch su/sudo ermöglichte.

LDAP-Benutzersynchronisationsprobleme (Unternehmensumgebungen, Fortlaufend)

Organisationen, die LDAP-Synchronisation verwenden, haben Probleme erfahren, bei denen Gruppenmitgliedschaften nicht ordnungsgemäß synchronisiert wurden, was dazu führte, dass Benutzer entweder zu viel oder zu wenig Zugang hatten.


Tools zum Testen/Ausnutzen

  • BloodHound — Active Directory-Analysetool zur Identifikation von Benutzergruppen-Fehlkonfigurationen.

  • id/groups-Befehle — Unix-Tools zur Verifikation von Benutzergruppenmitgliedschaften.

  • ADRecon — Active Directory-Aufklärungstool zur Prüfung von Benutzerkonfigurationen.


CVE-Beispiele

  • CVE-2022-36109 — Containerisierungsprodukt versäumte es, ergänzende Gruppen-ID aufzuzeichnen, was Gruppenbeschränkungsumgehung ermöglichte.

  • CVE-1999-1193 — Betriebssystem wies Benutzer fälschlicherweise der privilegierten wheel-Gruppe zu.


Referenzen

  1. MITRE Corporation. "CWE-286: Incorrect User Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/286.html

  2. NIST. "Role-Based Access Control." https://csrc.nist.gov/projects/role-based-access-control

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