Nmap NSE Hacking, Teil 3: Komplexes Skript mit Version Info

Nmap NSE Hacking, Teil 3

Komplexes Skript mit Version Info

Marc Ruef
von Marc Ruef
Lesezeit: 12 Minuten

In Teil 1 haben wir das grundlegende Konzept von NSE-Skripting vorgestellt und in Teil 2 ein simples Plugin zur Ableitung von Portzuständen entwickelt. Im dritten Teil soll die Entwicklung vorangetrieben werden. So werden wir ein komplexeres Skript umsetzen, welches die Möglichkeiten des Application Fingerprinting resultierend aus dem Aufruf mit dem Schalter -sV umfänglich ausschöpfen wird.

Wird nmap mit dem Schalter -sV aufgerufen, wird das sogenannte Service and Version Fingerprinting umgesetzt. Als erstes wird bei einem offenen Ports mittels Application Mapping versucht zu ermitteln, was für ein Transportprotokoll angeboten wird. Es ist schliesslich wichtig für weiterführende Zugriffe zu wissen, ob ein Webserver mit HTTP oder ein Mailserver mit SMTP eingesetzt wird. Im gleichen bzw. im zweiten Schritt wird versucht mittels Application Fingerprinting das eingesetzte Produkt (Name und Versionsnummer) zu erkennen. Eine solche Identifikation wird erforderlich, um produktspezifische Auswertungen und Angriffe voranzutreiben.

Wird ein Scan mit aktivierter Version Detection durchgeführt, kann innerhalb von NSE auf die damit zusammengetragenen Informationen zurückgegriffen werden. Diese sind in port.version.* abgelegt und können einzeln angesteuert werden. Folgende Tabelle verdeutlicht, dass sich ein analysierter SSH-Dienst umfassend auswerten lässt:

Variable Inhalt Beispiel
port.version.name Name des Anwendungsprotokolls ssh
port.version.product Name des Produkts OpenSSH
port.version.version Versionsnummer des Produkts 4.7
port.version.extrainfo Zusätzliche Informationen (protocol 1.99)

Im zweiten Teil haben wir die shortport-Library genutzt, um eine möglichst simple Portrule zu definieren. Doch es gibt Situationen, nämlich wenn komplexe Ausdrücke verwendet werden sollen, in denen eine manuelle Portrule umgesetzt werden muss. Durch eine entsprechende Funktion soll in portrule ein wahrer Wert abgelegt werden. Liefert portrule entweder nil, false oder eine leere Zeichenkette zurück, dann wird action nicht ausgeführt. In allen anderen Fällen schon. Es liegt nun also an uns, anhand des komplexen Ausdrucks die effektive Skript-Ausführung einzuleiten.

Nachfolgende Funktion versucht zu erkennen, ob in port.service als erkanntes Anwendungsprotokoll smtp definiert wurde. Zusätzlich wird in port.version.product überprüft, ob die Zeichenkette sendmail im Rahmen der Version Detection ermittelt wurde. Dadurch kann eindeutig identifiziert werden, ob auf dem Zielport eine Sendmail-Implementierung vorhanden ist. Dies geschieht durch die uns schon bekannte Funktion string.match(), welche mit Pattern und regulären Ausdrücken umgehen kann.

portrule = function(host, port)
   if port.service == "smtp" and
      (port.version.product ~= nil and
      string.match(port.version.product, "Sendmail")) then
      return true
   else
      return false
   end
end

Obschon diese Determinierung relativ simpel erscheint, können mit ihr gewisse Komplikationen einhergehen. Doch bevor darauf eingegangen werden soll, soll das grundlegende Prinzip der Version Detection besprochen werden. Nmap nutzt die Datei nmap-service-probes, um unterschiedliche Anfragen an einen Zielport zu schicken. Anhand eines regulären Ausdrucks wird die Rückantwort untersucht, um die gegebene Implementierung zu erkennen. Nachfolgende Zeilen werden beispielsweise genutzt, um Sendmail auf einem SMTP-Port zu erkennen:

match smtp m|^220[\s-](\S+) E?SMTP Sendmail (\d[^; ]+)| p/Sendmail/ h/$1/ v/$2/ o/Unix/
match smtp m|^220[\s-](\S+) E?SMTP Sendmail AIX([\d.]+)/(\d[^; ]+)| p/Sendmail/ h/$1/ v/$3/ i/AIX $2/ o/AIX/
match smtp m|^220[\s-](\S+) E?SMTP Sendmail AIX([\d.]+)/UCB (\d[^; ]+);| p/Sendmail/ h/$1/ v/$3/ i/AIX $2/ o/AIX/
match smtp m|^220[\s-](\S+) E?SMTP Sendmail \(#\)Sendmail version (\d[^; ]+) - Revision ([\d.]+) | p/Sendmail/ h/$1/ v/$2 rev $3/ o/HP-UX/
match smtp m|^220[\s-](\S+) E?SMTP Sendmail \(#\)Sendmail version (\d[^; ]+) - Revision ([\d.]+):: HP-UX([\d.]+)| p/Sendmail/ h/$1/ v/$2 rev $3/ o/HP-UX $4/

Wie im zuvor gezeigten Code-Beispiel kann nun direkt in port.version.product nach dem Produktnamen Sendmail gesucht werden. Eine solche Prüfung kann jedoch versehentlich fehlschlagen, wenn die zur Identifikation eingesetzte Schreibweise nicht berücksichtigt wird. Ein typisches Beispiel der inkonsistenten Schreibweise ist der Produktenamen VMware, der von vielen Leuten als Vmware (das M ist klein) geschrieben wird. In letztgenannten Fall würde eine Prüfung mit if port.version.product == "VMware" fehlschlagen (gleiches Problem ist zum Beisipel auch bei JetDirect zu beobachten). Aus diesem Grund kann es wichtig sein, dass die zuvor eingeführte Prüfung normalisiert wird, indem die Gross-/Kleinschreibung vereinheitlicht wird. Durch die Funktion string.lower() kann eine Zeichenkette komplett kleingeschrieben werden. Dadurch kann dann eine Prüfung gegenüber der durchgängig kleingeschriebenen Schreibweise sendmail – also case-insensitive – stattfinden:

string.match(string.lower(port.version.product), "sendmail"))

Eine zusätzliche Schwierigkeit der Identifikation kann sein, dass der Produktenamen nicht eindeutig ausfällt. Zum Beispiel dann, wenn ein Hersteller den Namen einer Produkteserie anpasst oder verschiedene Produkte in einer Produktpalette zusammenfasst. Ein typisches Beispiel ist ISS RealSecure. Die kommerzielle Lösung bietet verschiedene Intrusion Detection-Komponenten an. Nachfolgend werden die Identifikationsmuster von nmap abgedruckt:

match iss-realsecure m|^\0\0\0.\x08\x01\x03\x01\0.\x02\0\0..\0\0.\0\0\0..\0\0\x80\x04..\0.\0\xa0|s p/ISS RealSecure IDS/ o/Windows/
match iss-realsecure m|^\0\0\0.\x08\x01\x04\x01\0..\0\0..\0\0.\0\0\0..\0\0\x80\x04..\0.\0\xa0\0\0|s p/ISS RealSecure IDS ServerSensor/ v/6.0 - 7.0/ o/Windows/

Es ist zu sehen, dass die Identifikation einer RealSecure-Installation als solche durchaus möglich ist. Schliesslich benutzt die Version Detection stets die Zeichenkette ISS RealSecure IDS in der Ausgabe. Von da unterscheiden sich jedoch die jeweiligen Implementationen und ihre Nennungen. Im ersten Fall wird generisch der Hinweis mit ISS RealSecure IDS auf Windows dargestellt. Im zweiten Fall wird jedoch zusätzlich die Versionsnummer mit IDS ServerSensor ServerSensor v6.0 - 7.0, ebenfalls auf Windows, eingeschränkt.

In letztgenanntem Fall findet also eine struktere Eingrenzung statt. Diese soll nun, soll denn eine RealSecure-Installation im Allgemeinen erkannt werden, wieder abstrahiert werden. Zu diesem Zweck kann innerhalb von string.match() mit regulären Ausdrücken gearbeitet werden. Mit dem Zeichen ^ wird angegeben, dass die nachfolgende Zeichenkette zu Beginn gefunden werden muss. Da diese Zeichenkette mit beiden Identifikationen übereinstimmt, lässt sich damit die generische Identifikation des Produkts umsetzen.

string.match(port.version.product, "^ISS RealSecure")

Die in den vorangehenden Teilen dieser Dokumentationsserie sowie dem an dieser Stelle diskutierten Thema erlauben nun das Umsetzen von mehrstufigen Skripten. Ein Skript kann als mehrstufig verstanden werden, wenn es eine zusätzliche Applikationslogik enthält, die eine Identifikation einer Gegebenheit bzw. Schwachstelle auf unterschiedlichen Ebenen durchführen kann.

Die nun gezeigte Erweiterung bietet eine dreistufige Lösung, um einen SMTP-Mailserver als solchen zu identifizieren. Als erstes wird versucht anhand der Service Detection in port.version.product die Zeichenkette Sendmail zu finden. Ist dies der Fall, liefert die Portrule die Zeichenkette Application Fingerprinting zurück. Die Genauigkeit der Identifikation ist damit sehr hoch. Kann sie jedoch nicht umgesetzt werden, wird als zweites versucht den Zielport mittels port.service als smtp zu identifizieren. Ist dies erfolgreich, wird die Zeichenkette Application Mapping zurückgeliefert. Und versagt auch dieser Test, wird als dritte und letzte Möglichkeit versucht den Zielport anhand seiner Nummer in port.number mit 25 als Standardport zu ermitteln. In diesem Fall wird die Zeichenkette Portscan zurückgegeben. Kann keine der drei Identifikationsebenen einen Erfolg verbuchen, schickt die Funktion den Wert false zurück.

portrule = function(host, port)
   if string.match(port.version.product, "Sendmail") then
      return "Application Fingerprinting"
   elseif port.service  "smtp" then
      return "Application Mapping"
   elseif port.number  25 then
      return "Portscan"
   else
      return false
   end
end

Die weiterführende Ausführung des Skripts kann sodann von den unterschiedlichen Rückgabewerten, den dabei zugrundeliegenden Identifikationsmethoden und der damit einhergehenden Genauigkeit abhängig gemacht werden. Zum Beispiel liesse sich in der Skript-Ausgabe ein Wert für Accuracy bzw. Confidence ausgeben. Der Benutzer des Skripts kann anhand dessen ableiten, wie genau und zuverlässig der Test funktioniert hat. Im weitesten Sinn versucht zum Beispiel der kommerzielle Vulnerability Scanner Qualys mit einer zweidimensionalen Risikoangabe das gleiche Ziel zu erreichen (PRACTICE bezeichnet potentielle Schwachstellen und VULN identifiziert ausgenutzte Schwachstellen).

Im vierten Teil werden wir erstmalig besprechen, wie sich eigene Netzwerkzugriffe realisieren lassen. Damit muss sich nicht mehr nur von den standardmässig durch nmap zusammengetragenen Informationen (Portstatus und Version Detection) abhängig gemacht werden. In ergänzender und alternativer Weise können effektive Anfragen an das Zielsystem geschickt und die Rückantworten ausgewertet werden. Damit wird sich ein voll funktionstüchtiger Vulnerability Scanner realisieren lassen.

Über den Autor

Marc Ruef

Marc Ruef ist seit Ende der 1990er Jahre im Cybersecurity-Bereich aktiv. Er hat vor allem im deutschsprachigen Raum aufgrund der Vielzahl durch ihn veröffentlichten Fachpublikationen und Bücher – dazu gehört besonders Die Kunst des Penetration Testing – Bekanntheit erlangt. Er ist Dozent an verschiedenen Fakultäten, darunter ETH, HWZ, HSLU und IKF. (ORCID 0000-0002-1328-6357)

Links

Sie wollen mehr als einen simplen Security Test mit Nessus und Nmap?

Unsere Spezialisten kontaktieren Sie gern!

×
Konkrete Kritik an CVSS4

Konkrete Kritik an CVSS4

Marc Ruef

scip Cybersecurity Forecast

scip Cybersecurity Forecast

Marc Ruef

Voice Authentisierung

Voice Authentisierung

Marc Ruef

Bug-Bounty

Bug-Bounty

Marc Ruef

Sie wollen mehr?

Weitere Artikel im Archiv

Sie brauchen Unterstützung bei einem solchen Projekt?

Unsere Spezialisten kontaktieren Sie gern!

Sie wollen mehr?

Weitere Artikel im Archiv