Learning Objectives: The goal of this project is to harden password-based authentication by incorporating information obtained from a second factor (two-factor authentication, or 2FA). We will use the Linux login command to explore this. Although somewhat contrived, the motivation for the 2FA scheme in this project is similar to the password hardening paper discussed in the lectures. More specifically, information maintained by the system to validate a login request is updated after each successful login to limit the effectiveness of offline guessing attacks. The learning objectives of this project are listed below.
1. Understand how password-based authentication is implemented.
2. Understand the benefits of using multiple factors for stronger authentication.
3. Augment a password-based login command to include an additional factor from a second source.
4. Analyze the security benefits (or lack thereof) of the 2FA implementation.
To keep it simple, this project focuses only on hardening the basic login scheme for a desktop or laptop system. The scheme can be extended to support password hardening for remote logins as well.
Project Setup
Note: The link to the VM will be posted on an Ed Discussion pinned post.
For this project, you will be provided with an Ubuntu-based Virtual Machine (VM). This
VM was tested on Oracle VM VirtualBox 7.0 and can be directly imported into it[1]. The VM has a default account “cs6238” with normal user privileges. To access a file as root, open a terminal, type sudo su, enter the “cs6238” password, and then access the file.
The password for the “cs6238” account is “cs6238”. Do not include the quotation marks when entering the password. Once logged in, run the following commands:
1. cd /home/cs6238/Desktop
2. git clone https://github.com/TA-gatech/Project2.git This project folder contains:
• 2 Python code files: check_login.py and create_user.py
• 2 application password files modeled after /etc/shadow and /etc/passwd:
./app/shadow and ./app/passwd
• 1 executable: token_generator
Additional details on these files and the executable are provided later.
IMPORTANT NOTE: Make sure to work with the ./app/passwd and ./app/shadow files provided while working on this project. These are full paths to the files necessary for testing when submitting to Gradescope.
Before starting the project, familiarize yourself with how the Linux login command works. In particular, you should be able to answer the following questions.
1. How are users created in Linux?
2. What algorithms are used to hash passwords?
3. Where is information derived from passwords stored?
4. How does the system verify a password submitted during login?
5. Why is salt used, and how does it work?
6. Who has access to the file that contains password-related information?
There are plenty of online resources for these questions. To help you get started, see “Getting Started on Linux Login/Passwords” in the Appendix.
Our project will be extending the Linux login command using the provided password files for the application.
1. Project Details
Getting Started: To help you get started, we have provided two Python code files that demonstrate how user creation and login work under the hood.
1. create_user.py: creates a new user. Study its code to understand what it does and what conditions must be met to run it successfully. Pay close attention to what changes are made to the ./app/shadow file after creating a user. A thorough understanding of those changes will be useful throughout this project.
2. check_login.py: checks whether a user can log in with a given user ID and password pair. By analyzing the code, you will learn how a user is validated after submitting a password. In particular, look at how it retrieves the hash from the provided shadow file and compares it against the hash computed from the submitted password.
Once you have a solid understanding of create_user.py and check_login.py, you are ready to proceed. Make sure to copy and paste the code from the two provided starter files into your 2FA.py. Do not import the files in your code.
2. Task 1: Implementing 2FA (80% of grade)
In this task, you need to implement 2FA using the provided token generator (TG) executable, which serves as the second factor. The 2FA method uses tokens produced by TG to harden the login mechanism in Linux.
In a typical 2FA deployment, a unique second-factor device is associated with each user (for example, your phone for Duo 2FA at Georgia Tech). In this project, the same TG will serve as the second factor for all accounts you create. To make this work, each user must be registered with TG along with a PIN.
Each user therefore has two accounts:
• One account on the 2FA system
• One account on TG
The Token Generator and the 2FA Method are described below. Implementation details are in the Implementation of 2FA section.
Token Generator (TG)
Before moving to the 2FA method, it is important to understand how TG works. TG presents three options: ‘1’ to register a new user, ‘2’ to generate a token for an existing user, and ‘3’ to delete a user account.
NOTE: You have been provided with the Token Generator executable. You only need to understand how it works so you can treat it as a black box. You do not need to implement TG.
If the user enters:
‘1’ then:
• TG prompts the user for a user ID and a six-digit PIN.
• TG generates an initial token IT and creates an encrypted text file named after the user ID.
• Deleting this file is equivalent to deleting the user’s TG account. The role of IT will become clear in the 2FA method description.
‘2’ then:
• The user must provide their user ID and the correct PIN (similar to unlocking a phone with a PIN when the phone is the 2FA device).
• If the correct information is provided, TG returns the current token CT and the next token NT.
• These tokens are used in the 2FA method.
‘3’ then:
• The user must provide the same information as in option ‘2’ (user ID and correct PIN).
• TG returns the current token CT, deletes the user account, and removes the associated file.
NOTE (Very Important): After each TG operation, the user is prompted to confirm whether the corresponding task in the 2FA method completed successfully. If it did, the user must enter ‘y’ or ‘Y’. Any other input causes TG to revert to its previous state for that user.
The 2FA Method
1. Create a User Account
When user U tries to create an account, the 2FA method requires four items: username U, password P (with confirmation), salt, and the initial token IT generated by TG when the user registered.
NOTE: The PIN for TG and the password for the 2FA system must be different. However, the username for the 2FA system and the user ID for TG must be the same.
The 2FA method takes token IT, concatenates it with password P to form the hardened password (P+IT), and passes this through the password hashing algorithm to produce the shadow file entry. With this entry saved, the new user is successfully created. The full process is illustrated in Figure 1 in the Appendix.
2. Logging into a User Account
After user U has been created, they can log into their account. For login, the user must provide username U, password P, current token CT from TG, and next token NT from TG[2].
The 2FA method first checks whether user U exists. If so, it concatenates P and CT to construct the hardened password (P+CT), as done during user creation. This hardened password is validated against the hash in ./app/shadow. After successful validation, P is concatenated with NT to form the new hardened password (P+NT). This value is hashed and used to update the corresponding field in ./app/shadow. Based on whether the operation succeeded or failed, the user enters the confirmation response in TG, which determines whether the changes are saved or discarded. The full login process is illustrated in Figure 2 in the Appendix.
3. Update and Delete
The 2FA system must support password updates to handle cases where a password is compromised or has expired. For an update, the user must provide username U, password P, new password NP (with confirmation), new salt NS, current token CT, and next token NT from TG.
The 2FA system must also support account deletion. For delete, the user must provide username U, password P, and current token CT.
The update and delete functionality should be modeled after the login functionality.
Implementation of 2FA
IMPORTANT: Follow the prompts exactly as specified below. Regrade requests based on incorrect prompt order will not be accepted.
Once you are familiar with the 2FA method and TG, create a standalone program that implements the full 2FA method. Start from the Python code provided. Your code must implement the prompts below in the exact order listed.
Your program must handle the following steps:
1. Prompting user for action selection: Prompt the user with the following menu: Select an action:
1) Create a user
2) Login
3) Update password
4) Delete user account
Your program must also prompt for all required inputs (username, password, salt, and tokens) for each action.
Prompt for action 1 (create user):
Username: Alice
Password: Alice123
Confirm Password: Alice123
Salt: salt0123
Initial Token: eYKCaN0kLB7T0.3Q.vPs40 Prompt for action 2 (login):
Username: Alice
Password: Alice123
Current Token: eYKCaN0kLB7T0.3Q.vPs40
Next Token: iGxl329/ugOeSnhOzYE1B/ Prompt for action 3 (update password):
Username: Alice Password: Alice123
New Password: New-Password
Confirm New Password: New-Password New Salt: salt3210
Current Token: eYKCaN0kLB7T0.3Q.vPs40
Next Token: iGxl329/ugOeSnhOzYE1B/ Prompt for action 4 (delete user):
Username: Alice Password: Alice123
Current Token: Gxl329/ugOeSnhOzYE1B/
When a user successfully completes an action, the 2FA.py program should re-prompt for action selection from the user.
2. Creating Users (20 pts.): If ‘1’ is selected, the program must:
a. Prompt for username, password, confirm password, salt, and initial token IT, in that order.
b. If the user already exists, display “FAILURE: user <username> already exists” and exit. This counts as a failed creation attempt. All inputs from step (a) must be collected before checking whether the user exists.
c. If the user does not exist, create the account. Update both ./app/shadow and
./app/passwd.
d. Add a corresponding home directory entry to ./app/passwd.
e. On success, print “SUCCESS: <user-id> created”.
NOTE: The salt remains the same for a user account unless the user updates or recreates their account.
3. Login (20 pts.): If ‘2’ is selected, the program must:
a. Collect the following inputs from the user:
Username: Alice
Password: Alice123
Current Token: eYKCaN0kLB7T0.3Q.vPs40
Next Token: iGxl329/ugOeSnhOzYE1B/
b. Execute the complete login process described in the 2FA Method section.
c. “SUCCESS: Login Successful” on success.
d. If the user does not exist, display “FAILURE: user <username> does not exist”. All inputs (username, password, current token, and next token) must be collected before checking whether the user exists.
e. If the password or token is incorrect, display “FAILURE: either passwd or token incorrect”.
4. Password Update (15 pts.): If ‘3’ is selected, the program must:
a. Prompt for username, password, new password, confirm new password, new salt, current token, and next token, in that order. Update the account accordingly.
b. On success, display “SUCCESS: user <username> updated”.
c. Handle errors the same way as the login functionality.
5. Deleting a User (15 pts.): If ‘4’ is selected, the program must:
a. Prompt for username, password, and current token, in that order.
b. If all values are correct, remove all entries for the user and delete their home directory.
c. On success, display “SUCCESS: user <username> Deleted”.
d. Error handling must follow the same pattern as the login functionality.
Keep the following in mind as you work on the project:
1. After every successful request, enter ‘y’ or ‘Y’ when TG prompts for confirmation. Do not enter ‘y’ or ‘Y’ before your script has completed the task.
2. The interaction between your 2FA implementation and TG is manual. Tokens must be copied and pasted from TG into your 2FA program.
3. Use the correct TG option for each 2FA function: enter ‘1’ when creating a user, ‘2’ when logging in or updating a password, and ‘3’ when deleting a user.
3. Task 2: Security Analysis of 2FA (20% of grade)
Complete a security analysis of the implemented 2FA method. Your analysis must address the following:
• Discuss two advantages, two disadvantages, and two possible attacks on the 2FA method described in this project.
• Consider a realistic production deployment of this 2FA scheme. Recommend one concrete improvement.
• Describe how you would implement this 2FA scheme in a client-server setting, and explain how you would secure the token transfer between the two systems.
4. Project Deliverables
Submit the following to the Gradescope assignment:
• Your Python script for the 2FA implementation. The file must be named 2FA.py.
• A PDF report named <gtid>_2FA.pdf. For example, for a student with GT username “gpburdell”, the file would be named gpburdell_2FA.pdf. The report must contain:
• Your answers for Task 2, under a section titled “Task 2”
5. Appendix – Figures
Figure 1: Creating an Account
Figure 2: Logging into an Account
Getting Started on Linux Login/Passwords
When Linux creates a user, it prompts for a password. Depending on the Linux version, one of several algorithms is selected for password hashing. The system generates a random salt, uses it to produce a one-way hash, and stores that hash with the user’s details in /etc/shadow. A sample entry looks like this:
cs6238:$6$UPICuFgR$0bA5equUygMEptwf//rCS6gVVToghXSkLb0NqVYPyBmkNMunvPcIj7G03uy5iszpNfbT7WqpDG cDRAQN6hpEil:17732:0:99999:7:::
This entry has 9 fields separated by “:”. The first field is the username; the second is the hash. The hash itself contains three sub-fields separated by “$”. The first sub-field identifies the hashing algorithm (“6” denotes SHA-512). The second is the salt, which makes each hash unique. The third is the hash of the combined salt and password. You can verify hash generation using the following Perl one-liner in your Ubuntu terminal:
perl -e ‘print crypt(“<PASSWORD>”,”\$<HASH-ALGO>\$<SALT-VALUE>\$”) . “\n”‘
Here: <PASSWORD> = cs6238, <HASH-ALGO> = 6, <SALT-VALUE> = UPICuFgR
Note: Explore all other fields in the shadow file, as you will need to know them for this project.
After storing the hash in /etc/shadow, the system creates a home directory and adds an entry for the user in /etc/passwd, which stores essential account information used during login. This file contains one entry per line per user. An entry in /etc/passwd for user cs6238 looks like this:
cs6238:x:1000:1000:CS6238,,,:/home/cs6238:/bin/bash
Each entry in /etc/passwd has seven fields separated by “:”. The first field is the username. The second is the password field, where “x” indicates that the actual hash is in the shadow file. The next two fields are the UID and GID. The last two are the user’s home directory and the path to their login shell. A detailed review of /etc/passwd is not required for this project, but exploring it further is encouraged. Once the /etc/passwd entry is written, user creation is complete.




