Konkrete Kritik an CVSS4
Marc Ruef
In den ersten drei Teilen dieser Artikelserie haben wir uns mit den grundlegenden Mechanismen von NSE vertraut gemacht und erste Plugins geschrieben, die sich auf den durch nmap selbst gesammelten Informationen abstützen. Diese haben wir als derivative Skripte bezeichnet.
Im vierten Teil werden wir beginnen die zusätzlichen Möglichkeiten von NSE gänzlich auszuschöpfen, indem eigene Netzwerkkommunikationen angestrebt werden. Durch das eigene Absetzen von unabhängigen Netzwerkzugriffen können weiterführende Auswertungen und Angriffe angestrebt werden, wodurch nmap zu einem vollumfänglichen Vulnerability Scanner erweitert werden kann. Dieses Prinzip werden wir an einem Test für FTP-Server illustrieren.
Wir versuchen durch das Ausführung des FTP-Kommandos STAT
eben die Unterstützung für dieses – es kann für Auswertungen der FTP-Implementierung missbraucht werden – auszumachen. Ein solcher Test erfordert eine initiale Authentisierung am FTP-Server mit legitimen Login-Credentials (im Beispiel wird ein anonymer FTP-Zugang verwendet) und die darauffolgende Eingabe des Befehls STAT
. Wird dieser unterstützt, liefert der FTP-Server den Statuscode 211
zurück und informiert über verschiedene Funktionalitäten und Eigenschaften der gegenwärtigen Verbindung:
C:\Users\mruef>telnet 192.168.0.11 21 220 192.168.0.11 FTP server ready USER ftp 331 Anonymous login ok, send your complete email address as your password. PASS example@test.invalid230-
Welcome to the Demo Server230 Anonymous access granted, restrictions apply. STAT 211-Status of ‘scip ftp server – this is just a demo’ Connected from maru.scip.ch (192.168.0.100) Logged in as ftp TYPE: ASCII, STRUcture: File, Mode: Stream No data connection 211 End of status
Dieser Zugriff soll nun mit einem NSE-Skript automatisiert werden. Zuerst sollen die Vorbereitungen für das Skript, in nachfolgendem Codeblock abgebildet, stattfinden. Mit der Funktion nmap.new_socket()
wird ein neuer Socket für die lokale Funktion angelegt, mit der wir die FTP-Zugriffe durchführen wollen. Die Rückantwort des FTP-Servers legen wir in der lokalen String-Variable result
ab und den aktuellen Status der FTP-Kommunikation speichern wir in der boolschen Variable status
. In einer weiteren boolschen Variable wird zwischengelagert, ob das geprüfte Kommando als unterstützt identifiziert werden konnte (durch die Initialisierung zu Beginn lautet der Wert false
).
local socket = nmap.new_socket() local result local status = true local cmdpossible = false
Danach richten wir eine Error Catch-Funktion ein, mit der wir Fehler abfangen wollen. Diese wird später automatisch durch eine Anweisung durchlaufen, wird sie denn mit try()
aufgerufen, sofern diese fehlschlägt. In diesem Beispiel wollen wir hiermit sämtliche Probleme abfangen, die bei der Netzwerkkommunikation entstehen können (z.B. Verbindungsabbruch). Tritt dieser Fall ein, wird die Funktion err_catch
genutzt, um mittels socket:close()
den etwaig belegten Socket zu schliessen und damit wieder freizugeben. Damit wird ein Skriptabbruch bzw. ein Skriptaufhängen verhindert.
local err_catch = function() socket:close() endlocal try = nmap.new_try(err_catch)
Jetzt können wir mit der Umsetzung effektiver Netzwerkkommunikationen beginnen. Zuerst definieren wir mit socket:set_timeout(10000)
das Timeout des genutzten Sockets. Nach 10’000 ms wird in jedem Fall ein Verbindungsabbruch initiiert, um ein Aufhängen des Skripts zu verhindern. Die nachfolgenden Befehle werden jeweils mittels der zuvor besprochenen try()
-Funktion aufgerufen. Durch socket:connect()
wird eine Verbindung zu einem Zielport hergestellt, wobei als erstes Argument das Zielsystem, als zweites der Zielport und als drittes das Transportprotokoll definiert wird.
Nachdem die TCP-Verbindung etabliert wurde, kann socket:send()
verwendet werden, um Kommandos zu verschicken. Hierbei findet eine übliche Authentisierung im Rahmen von FTP mit den Kommandos USER
und PASS
statt. Die while
-Schleife wird nun solange durchlaufen, bis entweder status
auf false
gesetzt wird (wurde mit true
initialisiert) oder das Timeout einsetzt (wurde auf 10 Sekunden gesetzt). Bei jedem Durchlaufen der Schleife wird versucht mittels socket:receive_lines(1)
jeweils eine Zeile der Rückantwort – sie wird als String in result
abgelegt – zu erhalten. Ist dies der Fall, wird durch den regulären Ausdruck in string.match(result, "^230")
versucht zu erkennen, ob die Zeile mit dem Statuscode 230
beginnt. Dies ist der zu erwartende Statuscode eines FTP-Servers, wenn dieser eine anonyme Authentisierung erfolgreich zugelassen hat. Ist dies der Fall, wird die Schleife mittels break
beendet und weiter im Code verfahren.
socket:set_timeout(10000) try(socket:connect(host.ip, port.number, port.protocol)) try(socket:send("USER anonymous\r\n")) try(socket:send("PASS example@test.invalid\r\n")) while status do status, result = socket:receive_lines(1); if string.match(result, "^230") then break end end
Nach der erfolgreichen Authentisierung kann nun in gleicher Weise probiert werden, ob der FTP-Server auf das STAT
-Kommando reagiert. Auch hier wird mit socket:send()
die FTP-Anfrage geschickt, mit einer while
-Schleife auf die Rückantwort gewartet, diese versucht mittels socket:receive_lines()
abzugreifen und durch string.match(result, "^211")
auf Erfolg hin zu prüfen. Der FTP-Server schickt den Statuscode 211
zurück, sollte er das STAT
-Kommando unterstützen. Ist dies der Fall, wird die Variable cmdpossible
auf true
gesetzt.
Jetzt kann mit socket:close()
der offene Socket geschlossen werden (in manchen NSE-Dokumentationen wird zuerst der reguläre Verbindungsabbau innerhalb des Anwendungsprotokolls empfohlen; im Fall von FTP ist dies QUIT
). Durch eine letzte Prüfung von cmdpossible
auf true
kann nun enddgültig verifiziert werden, ob die Schwachstelle existiert. Ist dies der Fall, wird die letzte Rückgabe, die in der Variable result
abgelegt wurde, mittels return
ausgegeben werden.
try(socket:send(“STAT\r\n”)) while status do status, result = socket:receive_lines(10); if string.match(result, “^211”) then cmdpossible = true break elseif string.match(result, “^502”) then cmdpossible = false break end end socket:close()if cmdpossible == true then return result end
Dieses Plugin kann nun in Aktion gesehen werden. Wir rufen es in üblicher Weise auf. Es stellt nun wie gewollt die Rückantwort des FTP-Servers, unterstützt dieser denn das geprüfte STAT
-Kommando, dar. Dieser hohe Detailgrad hilft dem Anwender dabei, auf einen Blick zu sehen, welche Funktionalität gewährleistet wird und wie sich diese genau verhält.
C:\Users\mruef>nmap -sS -PN —script=“labs” -p 21 ftp.scip.chStarting Nmap 5.21 ( http://nmap.org ) at 2010-04-04 15:40 Mitteleuropõische Sommerzeit Nmap scan report for ftp.scip.ch (192.168.0.11) Host is up (0.025s latency). rDNS record for 192.168.0.11: ftp.scip.ch PORT STATE SERVICE 21/tcp open ftp | ftp_stat_support: 211-Status of ‘scip ftp server – this is just a demo’ | Connected from maru.scip.ch (192.168.0.100) | Logged in as ftp | TYPE: ASCII, STRUcture: File, Mode: Stream | No data connection |_211 End of status
Nmap done: 1 IP address (1 host up) scanned in 12.87 seconds
Im zweiten Teil haben wir den Debug-Schalter besprochen. Dieser kann beim Aufruf von nmap mittels -d
aktiviert werden, um Debugging-Informationen zum Scan-Ablauf ausgeben zu lassen. Dies kann sehr hilfreich sein, um die Funktionalität eines Skripts zu überprüfen.
Ein Skript selber kann über nmap.debugging()
die Aktivierung dieser Option überprüfen. Wurde das Debugging nicht aktiviert, liefert diese Funktion den Wert 0
zurück. Mit einem Aufruf von -d2
kann gar das Debugging-Level 2
, es wird ebenfalls so von der Funktion zurückgegeben, aufgerufen werden.
if nmap.debugging() > 0 then
Im Rahmen von intelligenten Plugins kann mit einer solchen Abfrage das Verhalten bzw. die Ausgabe dessen beeinflusst werden. Zum Beispiel könnte das soeben entwickelte Skript ohne Aktivierung des Debugging lediglich die Unterstützung der geprüften Funktion ausweisen. Im Fall von -d
könnte aber, so wie im Beispiel gezeigt, zusätzliche Informationen zu den Rückgabewerten abgedruckt werden.
Im nächsten Teil werden wir uns mit der Library http
vertraut machen. Diese bietet verschiedene Funktionen an, mit denen HTTP-Kommunikationen durchgeführt werden können. Das Auswerten von Webserver und Webapplikationen wird damit massgeblich vereinfacht.
Unsere Spezialisten kontaktieren Sie gern!
Marc Ruef
Marc Ruef
Marc Ruef
Marc Ruef
Unsere Spezialisten kontaktieren Sie gern!