lsof: Unterschied zwischen den Versionen

Aus Mikiwiki
Zur Navigation springen Zur Suche springen
Zeile 132: Zeile 132:
  $ <b>lsof -a -i -u www-data</b>
  $ <b>lsof -a -i -u www-data</b>


=== Identifikation von Prozessen, die verhindern, dass der Benutzer einen Datenträger aushängen kann ===
=== Identifikation von einen Datenträger blockierenden Prozessen ===


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.
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.


  $ <b>umount /dev/cdrom</b>
  $ <b>umount /dev/cdrom</b>

Version vom 10. Januar 2009, 12:32 Uhr

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.

Installation

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

Holen der Quellen aus dem Netz, Prüfen der Signatur mit GNU PG, Konfiguration der Quellen und Kompilierung. 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.

$ 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
$ ./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 allerdings ein Eindringling den Kernel (etwa mit einem Kernel-Rootkit) ä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
-i4 Anzeige aller IPv4-Verbindungen.
-n Unterdrücken der Namensauflösung.
-P Unterdrücken der Portnamensauflösung.

Verwendung

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

lsof gibt die je nach Parameterliste gefilterten Informationen der offenen Dateien in einem tabellarischen Format aus. Per Vorgabe zeigt es folgende Spalten:

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

Die Ausgabe lässt sich über "lsof -F <Felder>" auch für die Übergabe an weiterverarbeitende Programme aufbereiten. Eine spezielle Formatierung sorgt dafür, dass die nachgeschalteten Tools einzelne Felder besser parsen können. Details dazu finden sich im Manpage-Abschnitt "Output for other programs".

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

Anzeige aller Prozesse, die gerade auf Dateien zugreifen.

$ lsof

Anzeige aller Prozesse, die gerade auf die Datei "/usr/bin/vim" zugreifen (also mit vi arbeiten).

$ lsof /usr/bin/vim

Anzeige aller Prozesse, die gerade auf die CD-ROM-Gerätedatei "/dev/hdc" zugreifen.

$ lsof /dev/hdc

Beenden aller Prozesse, die noch auf ein ins CD-ROM-Laufwerk eingelegtes Medium zugreifen.

$ kill $(lsof -t /cdrom)

Anzeige aller offenen Dateien des Prozesses mit der PID 2326.

$ lsof -p 2326

Anzeige aller offenen Dateien im Verzeichnis "/tmp" und seinen Unterverzeichnissen, ohne dabei auf symbolische Links zu achten.

$ lsof +D /tmp

Anzeige aller vom Benutzer "max" geöffneten Dateien.

$ lsof -u max

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

$ lsof -u ^root

Anzeige einer ähnlichen Prozessliste wie ps aux durch Auflisten der Einträge mit Dateideskriptoreintrag "txt" statt der sonst üblichen Nummer ("txt" steht für Programmcode und Daten, also eine ausgeführte Datei).

$ lsof -d txt

Anzeige aller gelöschten Dateien, die noch geöffnet sind und daher Plattenplatz verbrauchen, aber in keinem Verzeichnis erscheinen (Dateien mit weniger als einem Link).

$ lsof +L1

Anzeige aller netzwerkrelevanten Dateien.

$ lsof -i

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

$ lsof -i -P -n

Anzeige aller IPv6-bezogenen Dateien.

$ lsof -i6

Anzeige aller aktiven Verbindungen.

$ lsof -i | grep '\->'

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

$ lsof -a -i -u www-data

Identifikation von einen Datenträger blockierenden Prozessen

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 Netzwerk kopiert, verteilte Netzattacken ausführt oder Spam-E-Mails 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 Logdateien 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 Aufruf "lsof -a -d- txt -u www-data" darf in dieser Umgebung nur Prozesse listen, die "/usr/bin/apache2" als Benutzer "www-data" ausführen (Die Option "-a" sorgt für UND-Verknüpfung, "-d txt" listet nur ausgeführte Dateien, "-u www-data" beschränkt die Ausgabe auf den Benutzer "www-data"). Normalerweise trifft das nur auf die Apache-Prozesse zu.

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 Benutezr 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 abseits der 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 asls 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 dafpr, 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
Status vor der Aenderung:
$OLD

Status nach der Aenderung:
$NEW
EOF
  fi
  OLD="$NEW"
done

Zum Testen der Anomalie-Erkennung kann der Systemverwalter einen Port öffnen. Folgender Befehl startet Netcat im Mosus "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, z. B. 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.

Weblinks

  • lsof (JFranken.de) - Anwendungsbeispiele für lsof

Vorlage:enwi