How can I invoke buffer overflow?
Asked Answered
E

5

35

I got a homework assignment asking me to invoke a function without explicitly calling it, using buffer overflow. The code is basically this:

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Though I'm not sure how to proceed. I thought about changing the return address for the program counter so that it'll proceed directly to the address of g(), but I'm not sure how to access it. Anyway, tips will be great.

Electrolyze answered 25/2, 2010 at 12:27 Comment(7)
4 upvotes for a homework question! The OP didn't even come up with the question... wow, some people are easily impressed.Unsay
@Lazarus, I upvoted your comment. Uh oh! :-)Howlyn
@Unsay the fact that it is a homework question has nothing to do with the fact that I find it interesting. I also upvoted it because I want to encourage interesting homework questions rather than the simple "I closed the file buffer and now when I try reading from the file it doesn't work. Why?" (In other words, I upvote the questions I don't know the answer to, but want to)Golanka
@Alok, LOL - They were all my own words... does that help salve your conscience? ;)Unsay
@Yacoby, I believe the purpose of the up-vote was to indicate a good question or question topic so I suppose your up-vote is perfectly valid. A homework question to me implies that either the requisite knowledge has already been taught and is being re-enforced or that the student is expected to derive the solution themselves from knowledge already imparted. Either way getting SO users to answer it for them is counter productive. If the OP needs help then I would think their teacher would be the first port of call, not SO.Unsay
Whoa, that's a hw question? I'm already loving your teacher :DRoid
@Andreas: That's for hard work, not ware. :)Wormwood
V
14

The basic idea is to alter the function's return address so that when the function returns is continues to execute at a new hacked address. As done by Nils in one of the answers, you can declare a piece of memory (usually array) and overflow it in such a way that the return address is overwritten as well.

I would suggest you to not blindly take any of the programs given here without actually understanding how they work. This article is very well written and you'll find it very useful:

A step-by-step on the buffer overflow vulnerablity

Vimineous answered 25/2, 2010 at 12:53 Comment(0)
O
13

That is compiler dependent, so no single answer can be given.

The following code will do what you want for gcc 4.4.1. Compile with optimizations disabled (important!)

#include <stdio.h>
#include <stdlib.h>

void g()
{
    printf("now inside g()!\n");
}


void f()
{   
  int i;
  void * buffer[1];
  printf("now inside f()!\n");

  // can only modify this section
  // cant call g(), maybe use g (pointer to function)

  // place the address of g all over the stack:
  for (i=0; i<10; i++)
     buffer[i] = (void*) g;

  // and goodbye..
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Output:

nils@doofnase:~$ gcc overflow.c
nils@doofnase:~$ ./a.out
now inside f()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
now inside g()!
Segmentation fault
Obau answered 25/2, 2010 at 12:39 Comment(6)
I'm using gcc 4.4.1, and not sure how to turn optimization off: tried gcc -O0 -o buff buff.c (that's oh-zero) and also gcc -O1 -fno-defer-pop -fno-thread-jumps -fno-branch-probabilities -fno-cprop-registers -fno-guess-branch-probability -fno-omit-frame-pointer -o buff buff.c neither worked.Electrolyze
Make the application exit inside the 'g()' function to avoid Segmentation fault =)Bruyn
sa125, maybe gcc tries to optimize to a different cpu architecture. As far as I know it defaults to the cpu of the system you're running. That can change how the stackframe of f() looks like and may prevent the overflow from happening.Obau
Nils - maybe I'm a little slow this morning -- but how is it that you're getting "now inside g()" to be printed -- I see where you're storing the pointers to g(), but I don't see in your example code where you're de-referencing the pointer(s) & invoking g()Swart
Dan, f() gets called from main, During the call the compiler will put the return address onto the stack, so f() knows where it has to jump to when it's done. However, inside f() I overwrite a large portion of the stack with the address of g(). Chances are that I override the return address as well. So when f() exits, it will not return to main but jump to g() instead. It's really dirty, but that's what the question was about.Obau
@Nils -- great explanation, totally understand it & now I recall that that was the point of the question... I was thinking "buffer overflow", which was already accomplished with the out-of-bounds array writes, but I forgot about the "accidental" invocation of g(). Thanks for taking the time to explain!Swart
A
8

Since this is homework, I would like to echo codeaddict's suggestion of understanding how a buffer overflow actually works.

I learned the technique by reading the excellent (if a bit dated) article/tutorial on exploiting buffer overflow vulnerabilities Smashing The Stack For Fun And Profit.

Albata answered 25/2, 2010 at 15:7 Comment(0)
C
4

Try this one:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[-1]=&g;
}

or this one:

void f()
{   
    void *x[1];
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)
    x[1]=&g;
}
Coker answered 25/2, 2010 at 12:30 Comment(1)
x is a local variable, so it located on the stack. Since x is an array of size 1, only x[0] is valid. By writing the address of g in x[-1] or x[1], there is a chance that we will overwrite the return address. It depends of the organisation of the stack which version works.Coker
A
4

While this solution doesn't use an overflow technique to overwrite the function's return address on the stack, it still causes g() to get called from f() on its way back to main() by only modifying f() and not calling g() directly.

Function epilogue-like inline assembly is added to f() to modify the value of the return address on the stack so that f() will return through g().

#include <stdio.h>

void g()
{
    printf("now inside g()!\n");
}

void f()
{   
    printf("now inside f()!\n");
    // can only modify this section
    // cant call g(), maybe use g (pointer to function)

    /* x86 function epilogue-like inline assembly */
    /* Causes f() to return to g() on its way back to main() */
    asm(
        "mov %%ebp,%%esp;"
        "pop %%ebp;"
        "push %0;"
        "ret"
        : /* no output registers */
        : "r" (&g)
        : "%ebp", "%esp"
       );
}

int main (int argc, char *argv[])
{
    f();
    return 0;
}

Understanding how this code works can lead to a better understanding of how a function's stack frame is setup for a particular architecture which forms the basis of buffer overflow techniques.

Albata answered 18/6, 2010 at 20:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.