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 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.o, vcat1.o, hlp.o, trnd, magic.so, and README. Make sure that (1) no one else has access to ctf-1/ (e.g., chmod go-rx ctf-1) and (2) trnd can be executed (e.g., chmod u+x trnd). 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 execute vcat0 by typing make vcat0_run. This make(1) directive wraps the execution of vcat0 with setarch i686 -3 -R, which emulates a 32-bit x86 environment (i686), with a proper 3GB user space (-3) and without support for address space layout randomization (-R). 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 -3 -R, 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).

vcat0 contains a stack-based buffer overflow.

  1. Flag 1 (5 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?
  2. 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?
  3. 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?
  • Extra Credit (5 points)
    • Make the payload for flag 3 stack-independent. (The payload should not include absolute stack addresses.)

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).

vcat1 contains a stack-based buffer overflow.

  1. Flag 4 (15 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?
  • Extra Credit (5 points)
    • Make the payload for flag 4 stack-independent. (The payload should not include absolute stack addresses.) Note that you may not use a jmp *%esp gadget.
  1. Flag 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?
  2. Flag 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. 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 add $0x40, %esp instruction of the shellcode to get this flag.
  3. Flag 7 (15 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)?
    • Note When submitting this flag (see below), you should submit only the NULL-free shellcode. You will need to incorporate your shellcode into a full payload (using the methods from flag 4, flag 5, and flag 6 above) in order to test it, but the flag7 file should contain only shellcode; not an end-to-end payload that captures a particular flag.

Handin Instructions

  1. Save the payload(s) of your functioning exploit(s) by executing ./exp0 > flag# or ./exp1 > flag#, where # is the respective flag number (e.g., to dump the payload for flag 5, run ./exp1 > flag5, once make vcat1_exp succeeds). Dump all the seven payloads in separate files, named flag1, flag2, etc. You can double-check that you have correctly dumped a functioning payload (e.g., you have not accidentally corrupted it, or overwritten it, with something else) by running make vcat#_run < flag# (or cat flag# | make vcat#_run), where # is the respective flag number. Note that for flag 7, the payload file flag7 should only contain the NULL-free shellcode; not an end-to-end payload that captures flag 4, flag 5, or flag 6. If a payload file is missing, we will assume that your exploit does not work properly and read your README file (see below) for partial credit. You do not need to submit separate payloads for the extra credit; if the respective payload is stack-independent you will get the extra points automatically.
  2. Your write-up template is README. First, edit section 0x0 (whoami), and fill ‘Name’, ‘Login’, and ‘Hostname’, with your (full) name, CS login, and hostname(1) of the machine that you tested all your exploits. Next, fill every other section (0x10x7) with the corresponding 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 values, 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.
  3. Run /course/cs1650/bin/cs1650_handin 0x1 from within ctf-1/ to submit your hand-in—you may want to alias that command for multiple submissions (or future hand-ins). 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 1650 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 hand-in must be entirely your own work.