Game Rules


In each lab, you are asked to solve a set of challenges (typically 10 challenges, except for the first two weeks). For each challenge, you have to submit three things to the submission site (-A section, -O01/-OCY section): the flag you captured from the challenge, the exploit that you wrote to get the flag, and a write-up that summarizes how you formulated the exploit (see below).

A flag is a 512-byte hex string (like shown below) found in /proc/flag on the CTF server.

$ cat /proc/flag

Your job is to read this flag by exploiting the provided challenges.

Taking actions #1: registration

Register your account and get an api-key:

  • Visit the submission site (-A section, -O01/-OCY section) to use the Register menu.

  • Input your username (preferably your real name), GTID number, and e-mail address (we only accept accounts), and click the Email api-key button.

  • You will receive an email with your api-key. You can then use this to log in to the course website.

Taking actions #2: course workflow

  1. Log in to your account:

  • Go back to the submission site to use the Login menu.

  • Input your received api-key and click the Submit api-key button.

  1. You can now connect to the CTF server and begin your lab challenges. You can find ssh details for each lab on Canvas after they unlock.

# log in to one of the CTF servers
# ** Refer to Canvas for ssh information! **
[host] $ ssh lab01@ctf_server_address

# let's start lab01!
[CTF server] $ cat README
[CTF server] $ ./bomb
  1. While solving the challenges on the CTF server, you might need to write your own exploit scripts. Feel free to create a directory inside /tmp to store your files. Note that the CTF server and the lab account are shared with all other users, so avoid using directory names that are easily guessable (e.g., /tmp/cs6265), and do not reveal your secret directory name anywhere. Listing files (ls) in /tmp is not allowed. Also, we encourage you to keep backups of your files by copying them from the CTF server to your local machine, since /tmp might get emptied occasionally.

  2. Submit your flags and write-ups.

  • Login → Problems → (lab) → Submit (Flag / Writeup)

  • Remember that your score is only valid after you submit both a flag and a write-up.


Taking actions #3: building local environment (OPTIONAL)

Although you can solve all challenges on the CTF server, it may be inconvenient because you cannot install your own tools. In this case, you can build an environment to study the challenges on your own machine. Please note that you still have to read /proc/flag on the CTF server to get the real flag.

To build your own environment:

  1. Download and install VirtualBox:

Note: Ubuntu users may want to use the following command to install VirtualBox:

[host] $ sudo apt-get install virtualbox
  1. Download and install Ubuntu 18.04.2 in VirtualBox:

  • Download the Ubuntu 18.04.2 image.

  • Launch VirtualBox and follow the instructions to install a new VM. A handy walk-through can be found here.

  1. Install essential tools inside the VM:

  1. To do labs (lab03 and after):

After launching VirtualBox and your Ubuntu VM:

# disable ASLR (before lab05)
[vm] $ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

# enable ASLR (starting lab05)
[vm] $ echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

# download labXX challenges
[vm] $ scp -r labXX@server:~/[challenge] [your_directory]

# download libc used by the server for analysis (future labs)
# 32-bit
[vm] $ scp labXX@server:/lib/i386-linux-gnu/ [your_directory]
# 64-bit
[vm] $ scp labXX@server:/lib/x86_64-linux-gnu/ [your_directory]

# tackle challenges
[vm] $ cd [your_directory_for_challenge]
[vm] $ cat README

Feel free to ask for help on Ed Discussion or at office hours if you have any trouble with setup.

General Rules

Points are earned as follows:

  • Each lab has one or two tutorial(s) and 10 challenges.

  • Each challenge is worth 20 points.

    • You must submit a flag, a write-up, and your exploit to earn the points.

    • If you do not submit the write-up, you get 0 points for that challenge.

    • As an exception, you do not need to submit write-ups for the tutorial challenges.

  • The maximum points you can get in each lab is 220 if it has one tutorial (20 × 11 flags), or 240 if two (20 × 12).

  • Bonuses: starting with lab 3, first and second bloods (i.e., fastest solvers) for each challenge will get 2 and 1 bonus points, respectively, for that challenge.

  • Hints: we will provide up to two hints per challenge.

    • You can view them on the challenge page (Submission site → Lab N → Problem name → Hints: Show).

    • Hints cost one point to open.

    • Later labs generally have few or no hints available.

  • Late policy: challenges submitted within one week past the due date will receive 50% of the original points.


You must submit a write-up for each challenge to get the actual points.

  • Your write-up must be in plain text formatted with Markdown syntax:

  • Your write-up must contain

    • a simple description of how you solved the challenge, and

    • the actual exploit (i.e., code!).

  • Your write-up must be specific enough that we can run and validate your exploit ourselves.

  • You don’t need to submit write-ups for the tutorial challenges.

Here is an example write-up:

1) Write-up:

This binary stores its return addresses and frame pointers in a separate
stack; while we can overwrite those values on the regular stack, it
accomplishes nothing.

`main()` puts a pointer to `exit()` in its stack frame, which it jumps to
after `start()` finishes. We can overwrite this during `start()`'s buffer
overflow to instead point to `jump_to_here()`, which prints the flag.

Conveniently, due to the return-address protection and the fact that
`start()` doesn't have many meaningful local variables, we don't need
to be careful about the other values we clobber on the stack on the way
to `main()`'s local function pointer. The correct return addresses are
restored at the end of each function.

2) Exploit:

    #!/usr/bin/env python3

    from pwn import *
    p = process('./target')
    p.sendline(cyclic(52) + p32(0x8048948))  # (jump_to_here())