lsof

Aus Mikiwiki
Version vom 26. Juli 2021, 07:56 Uhr von Michi (Diskussion | Beiträge) (...)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche

Der Shell-Befehl lsof (list open files) zeigt dem unprivilegierten Benutzer alle geöffneten Dateien - also sowohl reguläre Dateien wie auch spezielle Blockdateien, ausführbare Programme, Bibliotheken, Verzeichnisse, rechnerinterne Datenströme (Unix Domain Sockets) und Netzwerkverbindungen. Dem Benutzer "root" zeigt lsof dagegen alle geöffneten Verbindungen, Ports und Dateien im Netzwerk.

Mit Hilfe der Befehle fuser, ps, netstat und top können ähnliche Informationen gesammelt werden - allerdings weit weniger bequem.

Glsof und Jlsof sind grafische Oberflächen für lsof.

Funktionsweise

Im sicheren Modus informiert lsof nur den Benutzer "root" umfassend. Aber auch im unsicheren Modus darf nur der Benutzer "root" auf alle Details im Verzeichnis "/proc" zugreifen.

lsof gibt die je nachden verwendeten Optionen gefilterten Informationen der gerade geöffneten Dateien in einem tabellarischen Format aus. Per Vorgabe werden folgende Spalten angezeigt:

Spalte Beschreibung
COMMAND Name des Prozesses
PID Prozessnummer
USER Name des Systembenutzers, unter dem der Prozess läuft
FD Dateideskriptor
TYPE Dateiformat
DEVICE Gerät
SIZE Dateigrösse
NODE Verbindung
NAME Vollständiger Name

Ein Aufruf von lsof ohne Parameter liefert zu viele Informationen, um sie zu überschauen. Mit gezielt gewählten Optionen beschränkt sich lsof auf die gerade gewünschten Daten. Bei der Kombination mehrerer Optionen verknüpft lsof diese per Vorgabe mit ODER-Logik. Um sicherzustellen, dass alle Bedingungen erfüllt sind, muss zusätzlich die Option "-a" (UND-Verknüpfung) angegeben werden.

Installation

Systemkompatibilität und Sicherheit sprechen gegen vorkompilierte Versionen. lsof sollte deshalb im Idealfall in einer aktuellen Version auf dem Zielsystem selber kompiliert werden, um den vollen Funktionsumfang und beste Stabilität zu garantieren.

Folgende Befehle holen die Quellen aus dem Internet, prüfen die Signatur mit GNU PG, konfigurieren die Quellen und kompilieren sie.

$ wget ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof.tar.bz2
$ tar xjf lsof.tar.bz2
$ cd lsof_4.77
$ wget ftp://lsof.itap.purdue.edu/pub/Victor_A_Abell.gpg
$ gpg --import Victor_A_Abell.gpg
$ gpg --verify lsof_4.77_src.tar.sig lsof_4.77_src.tar
$ tar xf lsof_4.77_src.tar
$ cd lsof_4.77_src

Während der Konfiguration muss der Anwender interaktiv Entscheidungen treffen: die Antworten [y], [y], [y], [n], [n], [n] und [y] erzeugen eine typische Umgebung mit Blick auf Sicherheit. Wichtig sind die Optionen "HASSECURITY" und "HASNOSOCKSECURITY": Um nur dem Benutzer "root" die Anzeige einer Liste aller offenen Dateien und Sockets aller Benutzer zu erlauben, muss hier mit [y] und [n] geantwortet werden.

$ ./configure linux
$ make -s

Um lsof an einem sicheren Ort aufzubewahren, genügt es, nach dem Kompilieren auf "make install" zu verzichten und die Binärdatei auf einem schreibgeschützten Datenträger unterzubringen, etwa auf einer CD-ROM. Sollte es allerdings einem Eindringling gelingen, den Kernel (etwa mit einem Kernel-Rootkit) zu ändern, so ist leider auch den Ausgaben des unveränderten lsof nicht mehr zu trauen.

Anzeige der Optionen, mit denen lsof übersetzt wurde. Die Ausgabe "Only root can list all files" bedeutet, dass normale Benutzer lsof nicht verwenden können, um systemkritische Informationen einzusehen.

$ ./lsof -v

Optionen

Option Beschreibung
Ohne Option werden sämtliche offenen Dateien angezeigt, die gerade von irgendeinem Prozess geöffnet sind.
$ lsof
Datei Anzeige der Prozesse, die gerade auf die angegebene Datei zugreifen. Im Beispiel werden die Prozesse angezeigt, die gerade auf die Datei "/usr/bin/vim" zugreifen (also mit vi arbeiten).
$ lsof /usr/bin/vim
Gerätedatei Anzeige der Prozesse, die gerade auf die angegebene Gerätedatei zugreifen. Im Beispiel werden alle Prozesse angezeigt, die gerade auf die CD-ROM-Gerätedatei "/dev/hdc" zugreifen.
$ lsof /dev/hdc
-a UND-Verknüpfung.
-d Dateideskriptor Anzeige aller gerade geöffneten Dateien, wobei anstatt der sonst üblichen Prozessnummer der angegebene Dateideskriptor aufgelistet wird. Dadurch ergibt sich eine ähnlcieh Liste, wie sie mit "ps aux" zu sehen ist. "txt" steht für Programmtext (weitere Dateideskriptoren finden sich über "man lsof").
$ lsof -d txt
+D Verzeichnis Anzeige aller gerade geöffneten Dateien im angegebenen Verzeichnis und seinen Unterverzeichnissen, ohne dabei auf symbolische Links zu achten.
$ lsof +D /tmp
-F Felder Diese besonders formatierte Ausgabe sorgt dafür, dass nachgeschaltete Programme einzelne Felder besser parsen können. Details dazu finden sich im Manpage-Abschnitt "Output for other programs".
+L Linkzähler Anzeige aller gelöschten Dateien, die noch geöffnet sind und daher Plattenplatz verbrauchen, aber in keinem Verzeichnis erscheinen (im Beispiel Dateien mit weniger als einem Link).
$ lsof +L 1
-i Anzeige aller gerade geöffneten netzwerkrelevanten Dateien.
$ lsof -i

Anzeige aller gerade vom Benutzer "www-data" geöffneten Netzwerkdateien (UND-Verknüpfung durch "-a").

$ lsof -a -i -u www-data

Anzeige aller gerade geöffneten netzwerkrelevanten Dateien, ohne die Portnummern als Dienstbezeichnung auszuschreiben und ohne die Hostnamen aufzulösen (daher deutlich performanter).

$ lsof -i -P -n

Anzeige aller aktiven Verbindungen.

$ lsof -i | grep '\->'
-i4 Anzeige aller gerade geöffneten IPV4-bezogenen Dateien.
$ lsof -i4
-i6 Anzeige aller gerade geöffneten IPV6-bezogenen Dateien.
$ lsof -i6
-n Unterdrücken der Namensauflösung.
-p Prozessnummer Anzeige aller Dateien, die gerade vom Prozess mit der angegebenen Prozessnummer (PID) geöffnet sind.
$ lsof -p 2326

Anzeige aller Dateien, die gerade von den Prozessen mit den angegebenen Prozessnummern (PID) geöffnet sind.

$ lsof -p 2326,5400,5720
-P Unterdrücken der Portnamensauflösung.
-u Benutzername Anzeige aller Dateien, die gerade vom angegebenen Benutzer geöffnet sind.
$ lsof -u max

Anzeige aller offenen Dateien, die nicht der Benutzer "root" geöffnet hat.

$ lsof -u ^root

Verwendung

Identifikation der einen Datenträger blockierenden Prozesse

lsof kann auch zur Identifikation von Prozessen dienen, die verhindern, dass der Benutzer einen Datenträger aushängen kann. Der lsof-Aufruf mit der Option "-t Verzeichnis" liefert eine Liste numerischer Prozess-IDs, die auf die CD-ROM zugreifen. Die Methode ist ebenso drastisch wie wirkungsvoll.

$ umount /dev/cdrom
umount: /cdrom: device is busy
$ kill -15 $(lsof -t /dev/cdrom)
$ umount /dev/cdrom
$ eject

Wiederherstellung gelöschter Daten

Dies klappt mit lsof und cat, solange irgendein Prozess die Dateien noch geöffnet hält. lsof ermittelt dann Datei und Prozess und je nachdem, auf welche Weise der Prozess die Datei geöffnet hat, ist ihr Inhalt an einer anderen Stelle im "/proc"-Dateisystem noch zugänglich.

Stark angestiegene Netzwerklast auf LAMP-System

Angenommen wird, dass die zusätzliche Last nicht über Seitenzugriffe, sondern durch einen Eindringling verursacht wird, der Dateien übers Rechnernetz kopiert, verteilte Netzattacken ausführt oder Spam verschickt. In einer LAMP-Umgebung ist die Schnittstelle von PHP zum System eines der Hauptangriffsziele, da PHP an etlichen konzeptionellen Schwächen leidet, auch schlampig geschriebene Skripte laden Angreifer ein. Der Webserver Apache läuft standardmässig als eigener Benutzer (als "www-data", "apache", "httpd" oder gar als "nobody"). In der Regel laufen zusätzliche Prozesse als Benutzer "root", um privilegierte Ports und die Protokolldateien zu öffnen. Die Datenkommunikation dagegen wird durch unprivilegierte Prozesse erledigt. Auf einem Webserver gibt es also einen bestimmten Erwartungshorizont an Kombinationen aus Benutzern, auszuführenden Dateien und geöffneten Ports.

So führt etwa der Benutzer "www-data" unter Debian das Programm "/usr/bin/apache2" aus. Der folgende Aufruf darf in dieser Umgebung nur Prozesse listen, die "/usr/bin/apache2" als Benutzer "www-data" ausführen. Normalerweise trifft das nur auf die Apache-Prozesse zu. Die Option "-a" sorgt für UND-Verknüpfung, "-d txt" listet nur ausgeführte Dateien und "-u www-data" beschränkt die Ausgabe auf den Benutzer "www-data".

$ lsof -a -d txt -u www-data

Ist es einem Angreifer gelungen, PHP oder PHP-Skripte zu manipulieren und Systembefehle und Programme auf dem Server auszuführen, so laufen diese üblicherweise als derselbe Benutzer wie Apache - ausser wenn der Eindringling über weitere Lücken die Rechte von Benutzer "root" erlangen und seine eigenen Spuren verschleiern konnte. Zeigen sich Prozesse des Apache-Benutzers, die auf anderen Binärdateien basieren oder unerwartete Ports offenhalten, so ist Vorsicht angebracht: mit "lsof -p PID" können verdächtige Prozesse detailliert auf Netzwerkverbindungen, geladene Bibliotheken, geöffnete Dateien und mehr untersucht werden.

Da Cracker gerne ihre eigenen Server für FTP, IRC, Telnet oder SSH mitbringen, gehört zur Erstanalyse auch die Suche nach offenen Ports. Folgender Aufruf listet alle IP-Sockets ("-i"), die der Apache-Benutzer ("-u www-data") geöffnet hat und die als Server auf Verbindungen warten (daher "grep LISTEN").

$ lsof -a -i -u www-data | grep LISTEN

Alles usser den Ports 80 (HTTP) und 443 (HTTPS) ist verdächtig. Ähnliche Resultate liefert zwar auch netstat, doch hilft lsof auch bei der weiteren Analyse und erspart somit einen Programmwechsel.

Mit Hilfe eines kleinen Skripts kann ein vordefinierter Systemzustand mit dem aktuellen Zustand verglichen und bei Abweichungen nach vordefinierten Regeln behandelt werden. Folgende Zeile weist lsof an, netzwerkbezogene Dateien auszugeben ("-i TCP"), ohne dabei Portnummern als Servicename auszuschreiben ("-P") und ohne IP-Adressen in Hostnamen aufzulösen ("-n"). awk fahndet in der Ausgabe nach Ports im Status "LISTEN" und formatiert sie neu als "Benutzername/Prozessname/IP:Port", wobei die IP-Adresse "*" für Server steht, die auf allen Schnittstellen lauschen. Das abschliessende sort ordnet die Ausgabe alphabetisch und sorgt dafür, dass jede Benutzer-Dienst-Kombination nur einmal erscheint ("-u").

$ lsof -i TCP -n -P | awk '/LISTEN/ { print $1"/"$3"/"$8 }' | sort -u

Folgendes lsof-Mini-IDS-Skript merkt sich die aktuelle Port-Konfiguration. Alle 10 Sekunden ("while sleep 10; do") holt lsof die Liste der geöffneten Ports und vergleicht sie mit dem vorigen Status. Hat sich etwas verändert, so wird eine E-Mail mit dem Vorher-Nachher-Status geschickt und der neue Status als neue Basis für weitere Vergleiche benutzt.

#!/bin/bash
MAILTO="root"
HOSTAME=$(hostname)

getports() {
  lsof -i -n -P | awk '/LISTEN/ { print $1"/"$3"/"$8 }' | sort -u
}

OLD="$(getports)"
echo -e "Beginne mit folgender Port-Belegung:\n$OLD"
while sleep 10
  do
  NEW="$(getports)"
  if test "$OLD" != "$NEW"; then
    echo "Aenderung der Portbelegung! Informiere Systemverwalter per E-Mail"
    mail -s "Achtung: $HOSTNAME LISTEN-Status geaendert" $MAILTO <<- EOF-EOF
    Status vor der Aenderung:
    $OLD
    
    Status nach der Aenderung:
    $NEW
EOF-EOF
  fi
  OLD="$NEW"
  done

Zum Testen der Anomalie-Erkennung kann der Systemverwalter einen Port öffnen. Folgender Befehl startet nc im Modus "LISTEN" ("-l") und hält den Port 12345 offen. Nach spätestens zehn Sekunden sollte das in seiner Schleife verharrende Shellskript die Veränderung bemerken und mit einer entsprechenden Warn-E-Mail reagieren.

$ nc -l -p 12345

Achtung: Manche Prozesse verändern ihre für lsof sichtbare Portbelegung, so beispilsweise E-Mail-Server, die je nach dem Zustand der eingehenden Verbindungen zusätzliche Prozesse forken und sie unter anderen Namen laufen lassen. Unter Umständen lösen also auch solche Prozesse einen (falschen) Alarm aus. Das ist durch eine Anpassung in der Abfragelogik des obigen Skripts aber rasch zu unterbinden: ein angehängtes "| grep -v Temporärer Dienst" in der Funktion "getports()" sollte genügen.

FAQ

...

$ lsof -i -P -n
COMMAND   PID     USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
rspamd    568  _rspamd    8u  IPv4   16578      0t0  TCP 127.0.0.1:11332 (LISTEN)
rspamd    568  _rspamd    9u  IPv6   16579      0t0  TCP [::1]:11332 (LISTEN)
rspamd    568  _rspamd   11u  IPv4   17475      0t0  TCP 127.0.0.1:11334 (LISTEN)
rspamd    568  _rspamd   13u  IPv6   17476      0t0  TCP [::1]:11334 (LISTEN)
rspamd    568  _rspamd   15u  IPv4   17481      0t0  TCP 127.0.0.1:11333 (LISTEN)
rspamd    568  _rspamd   17u  IPv6   17482      0t0  TCP [::1]:11333 (LISTEN)
dovecot   571     root   21u  IPv4   15535      0t0  TCP *:110 (LISTEN)
dovecot   571     root   22u  IPv6   15536      0t0  TCP *:110 (LISTEN)
...

Weblinks

Herausgeber Sprache Webseitentitel Anmerkungen
country DE.gif Johannes Franken eng, ger lsofwbm Anwendungsbeispiele für lsof
country US.gif Wikipedia eng lsofwbm Enzyklopädischer Artikel