Ir al contenido principal

IRC a machetazos [C - C#]


"El que conoce el arte de vivir consigo mismo ignora el aburrimiento." -Erasmo de Rotterdam.

He vuelto a facultad de nuevo, los días pasan alrededor de ecuaciones diferenciales, sentencias sql, programacion orientada a objetos, física electromagnética y tratando de convencer a mi maestra de biología en que enfoquemos la materia a ver algoritmos bioinformáticos para no aburrirme con la cátedra del día a día (triste... Aquí una lista de una pagina de retos de desarrollo de algoritmos bioinformáticos http://rosalind.info/problems/tree-view/). He rozado con mis dedos la monotonía de los días y de vez en cuando busco salir de la monotonía y darle rienda suelta a mis pensamientos y codeando en C (ohh my love) y C#(my second love).

He decidido realizar algunos wargames para salir de esta monotonía, pero no simplemente hacerlo si no tratarme de empaparme lo que mas pueda para poder resolverlo (como realizar un "estado del arte" preliminar antes de sentarme a codear para resolver estos retos).

PostData[0] = No diré de donde saque los retos para no dañarle la experiencia a las demás personas que quieran realizarlos.

PostData[1] = Publicare el código del reto pero intentare hacer un énfasis "investigativo" y tratar de exponer un poco lo que aprendí y no solo subir la solución del reto.

PostData[2] = Cambiare algunos valores del planteamiento del reto para que no lleguen a este post si están buscando una solución de este reto.

Planteamiento del reto

El reto encontrado nos planteaba la siguiente situación, debíamos conectarnos a un servidor IRC (irc.server.com) con un puerto definido donde se estaba ejecutando el servicio IRC (6667), despues de esto debíamos enviar un mensaje privado a un bot que llamado Pepegrillo diciéndole !problema1. El bot nos contestara el mensaje con el siguiente formato.
[numero_1] / [numero_2]
 
El siguiente procedimiento se debe realizar las siguientes operaciones con los números dados por el bot

1) calcular la raíz del numero_1
2) multiplicar el resultado anterior por el numero_2

Se debe enviar el bot Pepegrillo el resultado de la ultima operación redondeándolo a 2 cifras significativas para esto se tiene un tiempo de 2 segundos. Si el bot no responde es por que esta baneado el usuario y se debe esperar unos minutos antes de enviar una nueva respuesta.

Conocimientos necesarios
  •  Protocolo IRC
    • Introducción al protocolo
    • Aspectos del RFC
    • Análisis de cliente
    • Opiniones personales del irc a la fecha (2018).
  • Sockets Linux
    • Introducción a sockets
    • Estructuras
    • Uso del socket (Cliente)
  • Planteamiento del código
    • Descripción de pasos genéricos
    • Código
      • C - C#
  
Protocolo IRC
  •  Introducción al protocolo
 IRC (Internet Relay Chat) es un protocolo de comunicacion basado en texto para el intercambio de mensajes en tiempo real, incluyendo la tranferencia de archivos, mensajes privados entre usuarios que están en una misma sala de chat o en un mismo servidor.

El modelo de conexion de software es CLIENTE-SERVIDOR, donde el servidor es donde se estará ejecutando el demonio que recibirá las conexiones de los clientes concurrentes (que se conectan por medio de un programa llamado CLIENTE IRC para consumir los recursos ofrecidos por el servidor).
 
Para poder tener un servidor irc se debe tener instalado un demonio que nos deje operar nuestro servidor IRC. Existen varias alternativas de demonios para poder tener nuestro servidor IRC propio entre esos estan ircd-seven, InspIRCd, UnrealIRCd.

 (imagen: Banner Bahamut Deamon)
(imagen: Banner UnrealIRCd)

Existen varios clientes de irc, uno de los mas usados es el irssi. Ya que IRC esta basado en texto y como dicen en el propio RFC "siendo el cliente mas simple un programa capaz de conectarse a un servidor por medio de un socket" irssi es un cliente que permite conectarse por medio de un socket y poder interactuar con el servicio de IRC ( mas se realizara un análisis del protocolo con ngrep y irssi ).


  • Aspectos del RFC
RFC: Es un escrito realizado por una o varias personas y contiene una propuesta para una nueva tecnología, donde se especifica la información técnica del uso. Las RFC en resumen es la documentación de protocolos y tecnologías de internet, son mantenidas y aprobadas por el IETF (http://www.ietf.org/standards/rfcs/).

Invitacion: Existen muchos RFC sin traducir al español aqui https://www.rfc-es.org/ podrán ser parte del grupo de traducción de las RFC. (Es bueno a veces encontrar un RFC en español), debo pulir mi ingles intentar ser parte del grupo de traducción.

El RFC del protocolo IRC se puede encontrar aquí en español https://www.rfc-es.org/rfc/rfc1459-es.txt y la versión mas actualizada https://www.rfc-editor.org/rfc/pdfrfc/rfc2813.txt.pdf contiene todas las especificaciones tecnicas del protocolo. Solo comentare las que mas me llamaron la atencion :

  1. IRC se ha desarrollado para trabajar sobre TCP/IP pero eso no implica que sea la unica forma que funcione.
  2. Los servidores son la espina dorsal de la arquitectura para un servicio IRC, ya que un servidor puede estar a otros servidores irc para retro alimentar a un servidor principal.

    (imagen: arquitectura irc)

    (imagen: red pequeña de irc)
  3. El final de un mensaje se toma por CRLF o "\r\n" o "\x0d\x0a"
  4. El servidor envia el comando PING para verificar si un cliente sigue conectado, para que el cliente diga que esta vivo tiene que responder PONG
  5. Commandos de uso basico terminados por CRLF

    CONNECT <target server> <port> [<remote server>]
    INFO [<target>]
    JOIN <channels> [<keys>]
    LIST [<channels> [<server>]]
    USER <username> * * :<username>
    PRIVMSG <user> :<message>
    QUIT : <message>
  • Analisis del cliente
El plan aquí es literamente ver como se comporta el protocolo en caliente, ver como se inicia las comunicaciones y cual es el orden de esos comandos para poder ingresar a un server IRC. para ello se utilizara ngrep (full amor para esa herramienta) esta herramienta es un sniffer que puede matchear resultados por medio de "expresiones regulares".

Iniciamos el ngrep con los siguentes parametros -x para visualizar el content del paquete en hexadecimal, -d para definir la interface de red que queremos monitorear, port definimos el puerto en el que se ejecuta el server irc y a despues de esto iniciar nuestra conexion con un servidor irc por medio del irssi (/connect irc.server.com).


El inicio de la comunicacion empezar seteando el NICK del cliente, luego sigue definirle al servidor el usuario con el que nos conectaremos, y luego viene 2 repuestas del server, podremos ver que cada mensaje termina con un "\r\n".


  Despues de esto vendran mas respuestas por parte del servicor con el banner de inicio y luego el mecanismo para mantener live la conexion entre el cliente y el servidor (PING).

(imagen banner de inicio del server irc)

(imagen mecanismo de mantener live la conexion)

Con esto ya se "toca madera" sentando un poco de lo antes leido en el RFC y con ello confirmamos que podemos interactuar mediante sockets con un server IRC (claro... para la interaccion cifrada de SSL cambia todo el asunto pero por ahora solo me preucupare por el text-plain... I need more skills dude).
  • Opiniones personales del irc a la fecha (2018).
IRC estuvo muy movido una epoca, donde medio internet estaba por las redes de IRC, se usaba mucho para juegos, soporte, grupos de desarrolladores (aunque en esta fecha aun existen varios proyectos que intentan mantener live IRC como por ejemplo el grupo de telegram de radare, hicieron una integracion que los mensajes escritos en el irc se vean reflejados en el chat de telegram y asi mismo lo que se escriba en telegram se ve reflejado en el canal de IRC). Aun se veían botnets C&C administradas desde IRC... es una buena opcion pero hace poco tambien hicieron la implementacion de un RAT administrado por Telegram.  

Montar un servidor IRC propio es bueno por que tu eres el que lo administra,  porque tu le configuras el tipo de cifrado vas a manejar por SSL, los clientes o las IP que vas a dejar conectarse al servidor , etc (O sea hardenning del hardcore y del pesado).

IRC a la fecha sigue siendo una buena alternativa para la comunicacion de mensajes en tiempo real aunque existan muchas otras alternativas "mas seguras" que simplifican el uso y que traen ciertas opciones interesantes.

"IRC no ha muerto...".

CULTURA GENERAL : IRC fue el protocolo de comunicacion usado durante el intento de golpe de estado en la union sovietica desde 1991 para informar a traves de un periodo de censura a los medios de comunicacion.

Sockets linux
  • Introduccion sockets.
Los sockets son un abstraccion de software que permiten la intercomunicacion de datos y de informacion entre dos (o uno llegado el caso) por medio de la API del sistema operativo que se encargara de hacer interface con los protocolos de internet y de TPC/IP (o para intercomunicacion de procesos del sistema operativo).

Para el uso de sockets se deberan tener en cuenta estas librerias del sistema.

  • Estructuras.
Las estructura mostradas en esta seccion son muy importantes para trabajar con punteros, son estrucutras ya definidas dentro del archivo sys/socket.h. Estas estructuras se deberan llenarse adecuadamente por que luego se utilizaran por las funciones de sockets (creacion del handler y otros) y tiene informacion del socket.
  1.  hostent : informacion del host
  2. sockaddr : sockaddr_in minimizada
  3. in_addr : Contiene la ip del host
  4.  sockaddr_in : informaccion del socket
  • Uso de sockets (Cliente).
Se puede resumir el uso de un socket a nivel de cliente en los siguentes pasos (a nivel de codigo).
  1. Setear valores del socket (estructura sockaddr_in).
  2. Creacion del handle del socket
  3. Verificacion del handle
  4. Conexion
  5. Verificar conexion
  6. Envio/recibo
  7. Cerrar socket 
 Dos cosas que se deben tener en cuenta: 1) si estamos programando un servidor o un cliente con multiples peticiones lo mejor es crear procesos para manejar cada caso de ejecucion 2) ya que la filosofia de linux es que todo es un archivo (hasta el mismo socket) en cierta manera lo que obtenemos de crear el handle del socket es un handle de un archivo asi que podremos usar ciertas funciones con las que se pueden interactuar con archivos "real" y usarlas con el handle del socket.

En resumidas cuentas seria algo asi hasta el paso 5.
(en la funcion socket, se le envia el tipo de familia del protocolo AF_INET (conexiones a red, si fuera AF_UNIX seria para intercomunicarse entre procesos internos de la maquina) , SOCK_STREAM (TCP o UDP), 0 = PROTOCOLO = TCP ) 

(en la funcion connect se le pasa por parametros, el handle del socket creado por la funcion socket, luego la estructura sockaddr_in con un cast necesario y por ultimo la cantidad de bytes)


Planteamiento del codigo
  • Descripcion de programa 
Utilizare un diagrama de secuencia para describir la comunicacion entre el cliente y el servidor irc para la solucion del reto planteado (lo deje simple para solo enfocarme en comunicacion realizada, si encuentran algun error o alguna recomendacion la pueden escribir en los comentarios. Gracias)

Pasos:
  1. Realizar conexion por sockets al servidor
  2. Enviar comando "NICK s0d0ma\r\n"
  3. Respuesta por parte del servidor "\x00\x00\x00\x00\x00\x00"
  4. Enviar comando "USER s0d0ma * *:s0d0ma\r\n"
  5. Respuesta del servidor (banner 1, banner 2, banner 3)
  6. Enviar comando "PRIVMSG Pepegrillo:!problema1\r\n"
  7. Respuesta del servidor "numero2 / numero2\r\n"
  8. (procesar) Enviar respuesta "PRIVMSG Pepegrillo:!problema1 -rep%0.2f\r\n"
  9. Respuesta del servidor con la flag
  10. Cerrar conexion 

  • Codigo
C

En la implementacion realizada en C se define antes de todo 1) un offset para encontrar la flag en el mensaje de respuesta 2) El puerto irc, se define una nueva estructura para almacenar los datos del servidor. y en el prototipo de funciones se encuentran nuestras  3 funciones a usar.

  • Recibir()
Retornara un buffer donde esta almacenada la respuesta por parte del servidor y se debe pasar como parametro el handle del socket, crea un nuevo buffer de memoria de 2000 bytes. recibe información por medio de la función recv y queda almacenada en el buffer recién creado y al final se retorna el buffer.

  • Enviar()
No retorna algún valor, solo se encargara de enviar datos por medio del socket, se tendrá que pasar como parámetro el handle del puntero, y el buffer de datos que se quiere enviar. Se crea primeramente un buffer de memoria del tamaño de la longitud del commando ingresado y se le suman 3 espacios mas para almacenar "\r\n". Luego envía la información por medio de la función send() y se libera el buffer temporal que habíamos creado para el comando+"\r\n".

  •  Procesar()
Retornara la respuesta al reto que es de tipo float, se tendrá que pasar como parametros le buffer donde se encuentran los números a operar y la longitud del username. Primeramente se define el buffer inicial donde estará la flag. en el primer ciclo se concatenaran todos los números de numero1 y en el segundo ciclo almacenamos todos los digitos del numero2, realizamos luego un atoi a ambos strings y los convertimos a int. Se realiza las operaciones indicadas y se retorna el float. (Nota mental : printf("%0.2f",float_mio);


Dentro de la función main donde se puede visualizar los pasos efectuados para realizar este reto, se debe tener en cuenta que a la hora de generar los strings de los comandos se tenia que realizar una construcion de strings dinámico por medio de sprintf() que permite enviar un string dinámico a un buffer de memoria.  Se deben ir eliminando cada no de los buffers (entrada y de salida de datos) antes de usarlos para hacer un manejo de memoria adecuado.


Ejecución



C#

La clase ClienteIrc se utilizara en el código realizado en C#  para facilitarnos el manejo del protocolo IRC desde el código. Contiene los atributos :
  1. dirección = se almacenara la ip del servidor irc donde nos vamos a conectar.
  2. puerto = se almacenara el puerto (puerto de uso de irc 6667).
  3. SockIrc = es nuestro objeto Socket en cual nos permitira hacer uso del api de red para realizar nuestro socket (System.Net.Socket y System.Net).
  4. username = Se almacenara el Nick para el ingreso de IRC
  5. recvString = Se almacena el ultimo mensaje recibido por parte del servidor en un string.

Contiene los metodos:
  • (constructor) ClienteIrc :
Este método inicializa los atributos de la clase. recibe como parametros la ip, el puerto y el username.


Se instancia el objeto socket, el constructor recibe los parametros de configuracion del socket, el parametro AddressFamaly es el valor de una enumeración que contiene como valores los esquemas de direcciones que puede usar la clase socket, en este caso se Usara el valor InterNetwork que especifica que es una dirección IP versión 4. Existen otros esquemas de direcciones.


El parámetro SocketType, recibe el parámetro para el tipo de socket (en este caso STREAM), y el ultimo parámetro recibe el tipo de protocolo a usar (en este caso TCP). Luego se crea un objeto de tipo IPEndPoint el cual nos parseara la ip y el puerto del servidor para podérselo pasar al método de conexion, el constructor de este objeto recibe una una IP la cual se deberá parsear y el puerto. Por ultimo se inicia la conexion Con el método Connect() del socket. Si hay un error en la conexion el try-catch lo recibe.
  •   Recibir :
Este método recibirá los mensajes por parte del servidor. Primeramente de instancia un array de tipo byte (unsigned char) donde se almacenara la información que vamos a enviar por el socket.


Luego se recibe la respuesta y se almacena la cantidad de bytes leídos, luego de esto debemos convertir el array de byte a un string, para esto se debe tomar el array de byte y Encodearlo (a ASCII) se le envía los parametros 1) array de respuesta byte, 2) el índice de de donde empezara a encodear y 3) es la cantidad de bytes seleccionados (como un offset final).
  • Command :
Este método sera el encargado de enviar los datos por el socket. recibe como parámetro un string con los "comandos" que se le envia al servidor IRC. Se concatena un "\r\n" ya que en el RFC decía que los finales de un mensaje están marcados por "\r\n".


Luego se hace lo mismo en el método recibir pero encodeando un string a un array de bytes (recordar ASCII) y se envía el array de bytes por el socket.
  •  Close:
Esta función, libera y setea los recursos del objeto para poder ser utilizado posteriormente. Se envía el comando al IRC para salir de nuestra sesión, se cierra el Socket y se setean los valores "by default"


Aqui esta la implementacion de la clase y el codigo que soluciona el reto escrito en C#.


REFERENCIAS:

http://archive.oreilly.com/pub/h/1963
http://man7.org/linux/man-pages/man2/connect.2.html
https://doc.lagout.org/programmation/unix/The%20Linux%20Programming%20Interface.pdf
http://es.tldp.org/Tutoriales/PROG-SOCKETS/prog-sockets.html
https://github.com/rcos/CSCI2963-01-Spring2017/
https://www.gnu.org/software/libc/manual/html_node/Receiving-Data.html
https://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C/Sockets
https://www.rfc-es.org/rfc/rfc1459-es.txt
http://beej.us/guide/bgnet/pdf/bgnet_USLetter.pdf
https://en.wikipedia.org/wiki/Unistd.h
https://dl.packetstormsecurity.net/papers/general/ngreptut.txt
http://www.softpanorama.org/Net/Netutils/ngrep.shtml
http://www.yolinux.com/TUTORIALS/Sockets.html
https://github.com/secu77/La-seCta/blob/master/hangouts/sockets_1/teoria/socketsordie.pdf


Comentarios

  1. Muy interesante tu artículo, esta muy completo, se detalla la buena investigación sobre el protocolo IRC, me gusto mucho además que describes la historia y el uso del protocolo en épocas pasadas, se nota las técnicas que uno puede seguir para la solución de este reto complejo que no cualquier persona identificaría a simple vista su solución. Eres muy aspero. Saludosss

    ResponderEliminar
  2. Parcero muy teso, muy buen articulo.
    Saludos

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

[WINHTTP] Get/Post

“dando vueltas en circulos hasta que el sol no este”, se podria decir que ese es uno de los estados mas constantes en este momento de vida… Aun asi sigo perdiendome noche tras noche en algunos temas que me interesan. Entre estos temas esta la comunicacion por medio del protocolo de HTTP en C, Estuve probando con curl (una puta pasada… Muy genial a decir verdad) pude integrarlo a MinGW copiando los headers y las dependencias a sus respectivas carpetas y agregando el -lcurl a la hora de compilar pero tuve un pequeño problema con la implementacion que estaba tratando de realizar (requeria no tener mucho inconveniente con las dependencias de dlls) intente compilar el codigo haciendo una compilacion estatica de las dependencias pero aun asi no pude (debo aceptarlo aun me falta mucho camino por andar y esta parte esta un poco fuera de mis conocimientos). Luego intente hacerlo con socketRAW, fue una experiencia muy bonita a decir verdad pero cai en otra de mis falencias crear buffers dinami…

LinudecX

"Ninguna existencia puede ser válidamente realizada si se limita a si misma."-Simone de Beauvoir

He estado en proceso de asimilar mi proceso de transición en la facultad, una de las formas que he encontrado en esta asimilación es dar la pelea, intentar de hacer las cosas un poco distintas, intentar hacer un pequeño cambio en mi entorno, en pocas palabras ir en contra de la corriente (y no por mero capricho mio, si no tratar de encontrar un diferente enfoque). 
Gracias a una maestra que me ha apoyado (in)directamente en este proceso  he podido encontrar un pequeño lugar para mi y mis demonios dentro de la universidad. Este espacio es LinudecX, un espacio donde existe una libertad para poder investigar y profundizar dicha investigación hasta donde el limite indefinido exista.
LinudexC es un semillero de investigación de la universidad, que empezó con el enfoque de investigar, usar y incentivar el uso del sistema operativo GNU y del kernel Linux. Este semestre después de que me…