CTF-1

Preliminaries

CTF-1 is specifically designed to run on the department machines. You are expected to do all the development on that particular environment, which is also what we will be using for grading. Do not run CTF-1 on your personal desktop, laptop, VM, or any other non-standard setting -- you are free to do so, if you insist, or know what you are doing, but we are not going to provide any support in such cases. If you are connecting remotely, use ssh(1) and follow the instructions provided by tstaff.

Copy ctf-1.tar.gz to your home directory and extract it; you should get ctf-1/, which, in turn, should contain the following files: Makefile, exp0.c, exp1.c, vcat0, and vcat1. Make sure that no one else has access to ctf-1/ (e.g., chmod go-rx ctf-1), type cd ctf-1, and start hacking!

vcat0

vcat0 is a vulnerable program that reads from stdin(3) (standard input) and writes to stdout(3) (standard output) -- it is roughly equivalent to executing cat -. Note that you are not given the source code of vcat0.

You may run vcat0 by typing make vcat0_run. This make(1) directive wraps the execution of vcat0 with setarch i686 -R -3, which emulates a 32-bit x86 environment (i686), without support for address space layout randomization (-R), and with a proper 3GB user space (-3). Recall that the department machines are 64-bit; hence, do not invoke vcat0 directly, like ./vcat0, because you will end up solving a different assignment :-). Similarly, if you need to execute vcat0 under gdb(1), type make vcat0_dbg. More importantly, to aid the exploitation process, we provide exp0 (exp0.c). This binary dumps in stdout(3) the contents of a particular payload (i.e., variable unsigned char payload[] in exp0.c). By running make vcat0_exp, make(1) will effectively execute ./exp0 | ./vcat0, under setarch i686 -R -3, thereby allowing you to feed vcat0 with the exact contents of unsigned char payload[]. Lastly, if you wish to execute ./exp0 | ./vcat0 under gdb(1), and attach the debugger to vcat0, run make vcat0_dbg and commence execution as follows: r < <(./exp0).

You have been told that vcat0 contains a stack-based buffer overflow.

  1. Warm-up (5 points)
    • Disassemble vcat0 and provide a list of all its executable functions, along with their addresses. For example: 0xdeadbeef main, 0xdeadc0de foo, 0x0defaced bar, 0x0badf00d xyzzy, etc.
    • Replace the payload (i.e., variable unsigned char payload[] in exp0.c) with 'X'...'X', until you get a segfault on vcat0. (In other words, try "X", "XX", ..., until vcat0 crashes). What is the maximum size of the payload (in bytes) that does not crash vcat0? (That specific payload plus a single 'X' should trigger a segfault.)
  2. Flag 1 (10 points)
    • Smash the stack of vcat0 and redirect execution to function flag1(void). What should be the value of payload (i.e., variable unsigned char payload[] in exp0.c) for getting the flag?
  3. Flag 2 (10 points)
    • Smash the stack of vcat0 and redirect execution to function flag2(int). Note that this function takes as argument an integer, and you need to invoke is as follows: flag2(0xdeadbeef). What should be the value of payload (i.e., variable unsigned char payload[] in exp0.c) for getting the flag?
  4. Flag 3 (15 points)
    • Smash the stack of vcat0 and redirect execution to function flag3(char *). Note that this function takes as argument a string, and you need to invoke is as follows: flag3("pwn3d"). What should be the value of payload (i.e., variable unsigned char payload[] in exp0.c) for getting the flag?

vcat1

Similarly to vcat0, vcat1 is a vulnerable program that reads from stdin(3) and writes to stdout(3). Again, you are not given the source code of vcat1.

You may run vcat1 by typing make vcat1_run. Also, if you need to execute vcat1 under gdb(1), type make vcat1_dbg. To aid the exploitation process, we provide exp1 (exp1.c), which dumps in stdout(3) the contents of a particular payload (i.e., variable unsigned char payload[] in exp1.c). By running make vcat1_exp, make(1) will effectively execute ./exp1 | ./vcat1, allowing you to feed vcat1 with the exact contents of unsigned char payload[]. Lastly, if you wish to execute ./exp1 | ./vcat1 under gdb(1), and attach the debugger to vcat1, run make vcat1_dbg and commence execution as follows: r < <(./exp1).

You have been told that vcat1 contains a stack-based buffer overflow.

  1. Flag 4 (10 points)
    • The payload variable (unsigned char payload[] in exp1.c) already contains a proper shellcode. Smash the stack of vcat1 and redirect execution to the given shellcode. What should be the value of payload (i.e., variable unsigned char payload[] in exp1.c) for getting the flag?
  2. Flag 4+ (or 5) (20 points)
    • The payload variable (unsigned char payload[] in exp1.c) contains the shellcode at its beginning. Smash the stack of vcat1 and redirect execution to the given shellcode using the NOP sled technique. Specifically, move the shellcode closer to the saved return address (preferably right below it), and replace the beginning of the payload with NOP instructions (up to the shellcode). Lastly, transfer control to the shellcode by jumping in the middle of the payload. What should be the value of payload (i.e., variable unsigned char payload[] in exp1.c) for getting the flag?
  3. Flag 4++ (or 6) (20 points)
    • The payload variable (unsigned char payload[] in exp1.c) contains a shellcode at its beginning. Smash the stack of vcat1 and redirect execution to the given shellcode using the jmp *%esp technique. That is, move the shellcode right above the saved return address, and overwrite the return address with the address of a jmp *%esp gadget, located in the .text section of vcat1. What should be the value of payload (i.e., variable unsigned char payload[] in exp1.c) for getting the flag?
    • Hint You need to remove the first instruction of the shellcode (add $0x40, %esp) to get this flag. Why?
  4. Flag 7 (10 points)
    • The payload (unsigned char payload[] in exp1.c) contains a shellcode that includes NULL bytes (0x00). Construct an equivalent shellcode that does not have NULL bytes in it. What is the value of this NULL-free payload (i.e., variable unsigned char payload[] in exp1.c)?

Handin Instructions

  1. Copy ctf-1.extras.tar.gz to ctf-1/ (i.e., the directory that contains CTF-1) and extract it; you should get the following additional files: mget0, mget1, and README (and a new Makefile). Note that it is important to extract ctf-1.extras.tar.gz inside ctf-1/.
  2. Run make mget0_run, make mget0_dbg (and commence execution by typing r), make mget1_run, and make mget1_dbg (start execution by typing r), and record the four (4) hexadecimal numbers printed in stdout(3).
  3. Your write-up template is README. First, edit section 0xf (whoami), and fill ‘Name’, ‘mget0_run’, ‘mget0_dbg’, ‘mget1_run’, and ‘mget1_dbg’, with your name and the four hexadecimal numbers your got by running the corresponding make(1) directives (step 2 above). Next, fill every other section (0x0 -- 0x7) with the respective answer(s). If you cannot capture a flag, you can still get partial credit by providing a brief description of your attack plan (e.g., what exactly you plan on corrupting, with what value(s), and why; or what you plan on injecting, where, and why), the actions you took for implementing it (i.e., partial or incomplete payload values, memory dumps, and gdb(1) excerpts), as well as your findings.
  4. Run /course/cs1951h/bin/cs1951h_handin 0x1 from within ctf-1/ to submit your write-up -- you may want to alias that command for multiple submissions (or future write-ups). You can resubmit as many times as you like, prior to the deadline, but note that your old submission(s) will be overwritten by the latest one.

Collaboration Policy

You should not discuss CTF-1 with anyone except the CSCI 1951H course staff. You may consult ‘outside sources of information’, but you must cite them; and you may rely on such sources only for concepts, not for solutions to problems -- the write-up must be entirely your own work.