von relativen Aufrufen zu abgesicherten Umgebungen
PATH-Hijacking nutzt aus, dass Bash-Skripte Befehle über eine geerbte, potenziell manipulierte PATH-Variable auflösen, statt feste, vertrauenswürdige Pfade zu verwenden. Dieser Artikel zeigt, wie ein manipulierter PATH oder IFS ein Skript zur Ausführung fremder Programme bringt, wie Cronjobs und Systemd-Units besonders betroffen sind, und mit welchen konkreten Maßnahmen sich Bash-Skripte gegen dieses Angriffsmuster absichern lassen.
Inhaltsverzeichnis
- 1. Was PATH-Hijacking ist und wie es Bash-Skripte kompromittiert
- 2. Relative Befehlsaufrufe vs. absolute Pfade
- 3. IFS-Manipulation als verwandter Angriffsvektor
- 4. Vererbte Umgebungsvariablen in Cronjobs und Systemd-Units absichern
- 5. Ein sicheres PATH am Skriptanfang explizit setzen
- 6. Funktionsnamen-Kollisionen und command -p als Schutzmechanismus
- 7. Third-Party-Skripte und source: Vertrauenskette prüfen
- 8. Audit-Tools und ShellCheck-Regeln zur PATH-Absicherung nutzen
- 9. Vergleich: unsichere vs. sichere Umgebungsbehandlung
- 10. Zusammenfassung
- 11. FAQ
1. Was PATH-Hijacking ist und wie es Bash-Skripte kompromittiert
PATH-Hijacking nutzt aus, dass Bash bei einem nicht qualifizierten Befehlsnamen wie tar oder python die Verzeichnisse in der Umgebungsvariablen PATH der Reihe nach durchsucht und das erste gefundene ausführbare Programm mit diesem Namen startet. Enthält PATH ein Verzeichnis, in das ein Angreifer schreiben kann, etwa ein Verzeichnis im Heimatverzeichnis des Nutzers oder ein aktuelles Arbeitsverzeichnis, kann der Angreifer dort ein bösartiges Programm mit dem Namen eines häufig verwendeten Befehls platzieren. Wird dieses Verzeichnis in PATH vor dem eigentlichen Systemverzeichnis durchsucht, führt das Skript unbemerkt das bösartige Programm statt des erwarteten Systembefehls aus.
Das Grundproblem entsteht dadurch, dass PATH eine Umgebungsvariable ist, die ein Bash-Skript in aller Regel unverändert von seinem Elternprozess übernimmt. Ein Skript, das in einer kompromittierten oder unsauber konfigurierten Umgebung startet, etwa mit einem aktuellen Arbeitsverzeichnis als erstem PATH-Eintrag, ist damit strukturell anfällig für PATH-Hijacking, unabhängig davon, wie sorgfältig der eigentliche Skriptcode geschrieben ist.
Besonders kritisch ist PATH-Hijacking bei Skripten, die mit erhöhten Rechten laufen, etwa als root in einem Cronjob oder in einem CI Runner mit Zugriff auf Deployment-Zugangsdaten. Ein erfolgreicher PATH-Hijacking-Angriff auf ein solches Skript führt fremden Code mit denselben erhöhten Rechten aus, mit denen das Skript selbst läuft, und macht diesen Angriffsvektor zu einer der effektivsten Methoden für Rechteausweitung in Automatisierungsumgebungen.
2. Relative Befehlsaufrufe vs. absolute Pfade
Die wirksamste Einzelmaßnahme gegen PATH-Hijacking ist, sicherheitskritische Befehle in Bash-Skripten mit ihrem absoluten Pfad aufzurufen, statt sich auf die PATH-Auflösung zu verlassen. /usr/bin/tar statt tar, /usr/bin/python3 statt python3, und /bin/rm statt rm stellen sicher, dass das Skript immer genau das Programm ausführt, das der Entwickler erwartet hat, unabhängig davon, welche Verzeichnisse in PATH auftauchen oder in welcher Reihenfolge sie durchsucht werden.
Für Skripte mit vielen externen Befehlsaufrufen empfiehlt sich, die absoluten Pfade zentral als schreibgeschützte Variablen am Skriptanfang zu definieren, statt sie über den gesamten Code zu verstreuen. Das erleichtert spätere Audits und macht auf einen Blick sichtbar, welche externen Programme das Skript tatsächlich verwendet.
#!/usr/bin/env bash
set -euo pipefail
# Centralized absolute paths — resistant to PATH manipulation
readonly TAR_BIN="/usr/bin/tar"
readonly RSYNC_BIN="/usr/bin/rsync"
readonly OPENSSL_BIN="/usr/bin/openssl"
# UNSAFE: relies on PATH resolution
# tar -czf backup.tar.gz /data
# SAFE: absolute path, immune to a malicious "tar" earlier in PATH
"$TAR_BIN" -czf backup.tar.gz /data
"$RSYNC_BIN" -avz --delete /data/ backup-host:/backups/data/
"$OPENSSL_BIN" enc -aes-256-cbc -salt -in secret.txt -out secret.enc
Ein guter Nebeneffekt dieses Musters ist Reproduzierbarkeit: Ein Skript mit absoluten Pfaden verhält sich auf unterschiedlichen Systemen identisch, solange die referenzierten Binärdateien an denselben Stellen liegen, während ein Skript mit relativen Aufrufen je nach installierter PATH-Konfiguration unterschiedliche Programmversionen ausführen könnte.
3. IFS-Manipulation als verwandter Angriffsvektor
Verwandt mit PATH-Hijacking, aber weniger bekannt, ist die Manipulation der Variablen IFS, des Internal Field Separator, der bestimmt, anhand welcher Zeichen Bash Wörter bei der Expansion aufteilt. Der Standardwert von IFS ist Leerzeichen, Tab und Newline. Setzt ein Angreifer IFS auf einen anderen Wert, bevor ein Skript läuft, etwa auf einen Schrägstrich, kann das die Interpretation von Pfaden und Befehlen fundamental verändern und in bestimmten Konstellationen dazu führen, dass ein Skript unerwartete Wörter als separate Befehlsargumente oder sogar als eigenständige Befehle interpretiert.
Ein Bash-Skript, das IFS nicht selbst am Anfang explizit auf einen sicheren Standardwert setzt, übernimmt den geerbten IFS-Wert der aufrufenden Umgebung, genau wie bei PATH. Die Absicherung ist strukturell identisch: IFS am Skriptanfang explizit setzen, statt sich auf die geerbte Umgebung zu verlassen, und niemals annehmen, dass Standardwerte in jeder Ausführungsumgebung garantiert gelten.
#!/usr/bin/env bash
set -euo pipefail
# Explicit, safe IFS at script start — never trust the inherited value
IFS=$'\n\t'
# Also reset PATH explicitly for the duration of this script
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
echo "PATH and IFS are now controlled, not inherited"
4. Vererbte Umgebungsvariablen in Cronjobs und Systemd-Units absichern
Cronjobs sind ein besonders häufiger Ort für PATH-Hijacking-Risiken, weil die Standard-PATH-Variable in einer Cron-Umgebung oft minimal ist und stark von der PATH-Variable einer interaktiven Login-Shell abweicht. Viele Administratoren reagieren darauf, indem sie in der Crontab ein sehr weites PATH setzen, das zusätzliche, potenziell unsichere Verzeichnisse einschließt, um Skriptfehler zu vermeiden. Genau das öffnet aber die Tür für PATH-Hijacking, wenn eines dieser zusätzlichen Verzeichnisse für andere Nutzer beschreibbar ist.
Die sicherere Lösung ist, PATH nicht großzügig in der Crontab zu erweitern, sondern jedes Skript selbst mit einem minimalen, kontrollierten PATH und ausschließlich absoluten Pfaden für kritische Befehle auszustatten. Systemd-Units bieten mit der Direktive Environment= und EnvironmentFile= eine noch feinere Kontrolle, weil dort explizit definiert werden kann, welche Umgebungsvariablen ein Dienst erhält, ohne von einer geerbten, potenziell manipulierten Shell-Umgebung abhängig zu sein.
# Crontab: avoid overly broad PATH, let the script set its own
# BAD: PATH=/home/deploy/bin:/usr/local/bin:/usr/bin:/bin
# GOOD: minimal, predictable PATH, script handles the rest internally
PATH=/usr/bin:/bin
0 2 * * * /usr/local/bin/nightly-backup.sh >> /var/log/backup.log 2>&1
# /etc/systemd/system/nightly-backup.service
[Unit]
Description=Nightly backup job
[Service]
Type=oneshot
# Explicit, minimal environment — no inherited shell PATH
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/usr/local/bin/nightly-backup.sh
5. Ein sicheres PATH am Skriptanfang explizit setzen
Unabhängig davon, in welchem Kontext ein Bash-Skript letztlich ausgeführt wird, ist das explizite Setzen eines minimalen, ausschließlich Systemverzeichnisse umfassenden PATH am Skriptanfang eine der wirksamsten Einzelmaßnahmen gegen PATH-Hijacking. Ein solches PATH sollte nur Verzeichnisse enthalten, die ausschließlich von root beschreibbar sind, typischerweise /usr/local/sbin, /usr/local/bin, /usr/sbin, /usr/bin, /sbin und /bin, und niemals das aktuelle Arbeitsverzeichnis oder ein Verzeichnis im Home-Verzeichnis eines nicht privilegierten Nutzers.
Dieses Muster kombiniert sich gut mit dem im vorherigen Abschnitt gezeigten Ansatz absoluter Pfade: Selbst wenn ein Entwickler versehentlich einen relativen Befehlsnamen verwendet, sorgt das explizit gesetzte, minimale PATH dafür, dass nur vertrauenswürdige Systemverzeichnisse durchsucht werden, was das Risiko eines erfolgreichen PATH-Hijacking-Angriffs erheblich reduziert, auch wenn absolute Pfade weiterhin die robustere erste Verteidigungslinie bleiben.
6. Funktionsnamen-Kollisionen und command -p als Schutzmechanismus
Ein weiterer, oft übersehener Aspekt von PATH-Hijacking betrifft Funktionsnamen-Kollisionen: Wenn ein Skript oder eine per source eingebundene Bibliothek eine Bash-Funktion mit demselben Namen wie ein Systembefehl definiert, etwa eine Funktion namens cd oder ls, überschreibt diese Funktion den eigentlichen Befehl für den Rest der Skriptausführung. Das ist zwar kein klassisches PATH-Hijacking, folgt aber demselben Grundmuster: Der Aufrufer erwartet ein bestimmtes Programm, bekommt aber tatsächlich etwas anderes ausgeführt.
Das Bash-Builtin command -p löst dieses Problem elegant: Es führt einen Befehl garantiert mit einem sicheren, vordefinierten PATH aus und ignoriert dabei sowohl gleichnamige Funktionen als auch die aktuelle PATH-Variable. In sicherheitskritischen Skripten, die ihre eigenen Hilfsfunktionen definieren, ist command -p deshalb die zuverlässigste Methode, um sicherzustellen, dass tatsächlich das erwartete Systemprogramm läuft.
#!/usr/bin/env bash
set -euo pipefail
# A library might accidentally define a function shadowing a builtin command
ls() {
echo "custom logging wrapper"
}
# UNSAFE: this calls the shadowing function above, not /bin/ls
ls -la /var/log
# SAFE: command -p bypasses functions AND the current PATH entirely
command -p ls -la /var/log
7. Third-Party-Skripte und source: Vertrauenskette prüfen
Jedes source Kommando in einem Bash-Skript bindet fremden Code mit denselben Rechten ein, mit denen das aufrufende Skript läuft, einschließlich der Fähigkeit, PATH, IFS und andere sicherheitsrelevante Umgebungsvariablen zu verändern. Ein Third-Party-Skript, das per source eingebunden wird, sollte deshalb genauso sorgfältig geprüft werden wie eigener Code, insbesondere wenn es aus einem externen Repository, einem Paket-Manager oder einer nicht vollständig vertrauenswürdigen Quelle stammt.
Ein praktisches Absicherungsmuster ist, den PATH und andere kritische Umgebungsvariablen unmittelbar nach jedem source Kommando erneut zu überprüfen und bei unerwarteten Änderungen das Skript abzubrechen. Das verhindert, dass eine kompromittierte oder unsorgfältig geschriebene eingebundene Bibliothek die Sicherheitsannahmen des Hauptskripts unbemerkt untergräbt.
#!/usr/bin/env bash
set -euo pipefail
readonly EXPECTED_PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
export PATH="$EXPECTED_PATH"
source ./lib/third-party-helpers.sh
# Verify PATH was not silently altered by the sourced library
if [[ "$PATH" != "$EXPECTED_PATH" ]]; then
echo "[ERROR] PATH was modified after sourcing third-party code: $PATH" >&2
exit 1
fi
8. Audit-Tools und ShellCheck-Regeln zur PATH-Absicherung nutzen
ShellCheck erkennt bestimmte Muster, die auf PATH-Hijacking-Risiken hindeuten, etwa relative Aufrufe von ./skript.sh ohne Prüfung, ob der Punkt bereits gefährlich im PATH steht. Ein zusätzlicher, manueller Audit-Schritt sollte systematisch nach nicht qualifizierten Befehlsaufrufen in sicherheitskritischen Skripten suchen und jeden Fund gegen die im vorherigen Abschnitt gezeigte Liste absoluter Pfade abgleichen.
Für regelmäßige Audits eignet sich ein einfaches Skript, das die aktuelle PATH-Variable in kritischen Ausführungskontexten wie Cronjobs und Systemd-Units protokolliert und gegen eine erwartete, minimale Liste von Systemverzeichnissen prüft. Jede Abweichung, etwa ein zusätzliches, für andere Nutzer beschreibbares Verzeichnis, sollte als Finding gemeldet werden, bevor sie zu einem tatsächlichen PATH-Hijacking-Vorfall führt.
#!/usr/bin/env bash
set -euo pipefail
readonly SAFE_DIRS="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
check_path_safety() {
local IFS=':'
local -a dirs=($PATH)
for dir in "${dirs[@]}"; do
if [[ ":$SAFE_DIRS:" != *":$dir:"* ]]; then
echo "[WARNING] Untrusted PATH entry: $dir" >&2
fi
if [[ -w "$dir" && "$dir" != "/usr/local/bin" ]]; then
echo "[CRITICAL] World-writable-ish PATH entry: $dir" >&2
fi
done
}
check_path_safety
9. Vergleich: unsichere vs. sichere Umgebungsbehandlung
Die folgende Tabelle stellt häufige unsichere Muster im Umgang mit PATH und Umgebungsvariablen ihren sicheren Gegenstücken gegenüber.
| Situation | Unsicher | Sicher | Vorteil |
|---|---|---|---|
| Systembefehl aufrufen | tar -czf … /data |
/usr/bin/tar -czf … /data |
Immun gegen PATH-Manipulation |
| PATH im Skript | Geerbte Umgebung übernehmen | Explizit auf Systemverzeichnisse setzen | Kontrollierte, vorhersehbare Auflösung |
| Cronjob-PATH | Sehr weites PATH in Crontab | Minimales PATH, Skript setzt Rest selbst | Keine zusätzlichen beschreibbaren Verzeichnisse |
| Befehl trotz Funktionsnamen | ls -la /var/log |
command -p ls -la /var/log |
Ignoriert Funktionen und PATH gleichermaßen |
| Third-Party-Code einbinden | source ohne Nachprüfung | PATH nach source erneut verifizieren | Unbemerkte Manipulation wird erkannt |
Mironsoft
PATH-Audits und Härtung von Bash-Automatisierung
PATH-Hijacking-Risiken in euren Cronjobs und Deployment-Skripten?
Wir prüfen PATH- und IFS-Absicherung in euren Bash-Skripten, Cronjobs und Systemd-Units systematisch und ersetzen riskante relative Aufrufe durch geprüfte, absolute Pfade.
PATH-Audit
Alle Ausführungskontexte auf riskante PATH-Werte prüfen
Refactoring
Relative Aufrufe durch absolute Pfade ersetzen
Cron & Systemd
Minimale, kontrollierte Umgebungen für Automatisierung einrichten
10. Zusammenfassung
PATH-Hijacking entsteht, weil Bash-Skripte nicht qualifizierte Befehlsnamen über eine geerbte, potenziell manipulierte PATH-Variable auflösen. Absolute Pfade für sicherheitskritische Befehle sind die wirksamste einzelne Gegenmaßnahme, weil sie die PATH-Auflösung vollständig umgehen. Ein explizit gesetztes, minimales PATH am Skriptanfang, kombiniert mit einem sicheren IFS-Wert, schließt die verbleibende Angriffsfläche für Skripte, die dennoch relative Befehlsnamen verwenden.
Cronjobs und Systemd-Units verdienen besondere Aufmerksamkeit, weil ihre Standardumgebungen oft unbedacht mit zu weiten PATH-Werten konfiguriert werden. command -p schützt zusätzlich vor Funktionsnamen-Kollisionen, und eine erneute Prüfung von PATH nach jedem source Kommando deckt unbemerkte Manipulation durch eingebundenen Code auf. Zusammen bilden diese Maßnahmen eine robuste Verteidigung gegen PATH- und Umgebungsvariablen-Hijacking in Bash-Automatisierung.
PATH-Hijacking in Bash verhindern — Das Wichtigste auf einen Blick
Grundproblem
Nicht qualifizierte Befehle werden über eine geerbte, potenziell manipulierte PATH-Variable aufgelöst.
Wirksamste Maßnahme
Absolute Pfade für sicherheitskritische Befehle, unabhängig vom PATH-Wert.
Explizite Umgebung
PATH und IFS am Skriptanfang explizit auf minimale, sichere Werte setzen.
Cron & Systemd
Kein zu weites PATH in der Crontab, Environment= in Systemd-Units für kontrollierte Werte.