CTF-2

Preliminaries

CTF-2 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-2 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-2.tar.gz to your home directory and extract it; you should get ctf-2/, which, in turn, should contain the following files: Makefile, exp2.c, exp3.c, vcat2.o, vcat3.o, hlp.o, trnd, magic.so, magic.txt, and README. Make sure that (1) no one else has access to ctf-2/ (e.g., chmod go-rx ctf-2) and (2) trnd can be executed (e.g., chmod u+x trnd). Type cd ctf-2 and start hacking!

vcat2

vcat is back! vcat2 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 vcat2.

Similarly to CTF-1, you may run vcat2 by typing make vcat2_run. This make(1) directive wraps the execution of vcat2 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 vcat2 directly, like ./vcat2, because you will end up solving a different assignment :-). Similarly, if you need to execute vcat2 under gdb(1), type make vcat2_dbg. More importantly, to aid the exploitation process, we provide exp2 (exp2.c). This binary dumps in stdout(3) the contents of a particular payload (i.e., variable unsigned char payload[] in exp2.c). By running make vcat2_exp, make(1) will effectively execute ./exp2 | ./vcat2, under setarch i686 -3 -R, thereby allowing you to feed vcat2 with the exact contents of unsigned char payload[]. Lastly, if you wish to execute ./exp2 | ./vcat2 under gdb(1), and attach the debugger to vcat2, run make vcat2_dbg and commence execution as follows: r < <(./exp2).

vcat2 contains a stack-based buffer overflow, and exp2 already exploits this vulnerability using the jmp *%esp technique. In particular, exp2 smashes the stack of vcat2, overwrites a (saved) return address with the address of a jmp *%esp gadget (located in the .text section of vcat2), and effectively transfers the control right above the overwritten return address on the stack. The payload variable (unsigned char payload[] in exp2.c) contains a template that transfers control to a “dummy” shellcode that consists of a single trap instruction (int 3), thereby raising a SIGTRAP signal and terminating the execution of vcat2.

  1. Flag 1 (10 points)
    • Replace int 3 (0xcc) with a proper, NULL-free shellcode for invoking the following (chain of) system calls: kill(getpid(), SIGUSR1). More specifically, first invoke getpid(), to get the process identifier (pid) of vcat2, and then proceed to call kill(), with pid and SIGUSR1 as first and second argument, respectively. What should be the value of payload (i.e., variable unsigned char payload[] in exp2.c) for getting the flag?
  2. Flag 2 (30 points)
    • Replace int 3 (0xcc) with a proper, NULL-free shellcode for invoking the following (chains of) system calls: write(open("magic.txt", O_WRONLY, 0), "xyzzy", 5); kill(getpid(), SIGUSR2). Start by invoking open(), for opening the file magic.txt, in write-only mode, and getting the respective file descriptor (fd). Next, proceed to call write(), using the fd you got from the previous call to open(), for writing the word “xyzzy” in magic.txt. Lastly, repeat the chain of system calls for flag 1 (kill(getpid(), SIGUSR2)), but this time invoke kill() with SIGUSR2. What should be the value of payload (i.e., variable unsigned char payload[] in exp2.c) for getting the flag?

vcat3

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

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

vcat3 contains a stack-based buffer overflow, but it is hardened against code injection with executable space protection. exp3 contains a template payload (unsigned char payload[] in exp3.c) that smashes the stack of vcat3 and transfers control to address 0xdeadbeef.

  1. Flag 3 (10 points)
    • Modify the payload and invoke raise(SIGUSR1), using the return-to-libc (ret2libc) technique. What should be the value of payload (i.e., variable unsigned char payload[] in exp3.c) for getting the flag?
  2. Flag 4 (20 points)
    • Modify the payload and invoke the following sequence of libc routines: system("echo -n xyzzy! > magic.txt"); raise(SIGUSR2); for this flag you have to leverage the ret2libc chaining technique. What should be the value of payload (i.e., variable unsigned char payload[] in exp3.c) for getting the flag?
  3. Flag 5 (30 points)
    • Modify the payload and invoke the following sequence of libc routines: open("magic.txt", O_WRONLY, 0); write(3, "!xyzzy", 6); raise(SIGUSR2); for this flag you have to leverage both the ret2libc chaining and %esp lifting techniques. What should be the value of payload (i.e., variable unsigned char payload[] in exp3.c) for getting the flag?
  • Hint
    • SIGUSR1 = 0x0a, SIGUSR2 = 0x0c, and O_WRONLY = 0x01.

Handin Instructions

  1. Save the payload(s) of your functioning exploit(s) by executing ./exp2 > flag# or ./exp3 > flag#, where # is the respective flag number (e.g., to dump the payload for flag 5, run ./exp3 > flag5, once make vcat3_exp succeeds). Dump all the five functioning payloads in separate files, named flag1, flag2, etc. 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 alphanumeric you will get the extra points automatically.
  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 (0x10x5) 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 0x2 from within ctf-2/ 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-2 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.