I have been playing with some wargames and I ported some of then on my Linux machine as well. I noticed that when not using -mpreferred-stack-boundary=2, gcc might compile "main" with an interesting prologue/epilogue: effectively "relying on $ecx (which relies on $ebp-4) for $esp value before ret". Has anyone else come across this observation?
This means you can not overwrite normal ret address staying at $ebp+4, but instead you have to overwrite $ebp-4 (that is ecx) and reposition the stack pointer and your return address (effectively using a stack pivot) to further the exploitation.
Kindly find an example code and related assembly below:
$ cat stack4.c /* stack4-stdin.c * * specially crafted to feed your brain by gera */ #include <stdio.h> int main() { int cookie; char buf[80]; printf("buf: %08x cookie: %08x\n", &buf, &cookie); gets(buf); if (cookie == 0x000d0a00) printf("you win!\n"); } $ objdump -D ./stack4_normal | grep -A31 main.: 0804845b <main>: 804845b: 8d 4c 24 04 lea 0x4(%esp),%ecx 804845f: 83 e4 f0 and $0xfffffff0,%esp 8048462: ff 71 fc pushl -0x4(%ecx) 8048465: 55 push %ebp 8048466: 89 e5 mov %esp,%ebp 8048468: 51 push %ecx 8048469: 83 ec 64 sub $0x64,%esp 804846c: 83 ec 04 sub $0x4,%esp 804846f: 8d 45 f4 lea -0xc(%ebp),%eax 8048472: 50 push %eax 8048473: 8d 45 a4 lea -0x5c(%ebp),%eax 8048476: 50 push %eax 8048477: 68 50 85 04 08 push $0x8048550 804847c: e8 8f fe ff ff call 8048310 <printf@plt> 8048481: 83 c4 10 add $0x10,%esp 8048484: 83 ec 0c sub $0xc,%esp 8048487: 8d 45 a4 lea -0x5c(%ebp),%eax 804848a: 50 push %eax 804848b: e8 90 fe ff ff call 8048320 <gets@plt> 8048490: 83 c4 10 add $0x10,%esp 8048493: 8b 45 f4 mov -0xc(%ebp),%eax 8048496: 3d 00 0a 0d 00 cmp $0xd0a00,%eax 804849b: 75 10 jne 80484ad <main+0x52> 804849d: 83 ec 0c sub $0xc,%esp 80484a0: 68 68 85 04 08 push $0x8048568 80484a5: e8 86 fe ff ff call 8048330 <puts@plt> 80484aa: 83 c4 10 add $0x10,%esp 80484ad: 8b 4d fc mov -0x4(%ebp),%ecx 80484b0: c9 leave 80484b1: 8d 61 fc lea -0x4(%ecx),%esp 80484b4: c3 ret
I have found several StackExchange topics and explanation about why this happens. Nevertheless, I am looking for a guide/tutorial that specifically deals with the exploitation part. Perhaps someone smarter than me has standardised this exploitation in a much better way than I do.
It seems that most people, in tutorials, just use -mpreferred-stack-boundary=2 to avoid this problem and continue normally with the exploitation tutorial.
I find it hard to believe that no-one has mentioned this in a tutorial as new versions of gcc compile like this by default (at least at my machine).
In any case, the question is:
Is this the optimal way to exploit this (using a stack pivot)?
If no, can someone please point me to a tutorial or explanation of a better way?