Lab - SSH and OTP

Authors: João Paulo Barraca, Vitor Cunha, Paulo C. Bartolomeu, Alfredo Matos, Catarina Silva

Slides

Download here

Introduction

This guide will explore authentication mechanisms by configuring SSH (Secure Shell) secure sessions. SSH is an IETF standard comprised of Authentication, Connection, and Transport standards, composed of several RFCs (RFC 4250, RFC 4251, RFC 4252, RFC 4253, and RFC 4254), and is a common protocol used for several purposes, such as remote shells, git repository data transport, and many other interesting scenarios.

It supports several authentication mechanisms, from which we will explore simple username and password authentication, asymmetric key authentication, and finally, One Time Passwords (OTP).

Setup

To execute this guide, you will create a base Docker image with the latest Ubuntu LTS server to simulate a different virtual machine within a container. This image and general approach are not representative of a real-world docker deployment. The Ubuntu container will take the server role, while your course VM will take the client role.

Server Configuration

Ubuntu Container

Use the following Dockerfile to create the base image with the latest Ubuntu LTS server.

FROM ubuntu:noble

RUN apt update && apt install -y iproute2 net-tools adduser nano

CMD ["/bin/bash", "-c", "trap : TERM INT; sleep infinity & wait"]

Create the image with the following command:

vm:~$ docker build . -t ubuntu-lts

Upon success of the previous command, launch the Ubuntu container

vm:~$ docker run --name server --hostname server -d ubuntu-lts

Now check if the Ubuntu cointainer is alive:

CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
d4a9c0da905e   ubuntu-lts         "/bin/bash -c 'trap …"   4 seconds ago    Up 4 seconds                                                           eager_leakey
(...)

Services

Enter the console of the server and check its IP address:

vm:~$ docker exec -it server /bin/bash
root@server:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:0a:8b:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.139.0.3/24 brd 10.139.0.255 scope global eth0
       valid_lft forever preferred_lft forever

In this case, the IP address is 10.139.0.3. In the container, create a user that you can use to log remotely into the server (we suggest user sio, password sio), and install the required services.

root@server:/# adduser sio

You can check if the Telnet and SSH services are already running in the server (Ubuntu container). For that, use the following command to check if the TCP ports used by those services are available to accept connections. (It is not expected that any services should be running now.)

root@server:/# netstat -atnup
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name  

Using the following commands, you may update the apt database, install and configure the SSH and Telnet services. Use those that are adequate to install the services missing in Ubuntu container.

root@server:/# apt update
... OUTPUT OMITTED...
root@server:/# apt install inetutils-telnetd

Edit /etc/inetd.conf with nano, and enable (uncomment) the Telnet line (23):

# /etc/inetd.conf
telnet stream tcp nowait root /usr/sbin/tcpd /usr/sbin/telnetd

Then restart the Telnet service, with the command:

root@server:/# service inetutils-inetd restart

Install the SSH service in the container with the following command:

Hint: Should you be asked during installation, the Geographic area is 8, and the Time zone is 25

root@server:/# apt install openssh-server

If you need to restart the SSH service, you may use the command:

root@server:/# service ssh restart

Check that both services are up and running.

root@server:/# netstat -atnup
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      4121/sshd: /usr/sbi 
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN      432/inetutils-inetd 
tcp6       0      0 :::22                   :::*                    LISTEN      4121/sshd: /usr/sbi 

Client Configuration

SSH and Telnet client applications are installed in most Linux distributions by default. In case you need to install any of them (you shouldn’t need to with the course Virtual Machine), you may use the following commands (choose the ones that are missing, if any):

vm:~$ sudo apt install telnet ssh

Inspecting network traffic

One of the toolkits under an engineer’s belt is using traffic-capturing utilities to find out what is going on. This tool can be very useful for security purposes.

You must also install Wireshark in your _Virtual Machine (not the container) to capture and analyze packets exchanged between the Ubuntu container (the server) and the Virtual Machine (the client).

For this, issue:

vm:~$ apt install wireshark

In the client (the Virtual Machine), use Wireshark capture the traffic exchanged between the server and the client. Select the docker0 network bridge; you need to start Wireshark as root, or the proper capability to see this network interface. Apply a filter to only observe Telnet and SSH packets by applying the following rule in the Wireshark filter window:

telnet || ssh

With this filter applied, Wireshark will show all the SSH and Telnet packets between server and client.

Inspecting Telnet traffic

In the client (the Virtual Machine), with an active traffic capture, start a Telnet session to the server (Ubuntu container). Use the previously acquired Ubuntu container IP address and, when asked, use the credentials you created before:

vm:~$ telnet IP_ADDRESS

After login, list the contents of the root folder using the command:

sio@server:~$ ls /

Close the Telnet session, stop the Wireshark capture, and analyze the captured packets. Can you observe the contents of the root folder you listed above in the captured packets?

Still analyzing the captured Telnet traffic, can you find the password you used to log in when starting the Telnet session on the server (Ubuntu container)?

What do you conclude regarding the security of the Telnet protocol?

Inspecting SSH traffic

In the client (the Virtual Machine), start a new capture and apply a filter to show only the captured SSH packets.

Start an SSH session with the server (Ubuntu container). If it is the first connection to that server, the server will authenticate, presenting its public key, and you will be asked if you trust the key and want to save it. Say yes to proceed. Login into the server and list the contents of the root folder using the command:

vm:~$ ssh username@host # ssh sio@DOCKER_SERVER_IP
... OUTPUT OMITTED ...
sio@server:~$ ls /

Close the Telnet session, stop the Wireshark capture, and analyze the captured packets. Can you observe any data in the packets? What do you conclude about SSH general security compared to Telnet?

Authentication in SSH

In this section, you will analyze how the server and clients authenticate in the SSH protocol. It is assumed that SSH configuration files are in their original state, i.e., no change has been made to the SSH configuration.

Server authentication

In the first interaction of an SSH client with an SSH server, the client must validate the server’s identity. For that purpose, the SSH server sends its public key to the client, and the respective fingerprint is presented to the user so they can verify it and indicate if the key is correct or not, i.e., if the user trusts the server to which a session is being started, or not. For this, the user must have the public key fingerprint of the SSH server to which they want to connect (the fingerprint should have been given the public key fingerprint when her account was created). To get the fingerprint of the SSH server public key, issue the following command in the server computer and write the fingerprint value:

root@server:/# ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub

In the client (the Virtual Machine), eliminate the public keys you possibly stored from previous SSH connections. For that purpose, use the following command:

vm:~$ rm ~/.ssh/known_hosts

From the , start an SSH session with the server using the following command, where username (e.g., sio) is your account name in the server, and host is the name or IP address of the computer with the SSH server (Ubuntu container):

vm:~$ ssh username@host # ssh sio@DOCKER_SERVER_IP

The user on the client will be presented with a message similar to the one shown below, asking if the user trusts the identity of the SSH server they are trying to connect to. Compare the presented public key fingerprint with the fingerprint you get in the SSH server. If they are equal, you are trying to connect to the SSH server you intended to connect to and must answer yes. Otherwise, your connection may be intercepted, or you are connecting to a wrong server.

The authenticity of host '10.139.0.3 (10.139.0.3)' 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)? yes

After the confirmation, the client stores the public key in the ~/.ssh/known_hosts file, and the user is never again requested to confirm that SSH server public key, as long as the server keeps presenting the same public key.

Start the SSH session by introducing your password to authenticate yourself to the SSH server. Login and password is the default mechanism for user authentication with SSH servers.

User authentication with an asymmetric key pair

In the client (the Virtual Machine), you must generate an asymmetric key pair to use for client authentication when starting a session on an SSH server. For that, use the following command:

vm:~$ ssh-keygen -t rsa

Press Enter to accept the default name for the file where the key pair will be stored and define a password for key protection.

Now, you need to install your public key in the SSH server, in order the server can use it to authenticate you when starting SSH sessions. For that purpose, use the following command, where ~/.ssh/id_rsa.pub is the default filename used to store client keys (replace it with the name of the file where you stored your key pair, in case you haven’t used the default file name), and username and server are the name of the account and the name of the computer where you want to install your public key:

vm:~$ ssh-copy-id -i ~/.ssh/id_rsa.pub <username>@<server>

This command stores your public key in the ~/.ssh/authorizedkeys file in the user account’s home folder on the server computer. This public key will be used to verify the user’s possession of the corresponding private key whenever the user starts an SSH session with the server.

Start a new SSH session with the SSH server (in the Ubuntu container) using the client. Notice that your public key is used for your authentication, and you are not requested to introduce your password.

Compare public key authentication with password authentication when starting an SSH session and analyze the advantages and disadvantages from one in relation to the other.

Public key authentication on SSH is substantially different from the authentication in SSL protocol. Explain the differences.

Do you think it is adequate to use the SSH public key authentication to authenticate Web servers in the Internet, for example to authenticate Google or Facebook servers? Explain.

User authentication with one-time passwords

Situations may exist where asymmetric key pairs might not be the most adequate mechanism to authenticate users when establishing SSH sessions. For example, one such situation may occur when the user uses a shared computer and fears that its key pair can be compromised. In such situations, one-time passwords may be the most adequate mechanism for user authentication when establishing an SSH session with a remote server, since one-time passwords can only be used one single time (they are not reusable), and therefore no security mechanisms are needed to secure its use.

Server configuration

To use one-time passwords in SSH, you need to install OTPW in the server. Use the following command:

root@server:/# apt install libpam-otpw otpw-bin

Then you need to configure PAM (Plugable authentication Module) module of SSH. For that, you must edit the /etc/pam.d/sshd configuration file (using nano, for example). You must disable password authentication, by commenting the following line (by placing a # character in the beginning of the line):

#@include common-auth

Then, you must add the following two lines to enable user authentication using one-time passwords:

auth    required    pam_otpw.so
session optional    pam_otpw.so

Then you must configure the SSH server to accept one-time passwords. For that, you must edit the /etc/ssh/sshd_config file to enable the following three parameters (check that none of these parameters is duplicated, to avoid server failures when starting):

ChallengeResponseAuthentication yes

You also need to disable password authentication. However, we will allow public key authentication to prevent the possibility of all one-time passwords were used. For that, edit again the /etc/ssh/sshd_config file and check the following two parameters have the indicated values:

PubkeyAuthentication    yes
PasswordAuthentication  no

SSH server configuration is completed, and must be restarted.

One-time passwords generation

One-time passwords for user authentication must be generated and given to the user, in order they can use to authenticate when establishing an SSH session. To generate the user one-time passwords, the user must be logged in the SSH server (not has root) and must execute the following command, where fname.txt is a name for the file to store the generated one-time passwords. When executing the command, the user will be requested to introduce a prefix for the one-time passwords, that the user must memorize because it will be requested, together with the one-time password, when authenticating.

sio@server:~$ otpw-gen > fname.txt

Look at the contents of the file with the generated one-time passwords. Note that the one-time passwords are numbered and that each occupies two columns to make them easy to read. When the user is requested to introduce a one-time password for authentication, they must concatenate the text in the two columns, i.e., the blank space between the two columns must not be introduced.

The user must print the file to bring the one-time passwords with her, in order they can use them whenever they establish a new SSH session with the server.

Using one-time passwords

The establishment of a new SSH session is done with the same command as indicated elsewhere above in this guide, but now, the server will request one of the one-time passwords the user generated. The requested one-time password is identified by its number in a format similar to:

Password 123:

The full one-time password to be introduced is composed by two parts: the prefix (defined by the user when they generated the one-time passwords) and the identified one-time password that the user must read from the file containing the one-passwords they generated. The user must concatenate the prefix with the requested one-time password. If the correct password is introduced, SSH session is established.

2FA with Google Authenticator (TOTP/HOTP)

We can also complement the login with 2-factor authentication (2FA). This is simple to achieve with SSH and a complementary time based one time passwords, such as TOTP or HOTP. This can be done with Google Authenticator for example.

The setup is similar to what was done before, by setting up SSH and PAM. So, please ensure the following:

  1. Comment/remove the information from OTPW (previous exercise)
  2. Install Google Authenticator from the Play/App Store

Now, let’s jump into setting up the server and the account.

Server Authentication

root@server:/# apt install libpam-google-authenticator

With the user you want to setup

root@server:/# su sio
sio@server:~$ google-authenticator # go through the setup process

Scan the information with Google Authenticator, and lets enable it on SSHD.

Then you must configure the SSH server to accept one-time passwords. For that, you must edit the /etc/ssh/sshd_config file to enable the following three parameters (check that none of these parameters is duplicated, to avoid server failures when starting):

UsePAM  yes
ChallengeResponseAuthentication yes

Then you need to configure PAM (Plugable authentication Module) module of SSH. For that, you must edit the /etc/pam.d/sshd configuration file

#@include common-auth
auth   required   pam_google_authenticator.so

Then just restart SSH, and it should be working.

Bibliography

http://en.wikipedia.org/wiki/Secure_Shell

Previous
Next