0

So If I had this code:

int main() {
    char buff[20];
    int x = 0;
    gets(buff);
    if (x==1337) {
        print("Congrats");
    }
    printf("%d\n", x);
    return 0;
}

Knowing that this is written in C (not that it matters too much), how would one go about overflowing this char[] by exactly 1337? And also, I don't really understand the output I'm getting.. For example, if I run this code and input:

12345678901234567890a

The output is:

0

In fact, I have to overflow my char[] by an additional 8 characters past my array size before the data leaks into the value for X. I have no idea why this is, and would really like some help if somebody understand that.. However, it doesn't stop there.

If my input is:

1234567890123456789012345678aa

My output is:

24929

This throws me for quite a twirl.. Since I would've expected it to either overflow by the char value of a+a or maybe even a*a, alas it is neither. (the char value of a is 97).

So to sum it up, since I now it is probably confusing.. I would like to know how to overflow a buffer (in C) into an int, leaving the int a very specific value (in this case 1337). And in addition, if you could explain how these numbers are coming out, I would greatly appreciate it! By the way, it might help to mention the code is being executed on a Linux shell.

  • You're not printing the value of `x`, you're printing the ***pointer*** `"Wrong: " + x`. Adding an integer to a pointer give you another pointer. In fact, doing `"Wrong: " + x` is the same as doing `&("Wrong: "[x])` – Some programmer dude Nov 07 '15 at 21:00
  • Change the type of `x` to `unsigned int`, and change `print("Wrong: " + x)` (which *cannot possibly* be your actual code, but never mind) to `printf("Wrong: %08x\n", x)`. The output will now have a more obvious connection to the input. – zwol Nov 07 '15 at 21:00
  • I have to admit, I don't really use C ever. I have updated the question with the exact printf statement used in the code, does this satisfy the pointer mishap? –  Nov 07 '15 at 21:04
  • @zwol please read the code again, because I assure you I have changed the value of X (or at least I have changed the value being printed) if I overflow the buffer. –  Nov 07 '15 at 21:07
  • One problem here is that the data you overflow the buffer with is *characters*, and seeing them in an `int` in decimal form doesn't tell you in an easy way what characters is in `x`. Print it out as hexadecimal instead, and compare the single bytes of the integer with [an ASCII table](http://en.cppreference.com/w/cpp/language/ascii). That should tell you exactly which part of the input overwrote `x` as well as the byte order. Then you simply has to replace those bytes in the input with some characters that come out to `1337` in decimal (and don't forget the byte order!) – Some programmer dude Nov 07 '15 at 21:12
  • @JaredMassa If you're referring to what I wrote in the comment that I deleted, you misunderstood me: I'm not saying it can't be clobbering X *for you*, I'm saying it doesn't *for me* because my compiler does things differently. – zwol Nov 07 '15 at 21:20
  • @JaredMassa Yes, your update with "the exact printf statement used in the code" does clarify the "pointer mishap". It's very important, when asking questions like this, to show *the exact same program you are testing*, not some variation on it. – zwol Nov 07 '15 at 21:23
  • See [this answer](http://stackoverflow.com/a/33559967/1517864) to a similar question. I am not sure what platform you're on and how you compile your code. But it seems that you are somehow able to overflow and write to `x`. Try running it with a debugger and see what happens – jayant Nov 07 '15 at 21:24

1 Answers1

4

Since this is probably homework, rather than give you a direct answer, what I'm going to do is show you the C program that does what you thought your program would do, and how it behaves when fed over-length input.

#include <stdio.h>
int main(void)
{
  struct {
    char buff[20];
    volatile unsigned int x;
  } S;
  S.x = 0;
  gets(S.buff);
  if (S.x == 1337)
    puts("Congrats");
  else
    printf("Wrong: %08x\n", S.x);
  return 0;
}

The key difference is that I am forcing the compiler to lay out the stack frame a particular way. I am also printing the value of x in hexadecimal. This makes the output both more predictable, and easier to interpret.

$ printf 'xxxxxxxxxxxxxxxxxxxxABCD' | ./a.out
Wrong: 44434241

$ printf 'xxxxxxxxxxxxxxxxxxxxABC' | ./a.out
Wrong: 00434241

$ printf 'xxxxxxxxxxxxxxxxxxxxAB' | ./a.out
Wrong: 00004241

$ printf 'xxxxxxxxxxxxxxxxxxxxA' | ./a.out
Wrong: 00000041

Everything that confused you is caused by one or more of: the compiler not laying out the stack frame the way you expected, the ordering of bytes within an int not being what you expected, and the conversion from binary to decimal obscuring the data in RAM.

Exercise for you: Compile both my program and your original program in -S mode, which dumps out the generated assembly language. Read them side by side. Figure out what the differences mean. That should tell you what input (if any -- it might not be possible!) will get your program to print 'Congrats'.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • To clarify, this isn't homework, its a program I'm executing on someone else's shell. I was kinda hoping I wouldn't have to learn all about C to complete this task.. So if you wouldn't mind more depth it would be greatly appreciated. –  Nov 07 '15 at 21:32
  • 1
    @JaredMassa I'm sorry to say that you are going to have to learn about C, *and* about a bunch of low-level details that C hides from you. Read "[Smashing the Stack for Fun and Profit](http://insecure.org/stf/smashstack.html)," and make a list of all the places where you don't know what Aleph One is talking about. Research all those things. Repeat until you fully understand the entire article. You should then be able to answer your own question. – zwol Nov 09 '15 at 22:22