sábado, 28 de febrero de 2015

Armando un Port Scanner en Python!



Hola nuevamente. En esta entrada me gustaría mostrarles como crear un scanner de puertos sencillo. Como reza el título, lo haré en Python. El código se encuentra en el libro "Violent Python" , igualmente (para el que no quiera bajarse el PDF) colocaré el enlace al script al final del artículo. Para que se entienda el funcionamiento, voy a mostrar el script por porciones e iré explicando que acciones va realizando.

Para este script usaremos las librerias "optparse" y "socket"

optparse: Nos sirve para parsear opciones de línea de comando (quizás ahora suene extraño pero ya comprenderemos su funcionamiento al utilizarlo).

Warning! ---> Deprecated since version 2.7: The optparse module is deprecated and will not be developed further; development will continue with the argparsemodule. (no importa, sirve a nuestros fines jeje)

socket: Esta librería, como se imaginarán, nos permite manejar los sockets; ponerlos a la escucha, recibir, enviar,data etc.


Descripción aquí ---> http://docs.Python.org/library/socket.html

En la descripción veremos todas las funciones que posee esta librería. Las que nos interesan para nuestro port scanner son las siguientes:


socket.gethostbyname(hostname) – This function takes a hostname such
as www.google.com and returns an IPv4 address format such as
69.163.177.2.

socket.gethostbyaddr(ip address) – This function takes an IPv4 address
and returns a triple containing the hostname, alternative list of
host names, and a list of IPv4/v6 addresses for the same interface
on the host.

socket.socket([family[, type[, proto]]]) – This function creates an
instance of a new socket given the family. Options for the socket
family are AF_INET, AF_INET6, or AF_UNIX. Additionally, the socket
can be specified as SOCK_STREAM for a TCP socket or SOCK_DGRAM for
a UDP socket. Finally, the protocol number is usually zero and is
omitted in most cases.

socket.create_connection(address[, timeout[, source_address]]) – This
function takes a 2-tuple (host, port) and returns an instance of a
network socket. Additionally, it has the option of taking a timeout
and source address.

Comenzamos..

Como mencionamos arriba, utilizaremos las librerias optparse y socket, así que a darle al import:

import optparse
import   socket
from socket import *

Luego,  definimos la función que se conectará al host:

def connScan(tgtHost, tgtPort):   #definimos la función y le pasamos los parámetros 
    try:
         connSkt = socket(AF_INET, SOCK_STREAM) '''definimos la familia de socket e indicamos que es un socket TCP'''

         connSkt.connect((tgtHost, tgtPort)) #Nos conectamos al host y puerto elegidos
         connSkt.send('Hi') #Enviamos algo al destino
         results = connSkt.recv(100) #Guardamos la respuesta
         print '[+]%d/tcp open'% tgtPort
         print '[+] ' + str(results) #Mostramos los resultados
         connSkt.close()
    except:
         print '[-]%d/tcp closed'% tgtPort    '''si nos devuelve un error, mostramos en pantalla que el puerto esta cerrado'''


def portScan(tgtHost, tgtPort):  #definimos la función que escaneará el puerto
   try:
         tgtIP = gethostbyname(tgtHost) '''utilizamos la función gethostbyname para resolver el host'''
   except:
         print "[-] Cannot resolve '%s': Unknown host"%tgtHost
         return
   try:
      tgtName = gethostbyaddr(tgtIP) #Resolvemos el hostname pasandole la ip
      print '\n[+] Scan Results for: ' + tgtName[0] #Mostramos el hostname resuelto
   except:
      print '\n[+] Scan Results for: ' + tgtIP
      setdefaulttimeout(1)
   print 'Scanning port ' + str(tgtPort)
   connScan(tgtHost, int(tgtPort)) '''Llamamos a la función que se conectará para traernos el resultado open/close y luego, si está abierto el puerto realizará el banner grabbing'''

Definimos la función principal:

def main():

'''Acá esta lo que comentaba mas arriba, gracias a optparse podemos manejar mucho mejor las lineas de comando a la hora de solicitar al usuario que ingrese datos. Nos permite mostrar opciones cuando el usuario no ingresa una opción (valga la redundancia cíclica jeje) o utiliza el comando help'''

parser = optparse.OptionParser('usage %prog -H ' +  '<target host> -p <target port>')
parser.add_option('-H' , dest='tgtHost', type='string' ,  help='specify target host')
parser.add_option('-p' , dest='tgtPort', type='int' ,  help='specify target port')

(options, args) = parser.parse_args()
tgtHost=options.tgtHost
tgtPort=options.tgtPort
if (tgtHost == None) | (tgtPort==None): '''Si uno de los dos parámetros no está hacemos que vuelva a ejecutarse el script (con exit(0)), mostrando el mensaje de opciones que deben ingresarse'''
      print parser.usage
               exit(0)
        portScan(tgtHost, tgtPort)

main()

Y acá lo tenemos en acción:

Resultado al escanear el puerto 25

Resultado al escanear el puerto 80


Espero que se haya entendido algo. Cualquier cosa me consultan, no hay problema.

Pueden obtener el código, sin todos esos comentarios horribles (jeje), en:
https://sites.google.com/site/mamaquieroserpentester/home/tools (como PortScanner.py)

Eso es todo por ahora.

Saludos y Happy Hacking!