Trust your SSH server

Friday, 23 October 2020
|
Écrit par
Grégory Soutadé

This article you're reading is hosted on my own server. This last one runs a lot of services : web, mail, database, XMPP... and to manage it I need an SSH connection which is the more secure way to connect to a remote server. But, how I can trust this connection in an hostile environment ?

Connection protocols and key exchange has greatly evolved the last 20 years, but there are still based on a root asymmetric key pair (RSA, DSA, ECDSA...). When you connect to a server for the first time, you get a message like this :

The authenticity of host 'mint.phcomp.co.uk (78.32.209.33)' can't be established.
RSA key fingerprint is 6a:de:e0:af:56:f8:0c:04:11:5b:ef:4d:49:ad:09:23.
Are you sure you want to continue connecting (yes/no)? no

This is a human readable fingerprint of the root key used to establish a connection. Personally, I don't know my server fingerprint by heart. There is some solutions to check it :

  • Manually by printing it on a paper/on your phone/on a USB key
  • Register it with a DNS record, but DNS server/response can be easily spoofed
  • Using a public key based connection (you need to keep it on a USB key)

The better remains having the secret (key or fingerprint) somewhere you could access it. I propose in this article an other solution you can always run in an hostile environment without any previous setup.

The idea is to create a restricted user that can only run a verification script that will check fingerprint once connection is established which avoid Man In The Middle attacks !

Setup

First, we'll have to create this user named check-user :

su
useradd --create-home --no-user-group --shell /bin/rbash check-user
cd /home/check-user

You can set a password or not. I don't do it, so I cannot open a connection from external nor internal as my server always checks for password (we can still use su/sudo command). I also set a restricted shell (rbash).

Then, we have to create a key pair

su check-user
ssh-keygen
cp .ssh/id_rsa.pub .ssh/authorized_keys

You can set or not a password for this key. Then, edit .ssh/authorized_keys and add :

command="rbash check_ssh_server.sh" ssh-rsa AAAA...

Now, downloads check_ssh_server.sh in /home/check-user and set execution permissions.

Then, go to your webserver directory were you can put some downloadable files (something like /var/www) and copy SSH the private key.

cd /var/www
cp /home/check-user/.ssh/id_rsa ssh_check
chmod a+r ssh_check

Now, you can edit and run check_ssh_client.sh from any network !

How does it works ?

The client starts by establishing an SSH connection and close it immediately in order to retrieve remote fingerprint. Then, it downloads check-user SSH private key and use it to connect to the server and send the fingerprint. The only command that can be run with this key is rbash check_ssh_server.sh which get the fingerprint and compare with the ones installed on the server side. A message is then displayed which indicates if the connection is secure or not.

Scripts

check_ssh_server.sh

#!/bin/bash

target_key=`echo $SSH_ORIGINAL_COMMAND| tr -d "\r\n"`

if [ -z "${target_key}" ] ; then
    echo "Empty key provided, abort"
    exit 0
fi

for keyfile in /etc/ssh/ssh_host_*_key.pub ; do
    a=`ssh-keygen -l -f ${keyfile}|grep "${target_key}"` # To avoid print
    if [ $? -eq 0 ] ; then
        echo "Target key found, your connection is secure !"
        exit 0
    fi
done

echo "!!! WARNING !!! Key not found, the connection may not be secure"

exit 1

check_ssh_client.sh

#!/bin/bash

KEY_TRACE="Server host key:"
SSH_CHECK_KEY="https://soutade.fr/files/ssh_check/ssh_check"
REMOTE_USER="check-user"

if [ -z "$1" ] ; then
    echo "usage : $@ <ssh server>"
    exit 0
fi

echo "Retrieve remote key for $1"
tmp_file=`mktemp`
ssh -v -o "NumberOfPasswordPrompts=0" $@ >${tmp_file} 2>&1
key=`cat ${tmp_file}|grep "${KEY_TRACE}"`
key=`echo ${key}|cut -d" " -f6`
rm -f ${tmp_file}

echo "Retrieve SSH private key from ${SSH_CHECK_KEY}"
wget -O ssh_check ${SSH_CHECK_KEY}
chmod 0400 ssh_check

echo "Check for key ${key}"
ssh -l ${REMOTE_USER} -i ssh_check $@ "${key}"
echo "Cleaning"
rm -f ssh_check
Auteur :


e-mail* :


Le commentaire :




* Seulement pour être notifié d'une réponse à cet article
* Only for email notification