Einordnung eines Benutzers in eine falsche Gruppe

Beschreibung

Einordnung eines Benutzers in eine falsche Gruppe ist eine Zugriffskontroll-Schwachstelle, bei der ein Produkt oder Administrator einen Benutzer einer Gruppe mit mehr Privilegien als beabsichtigt zuweist. Wenn Benutzer in Gruppen platziert werden, die größere Zugriffsrechte haben als sie sollten, können sie Sicherheitsrichtlinien umgehen, auf unautorisierte Ressourcen zugreifen und Aktionen ausführen, die über ihre beabsichtigte Autorisierungsstufe hinausgehen. Dies kann durch automatisierte Systeme auftreten, die Gruppenmitgliedschaften falsch zuweisen, Konfigurationsfehler oder Fehler in der Benutzerverwaltungslogik.

Risiko

Diese Schwachstelle führt direkt zu Privilegieneskalation. Benutzer, die überprivilegierten Gruppen zugewiesen werden, können auf sensible Daten zugreifen, kritische Systemkonfigurationen ändern, administrative Funktionen ausführen oder ihre Privilegien weiter eskalieren. Das Risiko ist besonders schwerwiegend, wenn Benutzer administrativen oder Root-Level-Gruppen zugewiesen werden, da dies nahezu unbegrenzten Systemzugriff gewährt. In Unternehmensumgebungen kann falsche Gruppenplatzierung Compliance-Anforderungen verletzen, vertrauliche Daten offenlegen und Audit-Trail-Lücken erzeugen. Das Problem kann über längere Zeiträume unentdeckt bleiben, da der Benutzer scheinbar legitimen Zugriff hat.

Lösung

Implementieren Sie strenge Gruppenzuweisungsvalidierung, die die Angemessenheit von Gruppenmitgliedschaften vor deren Anwendung verifiziert. Verwenden Sie das Prinzip der minimalen Privilegien - weisen Sie Benutzern die minimalen Gruppen zu, die für ihre Rolle notwendig sind. Implementieren Sie Genehmigungsworkflows für privilegierte Gruppenzuweisungen. Auditieren Sie regelmäßig Gruppenmitgliedschaften, um unangemessene Zuweisungen zu erkennen und zu korrigieren. Verwenden Sie rollenbasierte Zugriffskontrolle (RBAC) mit klar definierten Rolle-zu-Gruppe-Zuordnungen. Stellen Sie ordnungsgemäße Bereinigung von Gruppenmitgliedschaften sicher, wenn Benutzer Rollen wechseln oder die Organisation verlassen. Validieren Sie Konfigurationsoptionen, die Gruppenmitgliedschaften beeinflussen. Weisen Sie niemals Benutzer privilegierten Gruppen (wheel, admin, root) ohne explizite Verifizierung zu.

Häufige Auswirkungen

AuswirkungDetails
ZugriffskontrolleBereich: Zugriffskontrolle

Privilegien erlangen oder Identität annehmen - Benutzer erlangen Privilegien über ihre beabsichtigte Autorisierungsstufe hinaus durch falsche Gruppenmitgliedschaft.
VertraulichkeitBereich: Vertraulichkeit

Anwendungsdaten lesen - Falsche Gruppenplatzierung kann Zugriff auf sensible Daten gewähren, die der Benutzer nicht sehen sollte.
IntegritätBereich: Integrität

Anwendungsdaten modifizieren - Benutzer in privilegierten Gruppen können Daten oder Konfigurationen über ihre Befugnis hinaus modifizieren.

Beispielcode

Anfälliger Code

# Anfällig: Automatische Gruppenzuweisung ohne Validierung
class VulnerableUserManager:

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

        # Anfällig: Automatische Gruppenzuweisung basierend auf Abteilung
        # Keine Validierung, ob dies angemessen ist
        if 'IT' in department:
            # Anfällig: Alle IT-Mitarbeiter erhalten Admin-Gruppe
            user.groups.add(Group.objects.get(name='administrators'))

        if 'Finance' in department:
            user.groups.add(Group.objects.get(name='financial_data'))

        return user

    def update_user_department(self, user, new_department):
        # Anfällig: Gruppen werden bei Abteilungswechsel nicht bereinigt
        # Benutzer akkumuliert Privilegien aus allen früheren Abteilungen
        user.department = new_department

        if 'IT' in new_department:
            user.groups.add(Group.objects.get(name='administrators'))

        user.save()
// Anfällig: Gruppenzuweisung aus nicht vertrauenswürdiger Quelle
public class VulnerableUserService {

    public void processUserRegistration(HttpServletRequest request) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // Anfällig: Gruppe aus Request-Parameter
        String requestedGroup = request.getParameter("group");

        User user = new User(username, hashPassword(password));

        // Anfällig: Keine Validierung der Gruppenzuweisung
        if (requestedGroup != null) {
            Group group = groupRepository.findByName(requestedGroup);
            if (group != null) {
                user.addGroup(group);  // Benutzer kann jede Gruppe anfordern!
            }
        }

        userRepository.save(user);
    }
}

// Angreifer setzt group=administrators um Admin zu werden
// Anfällig: Standard-Gruppenzuweisung ist zu privilegiert
<?php
class VulnerableAccountCreator {

    const DEFAULT_GROUP = 'power_users';  // Anfällig: Überprivilegierter Standard

    public function createAccount($email, $password) {
        $user = new User();
        $user->email = $email;
        $user->password = password_hash($password, PASSWORD_BCRYPT);

        // Anfällig: Alle neuen Benutzer erhalten power_users-Gruppe
        $user->group = self::DEFAULT_GROUP;

        $user->save();
        return $user;
    }
}
?>
// Anfällig: Daemon löscht Gruppen nicht vor Privilegienabsenkung
#include <unistd.h>
#include <grp.h>

void vulnerable_drop_privileges(uid_t target_uid, gid_t target_gid) {
    // Anfällig: Setzt nur primäre GID, supplementäre Gruppen bleiben
    if (setgid(target_gid) != 0) {
        perror("setgid");
        exit(1);
    }

    if (setuid(target_uid) != 0) {
        perror("setuid");
        exit(1);
    }

    // Benutzer hat immer noch supplementäre Gruppen von vorher!
    // Könnte immer noch Mitglied von 'wheel', 'admin', etc. sein
}
// Anfällig: LDAP-Sync weist zu breite Gruppen zu
async function vulnerableSyncFromLDAP(ldapUser) {
    const user = await User.findOrCreate({ email: ldapUser.email });

    // Anfällig: Direkte Zuordnung von LDAP-Gruppen ohne Filterung
    for (const ldapGroup of ldapUser.memberOf) {
        // Anfällig: Keine Validierung der Gruppenangemessenheit
        const localGroup = mapLDAPGroupToLocal(ldapGroup);
        if (localGroup) {
            await user.addGroup(localGroup);
        }
    }

    // LDAP-Fehlkonfiguration könnte allen Benutzern Admin-Zugriff gewähren
    await user.save();
}

Korrigierter Code

# Korrigiert: Validierte Gruppenzuweisung mit Genehmigungsworkflow
class FixedUserManager:

    PRIVILEGED_GROUPS = {'administrators', 'root', 'superusers'}
    DEPARTMENT_GROUPS = {
        'Engineering': ['developers', 'git_users'],
        'Finance': ['financial_readonly'],
        'IT': ['helpdesk', 'it_support'],  # Nicht administrators
    }

    def create_user(self, username, email, department, requester):
        user = User(username=username, email=email)
        user.save()

        # Korrigiert: Nur angemessene Gruppen basierend auf Abteilung zuweisen
        allowed_groups = self.DEPARTMENT_GROUPS.get(department, [])

        for group_name in allowed_groups:
            group = Group.objects.get(name=group_name)
            user.groups.add(group)

        return user

    def request_group_membership(self, user, group_name, requester, justification):
        """Mitgliedschaft in einer Gruppe anfordern - privilegierte Gruppen erfordern Genehmigung"""

        if group_name in self.PRIVILEGED_GROUPS:
            # Korrigiert: Privilegierte Gruppe erfordert Genehmigung
            request = GroupMembershipRequest(
                user=user,
                group_name=group_name,
                requester=requester,
                justification=justification,
                status='pending'
            )
            request.save()
            self.notify_approvers(request)
            return {'status': 'pending_approval'}
        else:
            # Nicht-privilegierte Gruppen können Self-Service sein
            self.add_to_group(user, group_name)
            return {'status': 'completed'}

    def update_user_department(self, user, new_department, requester):
        # Korrigiert: Alte Gruppenmitgliedschaften bereinigen
        old_department = user.department
        old_groups = set(self.DEPARTMENT_GROUPS.get(old_department, []))
        new_groups = set(self.DEPARTMENT_GROUPS.get(new_department, []))

        # Gruppen aus alter Abteilung entfernen
        for group_name in old_groups - new_groups:
            group = Group.objects.get(name=group_name)
            user.groups.remove(group)

        # Gruppen für neue Abteilung hinzufügen
        for group_name in new_groups - old_groups:
            group = Group.objects.get(name=group_name)
            user.groups.add(group)

        user.department = new_department
        user.save()

        # Audit-Log
        AuditLog.log('department_change', user, requester,
                     f'{old_department} -> {new_department}')
// Korrigiert: Strenge Gruppenzuweisung mit Validierung
public class FixedUserService {

    private static final Set<String> SELF_ASSIGNABLE_GROUPS =
        Set.of("users", "newsletter_subscribers");

    private static final Set<String> PRIVILEGED_GROUPS =
        Set.of("administrators", "superusers", "security");

    public void processUserRegistration(HttpServletRequest request) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        User user = new User(username, hashPassword(password));

        // Korrigiert: Nur Standard-unprivilegierte Gruppe zuweisen
        user.addGroup(groupRepository.findByName("users"));

        // Korrigiert: Alle Gruppenanfragen vom Benutzer ignorieren
        // Gruppenzuweisungen über Standard erfordern Admin-Aktion

        userRepository.save(user);
        auditLog.log("user_created", user.getId(), "default_group_assigned");
    }

    public void assignGroupToUser(User user, String groupName, Admin admin) {
        // Korrigiert: Gruppenzuweisung validieren
        if (PRIVILEGED_GROUPS.contains(groupName)) {
            if (!admin.hasPermission("assign_privileged_groups")) {
                throw new AccessDeniedException(
                    "Kann privilegierte Gruppe nicht zuweisen: " + groupName);
            }
        }

        Group group = groupRepository.findByName(groupName);
        if (group == null) {
            throw new IllegalArgumentException("Unbekannte Gruppe: " + groupName);
        }

        user.addGroup(group);
        userRepository.save(user);

        // Korrigiert: Alle Gruppenzuweisungen auditieren
        auditLog.log("group_assigned", user.getId(), groupName, admin.getId());
    }
}
// Korrigiert: Minimale Privilegien-Standardgruppen
<?php
class FixedAccountCreator {

    const DEFAULT_GROUP = 'basic_users';  // Korrigiert: Minimale Privilegien-Standard

    private $groupValidator;

    public function createAccount($email, $password) {
        $user = new User();
        $user->email = $email;
        $user->password = password_hash($password, PASSWORD_BCRYPT);

        // Korrigiert: Minimale Standardgruppe zuweisen
        $user->group = self::DEFAULT_GROUP;

        $user->save();

        // Audit-Log
        $this->auditLog('account_created', $user->id, self::DEFAULT_GROUP);

        return $user;
    }

    public function assignGroup($userId, $groupName, $adminId) {
        // Korrigiert: Validieren, dass Gruppenzuweisung angemessen ist
        if (!$this->groupValidator->canAssign($adminId, $groupName)) {
            throw new UnauthorizedException(
                "Nicht autorisiert, Gruppe zuzuweisen: $groupName"
            );
        }

        $user = User::find($userId);
        $user->addGroup($groupName);
        $user->save();

        $this->auditLog('group_assigned', $userId, $groupName, $adminId);
    }
}
?>
// Korrigiert: Supplementaere Gruppen ordnungsgemäß löschen vor Privilegienabsenkung
#include <unistd.h>
#include <grp.h>

int fixed_drop_privileges(uid_t target_uid, gid_t target_gid) {
    // Korrigiert: Zuerst supplementäre Gruppen löschen
    if (setgroups(0, NULL) != 0) {
        perror("setgroups");
        return -1;
    }

    // Jetzt primäre GID setzen
    if (setgid(target_gid) != 0) {
        perror("setgid");
        return -1;
    }

    // Schließlich zu Ziel-UID absenken
    if (setuid(target_uid) != 0) {
        perror("setuid");
        return -1;
    }

    // Verifizieren, dass wir keine Privilegien wiedererlangen können
    if (setuid(0) == 0) {
        fprintf(stderr, "Fehler: Kann immer noch root wiedererlangen\n");
        return -1;
    }

    return 0;
}
// Korrigiert: LDAP-Sync mit Gruppenfilterung und Validierung
const ALLOWED_GROUPS = new Set([
    'users', 'developers', 'designers', 'support'
]);

const PRIVILEGED_GROUPS = new Set([
    'administrators', 'superusers', 'security_team'
]);

async function fixedSyncFromLDAP(ldapUser) {
    const user = await User.findOrCreate({ email: ldapUser.email });

    // Korrigiert: Existierende Gruppen für Bereinigung verfolgen
    const existingGroups = new Set(await user.getGroupNames());
    const newGroups = new Set();

    for (const ldapGroup of ldapUser.memberOf) {
        const localGroup = mapLDAPGroupToLocal(ldapGroup);

        if (!localGroup) continue;

        // Korrigiert: Nur nicht-privilegierte Gruppen von LDAP erlauben
        if (PRIVILEGED_GROUPS.has(localGroup)) {
            console.warn(`Überspringe privilegierte Gruppe ${localGroup} für ${ldapUser.email}`);
            continue;
        }

        if (!ALLOWED_GROUPS.has(localGroup)) {
            console.warn(`Unbekannte Gruppe ${localGroup} für ${ldapUser.email}`);
            continue;
        }

        newGroups.add(localGroup);
    }

    // Korrigiert: Gruppen atomar aktualisieren
    await user.setGroups(Array.from(newGroups));

    // Änderungen auditieren
    const added = [...newGroups].filter(g => !existingGroups.has(g));
    const removed = [...existingGroups].filter(g => !newGroups.has(g));

    if (added.length || removed.length) {
        await AuditLog.create({
            action: 'ldap_sync_groups',
            user: user.id,
            added,
            removed
        });
    }

    await user.save();
}

CVE-Beispiele

  • CVE-1999-1193: Betriebssystem wies neuen Benutzern automatisch die privilegierte "wheel"-Gruppe zu.
  • CVE-2010-3716: Webanwendung erlaubte Anfragen zur Erstellung beliebiger Gruppenmitgliedschaften.
  • CVE-2008-5397: Konfigurationsoptionen verursachten versehentlich unbeabsichtigte Gruppenmitgliedschaften.
  • CVE-2007-6644: CMS erlaubte Benutzern, sich selbst zur Administrator-Rolle zu befördern.
  • CVE-2007-3260: Produkt wies Mitglieder unangemessen der root-Gruppe zu.
  • CVE-2002-0080: Daemon scheiterte daran, supplementäre Gruppen vor Privilegienabsenkung zu löschen.

Verwandte CWEs

  • CWE-286: Fehlerhafte Benutzerverwaltung (Eltern)
  • CWE-269: Unzureichende Privilegienverwaltung (verwandt)
  • CWE-732: Falsche Berechtigungszuweisung für kritische Ressource (verwandt)
  • CWE-1212: Autorisierungsfehler (Kategorie)

Referenzen

  1. MITRE Corporation. "CWE-842: Placement of User into Incorrect Group." https://cwe.mitre.org/data/definitions/842.html
  2. OWASP. "Access Control Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html
  3. NIST. "Guide to Attribute Based Access Control (ABAC)."