So, nun ist aber gut mit Spielerei:
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Scan know Ports on a Host
usage:
portscanne.py [host]
Info: http://www.python-forum.de/viewtopic.php?t=3262
"""
import sys, socket, urllib, time
import zipfile, zlib
zlib.Z_DEFAULT_COMPRESSION = 9
class iana_port_info:
"""
Stell Port-Informationen bereit.
Diese werden von iana.org gelesen und in einer Cache-Datei
gespeichert. Beim nächsten Aufruf werden die Daten direkt
aus der Cache-Datei genutzt.
"""
url = "http://www.iana.org/assignments/port-numbers"
cachefile = "portscanner_data.zip"
def __init__( self, verbose = True ):
self.verbose = verbose
self.side_data = self._get_side_data()
self.port_data = {}
# Daten in Dict schreiben
self.prepare_data()
def prepare_data( self ):
"""
Die Rohdaten von iana.org parsen
"""
for line in self.side_data.splitlines():
line = line.split()
try:
if not "/tcp" in line[1]:
continue
self._insert_port_info( line )
except IndexError:
pass
def _insert_port_info( self, data ):
"""
Daten aufteilen und in Dict speichern
"""
try:
port_number = int( data[1].rsplit("/")[0] )
except ValueError:
return
keyword = data[0]
description = " ".join( data[2:] )
self.port_data[ port_number ] = "%s, %s" % (
keyword, description
)
def _get_side_data( self ):
"""
Port Daten lesen. Entweder aus Datei oder direkt von
iana.org, wenn die Datei nicht existiert.
"""
try:
return self._read_side_data()
except IOError:
# Aus Datei konnte nicht gelesen werden, also
# holen wir uns die Daten frisch von iana.org
data = self._iana_data_from_url()
# Speicher das ganze ab, für nächstes mal
self._save_side_data( data )
return data
def _iana_data_from_url( self ):
"""
Port Info-Seite von iana.org holen
"""
if self.verbose: print "connect to '%s'..." % self.url,
c = urllib.urlopen( self.url )
if self.verbose: print "OK"
if self.verbose: print "download portinfo...",
data = c.read()
if self.verbose: print "OK"
c.close()
return data
def _save_side_data( self, data ):
""" Port-Seite in Cache Datei schreiben """
print "Write Port-Data in ZIP-File...",
ziparchiv = zipfile.ZipFile( self.cachefile, "w", zipfile.ZIP_DEFLATED)
ziparchiv.writestr( "port-numbers.txt", data)
ziparchiv.close()
print "OK"
def _read_side_data( self ):
""" Port-Seite aus Cache Datei lesen """
ziparchiv = zipfile.ZipFile( self.cachefile, "r" )
data = ziparchiv.read( "port-numbers.txt")
ziparchiv.close()
return data
def known_ports( self ):
""" Liefert Liste aller bekannten Ports zurück """
return sorted( self.port_data.keys() )
def iteritems( self ):
""" Hilfreich zum Auflisten der Port-Informationen """
return sorted( self.port_data.iteritems() )
def __getitem__( self, port ):
""" Liefert Informationen zum angegebenen port """
try:
return self.port_data[port]
except KeyError:
return "unknow port"
def __len__( self ):
return len(self.port_data)
#~ t = iana_port_info()
#~ for port, info in t.iteritems():
#~ print port, "-", info
#~ sys.exit()
class portscanner:
# Timeout in Sek. nachdem ein Port als zu erkannt werden soll
timeout = 1
# Auf wievielfachen Wert soll der timeout gesenkt werden, wenn
# ein Port offen gescannt wurde
buffer_multiply = 1.75
# Mindest Timeout-Wert
min_timeout = 0.01
def __init__( self, host ):
self.host = host
self.iana_port_info = iana_port_info()
print "\n%s known ports" % len(self.iana_port_info)
self.print_IP_info()
self.set_timeout()
self.total_starttime = time.time()
def scan_range( self, start_port=1, end_port=65536 ):
"""
Scannt eine Port-Bereich durch.
"""
print "Beginning scan, Port %s - %s" % (
start_port, end_port
)
print "-"*80
self.total_ports = end_port+1 - start_port
self.index = 0
for port in xrange( start_port, end_port+1 ):
self.index += 1
self.scan_port( self.host, port )
def print_IP_info( self ):
server_name = socket.getfqdn( self.host )
print "%s - %s" % ( self.host, server_name )
def scan_known_ports( self, well_know=True ):
"""
Scannt nur Ports die in der iana.org Liste auftauchen.
Ist well_know == True werden nur Ports gescannt die als
Keyword in der iana.org Liste kein '#'-Zeichen haben
"""
print "scan know ports"
print "-"*80
self.total_ports = len(self.iana_port_info)
self.index = 0
for port in self.iana_port_info.known_ports():
self.index += 1
if well_know and self.iana_port_info[port].startswith("#"):
continue
self.scan_port( self.host, port )
def set_timeout( self ):
sys.stdout.write( "Set timeout" )
often_open_ports = (80,21,22,25,53,110,143)
total_time = 0
for port in often_open_ports:
sys.stdout.write(".")
start_time = time.time()
if self._scan( self.host, port ) == True:
scan_time = time.time() - start_time
self.new_timeout( scan_time )
print "timeout: %.1fms" % (self.timeout*100)
def scan_port( self, host, port ):
"""
Scannt einen port
"""
info_line = "%5s %-52s" % ( port, self.iana_port_info[port][:52] )
percent = "%.1f%%" % (float(self.index) / self.total_ports * 100)
elapsed = (time.time()-self.total_starttime) # Vergangene Zeit
estimated = elapsed / self.index * self.total_ports # Geschätzte Zeit
time_info = "%.1f/%.1fmin" % (elapsed/60, estimated/60)
sys.stdout.write(
"%s %s %s" % (info_line, percent, time_info)
)
start_time = time.time()
port_status = self._scan( host, port )
sys.stdout.write("\r")
scan_time = time.time() - start_time
if port_status != True:
# Port ist geschlossen
return
print "%s Open! (%.1fms, %.1fms)" % (
info_line, scan_time*100, self.timeout*100
)
self.new_timeout( scan_time )
def new_timeout( self, scan_time ):
new_timeout = scan_time * self.buffer_multiply
if new_timeout < self.min_timeout:
self.timeout = self.min_timeout
else:
self.timeout = new_timeout
def _scan( self, host, port ):
try:
sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout( self.timeout )
sock.connect( (host, port) )
sock.shutdown( socket.SHUT_RDWR )
except Exception, e:
return False
else:
sock.close()
return True
if __name__ == '__main__':
try:
host = sys.argv[1]
except IndexError:
print __doc__
sys.exit()
#~ host = "82.105.57.129"
scanner = portscanner( host )
#~ scanner.scan_range( 1, 65535 )
scanner.scan_known_ports()
Nun ist die Ausgabe auf der Consoler sinnvoller, man hat nun eine Fortschrittanzeige mit Prozent und Zeitangabe. Außerdem sieht man nun besser, welche Ports offen sind, denn nur diese Zeilen bleiben am Ende stehen.
EDIT: Ok, noch eine Änderung... Nun kann man die Adresse als Parameter angeben.
Außerdem wird nun der Timeout am Anfang gesetzt anhand von oft offenen Ports. Dann startet der Scann viel schneller...