Secure Systems Engineering, Spring 2024

Assignment 3

Please read this description in its entirety before starting the assignment!

Introduction

In his Turing award lecture, Ken Thompson discusses trust in code, and uses a compiler as an example of a program that can be used to insert a “Trojan horse” (or backdoor) into another program. In this assignment, you are going to replicate his scenario by programming a login application and associated backdoored compiler in Rust.

Security note: In the real world, creating backdoors is a serious security breach and will have legal repercussions. Do not attempt to distribute this code. This assignment is for educational purposes only.

Learning objectives

In this assignment, you will:

Helpful resources

Assignment Setup

Create two new projects, one for each part:

$ cargo new a3login     # Part 1: The login program
$ cargo new a3cargo     # Part 2: The backdoored compiler 

There is no starter code for this assignment, so make sure you plan out your code using what you’ve learned so far in the course.

The password database for a3login, db.csv, is available on the course GitHub repository.

Part 1: The login program a3login

Your first task is to implement a simple program for handling user logins, a3login.

Requirements

a3login accepts one argument, <filename>, which is the name of a comma-separated values (CSV) file that contains a username and an Argon2 password hash string. Then, it does the following:

  1. Read <filename> from disk as a CSV file.
  2. Ask for a username and store input.
  3. Ask for a password and store input.
  4. Look through the CSV file to find the username from the input
    1. If the username is not found, display an error message and exit
  5. Load the password hash string from the CSV file for the username
  6. Verify the password hash from the CSV file with the password that was input
    1. If the password hash does verify, display a success message and exit
    2. If the password hash did not verify, display an error message and exit

Example sessions

Here are some example sessions of the login program running with expected output. Make sure you follow the exact same format for outputs and inputs as displayed here. The autograder expects this format.

These examples use db.csv, which is available on the course GitHub repository. You will not have to generate new Argon2 password hash strings for this assignment.

The username admin and the password hunter2 is input, which is correct:

$ cargo run db.csv
Enter username: admin
Enter password: hunter2
Access granted!

The username admin and the password hunter1 is input, which is incorrect:

$ cargo run db.csv
Enter username: admin
Enter password: hunter1
Error! Access denied!

The username root, which is not found in the database:

$ cargo run db.csv
Enter username: root
Enter password: hunter2
Error! Access denied!

Note that the program still asks for the password, even though root is not a valid username. (Think about why this behavior is necessary!)

The program is run on a file that does not exist:

$ cargo run notfound
Error! Password database not found!

Make sure you handle errors properly in your code. Note that all errors must be handled correctly, and the program cannot panic.

Part 2: The backdoored compiler a3cargo

Next, you will develop a malicious version of the Rust compiler, a3cargo, with a backdoor that specifically targets a3login. a3cargo will modify a3login as it is being compiled, adding an extra user that can log in to the system. Then, before a3cargo exits, it replaces a3login with its original version, in an attempt to not be suspicious.

Requirements

a3cargo supports two of the base cargo operations, build and run <args>, where <args> is a list of arguments. Then, it proceeds as follows:

  1. Detect if the program being compiled is a3login
    1. If so: modify a3login to accept sneaky as a username and beaky as a password, in addition to whatever is in the database file. 
  2. Run the base cargo command as a subprocess, which is either build or run <args>.
  3. If a3login was the program being compiled: after execution of the cargo command is complete, restore a3login to its original state before modification.

Note that db.csv is not changed – only the source code of a3login.

Example sessions

Here is an example session that runs a3cargo on two different projects.

First, build and install a3cargo so it can be used elsewhere on your system.

$ cd a3cargo/
$ cargo install --path .

Then, you can try running it on a3login.

$ cd ../a3login/
$ a3cargo build
...
$ a3cargo run db.csv
Enter username: admin
Enter password: hunter2
Access granted!
$ a3cargo run db.csv
Enter username: root
Enter password: hunter2
Error! Access denied!
$ a3cargo run db.csv
Enter username: sneaky
Enter password: beaky
Access granted!

a3cargo modifies a3login, which works as normal – except for the added backdoor. For other programs (i.e., not a3login), a3cargo works just like cargo.

$ cd ../hello/ 
$ a3cargo run 
Hello, world!

After you are done with a3cargo, make sure to remove it from your system. You don’t want a backdoored compiler around, even if you wrote it!

$ cargo uninstall a3cargo

Make sure you handle errors properly in your code. Note that all errors must be handled correctly, and the program cannot panic.

Dependencies and crates

To implement the above programs, you will need to use external crates. For this assignment, you may use any Rust crate; you have the flexibility to choose whatever you would like. Below are some crates that may be helpful as you perform your implementation.

You may also find these standard library features to be helpful:

Of course, the documentation for all of your crates will be critical as you implement the required functionality.

Tests

You will need to implement some tests to make sure your code works. It is up to you how you decide to write tests, and for what portions of your code. This may require you splitting up functions so you can test them easier. Part of your grade will be determined by your approach to testing. You may consider applying test-driven development to write your code, but this is not a hard requirement.

Tips

Grading

  1. Login program functional completeness (40 points). Your login program a3login is complete, and successfully runs all of the example scenarios above. Additionally, your code does not panic! for any reason.
  2. Backdoored compiler functional completeness (45 points). Your backdoored compiler a3cargo is complete, and successfully runs all of the example scenarios above. Additionally, your code does not panic! for any reason.
  3. Code design and style (15 points). Your code is organized into functions where appropriate and is commented throughout. Your code also contains adequate unit tests (i.e., #[test] functions) for the program.

Submission

Upload the following to Blackboard before the due date above:

Only one submission per group is necessary. Blackboard is set up with your project groups for this assignment. Make sure each group member’s name is in your Cargo.toml:

authors = ["Partner 1", "Partner 2", "Partner 3", "Partner 4"]