CS177: Project 5 - Remote Buffer Overflows (15% of project score)

Project Goals


The goals of this project are:

  • to exploit a remote memory corruption vulnerability in a hardened binary
  • to use return-oriented programming (ROP) to compromise a remote process [10% extra credit]

Administrative Information


The project is an individual project. It is due on Friday, June 2, 2023, 23:59:59 PST (no further deadline extensions; late flags will not be accepted).

Introduction


As you have seen in the previous challenge, a buffer overflow occurs when a program or process tries to store more data in a buffer (or some temporary data storage area) than that buffer was intended to hold. This extra data, which has to go somewhere, overflows adjacent memory regions, corrupting or overwriting the valid data stored there. If the buffer is stored on the stack, as it is the case for local variables in C, control information such as function return addresses can be altered. This allows the attacker to redirect the execution flow to arbitrary memory addresses. By injecting machine code into the process memory (e.g., as part of the data used to overflow the buffer, or in environment variables), the attacker can redirect the execution flow to this code and execute arbitrary machine instructions with the privileges of the running process.

Detailed Description


Your task is to exploit vulnerabilities in remote server applications. Specifically, your objective is to create and then inject appropriate exploit inputs into the target application so that you force the program to return a flag. Like for previous challenges, you will first go to our CTFd site and launch your service instances. The site will give you the address and destination port where your server is running and listening for your connections.

For this challenge, we have prepared two vulnerable services. The first one is the same as we used for the last challenge (minecraft). However, now the service is running remotely and has enabled some exploit protection mechanisms. If you succeed in exploiting it, you will receive full credit for this project. The second application (lazy_panel) is significantly more challenging. You will receive extra credit (an additional 10% of your project score) if you manage to exploit it. Although we don't expect all students to be able to do so, we encourage everyone to at least give it a try. However, to keep it challenging, we don't plan to provide a lot of support for this part.

You can find the source code (for the first application) and the binaries (for both) here. Both applications are compiled for 64-bit x86 on Linux. The binaries running on the server are the exact copies of the binaries you get.

Our service is launched by xinetd. Xinetd is a wrapper that listens on a specific port and starts a corresponding program. When it receives data from the network, it will forward it to the (standard) input of the program. Similarly, it will send data that it gets from the program (written to the standard output) back over the network. To talk to the services and come up with exploits, we recommend pwntools.

We used gcc to build the binaries from the sources, using different command line flags for the different challenges. You can use checksec to understand what security related features the binary is built with.

Hints


Performing a successful remote buffer overflow can be tricky, because it is important to get all the little details right. We hope that the previous challenge has given you experience in crafting (and debugging) your exploits.

In addition to the hints from the previous challenge, here are a few more bits of information for minecraft.

  • The "mine" piece of the service implements an information leakage vulnerability. This allows you to read data from the stack of the remote program. This will come in very handy for you to understand what values are stored on the stack. Moreover, it will also be crucial to help you bypass certain security protections (such as stack canaries and random stack locations due to ASLR).
  • Our system has ASLR enabled. This means that, for each execution of a program, the operating system will place the stack segment at a random value. This makes it very difficult to predict where the stack will be, and as a result, it makes it hard to know the address of your buffer where you will put the shellcode. This is where the mining part (the info leak vulnerability) comes in handy. Find a value on the stack that points into the stack, and use this as an anchor to understand where the stack of the current instance (of the application that is running) is located. Then, adjust the address that you jump to accordingly to make it point to the buffer that you have overflown.
  • The binary is also hardened with stack canaries. That is, the compiler will insert a value before the return address that protects from buffer overflows. This means that you need to make sure that you include the canary value as part of your buffer overflow so that the correct value remains at the right position. Again, you will have to use the information leak vulnerability to find the right value and include it in your exploit.
  • Since you cannot debug the vulnerable programs directly (as it runs remotely), you might want to run a local version of the vulnerable program and try to exploit it first. Feel free to use the binary gym for this.
  • The flag is stored in the file /flag.

The second application (for extra credit): lazy_panel

  • lazy_panel requires you to first crack/bypass/guess-your-way-through a poor password check. Only then can you exploit a buffer overflow.
  • For this application, we have disabled stack canaries. However, we have enabled data execution protection (DEP). Thus, you can no longer just inject shellcode into the buffer on the stack and jump there. Instead, you have to launch your exploit using return-oriented programming (ROP). Writing a ROP chain by hand is very difficult, hence, you will want to use a ROP tool to make your life easier. Again, pwntools is a good choice for this task.
  • This time, you will have to reverse engineer the binary to understand the program logic.
  • The flag is stored in the file /flag.
  • The bingym virtual machine and the container running the challenge are both using the following libc: 2.35-0ubuntu3.1. To calculate the offsets between functions in the libc, once you have leaked one function address, you can use this resource.
  • Well... no more hints. Good luck!