它壹般是由於編成人員的疏忽造成的。
具體的講,溢出漏洞是由於程序中的某個或某些輸入函數(使用者輸入參數)對所接收數據的邊界驗證不嚴密而造成。
根據程序執行中堆棧調用原理,程序對超出邊界的部分如果沒有經過驗證自動去掉,那麽超出邊界的部分就會覆蓋後面的存放程序指針的數據,當執行完上面的代碼,程序會自動調用指針所指向地址的命令。
根據這個原理,惡意使用者就可以構造出溢出程序。 其實溢出原理很簡單(我以前以為很難理解,太菜了,o(∩_∩)o…)。當然,這裏為了讓大家容易理解,會引用壹些程序實例(如果沒有編程基礎的,可以略過程序不看,影響不大,還是能理解的),而且說得會比較通俗和簡單,不會太深入。
從書上找來找去,終於找到壹個適合的程序(汗!要找符合的程序簡單啊,但是要找特級菜鳥覺得特別簡單的程序就不多了,55~~)。大家看看下面這段程序:
#include “stdafx.h”
#include “string.h”
#include “stdio.h”
char buf[255], pass[4]; /*聲明變量,讓計算機分配指定的內存*/
int main (int argc , char* argv[ ])
{
printf(“請輸入您的密碼:”); /*指定輸出的字符*/
scanf(%s ,buf); /*輸入壹個字符串,保存在變量buf中*/
strcpy(pass , buf); /*把字符串buf中的字符串復制到變量pass中*/
if (strcmp(pass,”wlqs”)= =0) /*比較輸入的字符串是否為密碼*/
printf (“輸入正確!”);
else printf(“輸入錯誤!);
return 0;
}
(註:“/*”中的中文是對程序的註解)
這是壹段密碼驗證程序,與我們平時輸入密碼壹樣,先讓用戶輸入密碼,然後在取得真正的密碼,與之對比,如果差異為0,則輸出密碼正確,否則輸出密碼錯誤。很多帳號登錄的程序都是這樣做的,看起來沒有非常合理,其實不然,它有壹個致命缺陷!這個漏洞很容易就看出來了。那就是它給數據申請了4個字節的儲存空間,但是萬壹用戶輸入的數據不只4個字節,那麽剩余的字節存放在哪裏?
先舉個例子,有壹條壹米長的木頭,有壹張紅色紙條從尾巴往頭貼,上面寫有字,然後又有壹張藍色紙條,上面也寫有字,要從木頭的頭往它的尾巴貼,但是貼了紅色紙條過後只剩4cm的長度,貼完後會有人讀出後面96cm的字,並且執行字條的命令,但是藍色紙條卻有10cm的長度,怎麽辦呢?只有把藍色紙條剩下的部分貼在紅色紙條上了。那麽紅色紙條的壹些字就被覆蓋了。但是那個人還是會去讀那後面96cm的字,所以他就只有讀錯,前面讀的都是藍色字條的字。先前去執行的是藍色字條後面6cm的命令。
當然大家看了這個例子也不是很懂,下面來註解壹下:
人——CPU
紅色字條上的字——CPU要執行的命令
4cm的長度——計算機為數據申請的內存空間
藍色字條上的字——要儲存的數據
可以看見藍色字條已經覆蓋了紅色字條上的字,然而那個人還是必須讀出後面96cm的字並執行。後面已經不是規定的命令了!他根本就不能執行,根本讀不懂!那麽他就不能執行了,並且報錯。
如圖系統只為我的密碼分配4個字節的內存,那麽我輸入的密碼是“714718366”循環了6次的,不只4個字節吧,其他剩下的字符將溢出!剩下的數字將占用內存空間,那麽系統執行命令的時候將會執行占用內存的數據,而不是執行原先寫好的命令了!這些數字系統根本就讀不懂,如何執行?那麽它只好報錯了!說此程序遇到問題需要關閉。那麽計算機上的程序將出錯而無法執行或關閉。
二、本地溢出
</B>上面所說的本地計算機因數據溢出而關閉程序或無法執行就叫做本地溢出。輸入超長的數據已經把計算機要執行的代碼覆蓋掉了,可是,計算機不會管指令有沒有被更改,依舊取原先存放指令的空間裏的數據來運行,取到“shujucuole!shujucuole!shujucuole!”這些不合法的溢出數據,它依舊會執行,可是在計算機裏這樣的指令是非法指令,也就是不符合計算機邏輯的指令,用戶執行它的時候就會出錯,於是程序就被強行關閉了。
題外話:(想來想去,還是說壹說o(∩_∩)o…我的愛好……損人利己的愛好)利用這樣的溢出漏洞可以關閉很多程序,比如各學校機房裏安裝的那些遠程教育系統,學生的計算機被教師的計算機所控制是因為學生機上安裝有壹個學生端程序,教師機可以通過教師端來對學生端進行遠程控制,學生端沒有推出功能,學生所在的用戶組也沒有強行結束進程的權限,檔學生不想被老師控制的時候,可以打開學生端自帶的遠程消息功能,在消息裏輸入很長的數據,比如幾百上千句“敢控制我!看我不宰了妳!”,然後發送,就可以令學生端程序出錯而被系統強行關閉。這招對某些網吧的收費系統也有用的!^_^
三、遠程溢出
再舉個列子(哎,這英文字母也太難打了,程序更難找,還翻了好幾本書呢!55~~):
#include “stdafx.h”
#include <winsock.h>
#pragma comment(lib ,”ws2_32”)
int main(int argc,char* argv[ ])
{
char buf[255]=” ”,pass[4]=” ”; //聲明變量,讓計算機分配內存
//================================================================
//這節的代碼功能是出示化網絡連接
//並偵聽1234端口等待連接
//沒有編程基礎的特級菜鳥可以略過不看
SOCKET sock1,sock2;
struct sockaddr_in addr1;
struct sockaddr_in addr2;
addr1 .sin_addr.s_addr=INADDR_ANY;
addr1 .sin_family=AF_INET;
addr1 .sin_port=htons(1234);
WSADATA * wsadatal=new WSADATA( );
WSAStartup(MAKEWORD(2,2),wsadatal1);
sock1=socket(AF_INET,SOCK_STREAM,0);
bind(sock1,(sockaddr *)&addr1,sizeof(struct sockaddr) );
listen(sock1,10);
int iSin=sizeof(struct sockaddr_in);
//=================================================================
if(sock2=accept(sock1,(sockaddr *)&addr2,&iSin)
{//有用戶連接進來
send(sock2,“請輸入密碼,密碼正確,則告訴妳我的qq:”,36,0);
//發送提示用戶輸入密碼
if (recv(sock2,buf,255,0))
{//接受用戶發送過來的數據並保存在緩沖buf變量裏
strcpy (pass,buf);//把緩沖buf變量裏的數據復制到pass變量中
if(strcmp(pass,”wlqs”= =0)
//比較pass變量裏的數據跟“wlqs”字符串之間的差異是否為0
{//差異為0,則說明兩者相等,密碼正確
send(sock2,”714718366”,9,0);//發送QQ號給用戶
}
else
{//否則就說明密碼錯誤
send (sock2,”密碼錯誤!”,10,0);
}
}
}
//=================[/ft]關閉網絡連接並退出=======================
closesocket(sock2);
closesocket(sock1);
return 0;
}
(可把我打死了!這麽長的字母啊!我最討厭打英文了!和寫簡直是兩回事*_*)
這是壹個服務器程序,當有用戶連接的時候,它會先發送壹句話,提示用戶輸入登錄密碼。其實它和前面說的本地溢出例子形似,問題也就處在把數據從緩存復制刀內存的那句代碼裏,如果遠程用戶輸入的密碼太長,那麽同樣出現溢出的現象。那麽程序就會出錯,服務端將被強行關閉。
舉個例子,比如騰訊公司的即時通訊軟件服務端程序就曾被黑客不停地攻擊導致服務端崩潰,不能正常提供服務,只是很多用戶都不能登陸,及時登陸成功也會在幾分鐘之內再次掉線,就是因為他們的服務端有這樣的漏洞存在,被別人利用了,這給他們以及他們的客戶造成了不可估計的損失。