08. Stonks - PicoCTF 2021 Writeup

08. Stonks - PicoCTF 2021 Writeup

I wouldn't believe you if you told me it's unsecure!

ยท

3 min read

Category: Binary Exploitation | Author: Madstacks | Points: 20

Hello All ๐Ÿ‘‹,

This can seem a really tight one. First off, we'll download the given file. Turns out, it's c code. Then we will run the netcat command given. Interestingly enough, we get some replies back, and the replies suggest that the same code is running on the other side. This is interesting because now we can analyse the code and see whether there are any bugs in the code that we can take advantage of.

If we go through the code, one line of code within the buy_stonks() function sticks out from the rest :

char api_buf[FLAG_BUFFER];
FILE *f = fopen("api","r");

'FLAG_BUFFER' sounds like the flag we're looking for, and this is loaded from a file called 'api'. So this might be what we're looking for. But how do we get it from the other side?

Looking further, we see that it loads some more data, and then there's something interesting;

printf("What is your API token?\n");
scanf("%300s", user_buf);
printf("Buying stonks with token:\n");
printf(user_buf);

The application asks the user to enter the API and it prints it out immediately in the next line. The thing with C is that we can use strings to access variables. So if instead of sending a regular set of characters, we send '%p'; then we will get the data on the last pointer of the stack. And since the application loads the Flag to the stack, this means that if we print out enough '%p's, we can end up printing all of the characters of the flag as well in between.

To test it out, we will create an input file as follows:

1
%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.

The reason for including dots is to differentiate where each 32-bit hex values end. Now instead of running Netcat with just the given command, we will also input this input file to it.

nc mercury.picoctf.net 20195 < input

And interestingly enough, we get a reply with a bunch of 32-bit hex values. Now we know that a flag is of the form 'picoCTF{}', so whatever data we have, what we need is between the Hex codes of 'p' and '}'. If we quickly refer to an ASCII table, we see that 'p' is 70 and '}' is 7d.

Now, something to note is that in a 32-bit hex value, characters are stored in four chunks. Even though in reality, this data resides in binary, for simplicity we consider it in hexadecimal. And the last chunk of each value set is the first character of that set.

So instead of the first two numbers of each hex value we got, we refer to the last ones. If you look carefully, you will find '70' and '7d' in there. This means that we just found the first and last 32-bit hex value that we're interested in.

Now we will write the following Python code to extract the characters from this data. Make sure to remove any unnecessary replies such as '.(nil)'.:

hex_string = "".replace(".0x", "") # The hex string you got
split_bytes = [hex_string[i:i+8] for i in range(0, len(hex_string), 8)]
rotated = ""

for split_byte in split_bytes:
    rotated += split_byte[6:8] + split_byte[4:6] + split_byte[2:4] + split_byte[0:2]

chars = [rotated[i:i+2] for i in range(0, len(rotated), 2)]
decoded = ""

for char in chars:
    try:
        decoded += bytes.fromhex(char).decode("ASCII")
    except:
        decoded += ""

print(decoded)

And finally, we have the flag.

ย