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
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: Zugriffskontrolle Privilegien erlangen oder Identität annehmen - Benutzer erlangen Privilegien über ihre beabsichtigte Autorisierungsstufe hinaus durch falsche Gruppenmitgliedschaft. |
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen - Falsche Gruppenplatzierung kann Zugriff auf sensible Daten gewähren, die der Benutzer nicht sehen sollte. |
| Integrität | Bereich: 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
- MITRE Corporation. "CWE-842: Placement of User into Incorrect Group." https://cwe.mitre.org/data/definitions/842.html
- OWASP. "Access Control Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Access_Control_Cheat_Sheet.html
- NIST. "Guide to Attribute Based Access Control (ABAC)."