If you’re nobody special like me, you probably “only” get a few thousand failed SSH logins to your computer each day. If you run a high profile system, it’s probably worse. Of course you have a good password for your account (right?), but should someone actually get your password, like with a keystroke logger on the remote computer you’re using to log in, what protection do you have then?

Two factor authentication can increase your security by requiring more than just your password (one factor) to log in. I like using Perfect Paper Passwords from Gibson Research Corporation (GRC.com). With this system after entering my username and password (even a wrong password) in an SSH session, I am then prompted for a four-digit passcode that I’ve previously printed out and stashed in my wallet. Each code is only used one time, and protects me even if someone manages to get my password. In the case where attackers are guessing my password, they cannot tell if the password or passcode was guessed incorrectly.

Sample PPP passcard (courtesy grc.com)
Sample PPP passcard (courtesy grc.com)

There’s only a little bit of trickery involved to compile it for Mac OS X 10.6 Snow Leopard, and if you had it working before in Leopard, you’ll need to recompile the PAM module (I know, it’s like “ATM machine”) for 64-bit mode.

How Perfect Paper Passwords (PPP) Works

The principle behind PPP (https://www.grc.com/ppp) is simple:

  1. Pre-arrange for a list of random passcodes.
  2. When a user authenticates, ask for the next passcode on the list.
  3. If correct, grant access.
  4. Remember where on the list of passcodes we left off.

The beauty of this system is that even if someone has your password, they cannot gain access to your system unless they a) also have your one-time passcode list or b) happen to guess the one of 17 million passcodes that is next on the list. You could log in to your computer with a full keyboard logger from the most evil hacking organization you imagine, and they still would not be able to log in without your passcode list (guard your wallet!).

I use PPP in my SSH subsystem, so that this two-factor authentication is enforced on the only service I expose to the Internet. PPP plugs into SSH using the Pluggable Authentication Module (PAM) system.

The PPP Pluggable Authentication Module (PAM) on Google Code

The PAM system (PAM article on Wikipedia) does what its name suggests: it allows new authentication systems to be plugged in to a service. In this case we’ll use the ppp-pam project on Google Code, an open source implementation of the PPP system developed by GRC.

The documentation for the project exists mostly in the form of comments made on the author’s original “Building” page. Two comments of interest here are these two recommended patches:

  1. Don’t move to the next passcode until the proper one is entered.
  2. Echo the passcodes as they are typed.

The first patch avoids a denial of service attack. Imagine an attacker repeatedly attempting a log in and having the passcode pointer move on each failed attempt. After some number of failed attempts, the attacker will have moved the pointer past the end of the passcode list you printed for your wallet! This patch also changes the nature of how an opponent would use a brute force attack, but brute force is still the opponent’s best attack strategy (we like that).

The second patch is a usability improvement. Since the passcodes are only used once, there’s no harm in echoing the character back to the screen, and it makes it easier to type in the obscure passcodes.

You’re welcome to leave out either of these patches.

Compiling for Snow Leopard

We’ll walk through the steps to get this set up for your Mac. The instructions are nearly identical for all other platforms. At the end of this post is a link to a shell script that performs all these steps for you.

Download

Download the source code from http://code.google.com/p/ppp-pam/. The latest version at the time of this writing is ppp-pam-0.2.tar.gz. Decompress in a convenient location and change to that directory:

rob@mbp:~/Downloads $curl http://ppp-pam.googlecode.com/files/ppp-pam-0.2.tar.gz | tar xz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  597k  100  597k    0     0   443k      0  0:00:01  0:00:01 --:--:--  565k
rob@mbp:~/Downloads $cd ppp-pam
rob@mbp:~/Downloads/ppp-pam $

Patch Source Files

To include the patch that stops the passcode pointer from moving after failed login attempts, copy the following code and paste it in the Terminal (while in the ppp-pam directory):

patch -e ppp/ppp.c <<EOF
343,344c
        incrCurrPasscodeNum();
    }
.
341c
    if (strcmp(getPasscode(currPasscodeNum()), attempt) == 0){
.
EOF

This will patch the first file. To patch the second file, fixing both the missing header file problem and the echo preference, copy and paste the following into the Terminal:

patch -e ppp/pam_ppp.c <<EOF
90c
    message.msg_style = PAM_PROMPT_ECHO_ON;
.
47c
    #include "/Developer/SDKs/MacOSX10.5.sdk/usr/include/pam/_pam_macros.h"
.
EOF

You might want to check that you do in fact have that file:

$ locate _pam_macros.h
/Developer/SDKs/MacOSX10.4u.sdk/usr/include/pam/_pam_macros.h
/Developer/SDKs/MacOSX10.5.sdk/usr/include/pam/_pam_macros.h

Configure and Make

Now move into the build directory and run ../configure && make (we’ll combine to save time and space here):

rob@mbp:~/Downloads/ppp-pam $cd build
rob@mbp:~/Downloads/ppp-pam/build $../configure && make
checking for a BSD-compatible install... /opt/local/bin/ginstall -c
checking whether build environment is sane...
...and so forth

Install

If you get no errors, you can run sudo make install:

rob@mbp:~/Downloads/ppp-pam/build $sudo make install
Password:
/bin/sh ../mkinstalldirs /usr/bin
  /bin/sh ./libtool --mode=install /opt/local/bin/ginstall -c pppauth /usr/bin/pppauth
/opt/local/bin/ginstall -c pppauth /usr/bin/pppauth
cp pam_ppp.so /usr/lib/pam/pam_ppp.so
make[1]: Nothing to be done for `install-data-am'.
rob@mbp:~/Downloads/ppp-pam/build $

Generate Cards

Next we have to generate the pre-arranged passcode codes that our system will use. Will create a private key first, and then we’ll print out the first card to include in our wallet. The information is saved in the ~/.pppauth directory.

rob@mbp:~/Downloads/ppp-pam/build $pppauth --key

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  A new sequence key has been generated and saved.  It is
  HIGHLY RECOMMENDED that you IMMEDIATELY print new pass-
  cards in order to access your account in the future.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

rob@mbp:~/Downloads/ppp-pam/build $pppauth --text --card 1
MBP.local                          [1]
      A    B    C    D    E    F    G
 1: 7oCA R4%W dxy5 aMNK r:pb Kcg9 Z%fh
 2: yFbs @2NZ @iUv UY:o eiRL Ea29 xMfc
 3: =CUS roUa x@Hf Fmg8 h2NT DF6o RXwS
 4: hHKx t3ia Tj3r +Jfz ?xwc usks zJjY
 5: 6GpN rFgx y3f5 kZoD XYGH v!yD 7Kx2
 6: d#y4 RVRi R66W !js6 6Wah qGSR D8TT
 7: zorX NuzH 3Wfq B@nk wm3v pgGS 2zfm
 8: ZFir ZpuJ d35S #9@G Wazd m#32 F#7s
 9: S@JM K%mt xJ3p NxD= S6By wWie e9:t
10: JEz: SKk? BBHb D!t! XyhK ZbJ# %jB3

rob@mbp:~/Downloads/ppp-pam/build $

I'll leave it to your imagination as to how you want to print these and store them. You might consider some quality Rite-in-the-Rain paper, so it doesn't dissolve in your wallet, or maybe you want to take a different tack and use super-dissolvable "spy paper" that is easy to destroy.

Activate PAM

We'll take two steps to activate PAM and PPP with SSH. The first is to add a line to the /etc/pam.d/sshd file. If you put the line in a different position, your results will vary, but this worked for me.

# sshd: auth account password session
auth       optional       pam_krb5.so
auth       optional       pam_mount.so
auth       sufficient     pam_serialnumber.so serverinstall legacy
auth       required       pam_opendirectory.so
auth       required       pam_ppp.so
account    required       pam_nologin.so
account    required       pam_sacl.so sacl_service=ssh
account    required       pam_opendirectory.so
password   required       pam_opendirectory.so
session    required       pam_launchd.so
session    optional       pam_mount.so

Now you need to edit the /etc/sshd_config file and uncomment the following lines. I'd give you a patch, but I've tweaked my sshd_config file, so the line numbers are not the same. Sorry.

ChallengeResponseAuthentication yes
...
UsePAM yes

Optional chmod

I'm not sure if it matters, but I changed the permissions on the ~/.pppauth/ folder and files within to remove group permissions:

rob@mbp:~/Downloads/ppp-pam/build $chmod 700 ~/.pppauth
rob@mbp:~/Downloads/ppp-pam/build $chmod 600 ~/.pppauth/*

Download Script

I have a script pam_ppp_installer.sh that will download the code, patch it, and install it for you. You are welcome to simply run it or (I recommend) study it to see just what it's doing. Don't run strangers' scripts on your computer without inspecting them first! Still I promise I'm not trying to harm your computer.

If anyone knows how to use PAM to intercept logging in to a Mac via the loginwindow process, I'd love to hear about it.

Further Security

Explore the /etc/pam.d/ directory to see where else you can use this two factor authentication. For instance you can add a line to the sudo file to require this extended security for the sudo command:

# sudo: auth account password session
auth       required       pam_opendirectory.so
auth       required       pam_ppp.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

Other files in /etc/pam.d/ :

chkpasswd
cups
ftpd
login
login.term
other
passwd
samba
screensaver
sshd
su
sudo

Enjoy!