Latest Tweets

Integrating the IHaveBeenPwned API into Linux PAM

Introduction

I was writing another 4-page article for Linux User and Developer about Public APIs when I came out with the idea of showing the readers how to leverage the IHaveBeenPwned API using a Linux PAM module. The idea was to use their new “Pwned Passwords API v2” with the K-Anonymity feature.

Writing the module

Writing a Linux PAM module is relatively easy. Doing it the right way (i.e.: avoiding common programming mistakes, adhering to good PAM-developing practises, and so on) is quite another thing altogether. There are certain things to consider; writing a buggy PAM module can easily lead to a total system lock-down or even a total system take-over. For starters, you must ensure that you overwrite any memory you have dynamically allocated before freeing it (see http://www.linux-pam.org/Linux-PAM-html/mwg-see-programming-sec.html#mwg-see-programming-sec-token). This module is used whenever a user runs the “passwd” command or some application performs a call to the putspent() function in order to change a user’s password.

This module performs the following actions:

  1. It asks for the current UNIX password to authenticate the user.
  2. If the users is authenticated, it asks for a new password.
  3. It computes its SHA1 and then generates a call to the IHaveBeenPwned API.
  4. If there is any kind of error communicating with the API, and if the option “enforceonerror” is set, the module returns an error and ends. No password is changed.
  5. If there is any kind of error communicating with the API and the “enforceonerror” option is not set, it jumps to step 8.
  6. If the call to the API succeeds, it performs a simple search for the whole hash in a local buffer.
  7. If the hash is found, it prints an error message telling the user so and returns an error. No password is changed.
  8. If the hash is not found, it tells the user so and asks for the new password again for confirmation.
  9. If both passwords match up, the password is stacked for the next module to process (pam_unix.so).

The hash is computed using OpenSSL and the API call is performed with Curl3. That’s why this module must be linked against libopenssl (-lssl) and libcurl3 (-lcurl3).

Testing the module

I released my module’s source code some days ago on GitHub. Clone, build and install the module as described in the README.md file. I have tested it on Debian Wheezy, Debian Jessie, Debian Stretch and Ubuntu 16.0.6 distros so far. Consider installing a Virtual Machine and testing the module there first. Once the module is enabled, you can run the “passwd” command to change your password the usual way. Try some well-known pwned passwords such as mariobros, princesspeach, heyjude! and so on.

My module in action with some logging.

Future work

I’m now in the process of serious code reviewing, to make sure everything is in order. There are some bits that are quite redundant, and then prone to error. So I’m trying to simplify the code as much as possible. Bear in mind that I’m a newbie when it comes to writing Linux PAM modules, so feel free to comment on my project and open issues on Github ;-).

Happy hacking!