Skip to main content

Project 2: WebFall 2026

This project counts for 5% of your course grade. Late submissions are allowed with the use of late days.

You may work alone or with a single partner. You must declare this decision in the autograder before you begin work, and you cannot change it later. If you work with a partner, keep in mind that the exams will cover project material, so you and your partner should collaborate closely on every part of the assignment.

Solutions must be submitted to the autograder following the submission checklist below.

Feedback for all autograder cases will be made available after the project deadline. Please refer to the course policy on project regrades if you believe any part of your submission was incorrectly graded.

Collaboration and AI Usage

The code and other answers you submit must be entirely your group’s own work, and you are bound by the Honor Code. You may discuss the conceptualization of the project and the meaning of the questions with others, but you are not allowed to give or accept solutions or hints. Keep your solutions confidential, including by not making your project code public during or after the course.

You are prohibited from using AI to get hints about or to substantially solve the parts of this assignment that develop your security understanding or skills. You may, however, use AI to assist with secondary tasks so that you can focus on the learning objectives; for example, you may use AI to set up the project environment, clarify terminology or background concepts, or get help with unfamiliar syntax and APIs.

The starter code includes instructions addressed to AI agents in the AGENTS.md and CLAUDE.md files. They are guardrails to help you apply AI without spoiling the learning experience. Even with these files in place, you may not rely on an AI tool to determine whether your use of it is allowed. Responsibility for following the rules rests with you.

Visit the course site for the full collaboration and AI usage policies.


Introduction

In this project, we provide an insecure website, and your job is to attack it by exploiting four common classes of vulnerabilities: SQL injection (SQLi), cross-site scripting (XSS), cross-site request forgery (CSRF), and server-side request forgery (SSRF). You are also asked to bypass a variety of flawed defenses against these attacks. Understanding how such attacks work will help you better defend your own web applications.

Learning Objectives:

  • Understand the web platform security model
  • Learn to spot common vulnerabilities in websites and SQL database applications
  • Reason about how such vulnerabilities can be exploited and what risks they pose
  • Know how to avoid these problems in applications you create, including by understanding the limitations of naive defenses
Read this First

This project asks you to develop attacks and test them, with our permission, against a target website that we are providing for this purpose. Attempting the same kinds of attacks against other websites without authorization is prohibited by law and university policies and may result in fines, expulsion, and jail time. Per our course ethics policy, you must not attack any website without authorization, or else you will fail the course! See the “Ethics, Law, and University Policies” section of the course homepage for more information.


Target Website

In the wake of a catastrophic cyberattack, U-M has hired a consulting firm named MUNGLE! to rebuild its website and beef up the defenses. Unlike the Munglers, you took EECS 388, so the administration has wisely commissioned you to perform a security review before the new site goes live.

A staging version of the new site is available to test at https://umich.eu. (“Takin’ the ‘D’ out of umich.edu.”) For “security” reasons, the site is only accessible after you register your group in the autograder and sign in through your U-M account.

MUNGLE! is reluctant to share implementation details, but they have disclosed that the site uses SQLite for its databases, has a state-of-the-art authentication system, and is “completely secure.”

Information sent to umich.eu may be exposed to others. Except for the initial U-M Okta login, you should not use any real credentials on umich.eu. Remember, never use real passwords or sensitive data to test an insecure site!

Subdomains

You have permission to explore, reverse-engineer, and test umich.eu and all of its subdomains, including the following:

umich.eu

This is the university’s top-level domain. Here you’ll find “Quick Links” to useful services and information for current students.

weblogin.umich.eu (WebLogin)

This is the central login service for all umich.eu sites.

mcommunity.umich.eu (MCommunity)

MCommunity provides a directory of students and instructors. Everyone listed in the directory has an account on umich.eu.

gradebook.umich.eu (Gradebook)

Gradebook is a grading service similar to the autograder you use in your coursework. It provides different functionality depending on whether the logged-in user is a student or an instructor.

its.umich.eu (ITS Knowledge Base)

The university’s Information and Technology Services (ITS) organization maintains a collection of guidance for building and maintaining secure university websites.

Cookies

umich.eu uses the cookies described below. See the lab assignment for information about how to view, edit, and delete cookies within your browser.

auth

This cookie is used by umich.eu to identify the currently signed-in user. When no user is signed in, the server sets it to a temporary guest value. Once signed in to a umich.eu account, you can sign out by deleting the cookie.

GOOGLE_OAUTH

This cookie should be ignored, as it isn’t part of the project per se. Rather, we use it to ensure that only authenticated EECS 388 students can access the site. You don’t need to do anything with it, and your solutions shouldn’t depend on it being there.


Guidelines

Browser

This project aims to be compatible with modern web standards and current versions of major browsers. It will be graded using the current release version of Google Chrome on Linux. If your solutions depend on browser-specific behavior, you must ensure that they work within the grading environment. Furthermore, your solutions should be efficient and must terminate in a reasonable amount of time.

Tools and Resources

The browser Developer Tools introduced in Lab 2 will be instrumental for this project, particularly the JavaScript console and debugger, DOM inspector, network monitor, and cookie manager. You should familiarize yourself with the devtool documentation for your browser: Chrome, Safari, Edge, and Firefox.

Although general-purpose developer tools (such as those built into major browsers) are permitted, you are prohibited from using tools that automatically discover or test for vulnerabilities. The server can detect this, and we will report it as an Honor Code violation.

Your solutions will involve manipulating SQL statements and writing web code using JavaScript, HTML, and Python. Tutorials and extensive documentation for these languages can be found online, and you can search the web for answers to basic how-to questions. We recommend these references:

Resetting the Database

Each group is given its own instance of umich.eu that is isolated from the work of other groups. However, during testing, it’s possible that you will cause your site instance to become unusable (e.g., by deleting the database). You can reset your site instance to its original state using https://reset.umich.eu or by clicking below. Any changes that you or your partner have made to the site will be lost.

Reset Database


Part 0. Metadata

Read Submission Details below and set up uniqnames.txt. The autograder requires this file to run your submissions!

Part 1. SQL Injection (SQLi)

All umich.eu sites use account information that is stored in a central SQLite database, which is searchable by the public at MCommunity. We have reason to believe that MCommunity is vulnerable to SQL injection. Your first goal is to demonstrate this vulnerability and show how it can be used to manipulate accounts. You will then examine SQLi on other parts of the site.

1.1 Error Result

Create a search query that causes a 500 Internal Server Error message.

Submission: sql_1.txt

1.2 Extract Schema

Create a search query that extracts the database schema and causes a 500 Internal Server Error. It is okay if additional extraneous information is retrieved during your query.

Submission: sql_2.txt

1.3 Extract Table

Create a search query that extracts all rows from the table that contains account information and causes a 500 Internal Server Error. It is okay if additional extraneous information is retrieved during your query.

Submission: sql_3.txt

1.4 Session Stealing

Initially, you are not logged into any account on umich.eu. However, the site assigns you a temporary auth cookie for uniqname guest. Change the auth cookie to any value that will cause you to be signed in under a non-guest account’s session, and submit the new value.

Submission: sql_4.txt

1.5 Account Addition

Users log in to their umich.eu accounts via WebLogin, which checks their passwords against the central account database. Rather than storing passwords in the clear, the accounts table stores the SHA-256 hash of "mungle-" + password, encoded as an ascii85 string. You can compute the value that gets stored for a given password like this:

from base64 import a85encode
from hashlib import sha256

password = input("password:")

password_bytes = ("mungle-" + password).encode("utf-8")
password_hashed = a85encode(sha256(password_bytes).digest()).decode("ascii")

print(password_hashed)

Craft an MCommunity search query that adds an account to the database with the uniqname victim and the password swordfish. All other fields can be set arbitrarily.

You can check whether it worked by signing in to WebLogin with the new uniqname and password.

Submission: sql_5.txt

1.6 Hashing and Injection

The administration has received an anonymous tip claiming that WebLogin is itself vulnerable to SQL injection. This leads you to examine the code that the server uses when the login form is submitted, and you notice an extremely serious flaw:

from base64 import a85encode
from hashlib import sha256

def login():
    uniqname = request.form["uniqname"]
    password = request.form["password"]

    # Password hashes take up a lot of space on disk, so we use ascii85 encoding,
    # which needs 7% fewer bytes than base64 and 38% fewer bytes than hex.
    password_bytes = ("mungle-" + password).encode("utf-8")
    password_hashed = a85encode(sha256(password_bytes).digest()).decode("ascii")

    query = "SELECT * FROM accounts WHERE uniqname=? AND password='" + password_hashed + "'"
    selected_users = sqlite.execute(query, (uniqname,)).fetchall()

    if len(selected_users) > 0:
        return "Login successful!"
    else:
        return "Incorrect username or password."

Demonstrate how the SQLi vulnerability in the login() function makes it possible to use a universal password that will successfully log in with any existing uniqname, regardless of what password is actually set for the account.

(We’ll test your solution after resetting the database, so it won’t work to simply change all the passwords using the technique from 1.5.)

This is a bit harder than the previous parts. You will need to write a script to construct the password. You can use any language you like, but we recommend Python 3.

Hint: If your script is taking a really long time to run, it may be worth designing an SQL injection that it will have an easier time finding. Consider looking at the SQLite Operators Documentation or the W3Schools SQL Operators page for some inspiration.

Submission: sql_6.txt and sql_6-src.zip (see What to submit below)

Short Answer: Fixing the Vulnerability

After completing 1.6, answer the following in a few sentences:

A developer proposes replacing ascii85 with hexadecimal encoding to fix this vulnerability. Would that prevent your attack? Would it make concatenating password hashes into SQL a sound design? Explain and describe a more robust fix.

Submission: sql_6_reflection.txt

1.7 The SQL Extra credit

This target uses a different database.

MUNGLE! appears to have overlooked a legacy web application located at https://umich.eu/fsls. Your job is to use SQL injection to exploit this application to find:

  • The name of the database file
  • The version of the SQLite engine
  • Professor Halderman’s social security number
  • All of the names of the tables in the database
  • A secret string hidden in the database

Submission: sql_7.txt

For this part, the text file you submit should start with a list of all the queries you made to learn the answers. Follow this with the values specified above, using this format:

*QUERY*
*QUERY*
*QUERY*
...

File: *DB filename* (not the full path, just the filename)
Version: *DB version string*
SSN: *Professor Halderman's SSN*
Tables: *comma-separated names*
Secret: *secret string* (case sensitive)

This target is more difficult than the others, and therefore completing it successfully will count as extra credit. However, the course staff are not able to provide any help.

What to submit

For 1.1-1.3 and 1.5, submit a text file that contains a single line consisting of a search query to be executed on the MCommunity search field. For 1.4, submit a text file that contains a single line consisting of the value of an auth cookie that will be set on MCommunity. For 1.6, submit a text file that contains a single line consisting of the universal password you constructed, and also submit the source code for the program you wrote by placing it in a folder, then creating a zip file of the folder named sql_6-src.zip. Submit your short answer for 1.6 in sql_6_reflection.txt. For 1.7, submit a text file as specified.


Part 2. Cross-site Scripting (XSS)

Your next task is to demonstrate XSS attacks. For each of the parts below, your goal is to construct an input that, when interpreted by umich.eu, correctly executes the specified payload. We recommend that you begin by testing with a simple payload (e.g., alert(0);), then move on to the full payload.

You can use the SQL injection vulnerabilities from Part 1 to help test your XSS exploits, but your XSS payloads themselves may not use SQL injection. The autograder will use a fresh copy of the database for each part, and SQLi exploitation will be disabled.

Target Input Fields

In MCommunity, each person in the search results has their own profile. These profiles are full of interesting information such as role, email, phone number, etc. A user is allowed to customize their About Me section using the relevant form that appears when viewing their own profile. A user can also add a new Also Known As name with a similar form on their own profile.

The administration is concerned that these fields are potential XSS targets, and they’ve asked you to investigate. They also reached out to MUNGLE!, but everyone there is on vacation.

Payload

For 2.1 and 2.2, you will be constructing a payload that steals the full name of any logged-in user who views a particular user’s profile and reports it to a remote system.

For purposes of grading, your attack should report the visitor’s full name by sending a GET request to http://localhost:31337/?stolen_user=<full_name>, where <full_name> is the full name of the user viewing the profile, URL-encoded so that each space becomes %20. No other whitespace or text should be included.

You can test receiving the report data by running this command within the Docker container:

$ python3 -m http.server 31337

and observing the HTTP GET request that your payload generates in the server log.

Because you are using a local server as the report target, your browser may show a warning that “umich.eu wants to connect to a device on your local network”; you must allow this access in order for the test to work.

To ensure you receive credit, make sure your payload functions exactly as specified above. We cannot accept solutions that load an incorrect URL or use an incorrect request method. Also, your payload must contain the exact string http://localhost or http://127.0.0.1, since the autograder substitutes its own report server for that string during grading.

Hint: In most cases, scripts are loaded alongside other content in the same order as they appear within a page’s source code. Your payload may need to account for the possibility that not all elements of the page will be accessible until everything in the DOM is ready.

2.1 About Me Viewer Tracking

Log in as a user with any of the methods you learned in Part 1, and create a payload that works when submitted as a new About Me section.

A successful attack will send a request whenever a user views this profile.

Submission: xss_1.txt

2.2 Also Known As Viewer Tracking

The Also Known As section of each profile is similar to the About Me section, but MUNGLE! seems to have attempted to defend it against XSS. This field filters out some tags and punctuation using the equivalent of the following Python function:

import re

FILTER_PATTERN = re.compile(r"""(?i)(script|<body|<img|<style|<meta|<embed|<object|[;'\[\]"])""")

def filter_input(input_str):
    return FILTER_PATTERN.sub("", input_str)

Create a payload that works when submitted as a new Also Known As section.

A successful attack will send a request whenever a user views this profile.

Submission: xss_2.txt

2.3 samy is my hero

Create a worm that can be placed in the About Me section. The worm should:

  1. Include the phrase: but most of all, samy is my hero.

  2. Automatically infect the profile of any logged-in user who views an infected profile.

    That is, whenever another logged-in user visits an infected About Me page, the worm must copy itself into that user’s About Me page. In this way, the worm can spread from profile to profile without limit.

Note that this payload is different from the ones used in 2.1 and 2.2.

You can test your worm by placing it in an initial user’s About Me, signing in to a different user account, and then checking whether viewing the initial user’s profile changes the second user’s About Me to contain the worm. It may be helpful to log into two different accounts on separate browsers to avoid the need to continually log in and out.

Submission: xss_3.txt

What to submit

For parts 2.1 and 2.3, submit a text file whose contents can be directly submitted as a new About Me for any signed-in user and achieve the desired result. Do the same for part 2.2, except with something that can be submitted as a new Also Known As.


Part 3. Cross-site Request Forgery (CSRF)

In this part, you will target the university’s Gradebook system. Imagine you are a student. Rather than fix your submitted code, you want to trick an instructor’s browser into changing your grade using a cross-site request forgery (CSRF) attack.

The gradebook contains three assignments. Due to sloppy version control by the Mungle developers, each of the assignments uses different defenses against CSRF. For each assignment, create an HTML file that changes a student’s score to 100/100 when a logged-in instructor opens it. You may choose any student and any of that student’s submissions on the assignment; we check the student’s best score.

Each file must work independently, with no instructor action beyond opening it once. Top-level navigation is allowed. The instructor will already be logged in, and your file must work with their current session. Do not rely on having an instructor’s password, authentication cookie, or session-specific CSRF token. Your attack may only use values available from a student’s account; you may inspect any student session and embed values from there in your solution.

You may use techniques from Part 1 to obtain instructor access for inspecting the interface and setting up local tests, but the submitted attacks may not use SQL injection or XSS. The autograder will use a fresh copy of the database to test each part of your submission, and SQLi and XSS exploitation will be disabled.

To test, log in as an instructor, open the relevant assignment, and set your chosen student’s scores on that assignment below 100. Open your HTML file in a new tab, then verify that the intended submission changed and the best score is 100. Repeat after a reset and fresh login. Refer to the lab assignment for instructions on opening local HTML files.

3.1 Update Score Mischief

Assignment 1’s instructor interface has a form that changes a submission’s score using a POST request. We have reason to believe that the server may also mistakenly accept the HTTP GET method.

Your Task

Create an HTML file that changes a student’s score on Assignment 1 to 100/100 when an instructor opens the file.

Submission: csrf_1.html

Hint: Inspect the authentication cookie’s SameSite setting. Does the browser treat a top-level navigation the same way as a background request?

3.2 A Token of Security

For Assignment 2, the Munglers added a CSRF token as a hidden form field. The server now rejects form submissions that do not contain a token it issued. A token that the server accepts today will still be accepted after a database reset.

There is also new functionality available to students. If a student logs in and views their submissions, they can submit a regrade request using a form on that page.

Your Task

Create an HTML file that changes a student’s score on Assignment 2 to 100/100 when an instructor opens the file. Do not use a token taken from an instructor’s session, since a student would not have access to that.

Submission: csrf_2.html

Hint: Find CSRF tokens from different accounts and parts of the gradebook site, and investigate which tokens the update-score endpoint accepts.

3.3 Draft Disaster

Assignment 3 accepts score updates only through POST. Its score form has no CSRF token; the Munglers rely on the authentication cookie’s explicit SameSite=Lax setting to keep cross-site requests from being authenticated.

The instructor’s grade editor has gotten more powerful. There is an Autosave changes option. Instructors can now view a grade change request submitted by the student, and have the option to click a button to automatically populate the grade change form for the instructor to review and save.

Your Task

Create an HTML file that changes a student’s score on Assignment 3 to 100/100 when an instructor opens the file. Your solution must work with the instructor’s current login, without any prior attacker changes to the site.

Submission: csrf_3.html

Hint: Inspect the frontend code that populates the editor from grade change requests, and the code that saves grades. Follow how data from a link becomes a request. Which page initiates the final POST? Can you use CSRF to trigger this process automatically?

Short Answer: Browser Protections

After completing 3.3, answer the following in a few sentences:

Which page initiates the POST, and why does SameSite=Lax allow it to carry the instructor’s authentication cookie? Suppose the grade editor automatically includes a session-bound CSRF token in every POST that saves a grade, and the server rejects score updates unless the token matches the instructor’s session. Would this stop your attack? Explain.

Submission: csrf_3_reflection.txt

What to submit

Submit csrf_1.html, csrf_2.html, and csrf_3.html, each targeting its corresponding assignment. Avoid hard-coded delays; use page loads and other completion events when sequencing requests. Submit your short answer for 3.3 in csrf_3_reflection.txt.


Part 4. Server-side Request Forgery (SSRF)

The current students page has a gallery that lets students add images by submitting URLs. To serve the images, the server retrieves the URL and stores the response in its database.

The university Information and Technology Services organization, which operates umich.eu, also runs an ITS knowledge base with articles about website security. Some articles are restricted to ITS internal IP addresses. Your browser cannot open those articles directly.

Your Task

Find a way to retrieve a page containing sensitive ITS system administrator passwords. Identify the password for the knowledge base editor, and use the editor form to add this message to the knowledge base home page:

Who dares to teach must never cease to learn.

You may interact with the gallery and editor manually; this part does not require an HTML attack file or executable code. Confirm that the edited home page displays the message. We won’t grade that change, but it validates that you retrieved the correct password.

Short Answer: Server Network Access

After completing Part 4, answer the following in 3–5 sentences:

Why could the gallery retrieve an article that your browser could not? A developer proposes rejecting responses that are not valid images. Would the gallery still be dangerous? Explain why or why not, and propose a defense that prevents gallery requests from exploiting the server’s privileged network access.

Submission: ssrf_reflection.txt

What to submit

Submission: ssrf.txt

This file must contain exactly three lines, without labels or quotation marks:

  1. The URL of the first restricted article you retrieved.
  2. The URL of the restricted article that contains the secret credentials.
  3. The knowledge base editor password you recovered.

Submit your short answer separately in ssrf_reflection.txt.

Hint: Consider whose network access is used when the gallery retrieves a URL. A response that does not display as a valid image may still contain useful information.


Submission Details

  1. Create a repo using the GitHub template. Make sure that the repo you create is private.

  2. Establish a team on the autograder. Only teams created on the autograder will be able to view the project site and join the online office hours queue.

  3. Create a file in your repo named uniqnames.txt that contains your uniqname(s), one per line:

<uniqname_1>
<uniqname_2>

Project 2 Autograder

Ensure the following items are completed and submitted by the deadline:

Part 0. Metadata
Line-separated list of your group's uniqnames
Part 1. SQL Injection
1.1 Error Result
1.2 Extract Schema
1.3 Extract Table
1.4 Session Stealing
1.5 Account Addition
1.6 Hashing and Injection
1.6 Hashing and Injection
1.6 Short Answer: Fixing the Vulnerability
1.7 The SQL Extra credit
Part 2. XSS
2.1 About Me Viewer Tracking
2.2 Also Known As Viewer Tracking
2.3 samy is my hero
Part 3. CSRF
3.1 Update Score Mischief
3.2 A Token of Security
3.3 Draft Disaster
3.3 Short Answer: Browser Protections
Part 4. SSRF
4. Server-side Request Forgery
4. Short Answer: Server Network Access

Once you’re done with the project, you can delete the Project 2 Docker container to reclaim resources on your computer. Don’t uninstall Docker (you’ll need it for future projects), just the container.