Salta, salta conmigo

Si alguna vez has trabajado con máquinas alojadas en un CPD sabrás que es muy útil tener una puerta trasera para poder entrar en tu sistema en caso de necesidad, por si hay que levantar algún servicio o reiniciar alguna máquina. A mí me ha tocado alguna vez levantarme a las cuatro de la mañana para ir al CPD y dar un «botonazo».

Existen diversas formas de configurar una puerta trasera, pero si lo que tienes alojado es cosa de poca importancia, te puedes permitir el lujo de utilizar alguna solución casera y barata.

Utilizo una Raspberry Pi Zero W para poder saltar desde internet en caso de apuro, por poco dinero tienes un sitio por donde entrar. Lo importante es que esté bien asegurado. ¿Qué habría por lo tanto que tener en cuenta?

  • Lo primero es que no sea fácil para intruso poder entrar. A lo mejor no es buena idea exponer el puerto 22 a internet porque estás dando una pista de que hay un servidor SSH escuchando y puede existir un exploit que lo utilice. Un truco es sencillo es exponer al exterior un puerto raro, por ejemplo, el 5000, que no es un puerto que se utilice para nada. Luego se puede optar por tocar el equipo de casa que te conecta a Internet, el que te pone Telefónica u otra compañía y hacer la conversión del puerto 5000 al 22 o hacer que la máquina de salto escuche en ese puerto 5000. En mi caso esa máquina de salto escucha tanto en el puerto 22 como en el 5000.
  • Utilizar otro usuario del habitual. Por ejemplo, en una Raspberry viene por defecto el usuario pi. En mi caso ese usuario siempre deshabilito ese usuario y utilizo otro para las operaciones habituales y otro únicamente para saltar. Por ejemplo se puede utilizar el usuario jump para saltar. Ese usuario debe estar lo más capado posible, es decir, que no pertenezca a ningún grupo, sobre todo ¡que no pertenezca al grupo sudo!
  • Ese usuario debe estar enjaulado para que si alguien entra por ahí, pocas cosas pueda hacer. Esto se soluciona indicando en el fichero de configuración del demonio ssh la directriz ChrootDirectory <directorio>.

En la Rasp he instalado el sistema operativo estándar sin ningún tipo de interfaz gráfica.

Primero creo un usuario con pocos privilegios. Vamos a trabajar todo como root para no andar con el sudo para arriba y para abajo.:

# useradd jump

Con este comando no se crea ni el directorio home ni tampoco tiene contraseña, por lo que debemos establecer una con el comando passwd. Se recomienda poner una contraseña fuerte ya que con esta contraseña será con la que se entre desde el exterior:

# passwd jump
New password:
Retype new password:

Si la contraseña y su repetición son iguales nos dirá que la contaseña se ha actualizado correctamente:

passwd: password updated successfully

Se comprueba que no tiene directorio home:

# su - jump
su: warning: cannot change directory to /home/jump: No such file or directory

Miramos a ver a qué grupos pertenece:

# su -c id jump
uid=1004(jump) gid=1004(jump) groups=1004(jump)

La jugada entonces consiste en copiar y modificar el fichero de configuración del demonio SSHD para que cuando se conecte el usuario jump lo mande a la jaula que luego crearemos. Por lo tanto:

cp /etc/ssh/sshd_config /etc/ssh/sshd_config_salto

Y en ese fichero se modificará la directiva Port y la directiva AllowGroups y además se añadirán dos nuevas directivas Match User y ChrootDirectory. La cosa quedaría así:

Port 5000
...
AllowGroups jump
Match User jump
ChrootDirectory /jaula

Las tres líneas AllowGroups, etc, serán las últimas del fichero. Vienen a decir que sólo podrán entrar por SSH los usuarios pertenecientes al grupo jump y si el usuario es jump «caerá» en el directorio /jaula. En el caso que nos ocupa se cumple que el usuario jump pertenece al grupo jump por lo que al entrar por SSH acabaría enjaulado en el directorio /jaula que ahora veremos qué tiene.

Tenemos también que crear un servicio que escuche en el puerto 5000. Para ello copiamos el fichero de configuración del servicio SSHD y lo modificamos:

# cp /lib/systemd/system/ssh.service /lib/systemd/system/ssh_salto.service

Y esto es lo que se tocaría de ese fichero:

Description=OpenBSD Secure Shell server port 5000
...
ExecStartPre=/usr/sbin/sshd -t  -f /etc/ssh/sshd_config_salto
ExecStart=/usr/sbin/sshd -D -4 -f /etc/ssh/sshd_config_salto
ExecReload=/usr/sbin/sshd -t -f /etc/ssh/sshd_config_salto

Si no hemos metido la pata en algún sitio, ese servicio debería arrancar:

# systemctl start ssh_salto.service

Y si ha ido todo bien, mirando el status:

# systemctl status ssh_salto.service

Debería decir que está escuchando en el puerto 5000:

# systemctl status ssh_salto.service
● ssh_salto.service - OpenBSD Secure Shell server port 5000
   Loaded: loaded (/lib/systemd/system/ssh_salto.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2022-03-02 09:36:27 CET; 10h ago
     Docs: man:sshd(8)
           man:sshd_config(5)
  Process: 7090 ExecStartPre=/usr/sbin/sshd -t -f /etc/ssh/sshd_config_salto (code=exited, status=0/SUCCESS)
 Main PID: 7105 (sshd)
    Tasks: 1 (limit: 877)
   CGroup: /system.slice/ssh_salto.service
           └─7105 /usr/sbin/sshd -D -4 -f /etc/ssh/sshd_config_salto

Mar 02 09:36:27 zero sshd[7105]: Server listening on 0.0.0.0 port 5000.

Para que este servicio arranque cuando se reinicie la máquina, hay que habilitarlo:

# systemctl enable ssh_salto.service

En la jaula debe haber al menos dos comandos: bash y ssh si lo que queremos es saltar. Además son necesarias las librerías que utilicen esos comandos y también hacen falta algunos ficheros de dispositivo como /dev/null y algunos más.

# mkdir /jaula
# mkdir -p /jaula/usr/bin
# cp /usr/bin/{bash,ssh} /jaula/usr/bin

Con el comando ldd se mira las librerías que utiliza el ejecutable bash:

# ldd /usr/bin/bash
        /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v6l.so (0xb6f9b000)
        libtinfo.so.6 => /lib/arm-linux-gnueabihf/libtinfo.so.6 (0xb6f57000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6f44000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6df6000)
        /lib/ld-linux-armhf.so.3 (0xb6fae000)

Y los que utiliza el ejecutable ssh:

# ldd /usr/bin/ssh
        /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v6l.so (0xb6f1c000)
        libselinux.so.1 => /lib/arm-linux-gnueabihf/libselinux.so.1 (0xb6ed7000)
        libcrypto.so.1.1 => /lib/arm-linux-gnueabihf/libcrypto.so.1.1 (0xb6cbd000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6caa000)
        libz.so.1 => /lib/arm-linux-gnueabihf/libz.so.1 (0xb6c7f000)
        libresolv.so.2 => /lib/arm-linux-gnueabihf/libresolv.so.2 (0xb6c5b000)
        libgssapi_krb5.so.2 => /lib/arm-linux-gnueabihf/libgssapi_krb5.so.2 (0xb6c11000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6ac3000)
        /lib/ld-linux-armhf.so.3 (0xb6f2f000)
        libpcre.so.3 => /lib/arm-linux-gnueabihf/libpcre.so.3 (0xb6a4c000)
        libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6a22000)
        libkrb5.so.3 => /lib/arm-linux-gnueabihf/libkrb5.so.3 (0xb6967000)
        libk5crypto.so.3 => /lib/arm-linux-gnueabihf/libk5crypto.so.3 (0xb6927000)
        libcom_err.so.2 => /lib/arm-linux-gnueabihf/libcom_err.so.2 (0xb6914000)
        libkrb5support.so.0 => /lib/arm-linux-gnueabihf/libkrb5support.so.0 (0xb68fa000)
        libkeyutils.so.1 => /lib/arm-linux-gnueabihf/libkeyutils.so.1 (0xb68e6000)

Y se copian los ficheros creando antes los directorios dentro de la jaula. Es decir, que si el fichero libkeyutils.so.1 está en el directorio /lib/arm-linux-gnueabihf habría que crea ese directorio en la jaula, es decir:

# mkdir -p /jaula/lib/arm-linux-gnueabihf
# cp /lib/arm-linux-gnueabihf/libkeyutils.so.1 /jaula/lib/arm-linux-gnueabihf/

Y así con todas las librerías que nos diga el comando ldd.

Hay que crear algunos ficheros de dispositivos necesarios para que se ejecuten algunos comandos:

# mkdir -p /jaula/dev/		
# cd /jaula/dev/
# mknod -m 666 null c 1 3
# mknod -m 666 tty c 5 0
# mknod -m 666 zero c 1 5
# mknod -m 666 random c 1 8

Y se copian algunos ficheros de configuración:

# mkdir -p /jaula/etc
# cp /etc/{passwd,group,nsswitch.conf} /jaula/etc

Y crearemos un fichero profile de lo más simple:

# cat /jaula/etc/profile
PS1='> '

Y con esto ya se tendría todo. Podemos probar a entrar:

$ ssh -l jump -p 5000 maquina_salto

Y si la contraseña es correcta deberíamos de ver un mensaje del último login y un prompt que es simplemente el carácter «>»:

Last login: Tue Nov 2 20:33:00 2021 from 127.0.0.1
>

Si escribimos un comando tan simple como ls:

> ls
-bash: ls: command not found

Por otro lado, ejecutando el comando ssh que es el que interesa:

> ssh
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
           [-i identity_file] [-J [user@]host[:port]] [-L address]
           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] destination [command]

Se ve que sí funciona.

De este modo, tenemos una manera de poder llegar a nuestra infraestructura y si alguien consigue entrar en la máquina tiene una shell más que restringida, restringidísima. Eso sí, seguro que los malotes conocen alguna técnica para entrar de todos modos.

Comentarios 1

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *