Robustecimiento y securización del protocolo SSH
20 de febrero de 2019 • fjbalon
SSH es uno de los protocolos más interesantes de los que dispone el administrador de sistemas, permitiendo acceder a otros equipos de forma remota; pero sobretodo, de forma segura. Con SSH creamos un túnel entre cliente y servidor que simula, en la capa de aplicación, la shell o intérprete de comandos del servidor, dotando al administrador de toda funcionalidad en el equipo.
SSH puede considerarse una evolución del protocolo Telnet, pero el primero cuenta con técnicas de criptografía para proteger los datos intercambiados entre ambos nodos que conforman la conexión SSH. SSH utiliza un intercambio de claves basado en el protocolo criptográfico de Diffie-Hellman, imprescindible en el robustecimiento de la capa de transporte.
SSH trabaja sobre el protocolo TCP/IP. Por ello, en primer lugar se realiza la conexión TCP, realizando el three-way handshake. Después de abrir la conexión, cliente y servidor se envían la versión disponible del protocolo. Se utilizará luego el par de claves, pública y privada, de RSA. El servidor enviará su clave pública de host al cliente, de forma que éste pueda cifrar lo que necesite enviar al servidor. El cliente comparará la clave pública de host con la que tenga almacenada en el archivo known_hosts, si lo hubiera.
Una vez el cliente dispone de la clave pública del host del servidor, este generará una clave de sesión aleatoria y seleccionará un algoritmo de cifrado simétrico. Con esta clave de sesión, que se generará por defecto cada 3600 segundos, se cifrará el túnel. El cliente enviará un mensaje que contiene la clave de sesión y el algoritmo de cifrado seleccionado, información que viajará cifrada mediante la clave pública de host, al servidor. En este instante, el resto de la comunicación se utilizará el algoritmo de cifrado simétrico y la clave compartida de sesión, dando velocidad a la conexión (en técnicas de clave simétrica el cifrado y descifrado se hace más rápido), pero utilizando siempre primero el protocolo de Diffie-Hellman para poder enviar de forma segura la clave compartida de sesión; y supliendo así la principal carencia en seguridad de los algoritmos de criptografía simétrica: el intercambio de claves.
Con el túnel creado, se llevará a cabo la autenticación del usuario en el servidor, pudiendo utilizar distintos métodos para llevar a cabo tal autenticación.
una conexión común usando el protocolo SSH es de por sí segura; al menos más segura que una conexión no cifrada como telnet, pero presenta, grosso modo dos inconvenientes:
En ningún momento se envían claves por Internet (más que el envío de la clave pública al servidor en el primer contacto, para que éste la conozca). Por supuesto si alguien accede a nuestro equipo y nos roba la clave privada podría autenticarse como nosotros y suplantar nuestra identidad criptográfica. Por esta razón es necesario proteger las distintas formas de acceso, desde cifrado de particiones a configuración estricta de permisos.
También es posible asignar un cifrado simétrico sobre las claves asimétricas, dando una capa extra de seguridad a cambio de tener que introducir una clave cada vez que la usemos.
La configuración del servidor oldscizor es sencilla:
# /etc/ssh/sshd_config
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
Véase la última línea, donde añadimos el fichero que almacenará las claves públicas de los clientes reconocidos. Si no existiera este directorio y/o fichero deberemos crearlo.
Por otro lado, la configuración del cliente scizor consiste en la generación del par de claves RSA para éste:
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/scizor/.ssh/id_rsa):
/home/scizor/.ssh/rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/scizor/.ssh/rsa
Your public key has been saved in /home/scizor/.ssh/rsa.pub
The key fingerprint is:
SHA256:aVgQfYrakZnFhaw4Gcl0bHqrJj7QtR3dXm332wx9qdE scizor@client
The key's randomart image is:
+---[RSA 3072]----+
| o.o+= o. |
| +.o.* . |
| * O.+ . |
| * Xoo.. . o .|
| . . B.+S. . ..oo|
|. . o +. . ..E+|
| . . oo+|
| o o . .o|
| ..+ |
+----[SHA256]-----+
A continuación debemos configurar el ssh-agent para añadirle nuestra clave privada emparejada con la pública que enviaremos al servidor, de forma que, ejecutándose junto a la sesión, éste esté vinculado a ella directamente.
$ eval $(ssh-agent -s)
Agent pid 15081
$ ssh-add ~/.ssh/rsa
Identity added: /home/scizor/.ssh/rsa
(/home/scizor/.ssh/rsa)
Otra opción es utilizar el fichero config:
# ~/.ssh/config
Host oldscizor.es
User scizor
IdentityFile ~/.ssh/server_key
La clave pública deberá ser enviada al servidor y almacenada en authorized_keys o en el fichero seleccionado.
# cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCoaiQqlc0hhqdVsh52sB/ui
ISb1pRU/6DVWqyvpCYWQOd8PGNGjuFwYeOnTQ1mZYppuNoXmQxzKXJXGK4ke/
4HcgRHj9l2zZL0LBacnU1NEszqVYUgpI4+1qbyMi0LQZTpKedGULFcSVa1QDt
SWTLeQIYTK7dphN4wo7cer9EFkfj5Z1ZNWSjC4blTFTGD2L03aSUklek+BHkk
FFGYmVKw/+VD7aOA+Imsb/qHp1eUhEKcHSlWPfDS6qf+GwJoB72v4TMCH1At1
fM2LP8o/eRF31fZdRJGOHL+MzfXR0RqS1SLfr/1g6NRohmu1BFFdQQxisovPf
h1iOBs4apqQjRl6P6qQziwSVShkkzDW0xOnIflWwbYjo/w1SFN5YzwDaOV3QK
VYEeHQGm2mdwPGqPxyeyTaCZqf5Ca2k/Gv53BlRCUb3ATpXTbN6HzIliOUtFm
idUAYQwYM0n7VMpL7NW+/1ap6UthX/ep/CjcxGqYZc4+iTSSSict9caCSGSY+
Ec= scizor@client
Finalizada la configuración, observamos el proceso de conexión mediante el parámetro verbose:
$ ssh -v oldscizor.es
OpenSSH_8.8p1, OpenSSL 1.1.1l 24 Aug 2021
debug1: Reading configuration data /home/scizor/.ssh/config
debug1: /home/scizor/.ssh/config line 9: Applying options for oldscizor.es
debug1: /home/scizor/.ssh/config line 13: Applying options for oldscizor.es
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Connecting to oldscizor.es [54.38.52.183] port 22.
debug1: Connection established.
debug1: identity file /home/scizor/.ssh/oldscizor type 0
debug1: identity file /home/scizor/.ssh/oldscizor-cert type -1
debug1: identity file /home/scizor/.ssh/scizorc type 0
debug1: identity file /home/scizor/.ssh/scizorc-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.8
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.9p1 Debian-10+deb10u2
debug1: compat_banner: match: OpenSSH_7.9p1 Debian-10+deb10u2 pat OpenSSH* compat 0x04000000
debug1: Authenticating to oldscizor.es:22 as 'scizor'
debug1: load_hostkeys: fopen /home/scizor/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host key: ssh-ed25519 SHA256:d6TuEWkCHpZXztBeSP2s2dVCRC+nHu3a2JxnJXioA34
debug1: load_hostkeys: fopen /home/scizor/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: Host 'oldscizor.es' is known and matches the ED25519 host key.
debug1: Found key in /home/scizor/.ssh/known_hosts:7
debug1: rekey out after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey in after 134217728 blocks
debug1: Will attempt key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
debug1: Will attempt key: /home/scizor/.ssh/scizorc RSA SHA256:0zdBByBWUvwkcfgcRYL68IdoNMOmJwijG2QiHsgcTaM explicit
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521>
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
debug1: Server accepts key: /home/scizor/.ssh/oldscizor RSA SHA256:zFOQBJRsUuKhgVyvCkKaJDcJ/Y7qWq2VEN1lRkJxL74 explicit
Authenticated to oldscizor.es ([54.38.52.183]:22) using "publickey".
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: pledge: filesystem full
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug1: client_input_hostkeys: searching /home/scizor/.ssh/known_hosts for oldscizor.es / (none)
debug1: client_input_hostkeys: searching /home/scizor/.ssh/known_hosts2 for oldscizor.es / (none)
debug1: client_input_hostkeys: hostkeys file /home/scizor/.ssh/known_hosts2 does not exist
debug1: client_input_hostkeys: no new or deprecated keys from server
debug1: Remote: /home/scizor/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
debug1: Remote: /home/scizor/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
Linux oldscizor 4.19.0-17-cloud-amd64 #1 SMP Debian 4.19.194-3 (2021-07-18) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Nov 16 21:56:22 2021 from 172.16.7.12
scizor@oldscizor:~$
El cliente lee el fichero ssh_config antes de realizar la conexión al servidor oldscizor.es en su puerto por defecto 22. Tras esto, se crea la conexión TCP y, una vez se realiza el three-way handshake entre cliente y servidor, la conexión queda establecida; pero aún no existe canal cifrado.
El cliente verifica la existencia de posibles claves privadas y verifica si se encuentra alguna en la lista negra. Una vez realizado este proceso, verifica también la versión del protocolo. Es en este instante en el que se intercambian la clave pública host del servidor al cliente, para que éste pueda generar y cifrar la clave simétrica, la cual será la encargada de cifrar el canal.
Una vez el cliente recibe la clave del host, la verifica en el fichero known_hosts. Si se encuentra, se verifica la identidad del servidor. Si por el contrario no se encuentra mostraría un mensaje avisando de la posible suplantación (por defecto).
Tras aceptar el cliente al servidor, verificando la identidad de éste, se establece la conexión en un canal ya seguro. El servidor envía el banner y el cliente lo muestra por pantalla. Despues, el servidor envía al cliente los métodos de autenticación para el usuario de los que se disponen y el cliente valorará su configuración previamente cargada para realizar la autenticación pertinente; que en nuestro ejercicio es una autenticación basada en claves RSA, y tras autenticarse, se envían desde el servidor las variables de entorno de la sesión y proporciona el control de la shell en remoto.
Sobre SSH existen varias aplicaciones que sirven de arsenal bastante completo al administrador de sistemas. Enumero las que conozco:
La utilidad ssh-copy-id permite enviar las claves públicas directamente a tantos servidores sea necesario, automatizando y simplificando la comunicación cifrada contra múltiples equipos sin necesidad de abrir una sesión en cada uno de ellos.
.---------------------------------------.
| aws:/home/thufir/.ssh/authorized_keys |
|---------------------------------------|
| ssh-rsa AAAA... user10@host |
'---------------------------------------'
^
|
|
ssh-copy-id | .---------------------------------------.
| | aws:/home/ubuntu/.ssh/authorized_keys |
.---' |---------------------------------------|
| | ssh-rsa AAAA... user10@host |
| '---------------------------------------'
| ^
.---------------------------------------. |
| local:/home/user10/.ssh/id_rsa | | ssh-copy-id
| Private Key | |
|---------------------------------------| |
| BEGIN RSA PRIVATE KEY |----------.
| Proc-Type: 4,ENCRYPTED | |
| DEK-Info: AES- | | ssh-copy-id
'---------------------------------------' |
| v
| .---------------------------------------.
'---. | aws2:/home/user5/.ssh/authorized_keys |
| |---------------------------------------|
| | ssh-rsa AAAA... user10@host |
ssh-copy-id | '---------------------------------------'
|
v
.----------------------------------------.
| aws2:/root/.ssh/authorized_keys |
|----------------------------------------|
| ssh-rsa AAAA... user10@host |
'----------------------------------------'
Aunque no soy amigo de utilizar la autenticación básica por contraseña en mis infraestructuras SSH, a veces es necesario autenticar de esta forma, y nunca esta utilidad que permite al usuario cierta automatización a la hora de gestionar conexiones, principalmente cuando esta administración se hace desde otros programas o scripts donde no puede haber interactividad directa. La utilidad sshpass está diseñada para ejecutar SSH utilizando el modo de autenticación de contraseña interactiva de teclado, pero de una manera no interactiva, utilizando acceso TTY directo para garantizar que la contraseña sea emitida por un usuario de teclado interactivo, engañando a SSH haciéndole creer que está obteniendo la contraseña de un usuario interactivo.
Su modo de uso es tan sencillo como indicar previamente a la comunicación con el servidor SSH la clave de éste tras el comando propio de sshpass:
$ sshpass -p !4u2tryhack ssh user@host
SCP o Secure Copy es un protocolo similar funcionalmente a RCP (Remote Copy), cuyo objetivo es transferir archivos desde una máquina a otra. La diferencia entre ambos protocolos es que SCP utiliza el protocolo SSH para establecer sus comunicaciones, estableciendo un túnel cifrado por el que enviar dichos archivos.
La ejecución de SCP es realmente sencilla, contando con la sintaxis:
$ scp [opciones] origen destino
Donde el origen o destino local es la ruta, ya sea absoluta o relativa y el origen o destino remoto cumple con su propia sintaxis:
usuario@host:<ruta_archivo>
De tal forma que para enviar un archivo a un servidor mantendríamos la sintaxis:
$ scp /home/scizor/archivo oldscizor.es:/usr/archivo
Y siendo la forma inversa:
$ scp oldscizor:/usr/archivo2 /home/scizor/archivo2
Cabe destacar que también podemos realizar copias seguras entre máquinas remotas, no necesariamente debe ser una origen o destino local:
$ scp oldscizor.es:/root/origen root@172.16.1.2:/etc/destino
SSH File Transfer Protocol o SFTP permite el envío de ficheros a nivel de aplicación, a través de SSH, utilizando las aplicaciones y los comandos propios del protocolo FTP. Es sabido que el protocolo FTP no es seguro per se, debido a que no cuenta con cifrado.
La sintaxis es similar al protocolo FTP, manteniendo una vez establecida la conexión una cadena de conexión a nivel de aplciación similar a SSH.
$ sftp oldscizor.es
Connected to 10.101.5.3-
sftp>
El protocolo SSH dispone de la posibilidad de gestionar el sistema de archivos de manera remota y segura utilizando SSHFS o Secure Shell File System. En el equipo local donde se realiza el montaje de SSHFS, la implementación hace uso del módulo del kérnel FUSE.
La sintaxis es sencilla. Se debe ejecutar el comando sshfs seguido de la ruta remota que se quiere montar localmente y, por último, la ruta local que se utilizará como punto de montaje.
$ mkdir fs
$ sshfs oldscizor.es:/home/git fs
$ ls -l fs
drwxr-xr-x 7 git git 4096 Nov 15 09:47 arch.git
drwxr-xr-x 7 git git 4096 Oct 25 16:31 automata.git
drwxr-xr-x 7 git git 4096 Nov 12 10:33 crypto.git
drwxr-xr-x 7 git git 4096 Nov 12 10:22 dmenu.git
drwxr-xr-x 7 git git 4096 Nov 15 09:32 dotfiles.git
drwxr-xr-x 7 git git 4096 Nov 9 23:32 dwm.git
Una vez realizado el montaje, se puede utilizar cualquier tipo de operación como si la ruta fuera local. También podemos utilizar sobre el punto de montaje cualquier software, como un gestor de archivos gráfico para desempeñar el trabajo que sea. Todas las acciones remotas las hará de forma transparente al usuario y mediante un túnel cifrado.
Esta opción del protocolo SSH permite al usuario conectarse a un servidor para levantar procesos que requieran de un servidor gráfico para su interacción. De tal modo que un administrador pueda, por ejemplo, ejecutar un navegador en un servidor remoto, y la presentación gráfica se realizará en la máquina local a pesar del proceso encontrarse ejecutando en la máquina remota. Evidentemente, toda comunicación cliente-servidor se realizará de manera segura mediante el protocolo SSH, por lo que los datos de presentación del proceso viajarán por la red bajo este protocolo. Para poder redirigir la salida de las ventanas de los procesos que se ejecutan, el servidor debe habilitar la directiva X11Forwarding en su fichero sshd_config.
Si bien el SSH Tunneling puede considerarse una aplicación del protocolo, he decidido hacer una entrada a parte sólo para ese caso, pues es más complejo y especial.