Unsachgemäße Verwendung privilegierter APIs

Beschreibung

Die unsachgemäße Verwendung privilegierter APIs tritt auf, wenn eine Anwendung den Zugriff auf oder die Aufrufe von privilegierten Systemfunktionen nicht ordnungsgemäß kontrolliert. Dies umfasst das Aufrufen von APIs, die erhöhte Privilegien erfordern, ohne ordnungsgemäße Autorisierungsprüfungen, das Exponieren privilegierter APIs für nicht-privilegierte Benutzer oder das Versäumnis, Privilegien nach Abschluss privilegierter Operationen abzugeben. Die Schwachstelle ermöglicht es Angreifern, Operationen auszuführen, zu deren Ausführung sie nicht berechtigt sein sollten.

Risiko

Nicht-privilegierte Benutzer können administrative Funktionen ausführen. Privilegieneskalation durch unsachgemäß exponierte APIs. Systembefehle werden mit unnötig erhöhten Privilegien ausgeführt. Sensible Operationen werden ohne Autorisierung durchgeführt. Sicherheitsgrenzen werden durch API-Missbrauch verletzt. Vollständige Systemkompromittierung durch privilegierten API-Zugriff.

Lösung

Implementieren Sie ordnungsgemäße Autorisierung vor dem Aufrufen privilegierter APIs. Befolgen Sie das Prinzip der minimalen Rechte. Geben Sie Privilegien sofort nach privilegierten Operationen ab. Verwenden Sie wo verfügbar fähigkeitsbasierte Sicherheit. Auditieren Sie privilegierte API-Nutzung. Trennen Sie privilegierte und nicht-privilegierte Code-Pfade. Verwenden Sie Sicherheits-Frameworks für Zugriffskontrolle.

Häufige Konsequenzen

AuswirkungDetails
AutorisierungUmfang: Privilegieneskalation

Benutzer erhalten unautorisierten erhöhten Zugriff.
IntegritätUmfang: Systemmodifikation

Nicht autorisierte Änderungen am Systemzustand.
VertraulichkeitUmfang: Datenzugriff

Zugriff auf privilegierte Daten durch API-Missbrauch.

Beispielcode + Lösungscode

Anfälliger Code

// ANFÄLLIG: Privilegierte API ohne Autorisierung exponiert
@RestController
@RequestMapping("/api")
public class VulnerableSystemController {

    // ANFÄLLIG: Jeder kann Systembefehle aufrufen
    @PostMapping("/exec")
    public String executeCommand(@RequestBody String command) {
        // Keine Autorisierungsprüfung!
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec(command);
        return readOutput(process);
    }

    // ANFÄLLIG: Dateioperationen mit erhöhten Privilegien
    @PostMapping("/system/write")
    public void writeSystemFile(@RequestBody FileRequest request) {
        // Keine Autorisierung - jeder kann überall schreiben!
        Files.write(Paths.get(request.getPath()), request.getContent().getBytes());
    }

    // ANFÄLLIG: Benutzerverwaltung ohne Autorisierung
    @PostMapping("/users/create")
    public void createUser(@RequestBody User user) {
        // Sollte Admin erfordern, aber keine Prüfung!
        userService.createUser(user);
    }
}

// ANFÄLLIG: Privilegien werden nach Verwendung nicht abgegeben
public class VulnerablePrivilegedOperation {

    public void performOperation() {
        // Erhöhe Privilegien
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                // Führe privilegierte Operation aus
                readSensitiveConfig();

                // ANFÄLLIG: Läuft weiterhin privilegiert
                // auch für nicht-privilegierte Operationen
                handleUserInput();  // Sollte NICHT privilegiert sein!

                return null;
            }
        });
    }
}
# ANFÄLLIG: Privilegierte Operationen ohne Prüfungen
import os
import subprocess
from flask import Flask, request

app = Flask(__name__)

@app.route('/api/admin/exec', methods=['POST'])
def exec_command_vulnerable():
    # ANFÄLLIG: Keine Autorisierungsprüfung
    command = request.json['command']
    result = subprocess.run(command, shell=True, capture_output=True)
    return {'output': result.stdout.decode()}

@app.route('/api/system/config', methods=['POST'])
def write_config_vulnerable():
    # ANFÄLLIG: Jeder kann Systemkonfiguration schreiben
    config_path = request.json['path']
    content = request.json['content']

    # Schreiben in Systempfade ohne Autorisierung!
    with open(config_path, 'w') as f:
        f.write(content)

    return {'status': 'geschrieben'}

# ANFÄLLIG: Gesamte App läuft als root
# Die Anwendung läuft mit Root-Privilegien für alles
# auch für Operationen die es nicht brauchen

@app.route('/api/user/profile')
def get_profile_vulnerable():
    # Diese einfache Operation läuft mit vollen Root-Privilegien!
    user_id = request.args.get('id')
    return get_user_profile(user_id)

# ANFÄLLIG: setuid nicht ordnungsgemäß verwaltet
def perform_privileged_task():
    # Erhöhe zu root
    os.seteuid(0)

    # Führe privilegierte Operation aus
    perform_admin_task()

    # ANFÄLLIG: Vergessen Privilegien abzugeben!
    # Aller nachfolgender Code läuft als root

    handle_user_request()  # Läuft als root unnötigerweise
// ANFÄLLIG: Node.js privilegierte API-Exposition
const express = require('express');
const { exec } = require('child_process');
const fs = require('fs');

const app = express();

// ANFÄLLIG: Jeder kann Systembefehle ausführen
app.post('/api/system/exec', (req, res) => {
    const { command } = req.body;
    // Keine Autorisierungsprüfung!
    exec(command, (error, stdout) => {
        res.json({ output: stdout });
    });
});

// ANFÄLLIG: Admin-API ohne Autorisierung
app.post('/api/admin/users', (req, res) => {
    // Sollte Admin-Rolle erfordern, prüft aber nicht
    const userData = req.body;
    db.createUser(userData);  // Erstellt Admin-Benutzer!
    res.json({ success: true });
});

// ANFÄLLIG: Dateisystemoperationen exponiert
app.post('/api/files/write', (req, res) => {
    const { path, content } = req.body;
    // Keine Prüfung - jeder kann überall schreiben!
    fs.writeFileSync(path, content);
    res.json({ success: true });
});

// ANFÄLLIG: Datenbank-Admin-Operationen
app.post('/api/db/execute', (req, res) => {
    const { query } = req.body;
    // Keine Autorisierung - rohe SQL-Ausführung!
    db.raw(query).then(result => {
        res.json(result);
    });
});
// ANFÄLLIG: C-Programm mit unsachgemäßer Privilegien-Handhabung
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

// ANFÄLLIG: Läuft als root unnötigerweise
void vulnerable_process() {
    // Gesamte Funktion läuft als root
    // auch für nicht-privilegierte Operationen

    read_user_input();  // Braucht kein root!
    log_activity();     // Braucht kein root!

    // Nur dies braucht root
    write_system_file("/etc/config", data);

    // Läuft immer noch als root danach!
    process_user_request();  // Gefährlich!
}

// ANFÄLLIG: setuid nicht abgegeben
void vulnerable_setuid_program() {
    // Programm ist setuid root

    // ANFÄLLIG: Gibt Privilegien nie ab
    while (1) {
        char* command = read_user_command();
        // Führt Benutzerbefehle als root aus!
        system(command);
    }
}

// ANFÄLLIG: Privilegien-Prüfungs-Bypass
int check_admin() {
    // ANFÄLLIG: Kann umgangen werden
    return getenv("IS_ADMIN") != NULL;
}

void admin_function() {
    // Angreifer setzt IS_ADMIN=1 Umgebungsvariable
    if (check_admin()) {
        // Führt privilegierte Operationen aus
        delete_all_users();
    }
}

Korrigierter Code

// SICHER: Ordnungsgemäße Autorisierung für privilegierte APIs
@RestController
@RequestMapping("/api")
public class SafeSystemController {

    private final AuthorizationService authService;

    // SICHER: Strikte Autorisierung für Befehlsausführung
    @PreAuthorize("hasRole('SYSTEM_ADMIN')")
    @PostMapping("/exec")
    public String executeCommand(@AuthenticationPrincipal User user,
                                 @RequestBody String command) {
        // Validiere dass Benutzer erforderliche Rolle hat
        if (!authService.canExecuteSystemCommands(user)) {
            throw new AccessDeniedException("Nicht autorisiert");
        }

        // Whitelist erlaubter Befehle
        if (!isAllowedCommand(command)) {
            throw new IllegalArgumentException("Befehl nicht erlaubt");
        }

        // Audit-Log
        auditService.logPrivilegedOperation(user, "exec", command);

        // Führe mit minimalen Privilegien aus
        return executeWithLimitedPrivileges(command);
    }

    private boolean isAllowedCommand(String command) {
        Set<String> allowed = Set.of("status", "health", "metrics");
        return allowed.contains(command);
    }
}

// SICHER: Minimaler Privilegien-Umfang
public class SafePrivilegedOperation {

    public void performOperation(User user) {
        // Prüfe Autorisierung zuerst
        if (!user.hasRole("ADMIN")) {
            throw new AccessDeniedException("Admin erforderlich");
        }

        // Erhöhe nur für spezifische Operation
        String config = AccessController.doPrivileged(
            (PrivilegedAction<String>) this::readSensitiveConfig
        );
        // Privilegien hier automatisch abgegeben

        // Fortfahren mit normalen Privilegien
        processConfig(config);  // Nicht privilegiert
    }

    // SICHER: Separate privilegierte und nicht-privilegierte Methoden
    @Privileged
    private String readSensitiveConfig() {
        return Files.readString(Path.of("/etc/app/config"));
    }

    private void processConfig(String config) {
        // Läuft mit normalen Privilegien
    }
}
# SICHER: Ordnungsgemäße Privilegien-Verwaltung
import os
from functools import wraps
from flask import Flask, request, g

app = Flask(__name__)

def require_role(role):
    """Dekorator der spezifische Rolle für Endpunkt erfordert."""
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if not g.current_user:
                return {'error': 'Nicht authentifiziert'}, 401
            if not g.current_user.has_role(role):
                return {'error': 'Unzureichende Privilegien'}, 403
            return f(*args, **kwargs)
        return wrapper
    return decorator

def audit_privileged_action(action):
    """Protokolliere privilegierte Aktionen für Audit-Trail."""
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            audit_log.log(
                user=g.current_user,
                action=action,
                params=request.json
            )
            return f(*args, **kwargs)
        return wrapper
    return decorator

@app.route('/api/admin/exec', methods=['POST'])
@require_role('system_admin')
@audit_privileged_action('command_execution')
def exec_command_safe():
    command = request.json['command']

    # Whitelist erlaubter Befehle
    allowed_commands = {'status', 'health', 'restart'}
    if command not in allowed_commands:
        return {'error': 'Befehl nicht erlaubt'}, 400

    # Führe mit abgegebenen Privilegien aus
    result = run_as_unprivileged_user(command)
    return {'output': result}

# SICHER: Ordnungsgemäße setuid-Handhabung
def perform_privileged_task_safe(user):
    # Verifiziere Autorisierung
    if not user.is_admin:
        raise PermissionError("Admin erforderlich")

    # Speichere ursprüngliche uid
    original_euid = os.geteuid()

    try:
        # Erhöhe nur für spezifische Operation
        os.seteuid(0)
        perform_admin_task()
    finally:
        # Gib Privilegien immer ab
        os.seteuid(original_euid)

    # Fortfahren mit normalen Privilegien
    handle_user_request()

# SICHER: Kontext-Manager für Privilegien-Erhöhung
class PrivilegeElevation:
    def __init__(self, required_role):
        self.required_role = required_role
        self.original_euid = None

    def __enter__(self):
        # Prüfe Autorisierung vor Erhöhung
        if not current_user.has_role(self.required_role):
            raise PermissionError(f"Rolle {self.required_role} erforderlich")

        self.original_euid = os.geteuid()
        os.seteuid(0)
        return self

    def __exit__(self, *args):
        # Stelle ursprüngliche Privilegien immer wieder her
        if self.original_euid is not None:
            os.seteuid(self.original_euid)

# Verwendung
with PrivilegeElevation('admin'):
    write_system_config()
# Privilegien automatisch abgegeben
// SICHER: Node.js mit ordnungsgemäßer Autorisierung
const express = require('express');
const app = express();

// Autorisierungs-Middleware
function requireRole(role) {
    return (req, res, next) => {
        if (!req.user) {
            return res.status(401).json({ error: 'Nicht authentifiziert' });
        }
        if (!req.user.roles.includes(role)) {
            return res.status(403).json({ error: 'Unzureichende Privilegien' });
        }
        next();
    };
}

// Audit-Protokollierung
function auditLog(action) {
    return (req, res, next) => {
        logger.info({
            action,
            user: req.user.id,
            ip: req.ip,
            params: req.body
        });
        next();
    };
}

// SICHER: Geschützter privilegierter Endpunkt
app.post('/api/admin/users',
    requireRole('admin'),
    auditLog('create_user'),
    async (req, res) => {
        const userData = req.body;

        // Validiere Request
        if (!validateUserData(userData)) {
            return res.status(400).json({ error: 'Ungültige Daten' });
        }

        // Erlaube nur Erstellung von Nicht-Admin-Benutzern
        if (userData.roles?.includes('admin')) {
            if (!req.user.roles.includes('super_admin')) {
                return res.status(403).json({
                    error: 'Kann keine Admin-Benutzer erstellen'
                });
            }
        }

        await db.createUser(userData);
        res.json({ success: true });
    }
);

// SICHER: Whitelist erlaubter Operationen
const ALLOWED_OPERATIONS = new Set(['status', 'health', 'restart']);

app.post('/api/system/operation',
    requireRole('system_admin'),
    auditLog('system_operation'),
    (req, res) => {
        const { operation } = req.body;

        if (!ALLOWED_OPERATIONS.has(operation)) {
            return res.status(400).json({ error: 'Operation nicht erlaubt' });
        }

        // Führe erlaubte Operation aus
        const result = executeSystemOperation(operation);
        res.json(result);
    }
);
// SICHER: C-Programm mit ordnungsgemäßem Privilegien-Abgeben
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>

// SICHER: Gib Privilegien sofort nach Verwendung ab
void safe_privileged_operation() {
    uid_t original_uid = getuid();
    uid_t original_euid = geteuid();

    // Nur die privilegierte Operation läuft als root
    if (geteuid() == 0) {
        write_system_file("/etc/config", data);
    }

    // Gib Privilegien permanent ab
    if (drop_privileges() != 0) {
        fprintf(stderr, "Privilegien-Abgabe fehlgeschlagen\n");
        exit(1);
    }

    // Aller nachfolgender Code läuft unprivilegiert
    read_user_input();  // Sicher - nicht root
    process_request();  // Sicher - nicht root
}

int drop_privileges() {
    struct passwd *pw = getpwnam("nobody");
    if (pw == NULL) {
        return -1;
    }

    // Gib zusätzliche Gruppen ab
    if (setgroups(0, NULL) != 0) {
        return -1;
    }

    // Gib zu unprivilegiertem Benutzer ab
    if (setgid(pw->pw_gid) != 0) {
        return -1;
    }
    if (setuid(pw->pw_uid) != 0) {
        return -1;
    }

    // Verifiziere dass Privilegien abgegeben wurden
    if (getuid() == 0 || geteuid() == 0) {
        return -1;  // Immer noch root - etwas falsch
    }

    return 0;
}

// SICHER: Separate privilegierte Operationen
void safe_setuid_program() {
    // Gib Privilegien sofort beim Start ab
    uid_t real_uid = getuid();

    if (geteuid() == 0) {
        // Führe nur spezifische privilegierte Operationen aus
        bind_privileged_port(80);
        read_ssl_keys();

        // Gib Privilegien permanent ab
        if (drop_privileges() != 0) {
            exit(1);
        }
    }

    // Hauptschleife läuft unprivilegiert
    while (1) {
        handle_request();  // Sicher - nicht root
    }
}

Ausgenutzt in der Praxis

Container-Ausbrüche

Privilegierter API-Zugriff führt zu Container-Breakout.

Admin-API-Exposition

Nicht authentifizierte Admin-API-Endpunkte.

Privilegien-Beibehaltung

Dienste behalten erhöhte Privilegien unnötigerweise.


Tools zum Testen/Ausnutzen

  • API-Sicherheitsscanner.

  • Tools zum Testen von Privilegieneskalation.

  • Zugriffskontrolltests.


CVE-Beispiele

  • CVE-2019-5736: Container-Runtime Privilegieneskalation.

  • Zahlreiche API-Autorisierungs-CVEs.


Referenzen

  1. MITRE. "CWE-648: Incorrect Use of Privileged APIs." https://cwe.mitre.org/data/definitions/648.html

  2. OWASP. "Principle of Least Privilege."