Hi,
I`am experimenting with shellcode and stumbled upon the nop-slide technique. I wrote a little tool that takes buffer-size as a parameter and constructs a buffer like this: [ NOP | SC | RET ], with NOP taking half of the buffer, followed by the shellcode and the rest filled with the (guessed) return address. Its very similar to the tool aleph1 described in his famous paper.
My vulnerable test-app is the same as in his paper:
int main(int argc, char **argv) {
char little_array[512];
if(argc>1)
strcpy(little_array,argv[1]);
return 0;
}
I tested it and well, it works:
jth@insecure:~/no_nx_no_aslr$ ./victim $(./exploit 604 0)
$ exit
But honestly, I have no idea why. Okay, the saved eip was overwritten as intended, but instead of jumping somewhere into the buffer, it jumped into argv, I think.
gdb showed up the following addresses before strcpy() was called:
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x80483ed in main (victim.c:7); saved eip 0x154b56
source language c.
Arglist at 0xbffff1e8, args: argc=2, argv=0xbffff294
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
Address of little_array:
(gdb) print &little_array[0]
$1 = 0xbfffefe8 "\020"
After strcpy():
(gdb) i f
Stack level 0, frame at 0xbffff1f0:
eip = 0x804840d in main (victim.c:10); saved eip 0xbffff458
source language c.
Arglist at 0xbffff1e8, args: argc=-1073744808, argv=0xbffff458
Locals at 0xbffff1e8, Previous frame's sp is 0xbffff1f0
Saved registers:
ebp at 0xbffff1e8, eip at 0xbffff1ec
So, what happened here? I used a 604 byte buffer to overflow little_array, so he certainly overwrote saved ebp, saved eip and argc and also argv with the guessed address 0xbffff458.
Then, after returning, EIP pointed at 0xbffff458. But little_buffer resides at 0xbfffefe8, that`s a difference of 1136 byte, so he certainly isn't executing little_array. I followed execution with the stepi command and well, at 0xbffff458 and onwards, he executes NOPs and reaches the shellcode.
I'am not quite sure why this is happening. First of all, am I correct that he executes my shellcode in argv, not little_array? And where does the loader(?) place argv onto the stack? I thought it follows immediately after argc, but between argc and 0xbffff458, there is a gap of 620 bytes. How is it possible that he successfully "lands" in the NOP-Pad at Address 0xbffff458, which is way above the saved eip at 0xbffff1ec?
Can someone clarify this? I have actually no idea why this is working. My test-machine is an Ubuntu 9.10 32-Bit Machine without ASLR. victim has an executable stack, set with execstack -s.
Thanks in advance.