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?