I'm currently writing a shellcode that exploit a target program that uses the puts
function. The program looks like this:
#include <stdio.h>
main() {
char buf[123];
puts(gets(buf));
}
What I want to do is overflow this buffer and invoke execve
with some arguments. I have a test program that's written in c/inline assembly that can invoke execve
with some arguments, then I use gdb
to get the shellcode from this program. From my understanding, the stack layout looks like this:
|-------buffer(+padding)---------|---------sfp---------|-------ret-------------|
By looking at part of the assembly code of the target program generated by gcc:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
addq $-128, %rsp
leaq -128(%rbp), %rax
movq %rax, %rdi
call gets
movq %rax, %rdi
call puts
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
I think buffer and padding take up 128 bytes, and sfp and return address each takes 8 bytes, so that's 144 bytes in total. Based on this, my nop sled ,payload and new return address(equals to the address of the buffer) combined(that is, my shellcode) should be 144 bytes too. For example, if my payload is 36 bytes, since the return address takes up 8 byte, my nop sled will be 100 bytes. But when I did it that way it didn't work. So I think maybe the way I understood the stack layout was wrong. Is it wrong?
Notice in my case the buffer address was known and the stack was set as executable by using execstack
and ASLR was turned off by using setarch
. So if the return address was overwritten by the address of the buffer, the code written in that buffer will run.
And I'm working on a x86 64bit machine.
If my understanding of the stack layout is right, I'll put on more information about my shellcode.