Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

jueves, 30 de junio de 2016

Cómo crear un honeypot SSH en Linux

En el mundo de la seguridad informática hay una regla primordial: Cualquier cosa que esté expuesta en el exterior, va a sufrir cyber ataques... Esto es así nos guste o no y se acabará haciendo realidad tarde o temprano, cosa que se puede aprender por las buenas o por las malas... Generalmente siempre querremos intentar hacer que los atacantes no entren, pero a veces podemos "satisfacer" la curiosidad de nuestros atacantes mediante el uso de "tarros de miel" que les haga creer que han logrado entrar, aunque en realidad no sea así; tarros de miel que son conocidos mundialmente como honeypots. Un honeypot no es ni más ni menos que un entorno ficticio con información ficticia que hace de señuelo para que los atacantes no vayan a por la información real; dicho entorno ficticio deja que el atacante "juegue" con él a su libre albedrío pero en realidad no hace otra cosa que hacer perder el tiempo al criminal y evitar que consiga el verdadero objetivo de su ataque... Existen diversos honeypots: FTP, HTTP/HTTPs, SIP... Pero hoy nos centraremos en el tarro de miel más "goloso" de todos: El orientado al protocolo SSH.

Honeypot_ssh

Para crear nuestro tarro, recurriremos a una herramienta desarrollada en Python llamada Kippo, una herramienta especializada en la creación de honeypots orientados a ssh que nos creará un entorno ficticio para todos los curiosos que quieran entrar al puerto 22 de nuestro servidor. Para ello lo primero que haremos será cambiar el puerto de escucha de nuestro servidor ssh (si es que no lo tenemos cambiado de antes) a un puerto distinto; queremos que el puerto 22 sea el que usen para entrar el honeypot con lo que tendremos que hacer que el ssh real se realice a través de otro puerto... A modo de recomendación personal evitaría usar el puerto 2222 o 22000, pues dichos puertos son conocidos por ser usados como puertos alternativos al 22. Para cambiar el puerto de escucha editaremos el fichero /etc/ssh/sshd_config y cambiaremos el valor de Port a uno menos conocido como podría ser el 10000 (por ejemplo). Si quisiésemos hacerlo directamente desde la línea de comandos al mismo tiempo que aplicamos los cambios, podríamos hacerlo de la siguiente forma:

sed -i 's/Port 22/Port 10000/g' /etc/ssh/sshd_config && /etc/init.d/ssh restart

Esta línea estaría compuesta por una sustitución de la línea "Port 22" por "Port 10000" en el fichero sshd_config, seguido del reinicio del servicio ssh para aplicar los cambios.

Con este pequeño requisito cumplido, tocaría comenzar instalando los preparativos; es decir los paquetes necesarios para que Kippo funcione. Kippo no puede ser instalado desde los repositorios oficiales, pero este programa posee dependencias que sí que pueden ser instalados desde éstos, con lo que comencemos instalándolos. En este caso me he centrado en un entorno Debian, pero el proceso en entornos Red Hat no debería diferir mucho más allá del gestor de paquetes:

apt-get install python-dev openssl python-openssl python-pyasn1 python-twisted authbind

La mayoría de los paquetes están basados en python, a excepción del paquete authbind que se encarga de permitir que usuarios que no sean root, puedan trabajar con puertos menores 1024, pues queremos que el honeypot NO sea ejecutado por root. 

Ahora crearemos un usuario especialmente preparado para ejecutar el honeypot, un usuario que, valga la originalidad, llamaremos kippo y que pertenecerá al grupo sudo.

useradd -m kippo -g sudo

Dicho usuario podrá manipular/usar el puerto 22, un privilegio que única y exclusivamente tendrá él, si bien con lo que hemos hecho no basta, sino que también necesitamos preparar authbind para ello. Esto es tan sencillo como crear un fichero llamado 22 dentro del directorio /etc/authbind/byport/ y darle los permisos adecuados para que únicamente kippo pueda tener acceso a éste; lo cual se resumiría tal que así:

  1. touch /etc/authbind/byport/22
  2. chown kippo /etc/authbind/byport/22
  3. chmod 700 /etc/authbind/byport/22

Ahora que hemos preparado tanto el puerto como el usuario, llegaría el turno de movernos a la carpeta /home de kippo y descargarnos el fichero kippo; fichero que, tal y como he comentado antes, no está disponible desde los repositorios, pero sí desde github con lo que tras movernos a la carpeta, descargaríamos y descomprimiríamos la aplicación. A modo de recomendación, sería bueno crear una carpeta dentro del directorio home que guarde todo lo relacionado con la aplicación.

  1. su kippo
  2. cd /home/kippo
  3. mkdir kippo_DIR
  4. cd kippo_DIR
  5. wget https://github.com/desaster/kippo/archive/v0.9.tar.gz
  6. tar -xzf v0.9.tar.gz

Por fin tenemos kippo descargado, si bien eso no significa que esté operativo... Por un lado es importante tener en cuenta que, a diferencia de muchos programas descargados desde github, este programa no requiere ser compilado/instalado para funcionar y además requiere realizar algunos ajustes para ser del todo operativo... Para empezar, el fichero de configuración que existe ahí, está a modo de plantilla y ni siquiera se encuentra correctamente nombrado para evitar que pueda usarse... Esta plantilla tendría se llama kippo.cfg.dist y además está configurada para trabajar por defecto con el puerto 2222, cosa que nosotros no queremos pues queremos usar el puerto 22 para emular un puerto ssh "real". Es por eso que primero renombraremos el fichero de configuración y después cambiaremos el puerto de escucha del 2222 al 22 mediante el comando sed de forma parecida a como hemos hecho antes con el fichero sshd_config.

  1. cd /home/kippo/kippo-DIR/kippo-0.9/
  2. mv kippo.cfg.dist kippo.cfg
  3. sed -i '/ssh_port = 2222/ssh_port = 22/g' kippo.cfg

Ya lo tenemos casi preparado, solo faltan un par de detalles más. Por un lado, tenemos que saber que los usuarios ficticios del honeypot se encuentran dentro del fichero userdb.txt, el cual se encuentra dentro del directorio data que a su vez se encuentra dentro de la carpeta de la aplicación de kippo. Cada usuario existente dentro de dicho fichero tiene la siguiente estructura:

usuario:0:contraseña

He aquí un fichero de ejemplo:

  1. root:0:123456
  2. root:0:test
  3. ivan:0:ivan


Por otro lado, dentro del directorio de la aplicación de kippo, tenemos un fichero llamado start.sh, fichero encargado de arrancar kippo; dicho fichero tiene que ser modificado, pues ahora mismo no está preparado para trabajar con authbind. Éste tendría que ser editado para ofrecer este aspecto:

  1. #!/bin/sh
  2. echo -n "Starting kippo in background..."
  3. #twistd -y kippo.tac -l log/kippo.log --pidfile kippo.pid
  4. DIR=/home/kippo/kippo-DIR/kippo-0.9
  5. cd ${DIR}
  6. authbind --deep twistd -y kippo.tac -l log/kippo.log --pidfile kippo.pid

A base de prueba y error, he visto que esto no basta y que es necesario que creemos dos directorios nuevos, pues en caso contrario, la aplicación no funcionará correctamente... El primero es un directorio llamado log, que se crearía dentro de la carpeta de la aplicación, mientras que el otro se llamaría tty. Obviamente ambas carpetas tendrían que pertenecer al usuario kippo.

  1. mkdir /home/kippo/kippo-DIR/kippo-0.9/log
  2. mkdir /home/kippo/kippo-DIR/kippo-0.9/log/tty
  3. chown kippo /home/kippo/kippo-DIR/kippo-0.9/log
  4. chown kippo /home/kippo/kippo-DIR/kippo-0.9/log/tty

Con esto ya tendríamos todo preparado y si ejecutásemos el script start.sh podríamos arrancar kippo, pero en mi opinión dicho script no es demasiado funcional pues no puede ser ejecutado en el arranque y no te ofrece ninguna posibilidad de pararlo de una forma cómoda. Es por ello que he añadido un pequeño script en /etc/init.d / para poder manejar el servicio con más comodidad. Dicho script sería el de a continuación y se denominaría kippo.sh.

  1. #!/bin/bash
  2. #
  3. # preload init.d script
  4. ### BEGIN INIT INFO
  5. # Provides:          start.sh
  6. # Required-Start:    $local_fs $remote_fs $time
  7. # Required-Stop:     $local_fs $remote_fs $time
  8. # Default-Start:     2 3 4 5
  9. # Default-Stop:      0 1 6
  10. # Short-Description: Kipoo starter
  11. # Description:  Kippo automatic starter. It starts during the boot
  12. ### END INIT INFO
  13. PIDFILE=/home/kippo/kippo-DIR/kippo-0.9/kippo.pid
  14. NOMBRE="Kippo"
  15. SRV="twistd"
  16. function status()
  17. if [ -f ${PIDFILE} ];
  18. then
  19.         echo "${NOMBRE}  esta en marcha"
  20. else
  21.         echo "${NOMBRE} esta parado"
  22. fi
  23. function start(){
  24.  echo -n $"Iniciando servicio ${NOMBRE}: "
  25.  su - kippo -c "/home/kippo/kippo-DIR/kippo-0.9/start.sh" >/dev/null 2>&1
  26.  RETVAL=$?
  27.  echo $! > $PIDFILE
  28.  if [ ${RETVAL} -eq 0 ];
  29.  then
  30.         echo "Se ha iniciado ${NOMBRE}"
  31.  else
  32.         echo "No se ha podido iniciar ${NOMBRE}"
  33.  fi
  34.  echo
  35. }
  36. function stop(){
  37.  echo -n $"Parando servicio ${NOMBRE}... "
  38.  SERV=$(ps -e |grep ${SRV} |awk '{print $1}')
  39.  kill -9 ${SERV}
  40.  echo "Servicio detenido"
  41. }
  42. function restart(){
  43.  stop
  44.  sleep 10
  45.  start
  46. }
  47. case "$1" in
  48. start)
  49.  start
  50.  ;;
  51. stop)
  52.  stop
  53.  ;;
  54. restart)
  55.  restart
  56.  ;;
  57. status)
  58. status
  59. ;;
  60. *)
  61.  echo $"Usar: $0 {status|start|stop|restart}"
  62.  exit 1
  63. esac
  64. exit 0

Obviamente sobre dicho script tendríamos que ejecutar dos comandos más; uno que haga que sea ejecutable, y otro que haga que se arranque en el inicio con el fin de que en caso de apagar el servidor. no se pierda nuestro querido tarro de miel.

  1. chmod 755 /etc/init.d/kippo.sh
  2. insserv kippo.sh

Ahora cualquier que acceda al puerto 22 por ssh, en vez de acceder a nuestro entorno real, accederá al honeypot en cuestión, honeypot en el que en caso de acertar sus credenciales (por defecto está diseñado para tener un único usuario que sería root con contraseña 123456) accederíamos. Obviamente dicho honeypot estaría aislado del verdadero sistema y siempre nos estaría dando datos ficticios, desde la ip hasta los ficheros presentes.

Una evidencia de que no estamos accediendo al servidor de siempre, más allá de la información existente dentro de éste, sería el hecho de que el ssh fingerprinting del servidor ha cambiado, pues en realidad estaríamos accediendo a un entorno diferente al real.

Gracias a este sencillo pero útil procedimiento, lograríamos alejar a gran parte de los curiosos de nuestro servidor ssh, haciendo que los atacantes malgasten su tiempo en un entorno ficticio y evitando que centren su atención en el puerto ssh real.

Espero que os haya resultado útil.

Saludos.

lunes, 27 de junio de 2016

Flatpak: El "rival" de Snap creado por Red Hat

Hace alrededor de dos meses, con la aparición de la nueva LTS de Ubuntu, se habló en este blog sobre una de las características más novedosas de esa distribución: Los paquetes Snap. Dicho paquetes suponen una revolución en lo que se refiere a la paquetería, pues aportaba por un lado más seguridad todo lo instalado mediante dichos paquetes se realizaba en "sandboxes" aislados del resto de paquetes, haciendo que cualquier posible daño al programa instalado mediante Snap, no repercutiese en el resto... Además Snap también hacía desaparecer la necesidad de descargar las dependencias necesarias para el paquete en cuestión, pues ya las incluye todas dentro de éste (haciendo que obviamente, el paquete pesase bastante más que un paquete "normal). La cuestión está que Snap es un recurso exclusivo de Ubuntu y era obvio que Red Hat iba a tomar cartas en el asunto... Y así ha sido, pues Flatpak ha sido oficialmente anunciado por dicha compañía, haciendo que la "guerra" de paquetes vuelva de nuevo, con la diferencia de que en este caso los miembros serían Snap y Flatpak en vez de deb y rpm.

Portada_flatpal

Con el total respaldo de Red Hat, Flatpak parece llegará para quedarse y para impulsar el uso de éste en vez de Snap, argumentando tener las mismas características que Snap, pero no solo eso sino que además argumenta tener una cualidad que ningún otro sistema de paquetes posee: La posibilidad de acabar con una de las mayores pegas del mundo Linux, que es nada más y nada menos que la fragmentación. Es decir que su gran baza consiste en que dicha paquetería podría usarse como un standard válido para cualquier distribución lo cual hace que Flatpak sea una alternativa bastante atractiva. Por otro lado, si bien un paquete Flatpak siempre ocupará más que un rpm o deb, al parecer van a intentar reducir su tamaño lo máximo posible haciendo que las librerías y/o otros componentes estén deduplicados (Parece un concepto inventado, pero existe), con lo cual lograrían no solo que ocupasen menos en el disco duro, sino que los tiempos de descarga del paquete Flatpak sea el mínimo posible...

Obviamente a Flatpak le queda tiempo por madurar... Es una tecnología nueva, y probablemente necesite de cierto tiempo para ir puliéndose progresivamente... Es más, de momento parece que estos paquetes estarán disponibles únicamente en Fedora, pues probablemente querrán que esta distribución sirva como "campo de pruebas" antes de arriesgarse a incluirlo en Red Hat; una decisión muy inteligente por su parte, dicho sea de paso.

Al igual que Snap, los paquetes disponibles actualmente son bastante escasos, pero lo cierto es que actualmente tienen algunos paquetes de mucha relevancia ya disponibles bajo dicho formato, tales como LibreOffice o GIMP, con lo que todo apunta a que van a apostar fuertemente por dicha tecnología, si bien obviamente la decisión de usar dichos paquetes o no, recaerá, al menos de momento, en el usuario final... 

Todo parece que Ubuntu y Red Hat han puesto toda la carne en el asador y que la "carrera" entre ambos no ha hecho más que comenzar... Con Snap respaldado por Ubuntu y Flatpak por Red Hat, indudablemente ambos llegarán lejos ¿Logrará uno superponerse al otro? Yo espero que ambos triunfen, pues indudablemente Linux está compuesto de "sabores" y elecciones, y la adopción de una única elección supondría una situación muy parecida a la vivida con systemd. Lo que es indudable es que ambas tecnologías darán que hablar en los próximos años, cosa que esperemos que sirva para impulsar el uso del software libre.

Espero que os haya resultado interesante.

Saludos.

viernes, 24 de junio de 2016

La gran potencia de AWK en Linux

Revisando antiguos artículos relacionados con bash, he visto que más de una vez he mencionado un recurso del cual no he dado explicaciones, un parámetro extraordinariamente potente que, en mi opinión, merece ser mencionado y explicado para que todo el mundo lo entienda debidamente. Si no habéis realizado ningún script en bash, probablemente nunca hayáis tenido que recurrir a él, pero en caso contrario, es muy probable que lo hayáis usado, en mayor o menor medida. Se trata de awk, un recurso de programación de bash que puede sacarnos de más de un escollo; un recurso que se podría denominarse como parte recurso de ayuda para bash y como parte lenguaje de programación.

awk_linux

El uso más común de todos y el que más de una vez he usado en los scripts que he mostrado en este blog, es el filtrado de un resultado por columnas. A veces el parámetro cut se nos puede quedar corto y necesitamos algo más potente que nos pueda filtrar las columnas deseadas a nuestro gusto; para ello habría que acompañar el comando que queramos por la sintaxis: |awk '{print $número_columna $número_columna2}'.  El número de columnas que podemos mostrar es equivalente al número de columnas disponibles, con lo que podemos escoger mostrar únicamente una columna, dos, o las que queramos, siempre y cuando dicho número de columna sea válido. Para tener una visión clara de esto, lo mejor es plasmarlo en un pequeño ejemplo. Supongamos que queremos mostrar detalladamente el contenido del directorio etc; para simplificar el resultado únicamente mostraríamos las 10 primeras líneas. Esto lo lograríamos mediante el comando:

ls -l /etc/ |head -n 10

Esto mostraría algo como esto:

ls_normal

Lo malo de esto es que hay bastante información "innecesaria" o molesta que no nos interesa en estos momentos. ¿Qué nos importan los permisos de los ficheros y directorios? ¿Acaso queremos saber a qué usuario y grupo pertenecen? Para esta situación en concreto solo nos interesaría la última fecha de modificación de las carpetas/ficheros junto con, obviamente, el nombre de éstos. Es decir que solamente querremos obtener el resultado de las columnas 6,7,8 y 9. Esto lo lograríamos mediante el siguiente comando:

ls -l /etc/ |head -n 10 |awk $'{print $6 " " $7 " " $8 " " $9}'

ls_awk

Hasta aquí diríamos que sería el uso más habitual y básico de AWK, un uso que no debe de ser en absoluto desdeñado pues a mí, personalmente, me ha sido de gran ayuda en muchísimas ocasiones. Pero la verdad es que se puede ir mucho más allá de este uso tan básico. El uso del número de posición, en realidad hace referencia a unas variables, variables que van mucho más allá de estos "simples" números. Hay variables que pueden ser creadas por awk, pero hay un buen número de variables que ya posee de forma implícita awk; algunas de éstas serían:

  • NS: Esta variable haría referencia al número de columnas que ofrece un resultado; ya sea el resultado de un comando o una variable. Si por ejemplo, usásemos un |awk '{print $NF}', mostraríamos siempre la última columna, pues el número de la última columna sería equivalente al número de columnas. 
  • NR: A veces un resultado puede ofrecer varias filas; siendo difícil conocer a qué número de fila pertenece cada resultado; gracias al uso de |awk '{print NR}' (sin $), mostraremos el número de línea de cada resultado.
  • OFS: En el segundo ejemplo que he mostrado anteriormente, habéis visto que he usado " " para serparar cada columna entre sí con un espacio; podemos optar por hacer uso de la variable OFS para hacer exactamente lo mismo si así lo deseamos. Ejemplo: ls -l |awk $'{print $6 OFS $7 OFS $8 OFS $9}'.
  • ORS: Si en vez de separar las columnas con espacios en blanco, separamos éstas mostrando el resultado en diferentes líneas, haríamos uso de la variable ORS; algo como: ls -l |awk $'{print $6 ORS $7 ORS $8 ORS $9}'.

Existen muchas más variables, pero con esto os podéis hacer una idea de la potencia que awk ofrece mucha más potencia de lo que parece y que existen muchas más variables que las numéricas. 

AWK también permite realizar operaciones aritméticas; es decir que permite hacer operaciones matemáticas sobre los resultados obtenidos dentro de {}. Esto puede resultarnos útil cuando queremos convertir un valor numérico a otro más "legible" o simplemente queremos efectuar una operación sobre él... 

Un simple ejemplo de esto sería la contabilización de usuarios conectados... El comando uptime muestra, además del tiempo que lleva encendido el equipo, el número de usuarios logueados en el equipo; ya sean usuarios que han iniciado sesión local o remotamente en el susodicho... Dicha contabilización incluye al usuario que ha introducido el comando, con lo que aún cuando no haya absolutamente nadie más logueado, siempre mostrará un valor mínimo de 1; gracias a awk, podemos restarle 1 a dicho resultado para que el comando nos diga únicamente el número de usuarios ajenos conectados. Esto se plasmaría con este sencillo comando:

uptime |awk '{print $4-1}'

Pero tal y como he dicho antes, awk también puede admitir bloques de código; es decir que permite realizar ciertas instrucciones parecidas a las usadas en el desarrollo de otros lenguajes... Por ejemplo awk permite realizar bucles, introducir condicionales, etc... tal y como se hace en otros lenguajes de programación... Aquí uno puede jugar con los datos como quiera, pero he aquí unos pequeños ejemplos de la potencia de estos bloques de código sería esta muestra.

Esta sería una pequeña prueba de concepto de lo que podemos lograr mediante el uso de condicionales (if else)... Gracias a dichas condiciones he "transformado" una salida que tendría que haber mostrado 1 2 3 4 en: Hola que tal estas? 

  1. root@debian:~# echo "1 2 3 4" |awk '{if ($1 == 1){$1 = "Hola"} if ($2 >= 2) {$2 = "que"} if ($3 <= 3) {$3 = "tal"} if ($4 != 4) {$4 = 4} else {$4 = "estas?"} print $1 OFS $2 OFS $3 OFS $4}'
  2. Hola que tal estas?

Obviamente no todo se reduce a condicionales; también podemos hacer uso de bucles for, tal y como en este ejemplo; ejemplo en el que si estáis familiarizados con lenguajes de programación tales como C, probablemente encontréis similitudes:

  1. root@debian:~# echo "Bucle" |awk '{for ( x = 1; x <= 10; x++ ) {print $1,x} }'
  2. Bucle 1
  3. Bucle 2
  4. Bucle 3
  5. Bucle 4
  6. Bucle 5
  7. Bucle 6
  8. Bucle 7
  9. Bucle 8
  10. Bucle 9
  11. Bucle 10

Como podéis ver awk dista mucho de ser un simple recurso de filtrado de resultados; es toda una herramienta que nos permite realizar desde simples operaciones a ejecuciones de códigos de programación, siendo una utilidad muy a tener en cuenta por cualquiera que le guste sacar todo el partido posible a las terminales de Linux. Si deseáis profundizar más en esta utilidad, especialmente en lo referente a las variables predeterminadas de awk, os recomiendo que hagáis uso de man, pues sin duda encontrareis dicha información de utilidad.

Espero que os haya resultado útil.

Saludos.