Provider-less one-time password for linux servers

29.07.2018 - AYB - Reading time ~3 Minutes


image by Chloë Bregman

So, once upon a time you heard that password reusage is a bad idea. But you have dozens servers under control and have to take care of them all. Of course you can use password managers like LastPass, 1Password etc and this is fine. Sure thing that you’re using SSH-keys to authorize yourself against these servers. But there is a one small thing that ruins all this beauty — compromising your key and/or losing access to password manager makes your servers vulnerable and inaccessible.

Here one-time passwords come in. There are a lot of OTP providers around: Google Authenticator, Auth0 etc. But all of them require additional device to be accessible by you. And this device becomes a point of failure: if it’s compromised or inaccessible you’re getting into troubles again. So here comes a question:

How I can deploy a secure OTP without dependencies and 3rd-party devices?

You have to use a web-system that is obscured but accessible and provides you with the password data.

The goal is to make a web-service that will generate one-time passwords for the user known only by you so you can access it using ssh and received one-time password.

I’m a pretty lazy and don’t like dependencies. So I wrote this service using Bash and this script utilizes only the well-known components that are included in most Linux distro’s by default.

This is a single file that generates a random password with using RANDOM function twice and hashing it with MD5. Then the result is set as a password to desired user for 10 seconds. In 10 seconds after the password exposure its being reset again.

Here is a GitHub repo of the script:

How it works

This is a script for having one-time passwords to connect to the servers from the places you’re not sure are safe. Or in case you are away from the computer with the ssh-keys that server knows.
By default script uses user “looper” — change it to your desired username.
By default it uses simple function to generate a somewhat random number, combine it with the current system time and hash it twice then to get as most random sequence as possible without any dependencies.
You’re free to code any function you prefer to get any random character sequence.
The resulting hash is the password.
Your secret is the username used to login.
Script gives you 10 seconds to enter the revealed password, then resets it again.

So you just running this script and it listens to web-requests on a certain port. In 10 seconds after password was exposed it resets again in a loop.

Second variant to generate one-time password and don’t expose it in plain text:

  PW=$((RANDOM % 1234567890 * $((RANDOM % 1234567890))))
  echo "looper:$PW" | chpasswd
  echo $(($PW * 123)) | sed ':a;s/\B[0-9]\{3\}\>/ &/;ta' > /tmp/pw

Note the ‘123’ multiplier — this is a “second secret” which you have to use to get real password.
So you have to divide the exposed number by 123 to know the one-time password (keep in mind 10 seconds countdown to next reset)

You can enchance security even more, by placing the script to another server thus it will change the password over ssh-connection.
Change the line 28 to:
ssh user@yourserver.somewhere "echo \"looper:$PW\" | chpasswd"
Just don’t forget to add key from originating server to the host and use correct user.

How to use:
Place this script to any accessible path, e.g. /usr/share/bin
chmod +x on it
Add script with the full path to the /etc/rc.local to launch it at every boot.


Curl it: