There are a few points to note:
1. The strcpy function stops copying stuff into the destination buffer as soon as it encounters a NULL byte. A NULL byte is 0x00 or \x00. In 64-bit machines, the length of an address is 8 bytes. Let us consider pop_rdi_ret = 0x00000000004005cb. This has NULL bytes. So, as soon as strcpy encounters the first NULL byte(the NULL byte next to 0x40), it stops copying. So, the exploit payload is not being injected properly because of NULL bytes.
2. I hope you have compiled your vulnerable program without StackGaurd or the Stack Cookie protection. If that is there, it will kill the program when it detects a stack smash. You can use the -fno-stack-protector compiler flag to compile without StackGaurd.
3. I don't know why you are injecting NOPs into the buffer. There is no harm in doing it, but there is no use either because W XOR X is enabled.
And, please can anyone help me little to understand the concept of ROP stack frame in 64 bit, I mean 32 bit ROP stack frame is simple to understand as compared to 64 bit and available content on the internet about the 64 bit ROP didn't help me.
When it comes to ROP, there is no difference between 32-bit ROP and 64-bit ROP. That is because in both cases, the ROP Gadgets are chained.
If you are talking about ReturnToLibc, there are differences. ReturnToLibc is the fancy name given what you are doing in the above exploit. You are returning to a libc function to get god access.
The root cause of this difference is the way functions are called. The function calling mechanism in 32-bit and 64-bit processes are different. In 32-bit, arguments are passed to the callee function using the stack. But in 64-bit, the first 6 arguments are passed using registers and if there are any more arguments, stack is used.
Because we are calling functions here, the exploits for 32-bit and 64-bit will be different. As you righty mentioned, ReturnToLibc exploit for 64-bit is more or less ROP because you will have to find gadgets which will load stuff into rdi, rsi, rdx etc., . If you don't find the right gadgets, you will have to chain them.
Because of that, I am also confused about creating stack frame via ROP for mprotect call for my another exploit code.
Let me help you out with this.
Take a look at the manpage of mprotect.
MPROTECT(2) Linux Programmer's Manual MPROTECT(2)
mprotect - set protection on a region of memory
int mprotect(void *addr, size_t len, int prot);
Let us first create the fake stackframe for 32-bit.
Suppose you want to make the stack address space executable.
Let addr = 0xf1f2f3f4, size = 1000, prot = PROT_EXEC | PROT_WRITE | PROT_READ .
The values of PROT_READ = 1, PROT_WRITE = 2, PROT_EXEC = 4. Referring to this sourcefile.
So, PROT_READ | PROT_WRITE | PROT_EXEC = 7.
The strategy is this:
a. Overwrite the vulnerable function's returnaddress with mprotect's address. When the ret instruction is executed, control is transfered to mprotect function and stack is popped. For mprotect, the stack before ret instruction is executed should look like this:
<mprotect's Address> // This is vulnerable function's return address
<mprotect's Return Address> // This can be exit libc function
<prot = 0x00000007>
<len = 1000>
<addr = 0xf1f2f3f4>
So, there you go. you have the stackframe you wanted.
To exploit a 64-bit vulnerable function, we have to pass arguments through registers. This is not as easy as it was for the 32-bit exploit. This is what we need.
rdi = Stack's address = 0x00007ffff7123456 // just an example
rsi = 1000
rdx = 0x7
Now, we have to find gadgets which directly does this or have to find gadgets and chain them. This is where it gets a bit hard. Writing ROP chains by hand is time taking. You can try out ROPGadget or any other ROP tool out there.
Assuming you get the proper mov gadgets, I will continue my answer.
0x400123: mov rdi, 0x00007ffff7123456; ret
0x401234: mov rsi, 1000; ret
0x412345: mov rdx, 0x7; ret
The plan is, these 3 should get executed in a row and then mprotect should get executed. So, the stack should look something like this before the vulnerable function's ret is executed.
<0x400123> // This is originally vulnerable function's return address
<mprotect's return address>
In reality, the stack might be way more complex than this. This is just an example.
I hope you see the difference between the stack of a 32-bit exploit and a 64-bit exploit.
If anything is not clear, leave a comment below.