天天看點

雪城大學資訊安全講義 4.5

5 堆或 BSS 的緩沖區溢出

  • 堆或 BSS 的内容
    • 字元串常量
    • 全局變量
    • 靜态變量
    • 動态配置設定的記憶體
  • 示例:覆寫檔案指針
    /* The following variables are stored in the BSS region */ 
    static char buf[BUFSIZE], *tmpfile;
    
    tmpfile = "/tmp/vulprog.tmp"; 
    gets(buf); /* buffer overflow can happen here */
    
    ... Open tmpfile, and write to it ...           
    • Set-UID 程式的檔案指針指向了

      /tmp/vulprog.tmp

    • 程式需要在執行期間,使用使用者輸入寫入檔案、
    • 如果我們可以使檔案指針指向

      /etc/shadow

      ,我們就可以使程式寫入它。
    • 我們可以使用緩沖區溢出來改變變量

      tmpfile

      的記憶體。通常,它指向了

      /tmp/vluprog.tmp

      字元串。使用緩沖區溢出漏洞,我們就可以将

      tmpfile

      的内容修改為

      0x903040

      ,它就是字元串

      /etc/shadow

      的位址。之後,當程式使用

      tmpfile

      變量打開檔案來寫入時,它實際上打開了

      shadow

      檔案。
    • 如何尋找

      /etc/shadow

      • 我們可将字元串作為參數傳入程式,這樣字元串

        /etc/shadow

        就儲存在記憶體中。我們現在需要猜測它在哪裡。
  • 示例:覆寫函數指針:
    int main(int argc, char **argv) { 
        static char buf[16]; /* in BSS */ 
        static int (*funcptr)(const char *str); /* in BSS */
    
        funcptr = (int (*)(const char *str))goodfunc;
    
        /* We can cause buffer overflow here */ 
        strncpy(buf, argv[1], strlen(argv[1]));
    
        (void)(*funcptr)(argv[2]); 
        return 0;
    }
    /* This is what funcptr would point to if we didn’t overflow it */ 
    int goodfunc(const char *str) { 
        ... ... 
    }           
    • 函數指針(例如

      int (*funcptr)(char *str)

      )允許程式員動态修改被調用的函數。我們可以通過覆寫它的位址來覆寫函數指針,使之在執行時,它調用我們指向的函數。
    • argv[]

      方式:将 Shellcode 儲存在程式的參數中。這會使 Shellcode 儲存在棧上。之後我們需要猜測它的位址(就像我們在棧溢出中那樣)。這個方式需要可執行的棧。
    • 堆方式:将 Shellcode 儲存在堆或 BSS 中(通過使用溢出)。之後我們需要猜測它的位址,并将估算的位址賦給函數指針。這個方式需要可執行的堆(比可執行的棧機率更大)。
  • 函數指針
    • 函數指針可以通過多種手段儲存在堆或 BSS 中。這不需要由程式員定義。
    • 如果程式調用了

      atexit

      ,函數指針就會由

      atexit

      儲存在堆上,并且會在程式終止前調用。
    • svc/rpc

      注冊函數(

      librpc

      ,

      libnsl

      以及其他)将回調函數儲存在堆上。
  • 其它示例
    • BSDI

      crontab

      基于堆的溢出:長檔案名的傳遞會溢出靜态緩沖區。在記憶體中的緩沖區上面,我們擁有

      pwd

      結構,它儲存使用者名、密碼、UID、GID,以及其他。通過覆寫

      pwd

      的 UID/GID 字段,我們可以修改權限,使

      crond

      使用它執行我們的

      crontab

      (隻要他嘗試執行我們的

      crontab

      )。這個腳本之後可以産生 Suid Root Shell,因為我們的腳本會使用 UID/GID 0 來執行。

參考

  1. P. J. Salzman. Memory Layout And The Stack. In Book Using GNU’s GDB Debugger. URL: http://dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php .

繼續閱讀