CTF-4

Preliminaries

CTF-4 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-4 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-4.tar.gz to your home directory and extract it; you should get ctf-4/, which, in turn, should contain the following files: Makefile, exp6.c, vcat6, and README. Make sure that no one else has access to ctf-4/ (e.g., chmod go-rx ctf-4), type cd ctf-4 and start hacking!

vcat6

Yes, it's the usual “suspect”: vcat :-). vcat6 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 -. As always, you are not given the source code of vcat6.

Similarly to CTF-1, CTF-2, and CTF-3, you may run vcat6 by typing make vcat6_run. This make(1) directive wraps the execution of vcat6 with setarch i686 -3, which emulates a 32-bit x86 environment (i686) with a proper 3GB user space (-3). Recall that the department machines are 64-bit; hence, do not invoke vcat6 directly, like ./vcat6, because you will end up solving a different assignment :-). Also, if you need to execute vcat6 under gdb(1), type make vcat6_dbg. To aid the exploitation process, we provide exp6 (exp6.c), which: (a) dumps in stdout(3) the value of macro FMT_STR and the contents of variable unsigned char payload[]; and (b) reads from stdin(3) two hexadecimal values as two separate, consecutive string literals (e.g., "0x4100feeb""0xb700cafe"). By running make vcat6_exp, make(1) will effectively execute ./exp6 < fifo | ./vcat6 > fifo, allowing you to feed vcat6 with the exact contents of FMT_STR and unsigned char payload[], and exp6 with the output of vcat6. Lastly, if you wish to execute ./exp6 | ./vcat6 under gdb(1), and attach the debugger to vcat6, run make vcat6_dbg and commence execution as follows: r < <(sleep 1; ./exp6).

vcat6 contains both a stack-based buffer overflow and a format string vulnerability. However, it is hardened, against both code injection and code reuse, with executable space protection and full address space layout randomization; vcat6 is a position-independent executable (PIE). exp6 contains: (1) a format string template (FMT_STR) for leaking two 4-byte hexadecimal values from the stack of vcat6; and (2) a template payload (unsigned char payload[]) that overwrites a function pointer in the stack of vcat6 and transfers control to address 0xdeadbeef. (Note that the stack-based buffer overflow in vcat6 is bounded; you can only corrupt/overwrite a function pointer adjacent to the vulnerable buffer.)

  • Warm-up
    • Find the relative addresses of the following symbols (variables): mgk1, mgk2, rnd1, and rnd2.
    • Replace the provided format string template with one that leaks two addresses (4 bytes each) stored in the stack of vcat6: (1) an address belonging to the .text section of vcat6 (e.g., a saved return address); and (b) an address belonging to the .text section of libc-2.28.so. The leaked output should consist of two separate, consecutive string literals: i.e., "0x4100feeb""0xb700cafe". What should be the value of the format string template (i.e., macro FMT_STR in exp6.c) to achieve that?
  1. Flag 1 (10 points)
    • Replace the provided payload with a (dynamically composed) JIT-ROP payload that invokes flag1(void). What should be the value of payload (i.e., variable unsigned char payload[] in exp6.c) for getting the flag? (You must modify exp6.c in order to dynamically compose the required payload.)
  2. Flag 2 (25 points)
    • Replace the provided payload with a (dynamically composed) JIT-ROP payload that: (a) stores the value 0x0defaced (4 bytes) to mgk1; and (b) invokes flag2(void). What should be the value of payload (i.e., variable unsigned char payload[] in exp6.c) for getting the flag? (You must modify exp6.c in order to dynamically compose the required payload.)
  3. Flag 3 (30 points)
    • Replace the provided payload with a (dynamically composed) JIT-ROP payload that: (a) reads the values of rnd1 and rnd2 (4 bytes each); (b) sets mgk2 = rnd1 + rnd2; and (c) invokes flag3(void). What should be the value of payload (i.e., variable unsigned char payload[] in exp6.c) for getting the flag? (You must modify exp6.c in order to dynamically compose the required payload.)
  4. Flag 4 (35 points)
    • Replace the provided payload with a (dynamically composed) JIT-ROP payload that: (a) reads the values of rnd1 and rnd2 (4 bytes each); (b) sets mgk2 = rnd1 + rnd2 - 1; and (c) restores the execution of vcat6 right after the control-flow hijacking point (i.e., right after the dereference of the controlled function pointer). What should be the value of payload (i.e., variable unsigned char payload[] in exp6.c) for getting the flag? (You must modify exp6.c in order to dynamically compose the required payload.)
  • Hints
    • make vcat6_dbg executes vcat6 under gdb(1), but without feeding exp6 with the output of vcat6. Therefore, the leaked addresses from the stack of vcat6 will be printed in stdout(3), allowing you to experiment with different format string templates until you complete Warm-up. Once you have successfully leaked the addresses belonging to the .text section of vcat6 and libc-2.28.so, you can manually feed them to exp6, by typing them in stdin(3), which, in turn, will compute the base address of vcat6 and libc-2.28.so (see variables unsigned long baddr, unsigned long laddr, and the macros BIN_BASE_OFF and LIBC_BASE_OFF in exp6.c). Armed with that information, you can then dynamically compute the absolute address of each gadget, or symbol, in vcat6 or libc-2.28.so, and attempt the respective flags.
    • To compute the base address of vcat6 and libc-2.28.so, you have to set BIN_BASE_OFF and LIBC_BASE_OFF accordingly.
    • You may have to combine gadgets from both vcat6 and libc-2.28.so to successfully capture flag 2, flag 3, and flag 4.
    • To successfully capture flag 2, flag 3, or flag 4, you must use the stack pivoting technique. Also, for flag 4, you may have to perform stack pivoting twice; i.e., first pivot the stack pointer for setting mgk2 = rnd1 + rnd2 - 1, and then un-pivot it for reliably continuing the execution of vcat6.
  • Resources
    • You may find readelf(1), objdump(1), nm(1), or even gdb(1) useful for Warm-up.
    • Use ropshell to search for gadgets in vcat6 and libc-2.28.so. (Note that someone else may have already uploaded the binaries; do not upload them multiple times. Also, do not perform the analysis in RAW mode.)

Handin Instructions

  1. Save your functioning exploit(s) for vcat6 as follows: exp6-flag1.c, ..., exp6-flag4.c. If an exploit file is missing, we will assume that your exploit does not work properly and read your README file (see below) for partial credit.
  2. Your write-up template is README. First, edit section 0xf (whoami), and fill ‘Name’, ‘Login’, and ‘Host’, with your (full) name, CS login, and hostname(1) of the machine that you tested all your exploits. Next, fill every other section (0x00x4) 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 0x4 from within ctf-4/ to submit your hand-in—you may want to alias that command for multiple submissions. 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-4 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.