Lab - 4 - Pluggable Authentication Modules


The goal of these exercises is to explore the functionalities of PAM (Pluggable Authentication Modules) infrastructure present in current Linux distributions.

These exercises will also make use of several authentication methods, such as username and password, biometrics, one-time passwords and asymmetric key pairs (exploring the Portuguese Citizen Card as a way to authenticate users and to provide detailed logs).

Errors in PAM configuration files may block further access to the system. Beware! Keep at all times a session as root to be able to recover from mistakes!

Weak Passwords

By default, current Linux distributions do not verify the strength of the passwords in use. A weak password is a password which can be found through an intelligent search attack where a set of more likely passwords are tested (dictionary attack). The widespread availability of dictionaries with words and even well-known passwords, makes this attack very effective. Once the password is found, the security of the entire system is compromised as it can allow the execution of local exploits and access private data.

This policy can be changed so that the password modification procedure verifies the strength of the new passwords. In Linux these procedures are controlled using PAM (Pluggable Authentication Modules), which is also used to control several other authentication and access control aspects of any Linux system.

The pam_pwquality PAM module

Install libpam-pwquality using apt-get.

Take a look at the manual of pam_pwquality

man pam_pwquality

and understand the purpose of the module.

Note: pam_pwquality is an updated replacement of the former module pam_cracklib.

Create a test user named beaker1 (with the adduser beaker command) and set a password for this user. Verify that you can login into its account (with the su -l beaker command).

The file /etc/pam.d/common-password stores the rules controlling what happens when users change passwords. This is a good candidate for enforcing strong passwords and is typically used for this purpose.

NOTE: as a general safety rule never close the editor where you change PAM configuration files before testing the effect of the modifications performed. Otherwise, you may not be able to revert your mistakes!

  • Propose a reasonable policy for password security and enforce it. Consider password length, existence of symbols (e.g. _,;:"'~^+-*/=<>[]{}()!?@#$%&\)`, lower and upper case characters and (decimal) digits.

  • In order to better enhance the difficulty of finding the password, enforce a policy so that common passwords found in the system dictionary are forbidden. You can use the dictionary files available at /usr/share/dict.

Using the beaker user account, test the correct enforcement of the password safety model you have implemented.

In the end, please restore all PAM-related configurations! Otherwise you may be unable to log in into the system.


PAM can naturally support the use of biometrics for authentication. But since this requires some kind of biometric reader for capturing biometric features, we decided to use one that is common in most laptops used by people: a camera. And, with a camera, we will explore biometric authentications using faces.

To this end we will use howdy, a software that implements a Linux replica of the Windows Hello\texttrademark style facial authentication. It uses OpenCV and is implemented in Python. Python PAM modules can be used by means of a middleware module, pam_python, that makes the necessary bridge between C language PAM library calls to equivalent functions in Python. This module is distributed by the package libpam-python.

The instructions for installing howdy are provided in its GitHub repository, and are the following. First, add its repository to the list of repositories used by the laptop,

sudo add-apt-repository ppa:boltgolt/howdy

then update the list of packages,

sudo apt update

and finally install howdy,

sudo apt install howdy

Once installed, you can check that the installation steps included an optional facial authentication with howdy prior to the normal Linux authentication with username and password. You can check this in the file /etc/pam.d/common-auth, where you should have something like this:

auth	[success=2 default=ignore] /lib/security/howdy/
auth	[success=1 default=ignore] nullok_secure try_first_pass
auth	requisite

These 3 lines are interpreted as follow:

  • The howdy module is called. If the authentication succeeds, with will jump over the next 2 lines (as indicated by the clause success=2). Otherwise, it is ignored (as stated by the default=ignore clause) and the process continues in the next line.
  • The pam_unix module is called. If the authentication succeeds, with will jump over the next line (as indicated by the clause success=1). Otherwise, it is ignored (as stated by the default=ignore clause) and the process continues in the next line.
  • The pam_deny module is called. It always yields a failure, and since it is a requisite, a final failure decision was reached.

The howdy module has a timeout in the facial recognition, and it is mostly silent.

The configuration of howdy has two separate components: the definition of the personal profiles and the general configuration of the facial detection.

The definition of the facial profile for the current user is performed with the command

sudo howdy add


sudo howdy add -U <username>

for another user. For each user you can capture several snapshots, and you can label them accordingly (normal, with glasses, smiling, etc.).

The general configuration is performed with the command

sudo howdy config

It launches a vim editor with the configuration option for howdy.

Of special interest are the parameters certainty and use_cnn. A low value for certainty make the system more accurate (low False Positive Ratio), but also more difficult to use (high False Negative Ratio). With CNN (Convolutional Neural Network) instead of HOG (Histogram of the Oriented Gradient), with a value of 2 you should succeed from time to time, but not very often. With 2.8, on the other hand, it should balance well accuracy with usability. With higher values, it will basically accept any face as a good match.

Experiment these values, with both CNN and HOG. Try to use photographs or computer images as alternatives to faces. Use several accounts, each for different people, and use them to evaluate your system’s accuracy and usability.

One-Time Passwords

One-Time Passwords (OTPs) can also be used for authenticating users. OTP systems can have different flavours; the oldest one computes uses a list of OTPs that users must print and carry with them. Other system use an application executed in a personal device for computing OTPs. In this guide we experiment the former.

Challenge-response dialogues

There are many OTP protocols, and some of them require users to be guided to provide the correct OTP. Such guidance often is given by some contextual value that needs to be used to compute the expected OTP. When this is required, PAM allows modules to prompt users, but that needs to be handled by the application using PAM, which is responsible for knowing how to interact with the user being authenticated. Some applications do that by default, some do not, and some may never do it.

SSH is a case where challenge-response dialogues cannot happen by default, because SSH includes two intrinsic user authentication protocols that do not need it. But the SSH daemon supports it, with the proper configuration (in file /etc/ssh/sshd_config). Such configuration changed over time, but the more recent versions have the option KbdInteractiveAuthentication which, by default, is set to false. In the following examples, set it previously to yes and restart the daemon, in order to be able use the OTP authentication protocols with SSH.

Printed OTPs

As expected, PAM supports printed OTPs by means of a library and a definition in the configuration files. In Linux systems, it is required to install the packages libpam-otpw and otpw-bin.

If not available, get the source code file otpw-1.5.tar.gz from, unpack it with

tar xzvf otpw-1.5.tar.gz

install the package libpam0g-dev, run the


command to generate the necessary binaries and, finally, run

sudo make install

to install those binaries on the right directories. The library will be installed in the correct directory (/lib/x86_64-linux-gnu/security).

The next step is to add the module to the appropriate place in the PAM authentications stack. For the purpose of this laboratory guide, add it to the common-auth file, as an alternative authentication method relatively to the UNIX one:

auth    [success=2 default=ignore] nullok_secure
auth    [success=1 default=ignore]
auth    requisite             

Also, comment howdy to experiment only with pam_otpw and do not forget to adjust the success jump values.

You should take in consideration that the order is important! Place after Note that with this configuration you can choose among two types of authentication: first, with Unix, second, with OTP; if the first fails, OTP will be attempted. If they both fail, the authentication will fail.

NOTE: do not close the editor! Just write the contents of file being edited

After configuring PAM for using users can choose to use OTP by running the otpw-gen command. This will generate a file named ~/.otpw containing some metadata, as well as a list of one-way hashes for the purpose of verifying the response to challenges.

Run the command in order to create the above referred file. You will need a password prefix. Choose any string and remember it! The prefix will be required for authentication purposes. A table will also be printed to the generator’s standard output; this table provides the responses to the several challenges initiated by the PAM OTPW module. In a real exploitation scenario, this table would be printed on a sheet of paper or on a card. In this exercise you can save it on a file by redirecting the output of the generator.

otpw-gen > otps_to_print

To test if the system is working, execute sudo bash command to initiate a superuser shell session in the current console. Provide an empty password for the first password prompt. You should be presented with a new password prompt carrying a number as challenge. The correct answer is composed by the password prefix and the corresponding entry in the previously referred table (including or not the space). If multiple numbers are provided, you must provide the answer to all challenges. Spaces are ignored.

Test now with a user for which this system was not set up: beaker. For that, execute the command

su - beaker

In this case, you will see that the PAM OTPW module will not ask for an OTP, since it does not have a way to check it!

Google Authenticator

This PAM module works together with the Google Authenticator App, which you should add to a mobile terminal. This mechanism uses a shared key (not a password) for computing OTPs. In detail, it implements HOTP (HMAC-based One Time Password algorithm), which computes OTPs from the shared key and loosly synchronized counter, and TOTP, a HOTP extension that uses the current time as the challenge.

First, install libpam-google-authenticator using apt:

apt install libpam-google-authenticator

This installation keeps your PAM orchestration files unchanged, you must change them manually. Now you should have access to the google-authenticator application, which you can use to create a login random secret for the current account.

Time-based One-time Password (TOTP)

Running the google-authenticator application, it asks whether you want to use TOTP (a negative answer falls back to HOTP). Select TOPT for this first experiment.

Once selected the authentication method, the application will present you 3 ways for adding the randomly generated secret key to your mobile terminal:

  • A Google link (which should not be used, as it exposes the key to Google);
  • A QR code, that you can scan with the application in your mobile terminal to import the key; or
  • The key itself, that you can enter manually in the mobile terminal.

Once configured, you can use the code presented by the mobile application to check if the setup is working; notice that for TOTP the codes presented are time limited.

The setup completes with several other steps.

First, the user is presented with a set of 5 emergency scratch codes. These are codes that you should print and use in case you loose the secret key. You can only use each of them once.

Second, you configure whether you can use the same TOTP password several times during its validity period. Allowing it increases usability, but decreases robustness against eavesdroppers.

Third, you are asked if you want to allow to compensate time skews between the computer where you are configuring this method and the mobile terminal that generates the OTPs. Since usually mobile terminal will have a network connection, and thus will be able to keep their clock synchronized, you can assume that time skews will be negligible.

Forth, you can limit the number of wrong input credentials to 3 per each 30 seconds. This alternative is the safest one, but do not select it to facilitate the experiments.

This configurations correspond to running the command as follows:

google-authenticator -t -u -W -d

Now, its time to add this OTP method to the PAM configuration files. Manually edit the common-auth file, and add this other authentication method to the ones already existing:

auth    [success=2 default=ignore] nullok_secure
auth    [success=1 default=ignore]      pam_google_authenticator nullok 
auth    requisite             

Also, keep howdy commented and comment pam_otpw.

At this moment you should have your mobile application configured to login in this host using TOPT. Try it, using exactly the same commands used for experimenting the OTPW module.

HMAC-based One-time Password (HOTP)

Run again the command google-authenticator to set up an OTP mechanism based on a loosely coupled counter:

google-authenticator -c

Import the new configuration for your mobile application, it should overwrite the exist profile for your account. With this new configuration, the user is supposed to request a new code each time it needs to.

Each time you request a new code, the local counter is incremented. And, on the authenticator side, the same happens each time the PAM module is called. However, a desynchronisation can occur if (i) the user requests codes without need and (ii) the authenticator increments the counter upon a malicious logging attempt. The authenticator supports a configurable amount of clients' desynchronisation, by looking ahead for a correct response. The look-ahead amount is adjustable, being 3 by default. Thus, if the user requests more than 3 OTPs without using them, their counter will become desynchronised and they need to resort to the scrap codes. To thwart malicious increments on the authenticator side, you should use the following module option: no_increment_hotp.

Experiment the system with a correct synchronization. Then, request more than 3 OTPs without using them and try again; it should fail. Now make only attempts with fake OTPs. After a few, you should be able to authenticate again with the correct OTPs (the counters got close enough, and now became synchronized). Add the option above referred to the PAM module:

auth    [success=2 default=ignore] nullok_secure
auth    [success=1 default=ignore]      pam_google_authenticator nullok no_increment_hotp
auth    requisite             

Try again to use fake OTPs and confirm that you did not succeed in getting the counters desynchronised.

Authentication using Smartcards

An example source code in C of a PAM module implementing local authentication with the Portuguese Citizen Card (CC) can be found at: You can get the source code using git and the following command:

git clone

and moving to the ccpam directory.

Before you can compile the module, you should install the PAM library development files (libpam0g-dev), the C language PKCS#11 development files (libopencryptoki-dev) and the OpenSSL library development files (libssl-dev) using apt:

apt install libpam0g-dev libopencryptoki-dev libssl-dev

Also install the Portuguese Citizen Card middleware2

Compile the module by executing


and install it with

sudo make install

_Note: The test cards fail the integrity verification. Inorder to use these cards with the PAM library, you must remove the call to the functions PTEID_SetSODCAs and PTEID_SetSODChecking in the addCCuser.c file.

Edit the common-auth PAM configuration file and a line the line using as follows:

auth    [success=2 default=ignore] nullok_secure
auth    [success=1 default=ignore] /etc/CC/keys
auth    requisite             

as the second rule in the authentication stack. Keep all the other methods other than the UNIX one commented.

Using the addCCuser tool to bind a given CC to the test user (the default file is /etc/CC/keys).

Verify that you can use the CC to authenticate the test user.

Modify the library so that the actual name and BI of the user are logged to the auth.log file. You will have to consult the CC SDK documentation in order to determine the relevant PTEID API functions to use.

The following code may be helpful to log messages to syslog:

static void pam_cc_syslog( int priority, const char *format, ... )
    va_list args;
    va_start( args, format );

    openlog( "pam_PTEIDCC", LOG_CONS ` LOG_PID, LOG_AUTHPRIV );
    vsyslog( priority, format, args );
    vfprintf( stderr, format, args );
pam_cc_syslog( LOG_ALERT,"Name: %s Civil ID: %u\n", name, civil_id );

Once again, verify that this information is indeed present in the system authentication log file, /var/log/auth.log.

Final remarks

Use the several PAM modules experimented in this guide to make several kinds of two-factor authentication.

At the end, leave the configuration file as it was after installing howdy, but you may want to comment the line using it. That line should be removed upon uninstalling the howdy package.

NOTE: see if all works well with the final configuration before closing the editor!


  1. Beaker is a character from The Muppet Show; he is a laboratory assistant and often a Guinea-pig for dangerous experiments. ↩︎

  2. ↩︎