Hidden Program (Warmup)

Exploitation Challenge, Pwn2win 2017

Written October 23rd, 2017

Hidden Program

This was quite an elegant little challenge. Nothing fancy: no ROP, no web stuff, just abusing C's type casting. This challenge was a warm-up, and it was a nice change of pace.

The code for this challenge can be found in the downloads link above.

A Short Misdirection

The challenge requires you to connect to a remote service, and play a "game". The game goes like this:

It first asks you to enter a number, a string, and a second string. If string[number] is the same as the second string, you win. However, we don't want to win this game; we want the flag!

Taking a look at the code, we see the following struct:

Later in the code, we see that the flag is placed into the flag member of this struct. Perfect, how do we get it?

Before we dive into that, let's think about what the struct looks like on the stack. Assuming the stack starts at 0, we have:

With the stack in our mind, there is a piece of code we could use to access the flag:

In the code above, p1.n is controlled by us; if we enter a negative value, we can point back at the flag string! We need to point backwards by SHRT_MAX + 1, or 32768 (0x8000). Unfortunately, the code takes the absolute value of want we entered, and doesn't allow values greater than SHRT_MAX:

We can enter any negative value we want, but it will get converted back to a positive number. However, if we enter -32768, the value we want, it stays negative, and the flag prints! We have solved the challenge! But why did this work?

Casting

The key is in the abs function. Note that n is an integer in the struct.

p1.n = (short)abs((short)p1.n);

The following is executed as such:

  1. p1.n is cast to a short

  2. abs() is called; abs takes and returns an integer

  3. The return value of abs() is converted to a short

Execution for -32768:

  1. -32768(0xFFFF8000) becomes -32768(0x8000), as this is in short range

  2. -32768(0x8000) becomes 32768(0x00008000)

  3. 32768 is cast to a short. 0x00008000 becomes 0x8000. This is -32768!

Thus, our negative value has squeezed past the filter, and we can access the flag!