SEED實驗——return-to-libc實驗


實驗概述

本實驗的學習目標是讓學生獲得緩沖區溢出攻擊的一種有趣變體——return-to-libc攻擊實驗的親身體驗。這種攻擊可以繞過目前在主要linux操作系統中實現的現有保護方案。利用緩沖區溢出漏洞通常的方法是使緩沖區溢出,然后在溢出部分的返回地址指向一段惡意的shellcode,使程序跳轉到存儲在堆棧中的shellcode。為了防止這些類型的攻擊,一些操作系統允許管理員關閉堆棧的可執行功能。因此跳轉到shellcode將導致程序失敗。不幸的是,上述保護機制不是足夠安全的。存在一種成為return-to-libc攻擊的緩沖區溢出攻擊的變體,其不需要可執行堆棧,甚至不需要shellcode。相反,它會導致受到攻擊的程序跳轉到一些現有的代碼。例如已經加載到內存中的libc庫中的system()函數。在這個實驗中,學生被給予一個包含緩沖區溢出漏洞的程序,他們的任務是利用該漏洞,開發一個返回到libc庫函數的攻擊,最終獲得root權限。除了這些攻擊之外,學生們還將參與學習在ubuntu中實施的防止緩沖區溢出攻擊的幾項保護措施。學生需要評估方案是否有效,並解釋評估過程。


 

第二部分:實驗任務

該實驗共有三個任務:

  • 漏洞利用
  • 地址隨機化
  • StackGuard保護機制

任務一:漏洞利用

1.編譯代碼是關閉地址隨機化機制和非執行棧機制

sudo sysctl -w kernel.randomize_va_space=0         //注意:這里等號和0之間不能有空格

   在進行代碼編譯時,加上-fno-stack-protector,即可關閉ubuntu上StackGuard保護機制,加上-z -execstack/noexecstack即可打開或關閉可執行棧的機制。

  在本實驗中,我們按照如下命令編譯含有緩沖區溢出漏洞的代碼段:

   su root

   gcc -fno-stack-protector -z noexecstack -o retlib retlib.c

   chmod 4755 retlib  /  chmod u+s retlib

   exit

  

2.獲取/bin/sh地址

  為了獲取/bin/sh的內存地址,需要編寫一個程序。

//getenvaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char const *argv[])
{
    char *ptr;
    if(argc<3)
    {
        printf("Usage: %s <environment var> <target program name>\n", argv[10]);
        exit(0);
     }
    ptr = getenv(argv[1]);
    ptr += (strlen(argv[0]) - strlen(argv[2])) * 2 ;
    printf("%s will be at %p \n", argv[1], ptr ) ;
    return 0;
}

  其中,getenv的參數為一個環境變量,因此我們需要創建一個環境變量來記錄路徑export BIN_SH="/bin/sh"。調用程序./getenvaddr BIN_SH ./retlib得到/bin/sh的地址。

如上面截圖所示,/bin/sh的地址為:0xbffffe39。

3. 獲取system()和exit()地址

  這兩個程序是駐留在內核態的,所有程序共享內核態的函數,因此我們可以用gdb來獲取這兩個程序的地址。

如上圖所示,在main函數設置斷點,然后運行,運用gdb調試命令,我們可以得到system()函數的地址是0xb7e5f430,exit()函數的地址是0xb7e52fb0。

將上述獲得的三個地址寫到代碼中,


 

第三部分:

實驗指導:了解函數調用機制

3.1 獲取libc庫函數的地址

用gdb命令進行獲取。

3.2 將shell字符串放在內存中

本實驗的一個挑戰是將字符串“/bin/sh”放入內存中,並獲取其地址。這可以使用環境變量來實現。執行C程序時,它會繼承執行它的shell的所有環境變量。環境變量SHELL直接指向/bin/bash並且環境變量同時也被其他程序需要。所以我們引入一個新的shell變量MYSHELL,並指向zsh。

$ export MYSHELL = /bin/sh

我們將使用該變量的地址作為system()函數調用的參數。這個變量的位置在內存中使用以下代碼就可以發現:

 

void main()
{
    char 8shell = getenv("MYSHELL");
    if(shell)
    prinf("%x\n",(unsigned int)shell);
}

如果地址隨機化被關閉,將會發現打印出的地址是相同的。然而,當您運行漏洞程序retlib時,環境變量的地址可能與通過運行上述程序獲得的地址完全相同。當您更改程序名稱時,這樣的地址甚至會更改(文件名中的字符數不一樣)。好消息是,shell的地址將與上述程序打印出來的地址相當接近。因此,您可能喲啊嘗試幾次才能成功。

3.3 理解棧

要知道如何進行return-to-libc攻擊,必須了解堆棧的工作原理。我們使用一個小程序來了解函數調用對堆棧的影響。

/* foobar.c */
#include <stdio.h>
void foo(int x)
{
  printf("Hello world: %d\n", x);
}
int main()
{
  foo(1);
  return(0);
}

我們可以用“gcc -S foobar.c”來將程序編譯成匯編代碼。

 


免責聲明!

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



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