jueves, 13 de diciembre de 2018

Curso Python orientados a Redes (Parte I)

Python es el lenguaje de moda entre los hackers, eso es un hecho. Yo, personalmente utilizo más bash, me monto mis scripts en shell script de GNU/Linux. Lo prefiero porque así me siento más cómod y además, me aseguro de que sólo se va a ejecutar en GNU/Linux, algo que con Python no pasa. Y esto es curioso, porque Python fue pensado para GNU/Linux, no para Windows, pero el mercado ha sabido meterlo, aunque, todo sea dicho, los scripts en Python para Windows son horrorosos. No obstante, como informáticos y hackers, tenemos que aprender de todo, nos guste más o menos lo que tengamos que aprender, hay que aprenderlo, y es por eso que, a la par que yo perfecciono mis conocimientos en Python (que no son muy altos, debo decir), os dejaré en el blog un curso hecho por mi sobre Python aplicado a las redes, lo que nos permitirá elaborar, cuando sepamos un poco más, nuestras propias PoCs con nuestras propias herramientas eh Python. Espero que os sirva.


Tengo que decir que no voy a explicar Python desde 0, al menos no desde el punto de vista de tener que explicar lo que es un bucle while, lo que es un contador, lo que es una variable,etc. Eso doy por hecho que ya sabéis lo que es si seguís este curso. No obstante, si no sabéis nada de programación, os recomiendo que empecéis con C para ver, al menos, los fundamentos de un lenguaje como C de bajo nivel, cuando tengáis los fundamentos claros paséis al scripting de GNU/Linux y después volváis a este curso que voy a dar.

El curso que voy a dar va a ser de Python aplicado a Redes. Empezaré de 0 pero en la parte de redes, no de programación. Si aún así veo que hay mucha gente que solicite otros cursos, puedo ponerme y preparar un curso de programación en shellscript.

Pero vamos ya con el curso, no me entretenga más. Y es que al igual que para mis scripts prefiero bash, debo decir que cuando es algo en red más allá de descargar una web con wget y lanzar algunas herramientas ya hechas por otros como pueda ser nmap o theharvester, mis preferencias cambian a Python. 

Python tiene una ventaja fundamental. Cualquier cosa son 10 minutos. En Python, aún sin tener mucha idea, estás más enfocado en solucionar el problema que en los problemas que te origina el propio lenguaje. Esto también pasa con shellscript, aunque tenga sus peculiaridades con los espacios (ojo que Python tiene también los suyos). Pero realmente los problemas con la programación no son más que "Oye, cuidado con ese espacio", "oye, no has puesto los 2 puntos después del try" y poco más. En Python (y shellscript) con tener claro lo que quieres hacer, ya está, y eso es una ventaja porque te limitas a abordar el problema únicamente. Con otros lenguajes como JavaScript o el propio Java la cosa cambia. Cuando tengo que preparar alguna PoC que requiera de Java o JavaScript, me pongo a temblar y me despido de mis seres queridos, porque sé que me va a tener más tiempo la programación que la resolución del problema.

Por lo tanto, como he dicho que en Python es más importante tener claro lo que queremos hacer y el problema en sí, vamos con algunos conceptos en redes que van a ser de utilidad. Lo admito, muchos conceptos de redes los entendí mejor cuando me puse a programar en Python para redes que cuando estudié esos conceptos en sí. Espero que a vosotros os pase igual.

Antes de nada, en redes, muchos de los escenarios habituales es el de cliente-servidor. Por ejemplo, nosotros tenemos un cliente de correo que se conecta al servidor de correo para bajarse los mensajes que nos envían o, nosotros como clientes y nuestro navegador, nos conectamos al servidor de Twitter para ver lo que dice la gente a la que seguimos. Así pues, parece que es obligatorio tener estos conceptos bastante claros.

¿Qué es un cliente? Un cliente es todo programa que al ejecutarse, manda solicitudes al servidor y, tras esas peticiones, recibe una respuesta del servidor. Por ejemplo, pedimos la web de www.google.es y el servidor nos la devuelve. As simple as this.

¿Qué es un servidor? Un servidor es un programa cuya única función es permanecer a la escucha del/los cliente(s), recibir las solicitudes y dar una respuesta al/los cliente(s).

¿Qué es un Socket? Son los extremos de un canal de comunicación bidireccional. Estos sockets se pueden comunicar dentro de un proceso, entre procesos de la misma máquina o entre procesos de máquinas distintas.

En Python, para utilizar los sockets, utilizamos la librería socket. Y aunque no deba, me detengo un momento aquí. Si no sabéis lo que es una librería, os lo resumo en que es "un libro específico". Es decir, si no sé de medicina, voy a una "Librería" y utilizo para buscar información en los libros de medicina dentro de esa estantería o librería. Pues en programación igual, si queremos hacer algo más complejo, utilizamos las librerías. Dentro de librería sockets, tenemos distintos módulos como pueden ser:
  • socket()
  • bind()
  • listen()
  • accept()
  • connect()
  • connect_ex()
  • send()
  • recv()
  • close()
También tenemos que tener en cuenta que para programar en redes, necesitamos objetos de sockets en Pythom, y para iniciar un objeto lo haremos con socket.socket(). La sintaxis genérica es la siguiente:

socket_ex = socket.socket(socket_family,socket_type, protocol=0).

Vamos a explicar cada uno poco a poco.

  • socket_family. Es una familia de protocolos que usamos para el mecanismo de transporte de valores constantes como pueden ser AF_INET, PF_UNIX o PF_X25. Ya adelanto que el que más vamos a utilizar va a ser AF_INET.
  • socket_type. Tipi de comunicación entre los 2 extremos de la conexión. Solemos utilizar SOCK_STREAM para protocolos orientados a la conexión (TCP) y SOCK_DGRAM para protocolos no orientados a la conexión(UDP) {Aquí os toca repasar la pila TCP/IP si no sabéis de lo que hablo cuando me refiero a TCP y UDP}.
  • protocol. Suele tener valor 0, y, al menos yo, no lo pongo casi nunca. Se suele utilizar cuando queremos identificar la variante de un protocolo dentro de una familia y tipo de socket.
Vamos ahora a especificar lo que más vamos a utilizar cuando queremos establecer conexiones clientes-servidor.

  • socket.bind()--> Lo utilizamos para especificar un host y un puerto a un socket. Como ya sabéis, cuando nos conectamos a una web, lo que estamos haciendo es conectándonos a una IP en un puerto determinado. Otra cosa es que después se utilice DNS para hacer la navegación más legible para el usuario.
  • socket.listen()-->Inicia la escucha en TCP.
  • socket.accept()-->Acepta pasivamente una conexión de cliente TCP.
Pues venga, ahora, a programar un poco unos ejemplos sencillitos para empezar. Yo voy a programar un cliente y un servidor en TCP, ya que es confiable y tiene entrega de datos de forma ordenada.

Iniciando el servidor.

Vamos a ver primero los pasos, y después el código. Los pasos son 5.

  1. Importamos las librerías necesarias--> import {libería}
  2. Definimos el host, puerto y el tamaño del buffer.
  3. Creamos el objeto {socket_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  4. Vinculamos las variables al objeto-->{socket.bind((host,port))}
  5. Establecemos la conexión, aceptamos datos y los mostramos.
El código para el servidor sería el siguiente.

server.py



Con esto, ya tendremos nuestro servidor montado. Con lo explicado antes de mostrar el código, creo que se entiende bien lo que estamos haciendo, aún así en los comentarios explico un poco lo que hace cada cosa. Y si os fijáis, con pocas líneas en Python y de forma elegante y sencilla, tenemos ya un servidor a la escucha. Nos han bastando tan sólo 32 líneas contando los espacios.



Ahora vamos con el cliente, ya que si ejecutamos el servidor no vamos a ver nada, ya que, como se ha explicado, el servidor está a la escucha esperando las solicitudes del cliente.


El cliente es casi igual , único es que le he añadido una variable con el mensaje que va a enviar, el socket con el envía del mensaje y, al igual que ele servidor, el socket con los datos que va a recibir.


Para el cliente, si os fijáis, necesitamos muchas menos líneas que para el servidor, menos de 20 y contando los espacios. Esta es una de las ventajas de Python, con pocas líneas tienes programas bastantes potentes.

Y visto esto, nos toca testear nuestros programas. Para ejecutar programas en Python, tendremos que escribir en la terminal python {programa}. Eso sí, aseguraos con chmod +x {programa} que tiene permisos de ejecución



Para que lo veáis más claro, en la terminal de la izquierda vamos a ejecutar el cliente, y en la derecha, hemos ejecutado el servidor. Tenemos que ejecutar primer el servidor ya que este tiene que estar a la escucha antes de que el cliente mande los datos. Como vemos, hemos ejecutado el servidor, pero no muestra nada. Esto es porque el cliente aún no ha hecho ninguna solicitud.


Una vez que ejecutamos el cliente, este manda el mensaje que teníamos almacenado en la variable MESSAGE. Ese mensaje llega al servidor el cual nos muestra por pantalla el mensaje recibido.

Ojo, si intentáis esto y enviáis un mensaje muy grande, puede que no se envíe entero. Esto dependerá del tamaño que le hayáis dado al BUFFER_SIZE. Si le asignáis 1024 bytes, a lo mejor os sale H en lugar de Hi. Eso sería porque todo el mensaje no cabe en un sólo paquete de 1024 bytes.

Como apreciamos, estamos limitados con estos programas qu ehemos creado, ya que cada vez que queramos enviar un mensaje tendremos que entrar en el client.py y cambiar el contenido en la variable. Además tenemos el problema de buffer. Todo esto lo iremos perfeccionando conforme vayamos adquiriendo skills en la programación de Python y haremos cada vez, programas más complejos. Pero por hoy está ya bastante bien.

¿Hackeamos el Mundo?

1 comentario:

  1. Sigamos aprendiendo muchos aspectos como el de curso python que es uno de los que más me han recomendado.

    ResponderEliminar

Related Posts Plugin for WordPress, Blogger...

Entrada destacada

El server me sabe a poco.

Soy un fanático del Rock y de Debian . (Creo que voy a inventar Rockbian, que suena bien y todo xD) Llevaba tiempo queriendo unir estos 2 c...