Nmap NSE Hacking, Teil 4: Netzwerkkommunikationen

Nmap NSE Hacking, Teil 4

Netzwerkkommunikationen

Marc Ruef
by Marc Ruef
time to read: 10 minutes

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

230-

Welcome to the Demo Server

230 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()
end

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

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

About the Author

Marc Ruef

Marc Ruef has been working in information security since the late 1990s. He is well-known for his many publications and books. The last one called The Art of Penetration Testing is discussing security testing in detail. He is a lecturer at several faculties, like ETH, HWZ, HSLU and IKF. (ORCID 0000-0002-1328-6357)

Links

You want more than a simple security test with Nessus und Nmap?

Our experts will get in contact with you!

×
Specific Criticism of CVSS4

Specific Criticism of CVSS4

Marc Ruef

scip Cybersecurity Forecast

scip Cybersecurity Forecast

Marc Ruef

Voice Authentication

Voice Authentication

Marc Ruef

Bug Bounty

Bug Bounty

Marc Ruef

You want more?

Further articles available here

You need support in such a project?

Our experts will get in contact with you!

You want more?

Further articles available here