You may use the UPB's OpenStack cloud to instantiate a Virtual Machine. Read these instructions if you wanna know how!
Hashing is the process of converting data — text, numbers, files, or anything, really — into a fixed-length string of letters and numbers. Data is converted into these fixed-length strings, or hash values, by using a special algorithm called a hash function.
Linux Pluggable Authentication Modules (PAM) is a suite of libraries that allow a Linux system administrator to configure methods to authenticate users.
“pam_exec” is a PAM module that can be used to run an external command.
Multi-factor authentication (MFA) is a multi-step account login process that requires users to enter more information than just a password. For example, along with the password, users might be asked to enter a code sent to their email, answer a secret question, or scan a fingerprint. A second form of authentication can help prevent unauthorized account access if a system password has been compromised.
In the current security lab, we'll explore the fundamentals of Linux authentication.
We'll start by examining how the OS performs hashing. First, we'll crack it and then we'll replicate it using Python.
Then, we'll utilize the “pam_exec” module to set up a custom Python script for user authentication. By exploiting a weak password vulnerability, we will be able to perform a successful login.
Finally, we'll enhance security measures by implementing Multi-Factor Authentication (MFA) with Google Authenticator.
We use Docker:
docker pull ghcr.io/cs-pub-ro/isc-auth-pam:latest mkdir ~/auth-lab docker run --rm --name auth-lab -v $(pwd)/auth-lab/:/home/hacker/auth-lab -it ghcr.io/cs-pub-ro/isc-auth-pam
~/auth-lab
folder is used as persistent volume so you won't lose + sync your work inside the container!
Download the lab archive inside the ~/auth-lab
directory and unzip it.
Analyse the users and groups on the system. What user are we interested in?
Use John the Ripper to crack our user's password. You need to run it as super user on the file that contains the passwords.
We want to use the default mode “wordlist” with the default location /usr/share/john/password.lst
.
If you are getting an error “No password hashes loaded (see FAQ)”, you need to specify the format of the hash. It is named the same as the Linux password hashing function ;)
References:
Fill in the TODOs in gen_hash.py
to generate a new password hash. Using your super user privileges, manually overwrite the old password of our user.
Test if you were successful by trying to log in (su
) using the new password.
References:
As we want to use a Python script to log in to the user account we worked on so far, you need to delete and lock its password so that password-based authentication is disabled for this user account.
Reference:
We wish to write our own authentication module in Python.
For this, we must modify the common-auth
Linux PAM configuration file (look in /etc/pam.d
) and add this as the first rule:
auth sufficient pam_exec.so expose_authtok stdout quiet <path-to-auth.py>
As we want to use the script to authenticate only our special user, and because it will be called for all users, it should be sufficient to authenticate using it, but not required.
In order for authentication to be successfully performed using Python, we need 3 features, which can be achieved by passing the proper options to the pam_exec.so
module:
References:
Edit auth.py
and fill in TODOs(6.*).
When you're done, crack the new password hash and try to log in ;)
hashlib
to compute the input's user_hash
and compare them!
Finally, let's add two-factor authentication to our script!
Edit setup_mfa.py
, input a 32-byte secret and print its QR enrollment code to the console.
After this, run the script and enroll the key inside a RFC 6238 (TOTP) compatible (e.g.: Google Authenticator, TOTP Authenticator, KeePassXC etc.).
Solve the remaining TODOs(7.*) in auth.py
to integrate your MFA (note: the TOTP's secret key should be the same!).
input()
with the user-typed password (then closes stdin, any following reads will get EOF).
So, in order to read both a password and a numeric TOTP code, you must read them all at once (use whatever convention you desire, e.g.: password then 6-digit code either concatenated or split by space, then parse/extract it in Python).
Custom .so
PAM plugins have no such limitations (but you must then write them in a system programming language).
TOTP_SECRET
is 32 bytes in length!
References:
Please take a minute to fill in the feedback form for this lab.