Construyendo nuestro propio escáner de dispositivos conectados a Internet. Parte 4

Buenas a todos, en el post de hoy sobre nuestro escáner de Internet, vamos a ampliar sus funcionalidades para hacer banner grabbing (https://en.wikipedia.org/wiki/Banner_grabbing). 

En esta ocasión, los cambios los realizaremos sobre las funciones portscan y ports, aprovechando que es el punto exacto donde revisamos si tras los puertos revisados, hay algún servicio operativo. En la variable banner almacenaremos el resultado de la petición GET con la que hemos solicitado la información que nos devolverá el dato que nos interesa, y si detrás se esconde un Windows, Linux, etc. con un IIS, Apache, etc. etc. 

Ni que decir tiene, que no todo lo que dicen los banners es cierto, ya hemos visto en numerosos posts de Flu Project que este dato se puede (y se debe) ocultar y/o alterar: http://www.flu-project.com/2011/02/seguridad-en-los-banner-de-los_1437.html

A continuación os comparto el código completo del archivo principal del proyecto y en el que hemos hecho las nuevas modificaciones:

import pygeoip
import socket
import re
from ports import getcommonports

def geo(_file, _ip):
    ''' This function search the geolocation values of an IP address '''
    geoDb = pygeoip.GeoIP(_file)
    ip_dictionary_values = geoDb.record_by_addr(_ip)
    ip_list_values = ip_dictionary_values.items()
    print "*******************"
    print "*** Geolocation ***"
    print "*******************"
    for value in ip_list_values:
        print str(value[0]) + ": " + str(value[1])

def hosts(_ip):
    ''' This function search the hostnames '''
    print "\n*******************"
    print "***    Hosts    ***"
    print "*******************"
    try:
        hosts_values = socket.gethostbyaddr(_ip)
        print str(hosts_values[0])
    except:
        print 'No hosts associate'

def portscan(_host, _port):
    ''' This function execute a port scan '''
    banner = ''
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(0.10)
        result = sock.connect_ex((_host, _port))
        sock.send('GET HTTP/1.1 \r\n')
        banner = sock.recv(1024)
        sock.close()
    except:
        pass
    return result, banner

def ports(_ip):
    ''' This function search open ports '''
    common_ports = getcommonports()
    print "\n*******************"
    print "***    Ports    ***"
    print "*******************"
    for value in common_ports:
        banner_exists, banner = portscan(_ip, value)
        if not banner_exists:
            print 'Port: [' + str(value) + '] Protocol: [' + str(common_ports[value]) + ']'
            print 'Banner: [' + str(banner) + ']'

def main(_ip):
    ''' Main function, launch the main activities '''
    ''' You can download GeoIP databases from here: https://dev.maxmind.com/geoip/legacy/geolite '''

    # Extract geolocation values
    geo('GeoIP/GeoLiteCity.dat', _ip)
    hosts(_ip)
    ports(_ip)

if __name__ == "__main__":
    print 'FluScan, an IPv4 scanner. Created by http://www.flu-project.com\n'
    main('X.X.X.X')

Y en las siguientes líneas podéis ver un ejemplo de salida por pantalla:

$ python FluScan.py
FluScan, an IPv4 scanner. Created by http://www.flu-project.com

*******************
*** Geolocation ***
*******************
city: Madrid
region_code: 29
area_code: 0
time_zone: Europe/Madrid
dma_code: 0
metro_code: None
country_code3: ESP
latitude: 40.4167
postal_code: 28001
longitude: -3.6838
country_code: ES
country_name: Spain
continent: EU

*******************
***    Hosts    ***
*******************
XXXXX.XXXXX.XXXX.es

*******************
***    Ports    ***
*******************
Port: [80] Protocol: [http]
Banner: [<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.2.22 (Ubuntu) Server at XXXX.XXX.XX.es Port 80</address>
</body></html>
]
La salida de la variable banner la podéis filtrar, para mostrar solo el campo que nos interesa, y que podréis encontrar tras el tag "Server:" en el caso de IIS, <address> en el caso de Apache, etc. etc. Por Internet existen muchos desarrollos hechos por la comunidad que os serán de utilidad para esta tarea.

Saludos!