Scanner und Sockets

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
kT0Rz

Moin Moin miteinander,

ich hab mir kürzlich ein Buch zu Python gekauft und nun versuche ich einen kleinen Scanner zu schreiben, welcher
guckt wie die Antwort verschiedener Ports von verschiedenen IP-Adressen auf meinen Verbindungsversuch lautet (so verstehe ich zumindest das Script).

Ich hab mich hierbei nach der Anleitung gerichtet und bemerkt das der offizielle Quellcode, welcher ein wenig modifiziert wurde, nicht mal funktioniert.
Nachdem ich von Sockets keine Ahnung habe, wäre es nett wenn jmd mal drüber gucken könnte und mir sagen könnte was da am schieflaufen ist.

Code: Alles auswählen

import socket

def retBanner(ip, port):
    try:
        socket.setdefaulttimeout(2)
        s = socket.socket()
        s.connect((ip, port))
        banner = s.recv(1024)
        return banner
    except:
        print "ERROR - couldn't connect."    
        return
        
def checkVulns(banner):
    if 'FreeFloat Ftp Server (Version 1.00)' in banner:
        print '[+] FreeFloat FTP Server is vulnerable.'
    elif '3Com 3CDameon FTP Server Version 2.0' in banner:
        print '[+] 3CDameon FTP Server is vulnerable.'
    elif 'Ability Server 2.34' in banner:
        print '[+] Ability Server 2.34 is vulnerable.'
    elif 'Sami FTP Server 2.0.2' in banner:
        print 'Sami FTP Server is vulnerable.'
    else:
        print '[-] FTP Server is not vulnerable.'
    return
    
def main():
    portList = [21,22,25,80,110,443]
    for x in range(1, 255):
        ip = '192.168.0.' + str(x)
        for port in portList:
            banner = retBanner(ip, port)
        if banner:
            print '[+] ' + ip + ': ' + banner
            checkVulns(banner)
            
if __name__ == '__main__':
    main()
Ich verstehe hier ein paar Sachen leider auch nicht, wie z.B. am Ende der Funktion main(), wo die Variable banner zur print Ausgabe hinzugefügt wird und darunter eine Funktion einfach so da steht, ohne + ohne sonst was.

Den Error Code bei retBanner(ip,port) nach except hab ich selbst hingeschrieben, nachdem ich ansonsten gar keine Antwort zurück bekommen habe.
So weiß ich zumindest, dass es nicht geht.
Er scheint jedoch mehrere Sachen zu überprüfen, da der Error Code ins unendliche schießt (gefühlt).

Bei einem ähnlichen (einfacheren) Code, welcher auf dem gleichen Prinzip basiert, bekomme ich immer die Fehlermeldung "[Errno 111] Connection refused".
Also entweder bin ich zu dumm dafür, oder das Buch verzapft mir was falsches, da dieser Code eigentlich abgetippt ist.


Hoffe ihr könnt mir helfen.

Grüße
BlackJack

@kT0Rz: Es scheint als hättest Du da etwas abgeschrieben und versuchst jetzt durch raten die Python-Grundlagen herauszufinden. Warum sollte denn bei dem Funktionsaufruf irgendwo ein ``+`` stehen? Schau Dir noch mal die Einrückungen an, ob die Deiner Meinung nach alle korrekt sind. (Meiner Meinung nach nicht. ;-))
kT0Rz

Wow, so wird man gerne in einem Forum begrüßt, zumal meine eigentliche Frage hier ignoriert wurde.

Natürlich habe ich es abgeschrieben, habe ich ja auch im Post oben geschrieben....
Ich bin am Grundlagen erlernen mit diesem Buch, das Buch hat hier leider mehrere neue Sachen von ein auf der andere Seite eingeführt, wodruch ich mir halt eine Frage gestellt habe.
Wie böse von mir - kommt nicht wieder vor...
Die Einrückungen sind eins zu eins aus dem Buch, wenn mir die Grundlagen also falsch erlernt werden, kann ich doch nichts dafür...
BlackJack

@kT0Rz: Was war denn die eigentliche Frage? Die habe ich tatsächlich anscheinend überlesen.

Also entweder taugt das Buch nichts. Oder das Beispiel bringt Sachen die im folgenden dann erst erklärt werden, dann müsstest Du das Buch weiter durcharbeiten bis Deine Frage(n) bezüglich des Beispiels geklärt sind. Oder die Sachen wurde vorher erklärt, aber Du hast sie noch nicht ganz durchdrungen, dann müsstest Du nochmal zurück gehen im Buch.

Was an dem Programm auf jeden Fall falsch ist, das ist die Einrückung. Wenn die im Buch auch schon falsch ist, dann müsstest Du halt mal schauen wo sie falsch ist und das korrigieren, in dem Du Dir den Programmablauf klar machst wie er *jetzt* ist, und wie er eigentlich sein müsste.
kT0Rz

Die eigentliche Frage war, warum die Connection immer refused wird bzw. warum ich keine Antwort/ Ausgabe in der Konsole bekomme (außer meine selbst geschriebene Error-Meldung).

Könnte natürlich sein, dass das Buch zum Grundlagen beibringen auch im Code schon andere/ neue Sachen erwähnt, welche noch nicht von Relevanz sind.
Ich verstehe aber immer gerne alles, wodurch ich jz auch schon auf der ein oder anderen Seite viel Zeit verbracht habe, und mir mehrere Dokumentationen durchgelesen habe.

Was an der Einrückung (an welcher Stelle genau?) falsch ist verstehe ich leider nicht.
Wenn ich das Script laufen lasse, gibts nämlich auch keine Fehlermeldung.
Wie gesagt, sind die gleichen vom Buch, und so hab ich das jetzt immer erfolgreich gemacht.


Ich denke eher, dass oben bei den sockets etwas falsch ist, da ich noch nie irgendwo anders das so gesehen habe.

Meine Hauptfrage war nämlich der Fakt, dass das Script seine Aufgabe nicht tut und sich mit keiner einzigen IP auf keinen einzigen Port verbinden kann.

Grüße
BlackJack

@kT0Rz: Der Verbindungsfehler ist zu erwarten. Du versuchst Dich bei 254 IPs mit jeweils sechs Ports zu verbinden. Das gäbe nur dann keinen Verbindungsfehler wenn Du in dem Netz tatsächlich alle 254 IPs an Geräte vergeben hättest bei denen jeweils an jedem diesen sechs Ports auch ein Server lauschen würde der die Verbindung annimmt. Bei wie vielen der 1524 Verbindungsversuche erwartest Du das denn? Insofern ist 'ERROR' auch ein bisschen übertrieben.

Bei sinnhaft falscher Einrückung gibt es grundsätzlich erst einmal keine Fehlermeldung weil der Rechner nicht weiss was Du *eigentlich* machen möchtest. Der macht, so gut wie er kann, das was Du ihm sagst und nicht das was eigentlich gemeint war. Wenn Rechner *das* könnten, bräuchte man wahrscheinlich keine Programmierer im herkömmlichen Sinne mehr. ;-)
kT0Rz

Soll Leute geben die 250 Geräte im Netz haben :P
Spaß beiseite, ist klar, mein Fehler, natürlich sind nicht alle IPs vergeben, wodurch natürlich nicht alle angesprochen werden können.
Um die Anzahl der IPs gehts mir aber gar ned (war vllt blöd, dieses Script als Beispiel zu nehmen - sorry meinerseits), da auch bei einer IP mit nur einen Port zum Überprüfen alles geblockt wird.
Habe ich den was falsch beim Ansprechen der IP gemacht oder sollte dies stimmen?

Hier der andere Code:

Code: Alles auswählen


import socket

def main():

    socket.setdefaulttimeout(2)
    s = socket.socket()

    # try to connect to the IP 192.168.0.30 on port 80
    try:
        s.connect(("192.168.0.30",80))

    # if there's an error, then print it out
    except Exception, e:
        print ""+str(e)

# if the python interpreter starts, then do function main()
if __name__ == "__main__": main()

Ok, kannst du mir bitte trotzdem sagen, wo die Einrückung falsch ist, da mein Lehrbuch mir da nicht weiter helfen kann, weil es da genauso gehandled wird? :)

Grüße
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

Ich denke, dir ist nicht klar, was das Scanner-Programm eigentlich leisten soll. Es soll überprüfen, ob es im Netz 192.168.0.0/24 Rechner gibt bei denen man sich auf eines der Ports 21,22,25,80,110,443 verbinden kann. Ist dies der Fall, wird die Antwort des Rechners, die er bei einem Verbindungsaufbau gibt, zurückgegeben(retBanner). Erkennt das Programm an der Antwort, dass es sich um einen der Angeführten FTP_server Versionen handelt, die Sicherheitslücken enthalten, dann wird das zusätzlich ausgegeben (checkVulns). Wenn es keinen Rechner mit der IP gibt oder an dem Port keine Verbindung aufgebaut werden kann, sollte nichts zurückgegeben werden . Du gibst allerdings überflüssiger Weise "ERROR - couldn't connect." zurück.

Insgesamt werden bei 256 IP-Adressen 6 Ports überprüft, das sind ca. 1350 Überprüfungen. Meistens dauert die Überprüfung 2 Sekunden (Timeout), also dauert die gesamte Überprüfung etwa 2700 Sekunden. Das sind 45 Minuten.
BlackJack

@miracle173: Die Überprüfung dauert nicht zwei Sekunden! Meistens ist ganz schnell klar, dass auf der Gegenseite nichts auf dem Port lauscht und es gibt sofort den Verbindungsfehler den der OP sieht. Manchmal wird auf der Gegenseite ein Server lauschen und die Anfrage beantworten. Und von diesen Fällen könnte es ein paar geben die am Anfang keine Daten schicken sondern darauf warten das der Client Daten schickt. Und nur für diese ist dann die zwei Sekunden-Grenze nötig, damit wenn beide Seiten darauf warten das die jeweils andere Seite Daten schickt, nicht bis zum Sankt-Nimmerleinstag gewartet wird.
kT0Rz

Wie lange würde dann eine komplette Überprüfung der kompletten IP-range mit all den ausgewählten Ports (in meinen Fall von oben) ca. dauern?

Also hätte ich ja bei mir ja die defaulttimeout Funktion weglassen können, oder?
(Da es sich ja bei mir um einen ganz normalen Webserver handelt --> bezogen jetzt auf das zweite Script)

Hast du ein Beispiel für eine solche Konfiguration (Server wartet auf "Post" vom Client) parat?
Ich würde mir das so vorstellen, dass der Server beispielsweise ein Anmeldeformular bereitstellt, welches z.B. nicht über Port 80 läuft, wo der
Server auf eine Antwort vom Client wartet.
Oder habe ich das jetzt falsch verstanden?

Ich habe meinen Fehler übrigens gefunden...
Vor lauter Python-Scripting, habe ich ganz vergessen mir die IP meines Servers noch einmal genauer anzusehen...
So hat Virtualbox der Schlingel meinen Netzwerkmodus wieder verändert und auf NAT gestellt, keine Ahnung wieso.
Fakt ist, dass ist jetzt behoben und jetzt kann ich auch endlich auf den Server connecten und sehe es auch schön in Wireshark
wie das Paket reinkommt.
BlackJack

@kTORz: Wenn Du das defaulttimeout weg lässt kann Dir ein Server Deinen Scanner blockieren.

Ich weiss nicht was Du mit Konfiguration meinst — von was? Hinter so einem Port kann im Grunde ja irgend ein beliebiger Server stecken, von irgendwelchen Standardprotokollen bis hin zu selbst geschriebenem und nicht alle Protokolle sehen vor das der Server nach dem Verbinden Daten sendet. Anmeldeformular klingt jetzt irgendwie nach HTTP, das ist ja nur *ein* Protokoll. Aber HTTP wäre auch gleich ein schönes Beispiel: Das Protokoll sendet nichts von sich aus aus, sondern wartet darauf das der Client eine Anfrage sendet.

Das Programm ist insgesamt fehlerhaft. Der Autor hat es sich mit der Socket-Programmierung viel zu einfach gemacht. Das sieht man leider oft, entweder weil die Leute die so etwas schreiben es selbst nicht können, oder weil sie denken man könnte für Anfänger ruhig Beispiele bringen die nicht zuverlässig funktionieren solange die Chance gross genug ist, dass die Fehler bei kleinen Tests nicht auffallen. Verbunden damit das keine Ausnahmebehandlung im Buch stand und die Einrückung falsch ist, frage ich mich wie geeignet das zum Python-lernen sein kann.
kT0Rz

Ja, in diesem Fall könnte man natürlich beispielsweise HTTP oder HTTPS nutzen.
Jup, das meinte ich mit dem Anmeldeformular einer Website, deswegen bin ich jetzt mal von HTTP ausgegangen.

Wahrscheinlich war der Code aus dem Buch nur ein kleines Beispiel.
Ich habe mir inzwischen noch eine andere gute Lektüre für Python zugelegt und arbeite ab und zu mal auch ein wenig mit codecademy.

Die Ausnahmebehandlung stand doch im zweiten Script drin?
Im Ersten war sie nicht, das war auch der Code, welcher per Download mitgeliefert wurde, da wurde es wohl vergessen aber ansonsten
war die Ausnahmebehandlung ja dabei.
Ich hab sie nur fälschlicherweise beim ersten Code "Error - couldn't connect" genannt, um mir dazustellen, dass das Ding sich nicht verbinden kann.

Welche Einrückung meinst du denn?
Ich weiß leider immer noch nicht, welche Einrückung denn genau falsch sein soll.

Ich verbessere sie ja gerne, wenn du mir sagst wo sie ist.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

BlackJack hat geschrieben:@miracle173: Die Überprüfung dauert nicht zwei Sekunden! Meistens ist ganz schnell klar, dass auf der Gegenseite nichts auf dem Port lauscht und es gibt sofort den Verbindungsfehler den der OP sieht. Manchmal wird auf der Gegenseite ein Server lauschen und die Anfrage beantworten. Und von diesen Fällen könnte es ein paar geben die am Anfang keine Daten schicken sondern darauf warten das der Client Daten schickt. Und nur für diese ist dann die zwei Sekunden-Grenze nötig, damit wenn beide Seiten darauf warten das die jeweils andere Seite Daten schickt, nicht bis zum Sankt-Nimmerleinstag gewartet wird.
Nein, für alle IPs, für die es keinen Server gibt, kommt keine Antwort zurück und es muss bis zum Timeout gewartet werden.
BlackJack

@miracle173: Was meinst Du mit IPs für die es keinen Server gibt? Wenn ich eine nicht vergebene IP verwende, passiert das hier:

Code: Alles auswählen

In [3]: s.connect(('10.0.0.42', 80))
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-3-8b22239298db> in <module>()
----> 1 s.connect(('10.0.0.42', 80))

/usr/lib/python2.7/socket.pyc in meth(name, self, *args)
    222 
    223 def meth(name,self,*args):
--> 224     return getattr(self._sock,name)(*args)
    225 
    226 for _m in _socketmethods:

error: [Errno 113] No route to host
Und zwar so ziemlich sofort und ohne eine Zeitüberschreitung gesetzt zu haben.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@kT0Rz: Wenn das mit der Exception nicht Deine eigene Idee war, ist das Buch auch nicht besser zum Python lernen geeignet. Wenn man mehr als einen Socket-Error mit der Exception abfängt, macht man auch etwas falsch. Wie BlackJack schon geschrieben hat, ist es bei falscher Einrückung wichtig, zu verstehen, was der Code wann machen soll und warum er das bei Dir nicht macht. Schau mal, wie oft der Banner auf verwundbare Server geprüft wird.

@BlackJack: miracle173 meint wahrscheinlich eine existierende IP, bei der der entsprechende Port nicht belegt ist. Dann kann der Connect blockieren.
BlackJack

Da bekomme ich auch sofort eine Ausnahme, und zwar die die der OP auch so häufig sieht:

Code: Alles auswählen

In [9]: s.connect(('10.0.0.1', 1234))
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-9-8218c8853767> in <module>()
----> 1 s.connect(('10.0.0.1', 1234))

/usr/lib/python2.7/socket.pyc in meth(name, self, *args)
    222 
    223 def meth(name,self,*args):
--> 224     return getattr(self._sock,name)(*args)
    225 
    226 for _m in _socketmethods:

error: [Errno 111] Connection refused
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

BlackJack hat geschrieben:@miracle173: Was meinst Du mit IPs für die es keinen Server gibt? Wenn ich eine nicht vergebene IP verwende, passiert das hier:

Code: Alles auswählen

(...)
error: [Errno 113] No route to host
Und zwar so ziemlich sofort und ohne eine Zeitüberschreitung gesetzt zu haben.
Na ja, wenn du diese IP nicht erreichen kannst, macht es keinen Sinn, sie mit einem Portscanner zu überprüfen. Du kommst ja offenbar nicht in das Netzwerksegment in dem der Rechner steht (bzw. stehen könnte). Ich kann dir aber nicht genau sagen, wie es zu so diser Fehlermeldung kommt und habe auch nach einigem googeln noch keine sinnvoller Erklärung gefunden. Wenn du aber mit deinem Portscanner in das entsprechende Neztwerk kommst, z.b. weil der Rechner, wo der Portscanner läuft, in diesem Neztwerk steht, dann gibt es dort nichts, was dir sagt, das eine Adresse nicht benutzt ist, sondern es kommt einfach nichts zurück, wenn du an diese Adresse etwas sendest. Und nach einiger Zeit (timeout) nimmst du an, da gibt es keinen Rechner mit dieser Adresse.
BlackJack

@miracle173: Der Client befindet sich in dem Netzwerk, also komme ich da auch rein. Die IP ist halt nicht vergeben.
Benutzeravatar
miracle173
User
Beiträge: 127
Registriert: Samstag 6. Februar 2016, 00:28

BlackJack hat geschrieben:@miracle173: Der Client befindet sich in dem Netzwerk, also komme ich da auch rein. Die IP ist halt nicht vergeben.
Nein, ich denke das ist einfach falsch. Ich habe noch einmal etwas gegoogelt und hier eine verständliche, hoffentlich richtige Beschreibung gefunden:
http://aplawrence.com/Unixart/route.html

Du hast eine Linux-Maschine 192.168.200.83

Code: Alles auswählen

# ifconfig -a
(...)
inet addr:192.168.200.83  Bcast:192.168.200.255  Mask:255.255.255.0
(...)
und eine Windows Maschine 192.168.201.35

Code: Alles auswählen

C:\> ipconfig /all
(...)
   IPv4-Adresse  . . . . . . . . . . : 192.168.201.35(Bevorzugt)
   Subnetzmaske  . . . . . . . . . . : 255.255.255.0
(...)
Also wir haben zwei Netzwerke 192.168.200 und 192.168.201. Die genaue Bezeichnung lautet, da die Subnetmask 255.255.255.0 ist, 192.168.200.0/24 und 192.168.201.0/24. Jedes hat 254 IP-Adressen für Rechner zu vergeben. Die beiden restlichen Adressen nnn.nnn.nnn.0 Adresse (Netzwerkadresse) und die nnn.nnn.nnn.255 Adresse (Broadcast Adresse) können ja nicht vergeben werden.

Wenn du nun vom Windows Server ein "ping 192.168.200.83" absetzt, bekommst du ein "Destination host unreachable", wenn du vom Linux Server ein "ping 192.168.201.35" absetzt, bekommst du "No route to host". Das ist, weil kein Weg es keine Verbindung von dem einem Netz zum anderen Netz gibt.

Die gleichen Meldungen bekommst du, wenn du vom Windows Server ein "ping 192.168.200.123" absetzt und vom Linux Server ein "ping 192.168.201.123" und die 192.168.200.123 und 192.168.201.123 noch keinen Servern zugeteilt sind.

Die Fehlermeldung ist unabhängig davon, ob ein Server im anderen Netzt die IP-Adresse konfiguriert hat oder nicht. In dem einem Netz weiß man nichts über das andere Netz.

Nehmen wir nun an, dass beide Netze durch einen Router verbunden sind. Der Router hängt im Linux Server Netz mit 192.168.200.1 und im Windows Server Netz mit 192.168.201.1.

Setzt man nun die selben Kommandos ab, bekommt man noch immer die selben Fehlermeldungen.

Erst wenn man nun am Windows Server für das Netz 192.168.200.0 das Gateway 192.168.201.1 konfiguriert, kann man vom Windows Server nun den Linux Server 192.168.200.83 erreichen. Allerdings erhält man nun die Fehlermeldung "Request timed out". Warum? Weil der Windows Server zwar nun weiß, wie Pakete an den Linux Server 192.168.200.83 geschickt werden. Aber er erhält keine Antworten auf seine Pakete. Der Linux Server weiß noch nicht, wie er die Antworten zurück schicken soll. Erst wenn man am Linux Server 192.168.200.1 ls Gateway für 192.168.200.0 einträgt, können auch Pakete zurückgeschickt werden und die Kommunikation zwischen beiden Server funktioniert. Die Adresse 192.168.200.123 ist aber weiterhin noch keinem Server zugeordnet und deshalb erhält man hier weiterhin "Request timed out".

Natürlich wird die Situation im Allgemeinen komplizierter sein, da zwei Netzwerke meistens nur indirekt, also über Zwischennetzwerke, verbunden sind. Das Prinzip bleibt aber das gleiche.
Antworten