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
| Auswirkung | Details |
|---|---|
| Zugriffskontrolle | Bereich: 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
-
MITRE Corporation. "CWE-286: Incorrect User Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/286.html
-
NIST. "Role-Based Access Control." https://csrc.nist.gov/projects/role-based-access-control
-
OWASP Foundation. "Broken Access Control." OWASP Top 10. https://owasp.org/Top10/A01_2021-Broken_Access_Control/