Reputation: 111
I have a return value in my previous stack frame that points towards a buffer in my subsequent stack frame. How can I get machine instructions, placed in the buffer, to execute?
Is this even possible? From what I understand about the stack this is nonsensical. Since, of course, the stack is a last in-first out structure. In other words once the PC reaches the return address, the buffer will have already been popped off.
Any ideas?
the <test>
function (below) calls the <getbuf>
function (also below):
08048c53 <test>:
8048c53: 55 push %ebp
8048c54: 89 e5 mov %esp,%ebp
8048c56: 83 ec 28 sub $0x28,%esp
8048c59: e8 63 04 00 00 call 80490c1 <uniqueval>
8048c5e: 89 45 f0 mov %eax,-0x10(%ebp)
8048c61: e8 5f 00 00 00 call 8048cc5 <getbuf>
8048c66: 89 45 f4 mov %eax,-0xc(%ebp)
8048c69: e8 53 04 00 00 call 80490c1 <uniqueval>
8048c6e: 8b 55 f0 mov -0x10(%ebp),%edx
8048c71: 39 d0 cmp %edx,%eax
8048c73: 74 0e je 8048c83 <test+0x30>
8048c75: c7 04 24 f0 a3 04 08 movl $0x804a3f0,(%esp)
8048c7c: e8 9f fc ff ff call 8048920 <puts@plt>
8048c81: eb 40 jmp 8048cc3 <test+0x70>
8048c83: 8b 55 f4 mov -0xc(%ebp),%edx
8048c86: a1 20 e1 04 08 mov 0x804e120,%eax
8048c8b: 39 c2 cmp %eax,%edx
8048c8d: 75 21 jne 8048cb0 <test+0x5d>
8048c8f: 8b 45 f4 mov -0xc(%ebp),%eax
8048c92: 89 44 24 04 mov %eax,0x4(%esp)
8048c96: c7 04 24 19 a4 04 08 movl $0x804a419,(%esp)
8048c9d: e8 ae fb ff ff call 8048850 <printf@plt>
8048ca2: c7 04 24 03 00 00 00 movl $0x3,(%esp)
8048ca9: e8 a0 07 00 00 call 804944e <validate>
8048cae: eb 13 jmp 8048cc3 <test+0x70>
8048cb0: 8b 45 f4 mov -0xc(%ebp),%eax
8048cb3: 89 44 24 04 mov %eax,0x4(%esp)
8048cb7: c7 04 24 36 a4 04 08 movl $0x804a436,(%esp)
8048cbe: e8 8d fb ff ff call 8048850 <printf@plt>
8048cc3: c9 leave
8048cc4: c3 ret
08048cc5 <getbuf>:
8048cc5: 55 push %ebp
8048cc6: 89 e5 mov %esp,%ebp
8048cc8: 83 ec 38 sub $0x38,%esp
8048ccb: 8d 45 d8 lea -0x28(%ebp),%eax
8048cce: 89 04 24 mov %eax,(%esp)
8048cd1: e8 32 01 00 00 call 8048e08 <Gets>
8048cd6: b8 01 00 00 00 mov $0x1,%eax
8048cdb: c9 leave
8048cdc: c3 ret
Upvotes: 3
Views: 196
Reputation: 12610
Is this even possible?
Not if the Data Execution Prevention is in action.
the buffer will have already been popped off
POP
/RET
does not alter any data on the stack. It only changes the stack pointer SP
while the data remains where it was until replaced by a PUSH
or CALL
.
That's why bugs like
int* foo() {
int i = 123;
return &i;
}
may seem to work for a while before the error shows. The data is still there for an indeterminate time before it's location on the stack actually gets overwritten.
Upvotes: 3
Reputation: 13073
Yes it was possible pre Data Execution Prevention.
A piece of code would fill out a buffer with more than it was expected, which would drift onto the stack. At that point, you have 2 mechanisms available.
1) wikipedia: return into libc
2) wikipedia: stack buffer overflow
Here you overwrite the stack with a set of calls into functions (usually pre-existing in the program). This allows you to build up further code, and execute what you are after.
This the overwrite modifies the saved frame pointer, or the return address on the stack. These are changed to the expected location of the function on the stack. This is somewhat hit-and-miss, so normally a buffer (nop-slide) will be added to increase reliability.
wikipedia : address space layout randomization makes this harder from outside the program, as you can't predict where important functions and data are.
Data execution and Address space layout randomization help mitigate these issues, as they are not normally desired. I would strongly recommend avoiding this form of dynamic programming, as it would be easy to exploit by some malicious entity.
Upvotes: 1