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
- 我們可将字元串作為參數傳入程式,這樣字元串
- Set-UID 程式的檔案指針指向了
- 示例:覆寫函數指針:
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)
-
方式:将 Shellcode 儲存在程式的參數中。這會使 Shellcode 儲存在棧上。之後我們需要猜測它的位址(就像我們在棧溢出中那樣)。這個方式需要可執行的棧。argv[]
- 堆方式:将 Shellcode 儲存在堆或 BSS 中(通過使用溢出)。之後我們需要猜測它的位址,并将估算的位址賦給函數指針。這個方式需要可執行的堆(比可執行的棧機率更大)。
- 函數指針(例如
- 函數指針
- 函數指針可以通過多種手段儲存在堆或 BSS 中。這不需要由程式員定義。
- 如果程式調用了
,函數指針就會由atexit
儲存在堆上,并且會在程式終止前調用。atexit
-
注冊函數(svc/rpc
,librpc
以及其他)将回調函數儲存在堆上。libnsl
- 其它示例
- BSDI
基于堆的溢出:長檔案名的傳遞會溢出靜态緩沖區。在記憶體中的緩沖區上面,我們擁有crontab
結構,它儲存使用者名、密碼、UID、GID,以及其他。通過覆寫pwd
的 UID/GID 字段,我們可以修改權限,使pwd
使用它執行我們的crond
(隻要他嘗試執行我們的crontab
)。這個腳本之後可以産生 Suid Root Shell,因為我們的腳本會使用 UID/GID 0 來執行。crontab
- BSDI
參考
- 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 .