**Assignment 05: Binary Attacks** In this assignment, you will generate four attacks on two programs with different security vulnerabilities. The outcomes from this assignment include the following. # Learning Goals - Learn different methods used by attackers to exploit security vulnerabilities. - Understand how to prevent these attacks and write more secure programs. - Gain experience reading x86-64 assembly for our Linux machine. - Gain more experience with debugging tools like `gdb` and `objdump`. # Grading Walk-Throughs This assignment will be graded as "Nailed It" / "Not Yet" by a TA. To pass ("Nailed It") the assignment, you must 1. Complete the assignment and submit your work to gradescope. + You should start this assignment in class on the day shown on the calendar. + *Complete the assignment as early as possible*. 1. Schedule a time to meet with a TA. You can meet with them after the submission deadline. + You must book a time to meet with a TA + Sign-up on the Google Sheet *with at least 36 hours of notice*. + Contact your TA on Slack after signing up. + All partners must meet with the TA. If you cannot all make it at the same time, then each of you needs to schedule a time to meet with the TAs. 1. Walk the TA through your solutions prior to the deadline. + Walk-throughs should take no more than 20 minutes. + You should be well prepared to walk a TA through your answers. + You may not make any significant corrections during the walk-through. You should plan on making corrections afterward and scheduling a new walk-through time. Mistakes are expected---nobody is perfect. + You must be prepared to explain your answers and justify your assumptions. TAs do not need to lead you to the correct answer during a walk-through---this is best left to a mentor session. 1. The TA will then either + mark your assignment as "Nailed It" on gradescope, or + mark your assignment as "Not Yet" and inform you that you have some corrections to make. 1. If corrections are needed, then you will need to complete them and then schedule a new time to meet with the TA. + You will ideally complete any needed revisions by the end of the day the following Monday. If you have concerns about the grading walk-through, you can meet with me after you have first met with a TA. # Overview The purpose of this assignment is to help you learn about the runtime operation of programs and to understand the nature of these security weaknesses so that you can avoid them when you write system code. *We do not condone the use of any other form of attack to gain unauthorized access to any system resources.* As usual, this is a pair project, and you may choose your partners. Each pair will generate attacks for custom generated target programs. ## Quick Start Video
## Get Your Targets You must grab your starter files from: http://itbdcv-lnx04p.campus.pomona.edu:10503 The server will build your files and return them to your browser in a `tar` file called `target`$k$`.tar`, where $k$ is the unique number of your target programs. It takes a few seconds to build and download your target, so please be patient. You should only download one set of files. If for some reason you download multiple targets, choose one target to work on and delete the rest. Copy the `target`$k$`.tar` file in a (protected) Linux directory on the server, e.g., ~~~bash scp targetk.tar USERNAME@itbdcv-lnx04p.campus.pomona.edu:~/cs105/assignments ~~~ Log onto the server and unpack your files: ~~~bash cd ~/cs105/assignments tar xvf targetk.tar mv targetk A05-BinaryAttacks ~~~ **Warning:** If you let your browser unpack the archive, or if you expand your `target`$k$`.tar` on a PC by using a utility such as Winzip, you will risk resetting permission bits on the executable files--and possibly losing some of them. The files in `A05-BinaryAttacks` include: - `README.txt`: A file describing the contents of the directory - `ctarget`: An executable program vulnerable to *code-injection* attacks - `rtarget`: An executable program vulnerable to *return-oriented-programming* attacks - `cookie.txt`: An 8-digit hex code that you will use as a unique identifier in your attacks. - `farm.c`: The source code of your target's "gadget farm," which you will use in generating return-oriented programming attacks. **IMPORTANT: if you compile this file from scratch, make sure you are using the optimization flag `-Og`!** - `hex2raw`: A utility to generate attack strings. In the following instructions, we assume you copied the files to a protected local directory, and that you are executing the programs in that local directory. ## Assignment Rules These rules might not make sense upon your first read. Please read the entire assignment description prior to starting your attacks! - You must complete the assignment using the course VM. - Your solutions may not use attacks to circumvent validation code in the programs. Specifically, any address you incorporate into an attack string for use by a `ret` instruction should be to one of the following destinations: - The addresses for functions `touch1`, `touch2`, or `touch3`. - The address of your injected code. - The address of one of your gadgets from the gadget farm. - You may only construct gadgets from file `rtarget` with addresses ranging between those for functions `start_farm` and `end_farm`. ## Target Programs Both `ctarget` and `rtarget` read strings from standard input. They do so with the following function. ~~~c linenumbers unsigned getbuf() { char buf[BUFFER_SIZE]; Gets(buf); return 1; } ~~~ The function `Gets` is similar to the standard library function `gets`---it reads a string from standard input (terminated by '`\n`' or end-of-file) and stores it (along with a null terminator '`\0`') at the specified destination. In this code, you can see that the destination is an array `buf`, declared as having `BUFFER_SIZE` bytes. At the time your targets were generated, `BUFFER_SIZE` was a compile-time constant specific to your version of the programs. `Gets` (and `gets`) has no way to determine whether its destination buffer is large enough to store the string being read. They simply copy sequences of bytes, possibly overrunning the bounds of the storage allocated at the destinations. If the string typed by the user and read by `getbuf` is sufficiently short, it is clear that `getbuf` will return 1, as shown by the following execution examples: ~~~bash $ ./ctarget Cookie: 0x1a7dd803 Type string: Keep it short! No exploit. Getbuf returned 0x1 Normal return ~~~ The program will report an error if you type a long string that doesn't represent a specific attack: ~~~bash $ ./ctarget Cookie: 0x1a7dd803 Type string: This is not a very interesting string, but it has the property ... Ouch!: You caused a segmentation fault! Better luck next time ~~~ (Note that the value of the cookie shown above will differ from yours.) Program `rtarget` will have the same behavior. As the error message indicates, overrunning the buffer typically corrupts the program state, leading to a memory access error. Your task is to be more clever with the strings you feed `ctarget` and `rtarget` so that they do more interesting things. These are called *exploit* strings. Both `ctarget` and `rtarget` take several different command line arguments: - `-h`: Print list of possible command line arguments - `-q`: Do not send results to the grading server - `-i FILE`: Supply input from a file, rather than from standard input Your exploit strings will typically contain byte values that do not correspond to the ASCII values for printing characters. The program `hex2raw` will help you to generate these *raw* strings. See section Using hex2raw for more information. ## Important Details - Your exploit string must not contain byte value `0x0a` at any intermediate position, since this is the ASCII code for newline (`\n`). When `Gets` encounters this byte, it will assume you intended to terminate the string. - `hex2raw` expects two-digit hex values separated by one or more white spaces. So if you want to create a byte with a hex value of `0`, you need to write it as `00`. To create the word `0xdeadbeef` you should pass "`ef be ad de`" to `hex2raw`. Observe the reversal required for little-endian byte ordering. See [On Endianness](https://www.technicalsourcery.net/posts/on-endianness/) for some information on byte ordering for multi-byte types. - Remember to work on the VM! Otherwise, your solutions will not be recorded as valid. When you have correctly solved one of the phases, your target program will automatically send a notification to the grading server. For example: ~~~bash $ ./hex2raw < phase2.txt | ./ctarget Cookie: 0x1a7dd803 Type string: Touch2!: You called touch2(0x1a7dd803) Valid solution for level 2 with target ctarget PASSED: Sent exploit string to server to be validated. NICE JOB! ~~~ The server will test your exploit string to make sure it really works, and it will update the scoreboard page indicating that your userid (listed by your target number for anonymity) has completed this phase. You can view the scoreboard by visiting: http://itbdcv-lnx04p.campus.pomona.edu:10503/scoreboard There is no penalty for making mistakes in this assignment. Feel free to fire away at `ctarget` and `rtarget` with any strings you like. (But go easy on our server... no denial-of-service attacks please!) Table [phases] summarizes each phase. The first three involve code-injection (CI) attacks on `ctarget`, while the last two involve return-oriented-programming (ROP) attacks on `rtarget`. Only the first four phases are required. If you have time and are having fun, I encourage you to try Phase 5, but you will not receive any additional points for completing that phase. | Phase | Program | Level | Method | Function | Points | | ----- | --------- | ----- | ------ | -------- | ------ | | 1 | `ctarget` | 1 | CI | `touch1` | 10 | | 2 | `ctarget` | 2 | CI | `touch2` | 20 | | 3 | `ctarget` | 3 | CI | `touch3` | 20 | | 4 | `rtarget` | 2 | ROP | `touch2` | 20 | | 5 | `rtarget` | 3 | ROP | `touch3` | 0 | [Table [phases]: Summary of attack assignment phases] # Part I: Code Injection Attacks For the first three phases, your exploit strings will attack `ctarget`. This program is set up in a way that the stack positions will be consistent from one run to the next and so that data on the stack can be treated as executable code. These features make the program vulnerable to attacks where the exploit strings contain the byte encodings of executable code. ## Phase 1 For Phase 1, you will not inject new code. Instead, your exploit string will redirect the program to execute an existing procedure. Function `getbuf` is called within `ctarget` by a function `test` having the following C code: ~~~c linenumbers void test() { int val; val = getbuf(); printf("No exploit. Getbuf returned 0x%x\n", val); } ~~~ When `getbuf` executes its return statement (line 5 of `getbuf`---see the function in section Target Programs), the program ordinarily resumes execution within function `test` (at line 5 of this function). We want to change this behavior. Within the file `ctarget`, there is code for a function `touch1` having the following C representation: ~~~c linenumbers void touch1() { vlevel = 1; /* Part of validation protocol */ printf("Touch1!: You called touch1()\n"); validate(1); exit(0); } ~~~ Your task is to get `ctarget` to execute the code for `touch1` when `getbuf` executes its return statement, rather than returning to `test`. Note that your exploit string may also corrupt parts of the stack not directly related to this stage, but this will not cause a problem, since `touch1` causes the program to exit directly. ### Some Advice - All information needed to devise your exploit string for this phase can be determined by examining a disassembled version of `ctarget`. Use `objdump -d` to get this dissembled version. - The idea is to position a byte representation of the starting address for `touch1` so that the `ret` instruction at the end of the code for `getbuf` will transfer control to `touch1`. - Be careful about byte ordering. - You might want to use `gdb` to step the program through the last few instructions of `getbuf` to make sure it is doing the right thing. - The placement of `buf` within the stack frame for `getbuf` depends on the value of compile-time constant `BUFFER_SIZE`, as well the allocation strategy used by `gcc`. You will need to examine the disassembled code to determine its position. ## Phase 2 Phase 2 involves injecting a small amount of code as part of your exploit string. Within the file `ctarget` there is code for a function `touch2` having the following C representation: ~~~c linenumbers void touch2(unsigned val) { vlevel = 2; /* Part of validation protocol */ if (val == cookie) { printf("Touch2!: You called touch2(0x%.8x)\n", val); validate(2); } else { printf("Misfire: You called touch2(0x%.8x)\n", val); fail(2); } exit(0); } ~~~ Your task is to get `ctarget` to execute code for `touch2` rather than returning to `test`. In this case, however, you must make it appear to `touch2` as if you have passed your cookie as its argument. ### Some Advice - You will want to position a byte representation of the address of your injected code in such a way that `ret` instruction at the end of the code for `getbuf` will transfer control to it. - Recall that the first argument to a function is passed in register `rdi`. - Your injected code should set the register to your cookie, and then use a `ret` instruction to transfer control to the first instruction in `touch2`. - Do not attempt to use `jmp` or `call` instructions in your exploit code. Encodings of destination addresses for these instructions are difficult to formulate. Use `ret` instructions for all transfers of control, even when you are not returning from a call. - See the discussion in section Generating Byte Codes on how to use tools to generate the byte-level representations of instruction sequences. ## Phase 3 Phase 3 also involves a code injection attack, but passing a string as the argument. Within the file `ctarget` there is code for functions `hexmatch` and `touch3` having the following C representations: ~~~c linenumbers /* Compare string to hex representation of unsigned value */ int hexmatch(unsigned val, char *sval) { char cbuf[110]; /* Make position of check string unpredictable */ char *s = cbuf + random() % 100; sprintf(s, "%.8x", val); return strncmp(sval, s, 9) == 0; } ~~~ ~~~c linenumbers void touch3(char *sval) { vlevel = 3; /* Part of validation protocol */ if (hexmatch(cookie, sval)) { printf("Touch3!: You called touch3(\"%s\")\n", sval); validate(3); } else { printf("Misfire: You called touch3(\"%s\")\n", sval); fail(3); } exit(0); } ~~~ Your task is to get `ctarget` to execute the code for `touch3` rather than returning to `test`. You must make it appear to `touch3` as if you have passed a string representation of your cookie as its argument. ### Some Advice - You will need to include a string representation of your cookie in your exploit string. The string should consist of the eight hexadecimal digits (ordered from most to least significant) without a leading "`0x`." - Recall that a string is represented in C as a sequence of bytes followed by a byte with value `'\0'`. Type "`man ascii`" on any Linux machine to see the byte representations of the characters you need. - Your injected code should set register `rdi` to the *address* of this string. - When functions `hexmatch` and `strncmp` are called, they push data onto the stack, overwriting portions of memory that stored the buffer used by `getbuf`. As a result, you will need to be careful where you place the string representation of your cookie. # Part II: Return-Oriented Programming Performing code-injection attacks on program `rtarget` is different than for `ctarget`, because it uses two techniques to thwart such attacks: - It uses randomization so that the stack positions differ from one run to another. This makes it impossible to determine where your injected code will be located. - It marks the section of memory holding the stack as non-executable, so even if you could set the program counter to the start of your injected code, the program would fail with a segmentation fault. Fortunately, you can use *return-oriented programming* (ROP) [#Roemer2012, #Schwartz2011]. With ROP you identify byte sequences within an existing program that consist of one or more instructions followed by the instruction `ret` (`c3`). Such a segment is referred to as a *gadget*. Figure [rop] illustrates how the stack can be set up to execute a sequence of $n$ gadgets. Each gadget consists of a series of instruction bytes, with the final one being `0xc3`, encoding the `ret` instruction. When the program executes a `ret` instruction starting with this configuration, it will initiate a chain of gadget executions, with the `ret` instruction at the end of each gadget causing the program to jump to the beginning of the next. ![Figure [rop]: Setting up sequence of gadgets for execution. Byte value `0xc3` encodes the `ret` instruction.](ROPFigure.png) A gadget can make use of code corresponding to assembly-language statements generated by the compiler. In practice, there may be some useful gadgets of this form, but not enough to implement many important operations. For example, it is highly unlikely that a compiled function would have "`pop rdi`" as its last instruction before `ret`. Fortunately, with a byte-oriented instruction set, such as x86-64, a gadget can often be found by extracting patterns from other parts of the instruction byte sequence. For example, one version of `rtarget` contains code generated for the following C function: ~~~c void setval_210(unsigned *p) { *p = 3347663060U; } ~~~ The chances of this function being useful for attacking a system seem pretty slim. But, the disassembled machine code for this function shows an interesting byte sequence: ~~~text 0000000000400f15 : 400f15: c7 07 d4 48 89 c7 mov [rdi], 0xc78948d4 400f1b: c3 ret ~~~ The byte sequence `48 89 c7` represents part of the value `3347663060U`, but it also encodes the instruction "`mov rax, rdi`". (See Table [mov64] for the encodings of useful `mov` instructions.) This sequence is followed by byte value `c3`, which encodes the `ret` instruction. The function starts at address `0x400f15`, and the sequence starts on the fourth byte of the function. Thus, this code contains a gadget, having a starting address of `0x400f18`, that will copy the 64-bit value in register `rax` to register `rdi`. Your code for `rtarget` contains a number of functions similar to the `setval_210` function shown above in a region we refer to as the *gadget farm*. Your job will be to identify useful gadgets in the gadget farm and use these to perform attacks similar to those you did in Phases 2 and 3. **Important:** The gadget farm is demarcated by functions `start_farm` and `end_farm` in your copy of `rtarget`. Do not attempt to construct gadgets from other portions of the program code. ## Phase 4 For Phase 4, you will repeat the attack of Phase 2, but do so on program `rtarget` using gadgets from your gadget farm. You can construct your solution using gadgets consisting of the following instruction types, and using only the first eight x86-64 registers (`rax`--`rdi`). - `mov`: The codes for these are shown in Table [mov64]. - `pop`: The codes for these are shown in Table [pop]. - `ret`: This instruction is encoded by the single byte `0xc3`. - `nop`: This instruction (pronounced "no op," which is short for "no operation") is encoded by the single byte `0x90`. Its only effect is to cause the program counter to be incremented by 1. |   | `rax` | `rcx` | `rdx` | `rbx` | `rsp` | `rbp` | `rsi` | `rdi` | | ------ | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- | | `rax` | 48 89 c0 | 48 89 c8 | 48 89 d0 | 48 89 d8 | 48 89 e0 | 48 89 e8 | 48 89 f0 | 48 89 f8 | | `rcx` | 48 89 c1 | 48 89 c9 | 48 89 d1 | 48 89 d9 | 48 89 e1 | 48 89 e9 | 48 89 f1 | 48 89 f9 | | `rdx` | 48 89 c2 | 48 89 ca | 48 89 d2 | 48 89 da | 48 89 e2 | 48 89 ea | 48 89 f2 | 48 89 fa | | `rbx` | 48 89 c3 | 48 89 cb | 48 89 d3 | 48 89 db | 48 89 e3 | 48 89 eb | 48 89 f3 | 48 89 fb | | `rsp` | 48 89 c4 | 48 89 cc | 48 89 d4 | 48 89 dc | 48 89 e4 | 48 89 ec | 48 89 f4 | 48 89 fc | | `rbp` | 48 89 c5 | 48 89 cd | 48 89 d5 | 48 89 dd | 48 89 e5 | 48 89 ed | 48 89 f5 | 48 89 fd | | `rsi` | 48 89 c6 | 48 89 ce | 48 89 d6 | 48 89 de | 48 89 e6 | 48 89 ee | 48 89 f6 | 48 89 fe | | `rdi` | 48 89 c7 | 48 89 cf | 48 89 d7 | 48 89 df | 48 89 e7 | 48 89 ef | 48 89 f7 | 48 89 ff | [Table [mov64]: Byte-code encodings for the "`mov DEST, SRC`" instruction. `DEST` shown in the first column.] | `rax` | `rcx` | `rdx` | `rbx` | `rsp` | `rbp` | `rsi` | `rdi` | | ----- | ----- | ----- | ----- | ----- | ----- | ----- | ----- | | `58` | `59` | `5a` | `5b` | `5c` | `5d` | `5e` | `5f` | [Table [pop]: Byte-code encodings for the "`pop DEST`" instruction.] ### Some Advice - All the gadgets you need can be found in the region of the code for `rtarget` demarcated by the functions `start_farm` and `end_farm`. - You can complete this attack with just two gadgets. - When a gadget uses a `pop` instruction, it will pop data from the stack. As a result, your exploit string will contain a combination of gadget addresses and data. ## Phase 5 (Optional) Phase 5 asks you to complete an ROP attack on `rtarget` to invoke function `touch3` with a pointer to a string representation of your cookie. In addition to the gadgets used in Phase 4, you can also use 32-bit `mov` instructions, as shown in Table [mov32]. The byte sequences in this part of the farm also contain 2-byte instructions that serve as *functional nops*, i.e., they do not change any register or memory values. These include instructions, shown in Table [nop], such as that operate on the low-order bytes of some of the registers but do not change their values. |   | `eax` | `ecx` | `edx` | `ebx` | `esp` | `ebp` | `esi` | `edi` | | ------ | ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | | `eax` | `89 c0` | `89 c8` | `89 d0` | `89 d8` | `89 e0` | `89 e8` | `89 f0` | `89 f8` | | `ecx` | `89 c1` | `89 c9` | `89 d1` | `89 d9` | `89 e1` | `89 e9` | `89 f1` | `89 f9` | | `edx` | `89 c2` | `89 ca` | `89 d2` | `89 da` | `89 e2` | `89 ea` | `89 f2` | `89 fa` | | `ebx` | `89 c3` | `89 cb` | `89 d3` | `89 db` | `89 e3` | `89 eb` | `89 f3` | `89 fb` | | `esp` | `89 c4` | `89 cc` | `89 d4` | `89 dc` | `89 e4` | `89 ec` | `89 f4` | `89 fc` | | `ebp` | `89 c5` | `89 cd` | `89 d5` | `89 dd` | `89 e5` | `89 ed` | `89 f5` | `89 fd` | | `esi` | `89 c6` | `89 ce` | `89 d6` | `89 de` | `89 e6` | `89 ee` | `89 f6` | `89 fe` | | `edi` | `89 c7` | `89 cf` | `89 d7` | `89 df` | `89 e7` | `89 ef` | `89 f7` | `89 ff` | [Table [mov32]: Byte-code encodings of `mov` instructions with 32-bit operands] | Instruction | `al` | `cl` | `dl` | `bl` | | ----------- | ------- | ------- | ------- | ------- | | `and R, R` | `20 c0` | `20 c9` | `20 d2` | `20 db` | | `or R, R` | `08 c0` | `08 c9` | `08 d2` | `08 db` | | `cmp R, R` | `38 c0` | `38 c9` | `38 d2` | `38 db` | | `test R, R` | `84 c0` | `84 c9` | `84 d2` | `84 db` | [Table [nop]: Byte-code encodings of 2-byte functional `nop` instructions] # Using hex2raw `Hex2raw` takes as input a *hex-formatted* string. In this format, each byte value is represented by two hex digits. For example, the string "`012345`" could be entered in hex format as "`30 31 32 33 34 35 00`." (Recall that the ASCII code for decimal digit $x$ is `0x3`$x$, and that the end of a string is indicated by a null byte.) The hex characters you pass to `hex2raw` should be separated by whitespace (blanks or newlines). We recommend separating different parts of your exploit string with newlines while you are working on it. `hex2raw` supports C-style block comments, so you can mark off sections of your exploit string. For example: ~~~text 48 c7 c1 f0 11 40 00 /* mov rcx, 0x40011f0 */ ~~~ Be sure to leave space around both the starting and ending comment strings ("`/*`", "`*/`"), so that the comments will be properly ignored. If you generate a hex-formatted exploit string in the file `exploit.txt`, you can apply the raw string to `ctarget` or `rtarget` in several different ways: 1. You can set up a series of pipes to pass the string through `hex2raw`. ~~~bash $ cat exploit.txt | ./hex2raw | ./ctarget ~~~ 2. You can store the raw string in a file and use I/O redirection: ~~~bash $ ./hex2raw < exploit.txt > exploit-raw.txt $ ./ctarget < exploit-raw.txt ~~~ This approach can also be used when running from within gdb: ~~~bash $ gdb ctarget (gdb) run < exploit-raw.txt ~~~ 3. You can store the raw string in a file and provide the file name as a command-line argument: ~~~bash $ ./hex2raw < exploit.txt > exploit-raw.txt $ ./ctarget -i exploit-raw.txt ~~~ This approach also can be used when running from within gdb. # Generating Byte Codes Using `gcc` as an assembler and `objdump` as a disassembler makes it convenient to generate the byte codes for instruction sequences. For example, suppose you write a file `example.s` containing the following assembly code: ~~~nasm .intel_syntax noprefix push 0xabcdef add rax, 17 mov edx, eax ~~~ The code can contain a mixture of instructions and data. You can now assemble and disassemble this file: ~~~bash gcc -masm=intel -c example.s objdump --disassemble --disassembler-options=intel example.o ~~~ The output of the above command is: ~~~text example.o: file format mach-o 64-bit x86-64 Disassembly of section __TEXT,__text: 0000000000000000 <__text>: 0: 68 ef cd ab 00 push 11259375 5: 48 83 c0 11 add rax, 17 9: 89 c2 mov edx, eax ~~~ The lines at the bottom show the machine code generated from the assembly language instructions. Each line has a hexadecimal number on the left indicating the instruction's starting address (starting with 0), while the hex digits after the ':' character indicate the byte codes for the instruction. Thus, we can see that the instruction `push 0xabcdef` has hex-formatted byte code `68 ef cd ab 00`. From this file, you can get the byte sequence for the sequence of instructions: ~~~text 68 ef cd ab 00 48 83 c0 11 89 c2 ~~~ This string can then be passed through `hex2raw` to generate an input string for the target programs. Alternatively, you can save the output and omit extraneous values and to contain C-style comments for readability, yielding: ~~~text 68 ef cd ab 00 /* push 11259375 */ 48 83 c0 11 /* add rax, 17 */ 89 c2 /* mov edx, eax */ ~~~ This is also a valid input you can pass through `hex2raw` before sending to one of the target programs. # Using GDB
# Submitting Your Assignment You will submit your responses on gradescope. **Only one partner should submit.** The submitter will add the other partner through the gradescope interface. - [Submitting an Assignment](https://help.gradescope.com/article/ccbpppziu9-student-submit-work) - [Adding Group Members](https://help.gradescope.com/article/m5qz2xsnjy-student-add-group-members) - [gradescope Student Help Center](https://help.gradescope.com/category/cyk4ij2dwi-student-workflow) # Bibliography [#Roemer2012]: R. Roemer, E. Buchanan, H. Shacham, and S. Savage. Return-oriented programming: Systems, lan- guages, and applications. ACM Transactions on Information System Security, 15(1):2:1–2:34, March 2012. [#Schwartz2011]: E. J. Schwartz, T. Avgerinos, and D. Brumley. Q: Exploit hardening made easy. In USENIX Security Symposium, 2011.