I am working through the Stack buffer overflows on Protostar and my end goal is to get a better understanding of what is happening. I am on exercise 4 (https://exploit.education/protostar/stack-four/). I got my buffer overflow to execute the function desired but I can only do it in gdb. The reason I can only do it in gdb is because the second word after the end of the buffer I am exploiting holds the memory address of argc. If that second word gets overwritten then the function call will not work. I compiled with the -fno-stack-protector option.
In gdb I ran:
run <<< (echo -e "$(python -c "print('h'*64)")aaaa\xa0\xf0\xff\xbfaaaaaaaaaaaaaaaaaaaa\x3b\x84\x04\x08\x37\x16\xe2\xb7")
the 64 h's filled the buffer, the first four a's just overflowed a word, the next four bytes are the address of argc, next 5 words (20 a's) are just overflowing. Then I put the address of win (the function I want to call) and then the old return address to exit without a segfault.
When I run this in gdb I call the win function and the process exits. When I run this outside of gdb I get a segfault. I thought maybe the environment variables being different caused this but that is not the case I changed the environment variables in gdb to match exactly what I have outside of gdb and it still does not work.
the 7 words after the end of the buffer and before the return address are: 1: 0xb7fbb300 - Unknown 2: 0xbffff0a0 - address of argc 3: 0x00000000 - null 4: 0xb7e21637 - Return address but not the actual one that matters. (not sure why there are two) 5: 0xb7fbb000 - Unknown 6: 0xb7fbb000 - Unknown 7: 0x00000000 - Unknown
So my questions are why does this only work in gdb? and what is the significance of the address of argc to preventing a segfault? Also why do I see the return address twice? Once at the 4th word after the buffer and again at the 8th word after the buffer.